From c0134e2de24fb1d1d420bb7cf9d1385e658c7729 Mon Sep 17 00:00:00 2001 From: Felix H Date: Fri, 19 Sep 2025 13:43:55 +0000 Subject: [PATCH 01/16] split comments across multiple lines when necessary --- .github/scripts/generate_eip_report.py | 5 +- pyproject.toml | 2 +- src/cli/check_fixtures.py | 20 +- src/cli/compare_fixtures.py | 14 +- src/cli/eest/commands/clean.py | 26 +- src/cli/eest/make/cli.py | 13 +- src/cli/eest/make/commands/__init__.py | 4 +- src/cli/eest/make/commands/test.py | 35 +- src/cli/eest/quotes.py | 5 +- src/cli/eofwrap.py | 42 +- src/cli/evm_bytes.py | 50 +- src/cli/extract_config.py | 16 +- src/cli/fillerconvert/fillerconvert.py | 12 +- src/cli/fillerconvert/verify_filled.py | 10 +- src/cli/gen_index.py | 12 +- src/cli/generate_checklist_stubs.py | 9 +- src/cli/gentest/request_manager.py | 14 +- src/cli/gentest/source_code_generator.py | 30 +- src/cli/gentest/test_context_providers.py | 20 +- src/cli/gentest/test_providers.py | 28 +- src/cli/gentest/tests/test_cli.py | 8 +- src/cli/hasher.py | 5 +- src/cli/input/input_repository.py | 4 +- src/cli/input/questionary_input_repository.py | 5 +- src/cli/modify_static_test_gas_limits.py | 12 +- src/cli/order_fixtures.py | 53 +- src/cli/pytest_commands/base.py | 20 +- src/cli/pytest_commands/fill.py | 25 +- src/cli/pytest_commands/processors.py | 11 +- src/cli/show_pre_alloc_group_stats.py | 42 +- src/cli/tests/test_evm_bytes.py | 26 +- src/cli/tests/test_generate_all_formats.py | 24 +- src/cli/tests/test_order_fixtures.py | 4 +- src/cli/tests/test_pytest_fill_command.py | 27 +- src/cli/tox_helpers.py | 19 +- src/config/docs.py | 6 +- src/config/env.py | 24 +- src/conftest.py | 6 +- src/ethereum_clis/__init__.py | 5 +- src/ethereum_clis/cli_types.py | 8 +- src/ethereum_clis/clis/ethereumjs.py | 8 +- src/ethereum_clis/clis/ethrex.py | 3 +- src/ethereum_clis/clis/evmone.py | 11 +- src/ethereum_clis/clis/execution_specs.py | 31 +- src/ethereum_clis/clis/geth.py | 24 +- src/ethereum_clis/clis/nethermind.py | 35 +- src/ethereum_clis/clis/nimbus.py | 7 +- src/ethereum_clis/ethereum_cli.py | 41 +- src/ethereum_clis/fixture_consumer_tool.py | 4 +- .../tests/test_execution_specs.py | 19 +- .../tests/test_transition_tools_support.py | 4 +- src/ethereum_clis/transition_tool.py | 58 +- src/ethereum_test_base_types/base_types.py | 45 +- .../composite_types.py | 105 +- src/ethereum_test_base_types/conversions.py | 12 +- src/ethereum_test_base_types/mixins.py | 55 +- src/ethereum_test_base_types/pydantic.py | 8 +- .../reference_spec/reference_spec.py | 25 +- src/ethereum_test_base_types/serialization.py | 25 +- src/ethereum_test_checklists/eip_checklist.py | 85 +- .../eip_checklist.pyi | 3 +- .../test_checklist_template_consistency.py | 21 +- .../exception_mapper.py | 56 +- src/ethereum_test_exceptions/exceptions.py | 746 +- .../exceptions/base.py | 10 +- .../exceptions/block.py | 243 +- .../exceptions/eof.py | 211 +- .../exceptions/transaction.py | 295 +- .../tests/test_exceptions.py | 5 +- src/ethereum_test_execution/base.py | 8 +- .../blob_transaction.py | 13 +- .../transaction_post.py | 4 +- src/ethereum_test_fixtures/base.py | 18 +- src/ethereum_test_fixtures/blockchain.py | 76 +- src/ethereum_test_fixtures/collector.py | 32 +- src/ethereum_test_fixtures/consume.py | 30 +- src/ethereum_test_fixtures/file.py | 19 +- .../pre_alloc_groups.py | 13 +- src/ethereum_test_fixtures/state.py | 4 +- .../tests/test_blockchain.py | 6 +- .../tests/test_state.py | 6 +- src/ethereum_test_forks/base_fork.py | 245 +- src/ethereum_test_forks/forks/forks.py | 241 +- src/ethereum_test_forks/helpers.py | 42 +- .../tests/test_fork_range_descriptor.py | 4 +- src/ethereum_test_forks/tests/test_forks.py | 28 +- .../transition_base_fork.py | 4 +- src/ethereum_test_rpc/__init__.py | 4 +- src/ethereum_test_rpc/rpc.py | 119 +- src/ethereum_test_rpc/rpc_types.py | 11 +- src/ethereum_test_rpc/tests/test_types.py | 4 +- src/ethereum_test_specs/base.py | 40 +- src/ethereum_test_specs/base_static.py | 101 +- src/ethereum_test_specs/blockchain.py | 234 +- src/ethereum_test_specs/eof.py | 235 +- src/ethereum_test_specs/helpers.py | 24 +- src/ethereum_test_specs/state.py | 55 +- .../static_state/account.py | 9 +- .../static_state/common/common.py | 47 +- .../static_state/common/compile_yul.py | 21 +- .../static_state/common/tags.py | 19 +- .../static_state/expect_section.py | 9 +- .../static_state/general_transaction.py | 4 +- .../static_state/state_static.py | 9 +- src/ethereum_test_specs/tests/test_expect.py | 21 +- .../tests/test_fixtures.py | 4 +- src/ethereum_test_specs/transaction.py | 4 +- src/ethereum_test_tools/tests/test_code.py | 8 +- .../tools_code/generators.py | 99 +- src/ethereum_test_tools/utility/generators.py | 121 +- src/ethereum_test_tools/utility/pytest.py | 113 +- .../utility/tests/test_pytest.py | 6 +- src/ethereum_test_tools/utility/versioning.py | 7 +- src/ethereum_test_types/account_types.py | 19 +- src/ethereum_test_types/blob_types.py | 65 +- .../block_access_list/__init__.py | 5 +- .../block_access_list/modifiers.py | 23 +- src/ethereum_test_types/block_types.py | 13 +- src/ethereum_test_types/chain_config_types.py | 3 +- src/ethereum_test_types/eof/constants.py | 27 +- src/ethereum_test_types/eof/v1/__init__.py | 293 +- src/ethereum_test_types/helpers.py | 20 +- src/ethereum_test_types/request_types.py | 57 +- .../tests/test_blob_types.py | 37 +- .../tests/test_block_access_lists.py | 7 +- src/ethereum_test_types/tests/test_eof_v1.py | 3 +- .../tests/test_post_alloc.py | 8 +- src/ethereum_test_types/transaction_types.py | 93 +- src/ethereum_test_types/trie.py | 37 +- src/ethereum_test_vm/bytecode.py | 76 +- src/ethereum_test_vm/evm_types.py | 4 +- src/ethereum_test_vm/opcodes.py | 7681 ++++++++--------- src/pytest_plugins/concurrency.py | 16 +- src/pytest_plugins/consume/consume.py | 64 +- src/pytest_plugins/consume/direct/conftest.py | 7 +- .../consume/direct/test_via_direct.py | 8 +- src/pytest_plugins/consume/releases.py | 33 +- src/pytest_plugins/consume/simulators/base.py | 19 +- .../consume/simulators/exceptions.py | 8 +- .../consume/simulators/helpers/exceptions.py | 14 +- .../consume/simulators/helpers/ruleset.py | 8 +- .../consume/simulators/helpers/timing.py | 4 +- .../consume/simulators/rlp/conftest.py | 11 +- .../simulator_logic/test_via_engine.py | 17 +- .../simulator_logic/test_via_rlp.py | 12 +- .../simulator_logic/test_via_sync.py | 52 +- .../consume/simulators/single_test_client.py | 18 +- .../consume/simulators/sync/conftest.py | 16 +- .../simulators/test_case_description.py | 36 +- .../consume/tests/test_consume_args.py | 24 +- .../tests/test_fixtures_source_input_types.py | 16 +- src/pytest_plugins/custom_logging/__init__.py | 5 +- .../custom_logging/plugin_logging.py | 76 +- src/pytest_plugins/execute/__init__.py | 5 +- .../execute/eth_config/eth_config.py | 30 +- .../execute/eth_config/execute_eth_config.py | 37 +- .../execute/eth_config/execute_types.py | 32 +- .../tests/test_execute_eth_config.py | 4 +- src/pytest_plugins/execute/execute.py | 58 +- src/pytest_plugins/execute/pre_alloc.py | 39 +- .../execute/rpc/chain_builder_eth_rpc.py | 70 +- src/pytest_plugins/execute/rpc/hive.py | 13 +- src/pytest_plugins/execute/rpc/remote.py | 13 +- src/pytest_plugins/execute/sender.py | 35 +- src/pytest_plugins/filler/eip_checklist.py | 12 +- src/pytest_plugins/filler/filler.py | 242 +- src/pytest_plugins/filler/fixture_output.py | 14 +- .../filler/gen_test_doc/gen_test_doc.py | 142 +- .../filler/gen_test_doc/page_props.py | 59 +- src/pytest_plugins/filler/ported_tests.py | 47 +- src/pytest_plugins/filler/pre_alloc.py | 67 +- src/pytest_plugins/filler/static_filler.py | 24 +- src/pytest_plugins/filler/tests/conftest.py | 7 +- .../filler/tests/test_benchmarking.py | 20 +- .../filler/tests/test_collect_only.py | 4 +- .../filler/tests/test_format_selector.py | 15 +- .../filler/tests/test_generate_all_formats.py | 25 +- .../filler/tests/test_output_directory.py | 36 +- .../filler/tests/test_phase_manager.py | 28 +- .../filler/tests/test_prealloc_group.py | 5 +- .../test_prealloc_group_usage_example.py | 23 +- .../tests/test_slow_marker_pre_alloc.py | 27 +- .../filler/tests/test_verify_sync_marker.py | 44 +- src/pytest_plugins/filler/witness.py | 32 +- src/pytest_plugins/fix_package_test_path.py | 9 +- src/pytest_plugins/forks/forks.py | 247 +- .../tests/test_bad_command_line_options.py | 14 +- .../forks/tests/test_bad_validity_markers.py | 15 +- .../tests/test_fork_parametrizer_types.py | 5 +- src/pytest_plugins/help/__init__.py | 4 +- src/pytest_plugins/help/help.py | 9 +- src/pytest_plugins/help/tests/test_help.py | 9 +- src/pytest_plugins/pytest_hive/pytest_hive.py | 65 +- src/pytest_plugins/shared/benchmarking.py | 10 +- src/pytest_plugins/shared/execute_fill.py | 41 +- src/pytest_plugins/shared/helpers.py | 8 +- .../shared/transaction_fixtures.py | 8 +- src/pytest_plugins/solc/solc.py | 3 +- .../spec_version_checker.py | 60 +- tests/amsterdam/__init__.py | 5 +- .../test_block_access_lists_invalid.py | 41 +- tests/benchmark/conftest.py | 5 +- tests/benchmark/helpers.py | 3 +- tests/benchmark/test_worst_blocks.py | 72 +- tests/benchmark/test_worst_bytecode.py | 150 +- tests/benchmark/test_worst_compute.py | 484 +- tests/benchmark/test_worst_memory.py | 57 +- .../benchmark/test_worst_stateful_opcodes.py | 88 +- .../eip2929_gas_cost_increases/__init__.py | 6 +- .../test_precompile_warming.py | 34 +- .../test_tx_intrinsic_gas.py | 9 +- .../eip198_modexp_precompile/helpers.py | 26 +- .../eip198_modexp_precompile/test_modexp.py | 32 +- tests/cancun/eip1153_tstore/__init__.py | 43 +- .../cancun/eip1153_tstore/test_tload_calls.py | 19 +- .../eip1153_tstore/test_tload_reentrancy.py | 12 +- tests/cancun/eip1153_tstore/test_tstorage.py | 53 +- .../test_tstorage_clear_after_tx.py | 19 +- .../test_tstorage_create_contexts.py | 58 +- .../test_tstorage_execution_contexts.py | 28 +- .../test_tstorage_reentrancy_contexts.py | 103 +- .../test_tstorage_selfdestruct.py | 25 +- .../eip1153_tstore/test_tstore_reentrancy.py | 39 +- tests/cancun/eip4788_beacon_root/conftest.py | 22 +- .../test_beacon_root_contract.py | 159 +- tests/cancun/eip4844_blobs/conftest.py | 58 +- tests/cancun/eip4844_blobs/spec.py | 35 +- tests/cancun/eip4844_blobs/test_blob_txs.py | 242 +- .../eip4844_blobs/test_blob_txs_full.py | 23 +- .../eip4844_blobs/test_blobhash_opcode.py | 59 +- .../test_blobhash_opcode_contexts.py | 54 +- .../eip4844_blobs/test_excess_blob_gas.py | 107 +- .../test_excess_blob_gas_fork_transition.py | 42 +- .../test_point_evaluation_precompile.py | 98 +- .../test_point_evaluation_precompile_gas.py | 26 +- tests/cancun/eip5656_mcopy/common.py | 9 +- tests/cancun/eip5656_mcopy/test_mcopy.py | 31 +- .../eip5656_mcopy/test_mcopy_contexts.py | 35 +- .../test_mcopy_memory_expansion.py | 28 +- ..._dynamic_create2_selfdestruct_collision.py | 149 +- .../test_reentrancy_selfdestruct_revert.py | 29 +- .../eip6780_selfdestruct/test_selfdestruct.py | 240 +- .../test_selfdestruct_revert.py | 47 +- .../test_blobgasfee_opcode.py | 31 +- .../eip1014_create2/test_create_returndata.py | 17 +- .../eip1014_create2/test_recreate.py | 4 +- .../eip145_bitwise_shift/spec.py | 56 +- tests/frontier/create/test_create_one_byte.py | 4 +- tests/frontier/identity_precompile/common.py | 21 +- .../identity_precompile/test_identity.py | 5 +- .../test_identity_returndatasize.py | 5 +- tests/frontier/opcodes/test_all_opcodes.py | 14 +- tests/frontier/opcodes/test_call.py | 59 +- .../test_call_and_callcode_gas_calculation.py | 104 +- tests/frontier/opcodes/test_calldataload.py | 10 +- tests/frontier/opcodes/test_calldatasize.py | 10 +- tests/frontier/opcodes/test_dup.py | 16 +- tests/frontier/opcodes/test_push.py | 74 +- tests/frontier/opcodes/test_selfdestruct.py | 6 +- .../precompiles/test_precompile_absence.py | 5 +- .../frontier/precompiles/test_precompiles.py | 38 +- tests/frontier/scenarios/common.py | 54 +- .../programs/all_frontier_opcodes.py | 9 +- .../scenarios/programs/context_calls.py | 4 +- .../scenarios/scenarios/call_combinations.py | 39 +- .../scenarios/create_combinations.py | 8 +- tests/frontier/scenarios/test_scenarios.py | 34 +- tests/homestead/coverage/test_coverage.py | 13 +- tests/istanbul/eip152_blake2/common.py | 30 +- tests/istanbul/eip152_blake2/conftest.py | 4 +- tests/istanbul/eip152_blake2/spec.py | 14 +- .../eip152_blake2/test_blake2_delegatecall.py | 13 +- tests/osaka/__init__.py | 5 +- tests/osaka/eip7594_peerdas/__init__.py | 3 +- tests/osaka/eip7594_peerdas/test_get_blobs.py | 26 +- .../eip7594_peerdas/test_max_blob_per_tx.py | 20 +- .../eip7823_modexp_upper_bounds/conftest.py | 39 +- .../test_modexp_upper_bounds.py | 13 +- .../eip7825_transaction_gas_limit_cap/spec.py | 4 +- .../test_tx_gas_limit.py | 74 +- .../test_tx_gas_limit_transition_fork.py | 15 +- .../eip7883_modexp_gas_increase/conftest.py | 38 +- .../eip7883_modexp_gas_increase/helpers.py | 5 +- .../osaka/eip7883_modexp_gas_increase/spec.py | 24 +- .../test_modexp_thresholds.py | 203 +- .../test_modexp_thresholds_transition.py | 10 +- .../eip7918_blob_reserve_price/conftest.py | 22 +- .../osaka/eip7918_blob_reserve_price/spec.py | 8 +- .../test_blob_base_fee.py | 48 +- .../test_blob_reserve_price_with_bpo.py | 7 +- ...blob_reserve_price_with_bpo_transitions.py | 58 +- .../test_max_block_rlp_size.py | 53 +- .../test_count_leading_zeros.py | 44 +- .../conftest.py | 25 +- .../eip7951_p256verify_precompiles/helpers.py | 15 +- .../test_p256verify.py | 66 +- .../test_p256verify_before_fork.py | 8 +- .../security/test_selfdestruct_balance_bug.py | 35 +- tests/prague/__init__.py | 20 +- .../__init__.py | 7 +- .../conftest.py | 57 +- .../eip2537_bls_12_381_precompiles/helpers.py | 426 +- .../eip2537_bls_12_381_precompiles/spec.py | 5 +- .../test_bls12_g1add.py | 20 +- .../test_bls12_g1msm.py | 16 +- .../test_bls12_g1mul.py | 12 +- .../test_bls12_g2add.py | 17 +- .../test_bls12_g2msm.py | 16 +- .../test_bls12_g2mul.py | 9 +- .../test_bls12_map_fp2_to_g2.py | 28 +- .../test_bls12_map_fp_to_g1.py | 16 +- .../test_bls12_pairing.py | 14 +- .../test_bls12_precompiles_before_fork.py | 7 +- ...t_bls12_variable_length_input_contracts.py | 140 +- .../test_block_hashes.py | 82 +- .../test_contract_deployment.py | 25 +- tests/prague/eip6110_deposits/conftest.py | 13 +- tests/prague/eip6110_deposits/helpers.py | 110 +- .../prague/eip6110_deposits/test_deposits.py | 20 +- .../test_modified_contract.py | 62 +- .../conftest.py | 9 +- .../helpers.py | 92 +- .../spec.py | 5 +- .../test_contract_deployment.py | 6 +- .../test_modified_withdrawal_contract.py | 19 +- .../test_withdrawal_requests.py | 11 +- .../test_withdrawal_requests_during_fork.py | 20 +- .../prague/eip7251_consolidations/conftest.py | 15 +- .../prague/eip7251_consolidations/helpers.py | 104 +- .../test_consolidations.py | 11 +- .../test_consolidations_during_fork.py | 20 +- .../test_contract_deployment.py | 6 +- .../test_modified_consolidation_contract.py | 18 +- .../conftest.py | 118 +- .../eip7623_increase_calldata_cost/helpers.py | 15 +- .../test_execution_gas.py | 29 +- .../test_refunds.py | 91 +- .../test_transaction_validity.py | 35 +- .../conftest.py | 11 +- .../spec.py | 5 +- .../test_multi_type_requests.py | 100 +- tests/prague/eip7702_set_code_tx/helpers.py | 9 +- tests/prague/eip7702_set_code_tx/test_gas.py | 165 +- .../eip7702_set_code_tx/test_invalid_tx.py | 60 +- .../eip7702_set_code_tx/test_set_code_txs.py | 248 +- .../test_set_code_txs_2.py | 134 +- tests/shanghai/eip3855_push0/test_push0.py | 20 +- .../eip3860_initcode/test_initcode.py | 57 +- .../eip3860_initcode/test_with_eof.py | 12 +- .../eip4895_withdrawals/test_withdrawals.py | 47 +- tests/unscheduled/__init__.py | 5 +- .../eip7692_eof_v1/eip3540_eof_v1/__init__.py | 9 +- .../test_all_opcodes_in_container.py | 60 +- .../eip3540_eof_v1/test_container_size.py | 13 +- .../test_container_validation.py | 38 +- .../eip3540_eof_v1/test_eof_example.py | 52 +- .../eip3540_eof_v1/test_opcodes_in_legacy.py | 9 +- .../test_section_header_body_mismatch.py | 27 +- .../eip3540_eof_v1/test_section_order.py | 24 +- .../eip3540_eof_v1/test_section_size.py | 16 +- .../eip4200_relative_jumps/__init__.py | 10 +- .../eip4200_relative_jumps/test_rjump.py | 114 +- .../eip4200_relative_jumps/test_rjumpi.py | 109 +- .../eip4200_relative_jumps/test_rjumpv.py | 100 +- .../eip4750_functions/__init__.py | 11 +- .../eip4750_functions/test_callf_execution.py | 33 +- .../eip4750_functions/test_code_validation.py | 55 +- .../eip7692_eof_v1/eip5450_stack/__init__.py | 11 +- .../eip5450_stack/test_code_validation.py | 73 +- .../eip5450_stack/test_execution.py | 13 +- .../eip7692_eof_v1/eip6206_jumpf/__init__.py | 9 +- .../eip6206_jumpf/test_jumpf_execution.py | 35 +- .../eip6206_jumpf/test_jumpf_stack.py | 18 +- .../eip6206_jumpf/test_jumpf_target.py | 20 +- .../eip6206_jumpf/test_jumpf_validation.py | 38 +- .../test_nonreturning_validation.py | 28 +- .../eip663_dupn_swapn_exchange/__init__.py | 9 +- .../eip663_dupn_swapn_exchange/test_dupn.py | 6 +- .../test_exchange.py | 6 +- .../eip663_dupn_swapn_exchange/test_swapn.py | 6 +- .../eip7069_extcall/__init__.py | 10 +- .../test_address_space_extension.py | 12 +- .../eip7069_extcall/test_calldata.py | 44 +- .../eip7069_extcall/test_calls.py | 72 +- .../eip7069_extcall/test_gas.py | 34 +- .../test_returndatacopy_memory_expansion.py | 19 +- .../eip7069_extcall/test_returndataload.py | 37 +- .../eip7480_data_section/__init__.py | 10 +- .../eip7480_data_section/test_data_opcodes.py | 5 +- .../test_datacopy_memory_expansion.py | 19 +- .../eip7620_eof_create/__init__.py | 27 +- .../eip7620_eof_create/test_eofcreate.py | 47 +- .../test_eofcreate_failures.py | 115 +- .../eip7620_eof_create/test_gas.py | 5 +- .../test_legacy_eof_creates.py | 15 +- .../eip7620_eof_create/test_memory.py | 20 +- .../eip7620_eof_create/test_returncode.py | 21 +- .../test_subcontainer_validation.py | 57 +- .../eip7873_tx_create/__init__.py | 5 +- .../eip7873_tx_create/test_creation_tx.py | 6 +- .../eip7873_tx_create/test_txcreate.py | 47 +- .../test_txcreate_failures.py | 122 +- .../test_txcreate_validates.py | 18 +- tests/unscheduled/eip7692_eof_v1/gas_test.py | 26 +- 404 files changed, 13268 insertions(+), 11237 deletions(-) diff --git a/.github/scripts/generate_eip_report.py b/.github/scripts/generate_eip_report.py index 66ff8534c53..8cb3ab075e7 100644 --- a/.github/scripts/generate_eip_report.py +++ b/.github/scripts/generate_eip_report.py @@ -1,4 +1,7 @@ -"""Generate a markdown report of outdated EIP references from the EIP version checker output.""" +""" +Generate a markdown report of outdated EIP references from the EIP version +checker output. +""" import os import re diff --git a/pyproject.toml b/pyproject.toml index d85a73efbee..3c861811aa1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -129,7 +129,7 @@ line-length = 99 [tool.ruff.lint] select = ["E", "F", "B", "W", "I", "A", "N", "D", "C", "ARG001"] fixable = ["I", "B", "E", "F", "W", "D", "C"] -ignore = ["D205", "D203", "D212", "D415", "C420", "C901"] +ignore = ["D200", "D205", "D203", "D212", "D415", "C420", "C901"] [tool.ruff.lint.per-file-ignores] "tests/*" = ["ARG001"] # TODO: ethereum/execution-spec-tests#2188 diff --git a/src/cli/check_fixtures.py b/src/cli/check_fixtures.py index 6660bceab77..9cc4df7a1d6 100644 --- a/src/cli/check_fixtures.py +++ b/src/cli/check_fixtures.py @@ -26,15 +26,17 @@ def count_json_files_exclude_index(start_path: Path) -> int: def check_json(json_file_path: Path): """ Check all fixtures in the specified json file: - 1. Load the json file into a pydantic model. This checks there are no - Validation errors when loading fixtures into EEST models. - 2. Serialize the loaded pydantic model to "json" (actually python data - structures, ready to written as json). - 3. Load the serialized data back into a pydantic model (to get an updated - hash) from step 2. + 1. Load the json file into a + pydantic model. This checks there are no Validation errors when loading + fixtures into EEST models. + 2. Serialize the loaded pydantic model to "json" + (actually python data structures, ready to written as json). + 3. Load the serialized data back into a pydantic model + (to get an updated hash) from step 2. 4. Compare hashes: a. Compare the newly calculated hashes from step 2. and 3. and - b. If present, compare info["hash"] with the calculated hash from step 2. + b. If present, compare info["hash"] with the calculated + hash from step 2. """ fixtures: Fixtures = Fixtures.model_validate_json(json_file_path.read_text()) fixtures_json = to_json(fixtures) @@ -86,7 +88,9 @@ def check_json(json_file_path: Path): help="Stop and raise any exceptions encountered while checking fixtures.", ) def check_fixtures(input_str: str, quiet_mode: bool, stop_on_error: bool): - """Perform some checks on the fixtures contained in the specified directory.""" + """ + Perform some checks on the fixtures contained in the specified directory. + """ input_path = Path(input_str) success = True file_count = 0 diff --git a/src/cli/compare_fixtures.py b/src/cli/compare_fixtures.py index 787e0f9f077..bd7a5b9673e 100644 --- a/src/cli/compare_fixtures.py +++ b/src/cli/compare_fixtures.py @@ -1,9 +1,9 @@ """ Compare two fixture folders and remove duplicates based on fixture hashes. -This tool reads the .meta/index.json files from two fixture directories and identifies -fixtures with identical hashes on a test case basis, then removes the duplicates from -both of the folders. Used within the coverage workflow. +This tool reads the .meta/index.json files from two fixture directories and +identifies fixtures with identical hashes on a test case basis, then removes +the duplicates from both of the folders. Used within the coverage workflow. """ import json @@ -95,8 +95,8 @@ def batch_remove_fixtures_from_files(removals_by_file): def rewrite_index(folder: Path, index: IndexFile, dry_run: bool): """ - Rewrite the index to the correct index file, or if the test count was reduced to zero, - the entire directory is deleted. + Rewrite the index to the correct index file, or if the test count was + reduced to zero, the entire directory is deleted. """ if len(index.test_cases) > 0: # Just rewrite the index @@ -130,7 +130,9 @@ def main( dry_run: bool, abort_on_empty_patch: bool, ): - """Compare two fixture folders and remove duplicates based on fixture hashes.""" + """ + Compare two fixture folders and remove duplicates based on fixture hashes. + """ try: # Load indices base_index = load_index(base) diff --git a/src/cli/eest/commands/clean.py b/src/cli/eest/commands/clean.py index a0a65ab743a..90c191c0712 100644 --- a/src/cli/eest/commands/clean.py +++ b/src/cli/eest/commands/clean.py @@ -18,34 +18,26 @@ @click.option("-v", "--verbose", is_flag=True, help="Show verbose output.") def clean(all_files: bool, dry_run: bool, verbose: bool): """ - Remove all generated files and directories from the repository. - If `--all` is specified, the virtual environment and .tox directory will also be removed. + Remove all generated files and directories from the repository. If `--all` + is specified, the virtual environment and .tox directory will also be + removed. Args: - all_files (bool): Remove the virtual environment and .tox directory as well. + all_files (bool): Remove the virtual environment and .tox directory + as well. dry_run (bool): Simulate the cleanup without removing files. verbose (bool): Show verbose output. - Note: The virtual environment and .tox directory are not removed by default. + Note: The virtual environment and .tox directory are not removed by + default. - Example: Cleaning all generated files and directories and show the deleted items. + Example: Cleaning all generated files and directories and show the deleted + items. uv run eest clean --all -v - Output: - - \b - 🗑️ Deleted: .tox - 🗑️ Deleted: .venv - 🗑️ Deleted: src/cli/et/__pycache__ - 🗑️ Deleted: src/cli/et/commands/__pycache__ - 🗑️ Deleted: src/cli/et/make/__pycache__ - 🗑️ Deleted: src/cli/et/make/commands/__pycache__ - ... - 🧹 Cleanup complete! - """ # noqa: D417, D301 # List of items to remove can contain files and directories. items_to_remove = [ diff --git a/src/cli/eest/make/cli.py b/src/cli/eest/make/cli.py index 413050d7a70..ae0c75ba8a7 100644 --- a/src/cli/eest/make/cli.py +++ b/src/cli/eest/make/cli.py @@ -1,11 +1,14 @@ """ -The `make` CLI streamlines the process of scaffolding tasks, such as generating new test files, -enabling developers to concentrate on the core aspects of specification testing. +The `make` CLI streamlines the process of scaffolding tasks, such as generating +new test files, enabling developers to concentrate on the core aspects of +specification testing. -The module calls the appropriate function for the subcommand. If an invalid subcommand -is chosen, it throws an error and shows a list of valid subcommands. If no subcommand -is present, it shows a list of valid subcommands to choose from. + +The module calls the appropriate function for the subcommand. If an invalid +subcommand is chosen, it throws an error and shows a list of valid subcommands. +If no subcommand is present, it shows a list of valid subcommands to choose +from. """ import click diff --git a/src/cli/eest/make/commands/__init__.py b/src/cli/eest/make/commands/__init__.py index 706333ca042..e3a8ae4addd 100644 --- a/src/cli/eest/make/commands/__init__.py +++ b/src/cli/eest/make/commands/__init__.py @@ -1,7 +1,7 @@ """ Holds subcommands for the make command. New subcommands must be created as -modules and exported from this package, then registered under the make command in -`cli.py`. +modules and exported from this package, then registered under the make command +in `cli.py`. """ from .env import create_default_env diff --git a/src/cli/eest/make/commands/test.py b/src/cli/eest/make/commands/test.py index 0eb6e49141e..dc14dabb408 100644 --- a/src/cli/eest/make/commands/test.py +++ b/src/cli/eest/make/commands/test.py @@ -1,9 +1,10 @@ """ Provides a CLI command to scaffold a test file. -The `test` command guides the user through a series of prompts to generate a test file -based on the selected test type, fork, EIP number, and EIP name. The generated test file -is saved in the appropriate directory with a rendered template using Jinja2. +The `test` command guides the user through a series of prompts to generate a +test file based on the selected test type, fork, EIP number, and EIP name. The +generated test file is saved in the appropriate directory with a rendered +template using Jinja2. """ import os @@ -38,24 +39,22 @@ def test(): """ Generate a new test file for an EIP. - This function guides the user through a series of prompts to generate a test file - for Ethereum execution specifications. The user is prompted to select the type of test, - the fork to use, and to provide the EIP number and name. Based on the inputs, a test file - is created in the appropriate directory with a rendered template. + This function guides the user through a series of prompts to generate a + test file for Ethereum execution specifications. The user is prompted to + select the type of test, the fork to use, and to provide the EIP number and + name. Based on the inputs, a test file is created in the appropriate + directory with a rendered template. - Example: - uv run eest make test + Example: uv run eest make test - \f -
- -
+ + + +
""" # noqa: D301 test_type = input_select( "Choose the type of test to generate", choices=["State", "Blockchain"] diff --git a/src/cli/eest/quotes.py b/src/cli/eest/quotes.py index dfd8353072d..f026d062f2b 100644 --- a/src/cli/eest/quotes.py +++ b/src/cli/eest/quotes.py @@ -51,5 +51,8 @@ def box_quote(quote): def get_quote(): - """Return random inspirational quote related to system design formatted in a box.""" + """ + Return random inspirational quote related to system design formatted in a + box. + """ return box_quote(random.choice(make_something_great)) diff --git a/src/cli/eofwrap.py b/src/cli/eofwrap.py index c23a695a43d..65aad7940f9 100644 --- a/src/cli/eofwrap.py +++ b/src/cli/eofwrap.py @@ -1,14 +1,14 @@ """ -Generate a JSON blockchain test from an existing JSON blockchain test by wrapping its pre-state -code in EOF wherever possible. +Generate a JSON blockchain test from an existing JSON blockchain test by +wrapping its pre-state code in EOF wherever possible. Example Usage: 1. Wrap tests - ```console +```console eofwrap - ``` +``` """ import json @@ -44,8 +44,8 @@ @click.option("--traces", is_flag=True, type=bool) def eof_wrap(input_path: str, output_dir: str, traces: bool): """ - Wrap JSON blockchain test file(s) found at `input_path` and - outputs them to the `output_dir`. + Wrap JSON blockchain test file(s) found at `input_path` and outputs them to + the `output_dir`. """ eof_wrapper = EofWrapper() @@ -116,7 +116,9 @@ class EofWrapper: GENERATION_ERRORS = "generation_errors" def __init__(self): - """Initialize the EofWrapper with metrics tracking and a unique EOF set.""" + """ + Initialize the EofWrapper with metrics tracking and a unique EOF set. + """ self.metrics = { self.FILES_GENERATED: 0, self.FILES_SKIPPED: 0, @@ -135,7 +137,8 @@ def __init__(self): file_skip_list = [ "Pyspecs", - # EXTCODE* opcodes return different results for EOF targets and that is tested elsewhere + # EXTCODE* opcodes return different results for EOF targets and that is + # tested elsewhere "stExtCodeHash", # bigint syntax "ValueOverflowParis", @@ -168,10 +171,11 @@ def __init__(self): def wrap_file(self, in_path: str, out_path: str, traces: bool): """ - Wrap code from a blockchain test JSON file from `in_path` into EOF containers, - wherever possible. If not possible - skips and tracks that in metrics. Possible means - at least one account's code can be wrapped in a valid EOF container and the assertions - on post state are satisfied. + Wrap code from a blockchain test JSON file from `in_path` into EOF + containers, wherever possible. If not possible - skips and tracks that + in metrics. Possible means at least one account's code can be wrapped + in a valid EOF container and the assertions on post state are + satisfied. """ for skip in self.file_skip_list: if skip in in_path: @@ -301,9 +305,9 @@ def _wrap_fixture(self, fixture: BlockchainFixture, traces: bool): test.blocks.append(block) elif isinstance(fixture_block, InvalidFixtureBlock): - # Skip - invalid blocks are not supported. Reason: FixtureTransaction doesn't - # support expected exception. But we can continue and test the remaining - # blocks. + # Skip - invalid blocks are not supported. Reason: + # FixtureTransaction doesn't support expected exception. But we + # can continue and test the remaining blocks. self.metrics[self.INVALID_BLOCKS_SKIPPED] += 1 else: raise TypeError("not a FixtureBlock") @@ -331,13 +335,13 @@ def _validate_eof(self, container: Container, metrics: bool = True) -> bool: return True -# `no_type_check` required because OpcodeWithOperand.opcode can be `None` when formatting as a -# string, but here it can never be `None`. +# `no_type_check` required because OpcodeWithOperand.opcode can be `None` when +# formatting as a string, but here it can never be `None`. @no_type_check def wrap_code(account_code: Bytes) -> Container: """ - Wrap `account_code` into a simplest EOF container, applying some simple heuristics in - order to obtain a valid code section termination. + Wrap `account_code` into a simplest EOF container, applying some simple + heuristics in order to obtain a valid code section termination. """ assert len(account_code) > 0 diff --git a/src/cli/evm_bytes.py b/src/cli/evm_bytes.py index 1b847ed97fb..3cc4c5ee474 100644 --- a/src/cli/evm_bytes.py +++ b/src/cli/evm_bytes.py @@ -62,7 +62,8 @@ def terminating(self) -> bool: @property def bytecode(self) -> Bytecode: """Opcode as bytecode with its operands if any.""" - # opcode.opcode[*opcode.operands] crashes `black` formatter and doesn't work. + # opcode.opcode[*opcode.operands] crashes `black` formatter and doesn't + # work. if self.opcode: return self.opcode.__getitem__(*self.operands) if self.operands else self.opcode else: @@ -173,28 +174,18 @@ def hex_string(hex_string: str, assembly: bool): HEX_STRING is a string containing EVM bytecode. - Returns: - (str): The processed EVM opcodes in Python or assembly format. + Returns: (str): The processed EVM opcodes in Python or assembly format. - Example 1: Convert a hex string to EEST Python `Opcodes` + Example 1: Convert a hex string to EEST Python `Opcodes`: uv run evm_bytes hex-string 604260005260206000F3 - Output 1: - \b - Op.PUSH1[0x42] + Op.PUSH1[0x0] + Op.MSTORE + Op.PUSH1[0x20] + Op.PUSH1[0x0] + Op.RETURN + Output 1: Op.PUSH1[0x42] + Op.PUSH1[0x0] + Op.MSTORE + Op.PUSH1[0x20] + + Op.PUSH1[0x0] + Op.RETURN - Example 2: Convert a hex string to assembly + Example 2: Convert a hex string to assembly: uv run evm_bytes hex-string --assembly 604260005260206000F3 - Output 2: - \b - push1 0x42 - push1 0x00 - mstore - push1 0x20 - push1 0x00 - return - + Output 2: push1 0x42 push1 0x00 mstore push1 0x20 push1 0x00 return """ # noqa: D301 processed_output = process_evm_bytes_string(hex_string, assembly=assembly) click.echo(processed_output) @@ -207,24 +198,17 @@ def binary_file(binary_file, assembly: bool): """ Convert the BINARY_FILE containing EVM bytes to Python Opcodes or assembly. - BINARY_FILE is a binary file containing EVM bytes, use `-` to read from stdin. - - Returns: - (str): The processed EVM opcodes in Python or assembly format. + BINARY_FILE is a binary file containing EVM bytes, use `-` to read from + stdin. - Example: Convert the Withdrawal Request contract to assembly - \b - uv run evm_bytes binary-file ./src/ethereum_test_forks/forks/contracts/withdrawal_request.bin --assembly + Returns: (str): The processed EVM opcodes in Python or assembly format. - Output: - \b - caller - push20 0xfffffffffffffffffffffffffffffffffffffffe - eq - push1 0x90 - jumpi - ... + Example: Convert the Withdrawal Request contract to assembly: + uv run evm_bytes binary-file ./src/ethereum_test_forks/forks/ + contracts/withdrawal_request.bin --assembly - """ # noqa: E501,D301 + Output: caller push20 0xfffffffffffffffffffffffffffffffffffffffe eq push1 + 0x90 jumpi ... + """ # noqa: D301 processed_output = format_opcodes(process_evm_bytes(binary_file.read()), assembly=assembly) click.echo(processed_output) diff --git a/src/cli/extract_config.py b/src/cli/extract_config.py index 503c352eb1c..bf0e1f717c5 100755 --- a/src/cli/extract_config.py +++ b/src/cli/extract_config.py @@ -1,9 +1,11 @@ #!/usr/bin/env python """ -CLI tool to extract client configuration files (chainspec/genesis.json) from Ethereum clients. +CLI tool to extract client configuration files (chainspec/genesis.json) from +Ethereum clients. -This tool spawns an Ethereum client using Hive and extracts the generated configuration -files such as /chainspec/test.json, /configs/test.cfg, or /genesis.json from the Docker container. +This tool spawns an Ethereum client using Hive and extracts the generated +configuration files such as /chainspec/test.json, /configs/test.cfg, or +/genesis.json from the Docker container. """ import io @@ -119,7 +121,9 @@ def create_genesis_from_fixture(fixture_path: Path) -> Tuple[FixtureHeader, Allo def get_client_environment_for_fixture(fork: Fork, chain_id: int) -> dict: - """Get the environment variables for starting a client with the given fixture.""" + """ + Get the environment variables for starting a client with the given fixture. + """ if fork not in ruleset: raise ValueError(f"Fork '{fork}' not found in hive ruleset") @@ -176,8 +180,8 @@ def extract_config( Extract client configuration files from Ethereum clients. This tool spawns an Ethereum client using Hive and extracts the generated - configuration files such as /chainspec/test.json, /configs/test.cfg, or /genesis.json - from the Docker container. + configuration files such as /chainspec/test.json, /configs/test.cfg, or + /genesis.json from the Docker container. """ if not fixture: raise click.UsageError("No fixture provided, use --fixture to specify a fixture") diff --git a/src/cli/fillerconvert/fillerconvert.py b/src/cli/fillerconvert/fillerconvert.py index 6cb7a5f3b59..37897d33e30 100644 --- a/src/cli/fillerconvert/fillerconvert.py +++ b/src/cli/fillerconvert/fillerconvert.py @@ -39,10 +39,10 @@ def main() -> None: verified_vectors += verify_refilled(Path(refilled_file), original_file) print(f"Total vectors verified: {verified_vectors}") - # Solidity skipped tests - # or file.endswith("stExample/solidityExampleFiller.yml") - # or file.endswith("vmPerformance/performanceTesterFiller.yml") - # or file.endswith("vmPerformance/loopExpFiller.yml") - # or file.endswith("vmPerformance/loopMulFiller.yml") - # or file.endswith("stRevertTest/RevertRemoteSubCallStorageOOGFiller.yml") + # Solidity skipped tests or + # file.endswith("stExample/solidityExampleFiller.yml") or + # file.endswith("vmPerformance/performanceTesterFiller.yml") or + # file.endswith("vmPerformance/loopExpFiller.yml") or + # file.endswith("vmPerformance/loopMulFiller.yml") or + # file.endswith("stRevertTest/RevertRemoteSubCallStorageOOGFiller.yml") # or file.endswith("stSolidityTest/SelfDestructFiller.yml") diff --git a/src/cli/fillerconvert/verify_filled.py b/src/cli/fillerconvert/verify_filled.py index 706d62ac3e2..3c3302342e8 100644 --- a/src/cli/fillerconvert/verify_filled.py +++ b/src/cli/fillerconvert/verify_filled.py @@ -34,10 +34,9 @@ class FilledStateTest(RootModel[dict[str, StateTest]]): def verify_refilled(refilled: Path, original: Path) -> int: """ - Verify post hash of the refilled test against original: - Regex the original d,g,v from the refilled test name. - Find the post record for this d,g,v and the fork of refilled test. - Compare the post hash. + Verify post hash of the refilled test against original: Regex the original + d,g,v from the refilled test name. Find the post record for this d,g,v and + the fork of refilled test. Compare the post hash. """ verified_vectors = 0 json_str = refilled.read_text(encoding="utf-8") @@ -46,7 +45,8 @@ def verify_refilled(refilled: Path, original: Path) -> int: json_str = original.read_text(encoding="utf-8") original_test_wrapper = FilledStateTest.model_validate_json(json_str) - # Each original test has only 1 test with many posts for each fork and many txs + # Each original test has only 1 test with many posts for each fork and many + # txs original_test_name, test_original = list(original_test_wrapper.root.items())[0] for refilled_test_name, refilled_test in refilled_test_wrapper.root.items(): diff --git a/src/cli/gen_index.py b/src/cli/gen_index.py index a19e2394315..dcd82741bdc 100644 --- a/src/cli/gen_index.py +++ b/src/cli/gen_index.py @@ -1,4 +1,6 @@ -"""Generate an index file of all the json fixtures in the specified directory.""" +""" +Generate an index file of all the json fixtures in the specified directory. +""" import datetime import json @@ -71,8 +73,12 @@ def count_json_files_exclude_index(start_path: Path) -> int: expose_value=True, help="Force re-generation of the index file, even if it already exists.", ) -def generate_fixtures_index_cli(input_dir: str, quiet_mode: bool, force_flag: bool): - """CLI wrapper to an index of all the fixtures in the specified directory.""" +def generate_fixtures_index_cli( + input_dir: str, quiet_mode: bool, force_flag: bool, disable_infer_format: bool +): + """ + CLI wrapper to an index of all the fixtures in the specified directory. + """ generate_fixtures_index( Path(input_dir), quiet_mode=quiet_mode, diff --git a/src/cli/generate_checklist_stubs.py b/src/cli/generate_checklist_stubs.py index 36d3839b369..9468521dbf4 100644 --- a/src/cli/generate_checklist_stubs.py +++ b/src/cli/generate_checklist_stubs.py @@ -86,16 +86,17 @@ def generate_checklist_stubs(output: str | None, dry_run: bool) -> None: Generate mypy stub files for EIPChecklist classes. This is a development tool that generates .pyi stub files to help mypy - understand that EIPChecklist classes are callable, fixing type checking issues. + understand that EIPChecklist classes are callable, fixing type checking + issues. Examples: - # Generate stub files (auto-detect location) + Generate stub files (auto-detect location): uv run generate_checklist_stubs - # Generate to specific location + Generate to specific location: uv run generate_checklist_stubs --output /path/to/stubs.pyi - # Preview content without writing + Preview content without writing: uv run generate_checklist_stubs --dry-run """ diff --git a/src/cli/gentest/request_manager.py b/src/cli/gentest/request_manager.py index e4eac7e11d4..62f375c45aa 100644 --- a/src/cli/gentest/request_manager.py +++ b/src/cli/gentest/request_manager.py @@ -1,13 +1,17 @@ """ A request manager Ethereum RPC calls. -The RequestManager handles transactions and block data retrieval from a remote Ethereum node, -utilizing Pydantic models to define the structure of transactions and blocks. +The RequestManager handles transactions and block data retrieval from a remote +Ethereum node, utilizing Pydantic models to define the structure of +transactions and blocks. Classes: -- RequestManager: The main class for managing RPC requests and responses. -- RemoteTransaction: A Pydantic model representing a transaction retrieved from the node. -- RemoteBlock: A Pydantic model representing a block retrieved from the node. + RequestManager: The main class for managing RPC requests and + responses. + RemoteTransaction: A Pydantic model representing a transaction + retrieved from the node. + RemoteBlock: A Pydantic model representing a block retrieved from + the node. """ from typing import Dict diff --git a/src/cli/gentest/source_code_generator.py b/src/cli/gentest/source_code_generator.py index e437631aad5..35628f5f5e3 100644 --- a/src/cli/gentest/source_code_generator.py +++ b/src/cli/gentest/source_code_generator.py @@ -22,21 +22,24 @@ template_env.filters["stringify"] = lambda value: repr(value) -# generates a formatted pytest source code by writing provided data on a given template. +# generates a formatted pytest source code by writing provided data on a given +# template. def get_test_source(provider: Provider, template_path: str) -> str: """ - Generate formatted pytest source code by rendering a template with provided data. + Generate formatted pytest source code by rendering a template with provided + data. - This function uses the given template path to create a pytest-compatible source - code string. It retrieves context data from the specified provider and applies - it to the template. + This function uses the given template path to create a pytest-compatible + source code string. It retrieves context data from the specified provider + and applies it to the template. Args: - provider: An object that provides the necessary context for rendering the template. - template_path (str): The path to the Jinja2 template file used to generate tests. + provider: An object that provides the necessary context for rendering + the template. + template_path (str): The path to the Jinja2 template file + used to generate tests. - Returns: - str: The formatted pytest source code. + Returns: str: The formatted pytest source code. """ template = template_env.get_template(template_path) @@ -49,14 +52,13 @@ def format_code(code: str) -> str: """ Format the provided Python code using the Black code formatter. - This function writes the given code to a temporary Python file, formats it using - the Black formatter, and returns the formatted code as a string. + This function writes the given code to a temporary Python file, formats it + using the Black formatter, and returns the formatted code as a string. Args: - code (str): The Python code to be formatted. + code (str): The Python code to be formatted. - Returns: - str: The formatted Python code. + Returns: str: The formatted Python code. """ # Create a temporary python file diff --git a/src/cli/gentest/test_context_providers.py b/src/cli/gentest/test_context_providers.py index f0cb5c3e021..b958d160e22 100644 --- a/src/cli/gentest/test_context_providers.py +++ b/src/cli/gentest/test_context_providers.py @@ -2,13 +2,14 @@ Various providers which generate contexts required to create test scripts. Classes: -- Provider: An provider generates required context for creating a test. -- BlockchainTestProvider: The BlockchainTestProvider takes a transaction hash and creates - required context to create a test. + Provider: An provider generates required context for creating a + test. + BlockchainTestProvider: The BlockchainTestProvider takes a transaction + hash and creates required context to create a test. Example: - provider = BlockchainTestContextProvider(transaction=transaction) - context = provider.get_context() + provider = BlockchainTestContextProvider(transaction=transaction) + context = provider.get_context() """ @@ -80,17 +81,16 @@ def _get_pre_state(self) -> Dict[str, Account]: def _get_transaction(self) -> Transaction: assert self.transaction_response is not None - # Validate the RPC TransactionHashResponse and convert it to a Transaction instance. + # Validate the RPC TransactionHashResponse and convert it to a + # Transaction instance. return Transaction.model_validate(self.transaction_response.model_dump()) def get_context(self) -> Dict[str, Any]: """ Get the context for generating a blockchain test. - Returns: - Dict[str, Any]: A dictionary containing environment, - pre-state, a transaction and its hash. - + Returns: Dict[str, Any]: A dictionary containing environment, + pre-state, a transaction and its hash. """ self._make_rpc_calls() return { diff --git a/src/cli/gentest/test_providers.py b/src/cli/gentest/test_providers.py index dc29d306ee3..d9cdeaba6a2 100644 --- a/src/cli/gentest/test_providers.py +++ b/src/cli/gentest/test_providers.py @@ -1,14 +1,21 @@ """ -Contains various providers which generates context required to create test scripts. +Contains various providers which generates context required to create test +scripts. Classes: -- BlockchainTestProvider: The BlockchainTestProvider class takes information about a block, -a transaction, and the associated state, and provides methods to generate various elements -needed for testing, such as module docstrings, test names, and pre-state items. + BlockchainTestProvider: The BlockchainTestProvider class takes + information about a block, a transaction, and the + associated state, and provides methods to generate + various elements needed for testing, such as module + docstrings, test names, and pre-state items. Example: - provider = BlockchainTestProvider(block=block, transaction=transaction, state=state) - context = provider.get_context() + provider = BlockchainTestProvider( + block=block, + transaction=transaction, + state=state + ) + context = provider.get_context() """ @@ -22,7 +29,9 @@ class BlockchainTestProvider(BaseModel): - """Provides context required to generate a `blockchain_test` using pytest.""" + """ + Provides context required to generate a `blockchain_test` using pytest. + """ block: Environment transaction: TransactionByHashResponse @@ -103,8 +112,9 @@ def get_context(self) -> Dict[str, Any]: Get the context for generating a blockchain test. Returns: - Dict[str, Any]: A dictionary containing module docstring, test name, - test docstring, environment kwargs, pre-state items, and transaction items. + Dict[str, Any]: A dictionary containing module docstring, test + name, test docstring, environment kwargs, + pre-state items, and transaction items. """ return { diff --git a/src/cli/gentest/tests/test_cli.py b/src/cli/gentest/tests/test_cli.py index c8d9a869c6e..cac98388d95 100644 --- a/src/cli/gentest/tests/test_cli.py +++ b/src/cli/gentest/tests/test_cli.py @@ -92,10 +92,10 @@ def transaction_hash(tx_type: int) -> str: # noqa: D103 @pytest.mark.parametrize("tx_type", list(transactions_by_type.keys())) def test_tx_type(pytester, tmp_path, monkeypatch, tx_type, transaction_hash, default_t8n): """Generates a test case for any transaction type.""" - ## Arrange ## - # This test is run in a CI environment, where connection to a node could be - # unreliable. Therefore, we mock the RPC request to avoid any network issues. - # This is done by patching the `get_context` method of the `StateTestProvider`. + # This test is run in a CI environment, where connection to a + # node could be unreliable. Therefore, we mock the RPC request to avoid any + # network issues. This is done by patching the `get_context` method of the + # `StateTestProvider`. runner = CliRunner() tmp_path_tests = tmp_path / "tests" tmp_path_tests.mkdir() diff --git a/src/cli/hasher.py b/src/cli/hasher.py index bd5caaeca5a..ab1dd874805 100644 --- a/src/cli/hasher.py +++ b/src/cli/hasher.py @@ -20,7 +20,10 @@ class HashableItemType(IntEnum): @dataclass(kw_only=True) class HashableItem: - """Represents an item that can be hashed containing other items that can be hashed as well.""" + """ + Represents an item that can be hashed containing other items that can be + hashed as well. + """ type: HashableItemType parents: List[str] = field(default_factory=list) diff --git a/src/cli/input/input_repository.py b/src/cli/input/input_repository.py index 0a75d14de8f..83b31c830b0 100644 --- a/src/cli/input/input_repository.py +++ b/src/cli/input/input_repository.py @@ -6,8 +6,8 @@ class InputRepository(ABC): """ - Abstract base class for input handling. - This class defines the interface for different input types that can be swapped out. + Abstract base class for input handling. This class defines the interface + for different input types that can be swapped out. """ @abstractmethod diff --git a/src/cli/input/questionary_input_repository.py b/src/cli/input/questionary_input_repository.py index af0e2e144ce..8ddc6b18b65 100644 --- a/src/cli/input/questionary_input_repository.py +++ b/src/cli/input/questionary_input_repository.py @@ -9,7 +9,10 @@ class QuestionaryInputRepository(InputRepository): - """Repository for handling various types of user inputs using the Questionary library.""" + """ + Repository for handling various types of user inputs using the Questionary + library. + """ def input_text(self, question: str) -> str: """Ask a text input question.""" diff --git a/src/cli/modify_static_test_gas_limits.py b/src/cli/modify_static_test_gas_limits.py index 17f0b5137c4..35a259d88f2 100644 --- a/src/cli/modify_static_test_gas_limits.py +++ b/src/cli/modify_static_test_gas_limits.py @@ -1,6 +1,6 @@ """ -Command to scan and overwrite the static tests' gas limits to new optimized value given in the -input file. +Command to scan and overwrite the static tests' gas limits to new optimized +value given in the input file. """ import json @@ -46,7 +46,9 @@ class StaticTestFile(EthereumTestRootModel): def _check_fixtures(*, input_path: Path, max_gas_limit: int | None, dry_run: bool, verbose: bool): - """Perform some checks on the fixtures contained in the specified directory.""" + """ + Perform some checks on the fixtures contained in the specified directory. + """ # Load the test dictionary from the input JSON file test_dict = GasLimitDict.model_validate_json(input_path.read_text()) @@ -207,7 +209,9 @@ def _check_fixtures(*, input_path: Path, max_gas_limit: int | None, dry_run: boo help="Print extra information.", ) def main(input_str: str, max_gas_limit, dry_run: bool, verbose: bool): - """Perform some checks on the fixtures contained in the specified directory.""" + """ + Perform some checks on the fixtures contained in the specified directory. + """ input_path = Path(input_str) if not dry_run: # Always dry-run first before actually modifying diff --git a/src/cli/order_fixtures.py b/src/cli/order_fixtures.py index 7b90281452e..dda26d76151 100644 --- a/src/cli/order_fixtures.py +++ b/src/cli/order_fixtures.py @@ -1,18 +1,17 @@ """ Functions and CLI interface for recursively ordering and sorting .json files. -example: Usage - - ``` - order_fixtures -i input_dir -o output_dir - ``` +Usage Example: +```console + order_fixtures -i input_dir -o output_dir +``` The CLI interface takes the paths of an input directory and an output directory. It recursively processes each .json file in the input directory and -its subdirectories, and sorts lists and dictionaries alphabetically and -writes the sorted output to .json files to the corresponding locations in the -output directory. +its subdirectories, and sorts lists and dictionaries alphabetically and writes +the sorted output to .json files to the corresponding locations in the output +directory. """ import json @@ -27,16 +26,14 @@ def recursive_sort(item: Dict[str, Any] | List[Any]) -> Dict[str, Any] | List[An Recursively sorts an item. If the item is a dictionary, it returns a new dictionary that is a sorted - version of the input dictionary. - If the item is a list, it returns a new list that is a sorted version of the - input list. The elements of the list are also sorted if they are lists or - dictionaries. + version of the input dictionary. If the item is a list, it returns a new + list that is a sorted version of the input list. The elements of the list + are also sorted if they are lists or dictionaries. Args: - item: The item to be sorted. This can be a list or a dictionary. + item: The item to be sorted. This can be a list or a dictionary. - Returns: - The sorted item. + Returns: The sorted item. """ if isinstance(item, dict): @@ -45,8 +42,8 @@ def recursive_sort(item: Dict[str, Any] | List[Any]) -> Dict[str, Any] | List[An try: return sorted(cast(List[Any], [recursive_sort(x) for x in item])) except TypeError: - # If a TypeError is raised, we might be dealing with a list of dictionaries - # Sort them based on their string representation + # If a TypeError is raised, we might be dealing with a list of + # dictionaries Sort them based on their string representation return sorted((recursive_sort(x) for x in item), key=str) else: return item @@ -60,11 +57,10 @@ def order_fixture(input_path: Path, output_path: Path) -> None: to the output path. Args: - input_path: The Path object of the input .json file. - output_path: The Path object of the output .json file. + input_path: The Path object of the input .json file. + output_path: The Path object of the output .json file. - Returns: - None. + Returns: None. """ with input_path.open("r") as f: @@ -78,17 +74,14 @@ def process_directory(input_dir: Path, output_dir: Path): """ Process a directory. - Processes each .json file in the input directory and its subdirectories, and - writes the sorted .json files to the corresponding locations in the output - directory. - - Args: - input_dir: The Path object of the input directory. - output_dir: The Path object of the output directory. + Processes each .json file in the input directory and its subdirectories, + and writes the sorted .json files to the corresponding locations in the + output directory. - Returns: - None. + Args: input_dir: The Path object of the input directory. output_dir: The + Path object of the output directory. + Returns: None. """ if not output_dir.exists(): output_dir.mkdir(parents=True) diff --git a/src/cli/pytest_commands/base.py b/src/cli/pytest_commands/base.py index 7061741e47a..444de79561b 100644 --- a/src/cli/pytest_commands/base.py +++ b/src/cli/pytest_commands/base.py @@ -24,7 +24,10 @@ class PytestExecution: """Path to the pytest configuration file (e.g., 'pytest-fill.ini').""" command_logic_test_paths: List[str] = field(default_factory=list) - """List of tests that have to be appended to the start of pytest command arguments.""" + """ + List of tests that have to be appended to the start of pytest command + arguments. + """ args: List[str] = field(default_factory=list) """Arguments to pass to pytest.""" @@ -80,7 +83,8 @@ def run_multiple(self, executions: List[PytestExecution]) -> int: """ Run multiple pytest executions in sequence. - Returns the exit code of the final execution, or the first non-zero exit code. + Returns the exit code of the final execution, or the first non-zero + exit code. """ for i, execution in enumerate(executions): if execution.description and len(executions) > 1: @@ -102,8 +106,8 @@ class PytestCommand: """ Base class for pytest-based CLI commands. - Provides a standard structure for commands that execute pytest - with specific configurations and argument processing. + Provides a standard structure for commands that execute pytest with + specific configurations and argument processing. """ config_file: str @@ -138,8 +142,8 @@ def execute(self, pytest_args: List[str]) -> None: @property def test_args(self) -> List[str]: """ - Return the test-path arguments that have to be appended to all PytestExecution - instances. + Return the test-path arguments that have to be appended to all + PytestExecution instances. """ if self.command_logic_test_paths: return [str(path) for path in self.command_logic_test_paths] @@ -149,8 +153,8 @@ def create_executions(self, pytest_args: List[str]) -> List[PytestExecution]: """ Create the list of pytest executions for this command. - This method can be overridden by subclasses to implement - multi-phase execution (e.g., for future fill command). + This method can be overridden by subclasses to implement multi-phase + execution (e.g., for future fill command). """ processed_args = self.process_arguments(pytest_args) return [ diff --git a/src/cli/pytest_commands/fill.py b/src/cli/pytest_commands/fill.py index f0f3ce53283..d0f6d06b455 100644 --- a/src/cli/pytest_commands/fill.py +++ b/src/cli/pytest_commands/fill.py @@ -26,10 +26,12 @@ def __init__(self, **kwargs): def create_executions(self, pytest_args: List[str]) -> List[PytestExecution]: """ - Create execution plan that supports two-phase pre-allocation group generation. + Create execution plan that supports two-phase pre-allocation group + generation. Returns single execution for normal filling, or two-phase execution - when --generate-pre-alloc-groups or --generate-all-formats is specified. + when --generate-pre-alloc-groups or --generate-all-formats is + specified. """ processed_args = self.process_arguments(pytest_args) @@ -50,7 +52,10 @@ def create_executions(self, pytest_args: List[str]) -> List[PytestExecution]: ] def _create_two_phase_executions(self, args: List[str]) -> List[PytestExecution]: - """Create two-phase execution: pre-allocation group generation + fixture filling.""" + """ + Create two-phase execution: pre-allocation group generation + fixture + filling. + """ # Phase 1: Pre-allocation group generation (clean and minimal output) phase1_args = self._create_phase1_args(args) @@ -87,14 +92,16 @@ def _create_phase1_args(self, args: List[str]) -> List[str]: # Add required phase 1 flags (with quiet output by default) phase1_args = [ "--generate-pre-alloc-groups", - "-qq", # Quiet pytest output by default (user -v/-vv/-vvv can override) + "-qq", # Quiet pytest output by default (user -v/-vv/-vvv can + # override) ] + filtered_args return phase1_args def _create_phase2_args(self, args: List[str]) -> List[str]: """Create arguments for phase 2 (fixture filling).""" - # Remove --generate-pre-alloc-groups and --clean, then add --use-pre-alloc-groups + # Remove --generate-pre-alloc-groups and --clean, then add --use-pre- + # alloc-groups phase2_args = self._remove_generate_pre_alloc_groups_flag(args) phase2_args = self._remove_clean_flag(phase2_args) phase2_args = self._add_use_pre_alloc_groups_flag(phase2_args) @@ -138,7 +145,10 @@ def _remove_unwanted_phase1_args(self, args: List[str]) -> List[str]: return filtered_args def _remove_generate_pre_alloc_groups_flag(self, args: List[str]) -> List[str]: - """Remove --generate-pre-alloc-groups flag but keep --generate-all-formats for phase 2.""" + """ + Remove --generate-pre-alloc-groups flag but keep --generate-all-formats + for phase 2. + """ return [arg for arg in args if arg != "--generate-pre-alloc-groups"] def _remove_clean_flag(self, args: List[str]) -> List[str]: @@ -257,5 +267,6 @@ def phil(pytest_args: List[str], **kwargs) -> None: if __name__ == "__main__": - # to allow debugging in vscode: in launch config, set "module": "cli.pytest_commands.fill" + # to allow debugging in vscode: in launch config, set "module": + # "cli.pytest_commands.fill" fill(prog_name="fill") diff --git a/src/cli/pytest_commands/processors.py b/src/cli/pytest_commands/processors.py index ef6a44dd1ed..8e0f2d2e0cd 100644 --- a/src/cli/pytest_commands/processors.py +++ b/src/cli/pytest_commands/processors.py @@ -18,8 +18,9 @@ def __init__(self, command_type: str, required_args: List[str] | None = None): Initialize the help processor. Args: - command_type: The type of command (e.g., "fill", "consume", "execute") - required_args: The arguments that are required for the command to run + command_type: The type of command (e.g., "fill", "consume", + "execute") + required_args: The arguments that are required for the command to run """ self.command_type = command_type @@ -48,8 +49,8 @@ class StdoutFlagsProcessor(ArgumentProcessor): def process_args(self, args: List[str]) -> List[str]: """ - If the user has requested to write to stdout, add pytest arguments - to suppress pytest's test session header and summary output. + If the user has requested to write to stdout, add pytest arguments to + suppress pytest's test session header and summary output. """ if not self._is_writing_to_stdout(args): return args @@ -134,7 +135,7 @@ def __init__(self, is_hive: bool = False): Initialize the consume processor. Args: - is_hive: Whether this is a hive-based consume command + is_hive: Whether this is a hive-based consume command """ self.is_hive = is_hive diff --git a/src/cli/show_pre_alloc_group_stats.py b/src/cli/show_pre_alloc_group_stats.py index c7cf51cedfd..492c1f0c6ab 100644 --- a/src/cli/show_pre_alloc_group_stats.py +++ b/src/cli/show_pre_alloc_group_stats.py @@ -15,7 +15,9 @@ def extract_test_module(test_id: str) -> str: """Extract test module path from test ID.""" - # Example: tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py::test_beacon_root_contract_calls[fork_Cancun] # noqa: E501 + # Example: + # tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py:: + # test_beacon_root_contract_calls[fork_Cancun] if "::" in test_id: return test_id.split("::")[0] return "unknown" @@ -23,8 +25,12 @@ def extract_test_module(test_id: str) -> str: def extract_test_function(test_id: str) -> str: """Extract test function name from test ID (without parameters).""" - # Example: tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py::test_beacon_root_contract_calls[fork_Cancun] # noqa: E501 - # Returns: tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py::test_beacon_root_contract_calls # noqa: E501 + # Example: + # tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py:: + # test_beacon_root_contract_calls[fork_Cancun] + # Returns: + # tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py:: + # test_beacon_root_contract_calls if "::" in test_id: parts = test_id.split("::") if len(parts) >= 2: @@ -43,9 +49,10 @@ def calculate_size_distribution( Calculate frequency distribution of group sizes with appropriate binning. Returns: - - Group count distribution: [(range_label, group_count), ...] - - Test count distribution: [(range_label, test_count, cumulative_remaining, group_count), - ...] + Group count distribution: [(range_label, group_count), ...] + Test count distribution: [(range_label, test_count, + cumulative_remaining, + group_count), ...] """ if not test_counts: @@ -80,12 +87,15 @@ def calculate_size_distribution( # Test count distribution with group count tests_in_bin = sum(groups_in_bin) - test_distribution.append((label, tests_in_bin, 0, group_count)) # Added group_count + # Added group_count + test_distribution.append((label, tests_in_bin, 0, group_count)) - # Calculate cumulative values - # For the table sorted from largest to smallest: - # - Row N shows: if we exclude groups of size N and smaller, what % of tests remain? - # - Row N shows: if we include groups of size N and larger, how many groups is that? + # Calculate cumulative values For the table sorted from largest to + # smallest: + # Row N shows: if we exclude groups of size N and smaller, what + # percent of tests remain? + # Row N shows: if we include groups of size N and + # larger, how many groups is that? cumulative_remaining_tests = 0 cumulative_groups = 0 @@ -167,7 +177,8 @@ class SplitTestFunction(CamelModel): split_test_functions[test_function].groups += 1 split_test_functions[test_function].forks.add(fork) - # Filter to only test functions with multiple size-1 groups and calculate ratios + # Filter to only test functions with multiple size-1 groups and calculate + # ratios split_functions = {} for func, split_test_function in split_test_functions.items(): if split_test_function.groups > 1: @@ -355,7 +366,8 @@ def display_stats(stats: Dict, console: Console, verbose: int = 0): # Sort modules by group count (descending) - shows execution complexity sorted_modules = sorted( stats["module_stats"].items(), - key=lambda x: (-x[1]["groups"], -x[1]["tests"]), # Secondary sort by tests + # Secondary sort by tests + key=lambda x: (-x[1]["groups"], -x[1]["tests"]), ) # Show all modules if -vv, otherwise top 15 @@ -412,7 +424,8 @@ def display_stats(stats: Dict, console: Console, verbose: int = 0): # Shorten function path for display display_function = test_function if display_function.startswith("tests/"): - display_function = display_function[6:] # Remove "tests/" prefix + display_function = display_function[6:] # Remove "tests/" + # prefix split_table.add_row( display_function, @@ -475,7 +488,6 @@ def main(pre_alloc_folder: Path, verbose: int): The pre_alloc file is generated when running tests with the --generate-pre-alloc-groups and --use-pre-alloc-groups flags to optimize test execution by grouping tests with identical pre-allocation state. - """ console = Console() diff --git a/src/cli/tests/test_evm_bytes.py b/src/cli/tests/test_evm_bytes.py index 64bebd41828..438c81c7807 100644 --- a/src/cli/tests/test_evm_bytes.py +++ b/src/cli/tests/test_evm_bytes.py @@ -8,11 +8,26 @@ basic_vector = [ "0x60008080808061AAAA612d5ff1600055", - "Op.PUSH1[0x0] + Op.DUP1 + Op.DUP1 + Op.DUP1 + Op.DUP1 + Op.PUSH2[0xaaaa] + Op.PUSH2[0x2d5f] + Op.CALL + Op.PUSH1[0x0] + Op.SSTORE", # noqa: E501 + "Op.PUSH1[0x0] + Op.DUP1 + Op.DUP1 + Op.DUP1 + Op.DUP1 + " + "Op.PUSH2[0xaaaa] + Op.PUSH2[0x2d5f] + Op.CALL + Op.PUSH1[0x0] + " + "Op.SSTORE", ] complex_vector = [ - "0x7fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf5f527fc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf6020527fe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff60405260786040356020355f35608a565b5f515f55602051600155604051600255005b5e56", # noqa: E501 - "Op.PUSH32[0xa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf] + Op.PUSH0 + Op.MSTORE + Op.PUSH32[0xc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf] + Op.PUSH1[0x20] + Op.MSTORE + Op.PUSH32[0xe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff] + Op.PUSH1[0x40] + Op.MSTORE + Op.PUSH1[0x78] + Op.PUSH1[0x40] + Op.CALLDATALOAD + Op.PUSH1[0x20] + Op.CALLDATALOAD + Op.PUSH0 + Op.CALLDATALOAD + Op.PUSH1[0x8a] + Op.JUMP + Op.JUMPDEST + Op.PUSH0 + Op.MLOAD + Op.PUSH0 + Op.SSTORE + Op.PUSH1[0x20] + Op.MLOAD + Op.PUSH1[0x1] + Op.SSTORE + Op.PUSH1[0x40] + Op.MLOAD + Op.PUSH1[0x2] + Op.SSTORE + Op.STOP + Op.JUMPDEST + Op.MCOPY + Op.JUMP", # noqa: E501 + "0x7fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbeb" + "f5f527fc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdd" + "dedf6020527fe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9faf" + "bfcfdfeff60405260786040356020355f35608a565b5f515f556020516001556040" + "51600255005b5e56", + "Op.PUSH32[0xa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9bab" + "bbcbdbebf] + Op.PUSH0 + Op.MSTORE + Op.PUSH32[0xc0c1c2c3c4c5c6c7c8c" + "9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf] + Op.PUSH1[0x20] + " + "Op.MSTORE + Op.PUSH32[0xe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f" + "5f6f7f8f9fafbfcfdfeff] + Op.PUSH1[0x40] + Op.MSTORE + Op.PUSH1[0x78] + " + "Op.PUSH1[0x40] + Op.CALLDATALOAD + Op.PUSH1[0x20] + Op.CALLDATALOAD + " + "Op.PUSH0 + Op.CALLDATALOAD + Op.PUSH1[0x8a] + Op.JUMP + Op.JUMPDEST + " + "Op.PUSH0 + Op.MLOAD + Op.PUSH0 + Op.SSTORE + Op.PUSH1[0x20] + Op.MLOAD + " + "Op.PUSH1[0x1] + Op.SSTORE + Op.PUSH1[0x40] + Op.MLOAD + Op.PUSH1[0x2] + " + "Op.SSTORE + Op.STOP + Op.JUMPDEST + Op.MCOPY + Op.JUMP", ] rjump_vector = [ "0xe0fffe", @@ -24,8 +39,9 @@ ] rjumpv_vector = [ "0xe213b1465aef60276095472e3250cf64736f6c63430008150033a26469706673582212206eab0a7969fe", - "Op.RJUMPV[-0x4eba, 0x5aef, 0x6027, 0x6095, 0x472e, 0x3250, -0x309c, 0x736f, 0x6c63, 0x4300," - + " 0x815, 0x33, -0x5d9c, 0x6970, 0x6673, 0x5822, 0x1220, 0x6eab, 0xa79, 0x69fe]", + "Op.RJUMPV[-0x4eba, 0x5aef, 0x6027, 0x6095, 0x472e, 0x3250, -0x309c, " + "0x736f, 0x6c63, 0x4300," + " 0x815, 0x33, -0x5d9c, 0x6970, 0x6673, 0x5822, 0x1220, 0x6eab, " + "0xa79, 0x69fe]", ] diff --git a/src/cli/tests/test_generate_all_formats.py b/src/cli/tests/test_generate_all_formats.py index 9f49678464d..a939f61932d 100644 --- a/src/cli/tests/test_generate_all_formats.py +++ b/src/cli/tests/test_generate_all_formats.py @@ -30,7 +30,9 @@ def test_generate_all_formats_creates_two_phase_execution(): def test_generate_all_formats_preserves_other_args(): - """Test that --generate-all-formats preserves other command line arguments.""" + """ + Test that --generate-all-formats preserves other command line arguments. + """ command = FillCommand() with patch.object(command, "process_arguments", side_effect=lambda x: x): @@ -86,7 +88,8 @@ def test_legacy_generate_pre_alloc_groups_still_works(): phase1_args = executions[0].args assert "--generate-pre-alloc-groups" in phase1_args - # Phase 2: Should have --use-pre-alloc-groups but NOT --generate-all-formats + # Phase 2: Should have --use-pre-alloc-groups but NOT --generate-all- + # formats phase2_args = executions[1].args assert "--use-pre-alloc-groups" in phase2_args assert "--generate-all-formats" not in phase2_args @@ -110,7 +113,9 @@ def test_single_phase_without_flags(): def test_tarball_output_auto_enables_generate_all_formats(): - """Test that tarball output automatically enables --generate-all-formats.""" + """ + Test that tarball output automatically enables --generate-all-formats. + """ command = FillCommand() with patch.object(command, "process_arguments", side_effect=lambda x: x): @@ -124,7 +129,8 @@ def test_tarball_output_auto_enables_generate_all_formats(): phase1_args = executions[0].args assert "--generate-pre-alloc-groups" in phase1_args - # Phase 2: Should have --generate-all-formats (auto-added) and --use-pre-alloc-groups + # Phase 2: Should have --generate-all-formats (auto-added) and --use-pre- + # alloc-groups phase2_args = executions[1].args assert "--generate-all-formats" in phase2_args assert "--use-pre-alloc-groups" in phase2_args @@ -132,7 +138,10 @@ def test_tarball_output_auto_enables_generate_all_formats(): def test_tarball_output_with_explicit_generate_all_formats(): - """Test that explicit --generate-all-formats with tarball output works correctly.""" + """ + Test that explicit --generate-all-formats with tarball output works + correctly. + """ command = FillCommand() with patch.object(command, "process_arguments", side_effect=lambda x: x): @@ -150,7 +159,10 @@ def test_tarball_output_with_explicit_generate_all_formats(): def test_regular_output_does_not_auto_trigger_two_phase(): - """Test that regular directory output doesn't auto-trigger two-phase execution.""" + """ + Test that regular directory output doesn't auto-trigger two-phase + execution. + """ command = FillCommand() with patch.object(command, "process_arguments", side_effect=lambda x: x): diff --git a/src/cli/tests/test_order_fixtures.py b/src/cli/tests/test_order_fixtures.py index 27a88ceef7b..0c3f2db4f7f 100644 --- a/src/cli/tests/test_order_fixtures.py +++ b/src/cli/tests/test_order_fixtures.py @@ -57,7 +57,9 @@ def test_cli_invocation(input_output_dirs): def test_input_is_file_instead_of_directory(): - """Test the CLI interface when the input path is a file, not a directory.""" + """ + Test the CLI interface when the input path is a file, not a directory. + """ runner = CliRunner() with TemporaryDirectory() as temp_dir: temp_file = Path(temp_dir) / "temp_file.txt" diff --git a/src/cli/tests/test_pytest_fill_command.py b/src/cli/tests/test_pytest_fill_command.py index 95c3a3e8f47..0386b05d4e1 100644 --- a/src/cli/tests/test_pytest_fill_command.py +++ b/src/cli/tests/test_pytest_fill_command.py @@ -50,11 +50,12 @@ class TestHtmlReportFlags: @pytest.fixture def fill_args(self, default_t8n): """ - Provide default arguments for the `fill` command when testing html report - generation. + Provide default arguments for the `fill` command when testing html + report generation. - Specifies a single existing example test case for faster fill execution, - and to allow for tests to check for the fixture generation location. + Specifies a single existing example test case for faster fill + execution, and to allow for tests to check for the fixture generation + location. """ return [ "-k", @@ -81,8 +82,8 @@ def monkeypatch_default_output_directory(self, monkeypatch, temp_dir): """ Monkeypatch default output directory for the pytest commands. - This avoids using the local directory in user space for the output of pytest - commands and uses the a temporary directory instead. + This avoids using the local directory in user space for the output of + pytest commands and uses the a temporary directory instead. """ def mock_default_output_directory(): @@ -101,7 +102,10 @@ def test_fill_default_output_options( fill_args, default_html_report_file_path, ): - """Test default pytest html behavior: Neither `--html` or `--output` is specified.""" + """ + Test default pytest html behavior: Neither `--html` or `--output` is + specified. + """ default_html_path = temp_dir / default_html_report_file_path result = runner.invoke(fill, fill_args) assert result.exit_code == pytest.ExitCode.OK @@ -141,7 +145,9 @@ def test_fill_output_option( fill_args, default_html_report_file_path, ): - """Tests pytest html report generation with only the `--output` flag.""" + """ + Tests pytest html report generation with only the `--output` flag. + """ output_dir = temp_dir / "non_default_output_dir" non_default_html_path = output_dir / default_html_report_file_path fill_args += ["--output", str(output_dir)] @@ -156,7 +162,10 @@ def test_fill_html_and_output_options( temp_dir, fill_args, ): - """Tests pytest html report generation with both `--output` and `--html` flags.""" + """ + Tests pytest html report generation with both `--output` and `--html` + flags. + """ output_dir = temp_dir / "non_default_output_dir_fixtures" html_path = temp_dir / "non_default_output_dir_html" / "non_default.html" fill_args += ["--output", str(output_dir), "--html", str(html_path)] diff --git a/src/cli/tox_helpers.py b/src/cli/tox_helpers.py index 7dbe0c26cf1..63b4cee668f 100644 --- a/src/cli/tox_helpers.py +++ b/src/cli/tox_helpers.py @@ -2,8 +2,8 @@ CLI commands used by tox.ini. Contains wrappers to the external commands markdownlint-cli2 and pyspelling -(requires aspell) that fail silently if the command is not available. The -aim is to avoid disruption to external contributors. +(requires aspell) that fail silently if the command is not available. The aim +is to avoid disruption to external contributors. """ import os @@ -23,10 +23,11 @@ def write_github_summary(title: str, tox_env: str, error_message: str, fix_comma Write a summary to GitHub Actions when a check fails. Args: - title: The title of the check that failed - tox_env: The tox environment name (e.g., "spellcheck") - error_message: Description of what went wrong - fix_commands: List of commands to fix the issue locally + title: The title of the check that failed tox_env: The tox + environment name (e.g., "spellcheck") + tox_env: The tox environment + error_message: Description of what went wrong + fix_commands: List of commands to fix the issue locally """ if not os.environ.get("GITHUB_ACTIONS"): @@ -70,7 +71,8 @@ def markdownlint(args): """ markdownlint = shutil.which("markdownlint-cli2") if not markdownlint: - # Note: There's an additional step in test.yaml to run markdownlint-cli2 in GitHub Actions + # Note: There's an additional step in test.yaml to run markdownlint- + # cli2 in GitHub Actions click.echo("********* Install 'markdownlint-cli2' to enable markdown linting *********") sys.exit(0) @@ -194,7 +196,8 @@ def codespell(): @click.command() def validate_changelog(): """ - Validate changelog formatting to ensure bullet points end with proper punctuation. + Validate changelog formatting to ensure bullet points end with proper + punctuation. Checks that all bullet points (including nested ones) end with either: - A period (.) for regular entries diff --git a/src/config/docs.py b/src/config/docs.py index f081e92d151..18454aee8f4 100644 --- a/src/config/docs.py +++ b/src/config/docs.py @@ -1,8 +1,7 @@ """ A module for managing documentation-related configurations. -Classes: -- DocsConfig: Holds configurations for documentation generation. +Classes: - DocsConfig: Holds configurations for documentation generation. """ from pydantic import BaseModel @@ -19,5 +18,6 @@ class DocsConfig(BaseModel): DOCS_BASE_URL: str = "https://eest.ethereum.org" - # Documentation URLs prefixed with `DOCS_URL__` to avoid conflicts with other URLs + # Documentation URLs prefixed with `DOCS_URL__` to avoid conflicts with + # other URLs DOCS_URL__WRITING_TESTS: str = f"{DOCS_BASE_URL}/main/writing_tests/" diff --git a/src/config/env.py b/src/config/env.py index 0e2811b2055..f2bf92b2f2b 100644 --- a/src/config/env.py +++ b/src/config/env.py @@ -1,12 +1,14 @@ """ A module for exposing application-wide environment variables. -This module is responsible for loading, parsing, and validating the application's -environment configuration from the `env.yaml` file. It uses Pydantic to ensure that -the configuration adheres to expected formats and types. +This module is responsible for loading, parsing, and validating the +application's environment configuration from the `env.yaml` file. It uses +Pydantic to ensure that the configuration adheres to expected formats and +types. Functions: -- create_default_config: Creates a default configuration file if it doesn't exist. +- create_default_config: Creates a default configuration file if it + doesn't exist. Classes: - EnvConfig: Loads the configuration and exposes it as Python objects. @@ -32,9 +34,11 @@ class RemoteNode(BaseModel): Represents a configuration for a remote node. Attributes: - - name (str): The name of the remote node. - - node_url (HttpUrl): The URL for the remote node, validated as a proper URL. - - rpc_headers (Dict[str, str]): A dictionary of optional RPC headers, defaults to empty dict. + name (str): The name of the remote node. + node_url (HttpUrl): The URL for the remote node, validated as a + proper URL. + rpc_headers (Dict[str, str]): A dictionary of optional RPC headers, + defaults to empty dict. """ @@ -48,7 +52,7 @@ class Config(BaseModel): Represents the overall environment configuration. Attributes: - - remote_nodes (List[RemoteNode]): A list of remote node configurations. + remote_nodes (List[RemoteNode]): A list of remote node configurations. """ @@ -59,8 +63,8 @@ class EnvConfig(Config): """ Loads and validates environment configuration from `env.yaml`. - This is a wrapper class for the Config model. It reads a config file - from disk into a Config model and then exposes it. + This is a wrapper class for the Config model. It reads a config file from + disk into a Config model and then exposes it. """ def __init__(self): diff --git a/src/conftest.py b/src/conftest.py index 59fb310c5fb..82c42bb48b8 100644 --- a/src/conftest.py +++ b/src/conftest.py @@ -14,7 +14,8 @@ for transition_tool in TransitionTool.registered_tools if ( transition_tool.is_installed() - # Currently, Besu has the same `default_binary` as Geth, so we can't use `is_installed`. + # Currently, Besu has the same `default_binary` as Geth, so we can't + # use `is_installed`. and transition_tool != BesuTransitionTool ) ] @@ -32,7 +33,8 @@ def installed_transition_tool_instances() -> Generator[ transition_tool_instance.start_server() instances[transition_tool_class.__name__] = transition_tool_instance except Exception as e: - # Record the exception in order to provide context when failing the appropriate test + # Record the exception in order to provide context when failing the + # appropriate test instances[transition_tool_class.__name__] = e yield instances for instance in instances.values(): diff --git a/src/ethereum_clis/__init__.py b/src/ethereum_clis/__init__.py index 9b2850b7242..6a21ab3c2e1 100644 --- a/src/ethereum_clis/__init__.py +++ b/src/ethereum_clis/__init__.py @@ -1,4 +1,7 @@ -"""Library of Python wrappers for the different implementations of transition tools.""" +""" +Library of Python wrappers for the different implementations of transition +tools. +""" from .cli_types import ( BlockExceptionWithMessage, diff --git a/src/ethereum_clis/cli_types.py b/src/ethereum_clis/cli_types.py index b6c9b48bad0..d8745a1034a 100644 --- a/src/ethereum_clis/cli_types.py +++ b/src/ethereum_clis/cli_types.py @@ -99,8 +99,8 @@ def from_file(cls, trace_file_path: Path) -> Self: @staticmethod def remove_gas(traces: List[TraceLine]): """ - Remove the GAS operation opcode result from the stack to make comparison possible - even if the gas has been pushed to the stack. + Remove the GAS operation opcode result from the stack to make + comparison possible even if the gas has been pushed to the stack. """ for i in range(1, len(traces)): trace = traces[i] @@ -143,7 +143,9 @@ def print(self): class Traces(EthereumTestRootModel): - """Traces returned from the transition tool for all transactions executed.""" + """ + Traces returned from the transition tool for all transactions executed. + """ root: List[TransactionTraces] diff --git a/src/ethereum_clis/clis/ethereumjs.py b/src/ethereum_clis/clis/ethereumjs.py index 45e7aed7358..5c37822074c 100644 --- a/src/ethereum_clis/clis/ethereumjs.py +++ b/src/ethereum_clis/clis/ethereumjs.py @@ -38,14 +38,16 @@ def __init__( def is_fork_supported(self, fork: Fork) -> bool: """ - Return True if the fork is supported by the tool. - Currently, EthereumJS-t8n provides no way to determine supported forks. + Return True if the fork is supported by the tool. Currently, + EthereumJS-t8n provides no way to determine supported forks. """ return True class EthereumJSExceptionMapper(ExceptionMapper): - """Translate between EEST exceptions and error strings returned by EthereumJS.""" + """ + Translate between EEST exceptions and error strings returned by EthereumJS. + """ mapping_substring: ClassVar[Dict[ExceptionBase, str]] = { TransactionException.TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED: ( diff --git a/src/ethereum_clis/clis/ethrex.py b/src/ethereum_clis/clis/ethrex.py index 69cbbfde421..1d3c17a58da 100644 --- a/src/ethereum_clis/clis/ethrex.py +++ b/src/ethereum_clis/clis/ethrex.py @@ -48,7 +48,8 @@ class EthrexExceptionMapper(ExceptionMapper): r"blob versioned hashes not supported|" r"Type 3 transactions are not supported before the Cancun fork" ), - # A type 4 Transaction without a recipient won't even reach the EVM, we can't decode it. + # A type 4 Transaction without a recipient won't even reach the EVM, we + # can't decode it. TransactionException.TYPE_4_TX_CONTRACT_CREATION: ( r"unexpected length|Contract creation in type 4 transaction|" r"Error decoding field 'to' of type primitive_types::H160: InvalidLength" diff --git a/src/ethereum_clis/clis/evmone.py b/src/ethereum_clis/clis/evmone.py index c76dfd4cf9f..e2f34f8fb06 100644 --- a/src/ethereum_clis/clis/evmone.py +++ b/src/ethereum_clis/clis/evmone.py @@ -37,14 +37,16 @@ def __init__( def is_fork_supported(self, fork: Fork) -> bool: """ - Return True if the fork is supported by the tool. - Currently, evmone-t8n provides no way to determine supported forks. + Return True if the fork is supported by the tool. Currently, evmone-t8n + provides no way to determine supported forks. """ return True class EvmoneExceptionMapper(ExceptionMapper): - """Translate between EEST exceptions and error strings returned by Evmone.""" + """ + Translate between EEST exceptions and error strings returned by Evmone. + """ mapping_substring: ClassVar[Dict[ExceptionBase, str]] = { TransactionException.SENDER_NOT_EOA: "sender not an eoa:", @@ -82,7 +84,8 @@ class EvmoneExceptionMapper(ExceptionMapper): ), TransactionException.NONCE_MISMATCH_TOO_LOW: "nonce too low", TransactionException.NONCE_MISMATCH_TOO_HIGH: "nonce too high", - # TODO EVMONE needs to differentiate when the section is missing in the header or body + # TODO EVMONE needs to differentiate when the section is missing in the + # header or body EOFException.MISSING_STOP_OPCODE: "err: no_terminating_instruction", EOFException.MISSING_CODE_HEADER: "err: code_section_missing", EOFException.MISSING_TYPE_HEADER: "err: type_section_missing", diff --git a/src/ethereum_clis/clis/execution_specs.py b/src/ethereum_clis/clis/execution_specs.py index 31b5dd2e430..ec2ac7a3349 100644 --- a/src/ethereum_clis/clis/execution_specs.py +++ b/src/ethereum_clis/clis/execution_specs.py @@ -29,19 +29,22 @@ class ExecutionSpecsTransitionTool(TransitionTool): """ - Ethereum Specs EVM Resolver `ethereum-spec-evm-resolver` Transition Tool wrapper class. + Ethereum Specs EVM Resolver `ethereum-spec-evm-resolver` Transition Tool + wrapper class. - `ethereum-spec-evm-resolver` is installed by default for `execution-spec-tests`: + `ethereum-spec-evm-resolver` is installed by default for + `execution-spec-tests`: ```console - uv run fill --evm-bin=ethereum-spec-evm-resolver + uv run fill --evm-bin=ethereum-spec-evm-resolver ``` - To use a specific version of the `ethereum-spec-evm-resolver` tool, update it to the - desired version in `pyproject.toml`. + To use a specific version of the `ethereum-spec-evm-resolver` tool, update + it to the desired version in `pyproject.toml`. - The `ethereum-spec-evm-resolver` tool essentially wraps around the EELS evm daemon. It can - handle requests for different EVM forks, even when those forks are implemented by different - versions of EELS hosted in different places. + The `ethereum-spec-evm-resolver` tool essentially wraps around the EELS evm + daemon. It can handle requests for different EVM forks, even when those + forks are implemented by different versions of EELS hosted in different + places. """ default_binary = Path("ethereum-spec-evm-resolver") @@ -57,7 +60,9 @@ def __init__( trace: bool = False, server_url: str | None = None, ): - """Initialize the Ethereum Specs EVM Resolver Transition Tool interface.""" + """ + Initialize the Ethereum Specs EVM Resolver Transition Tool interface. + """ os.environ.setdefault("NO_PROXY", "*") # Disable proxy for local connections super().__init__( exception_mapper=ExecutionSpecsExceptionMapper(), binary=binary, trace=trace @@ -114,7 +119,8 @@ def is_fork_supported(self, fork: Fork) -> bool: """ Return True if the fork is supported by the tool. - If the fork is a transition fork, we want to check the fork it transitions to. + If the fork is a transition fork, we want to check the fork it + transitions to. `ethereum-spec-evm` appends newlines to forks in the help string. """ @@ -135,7 +141,10 @@ def _generate_post_args( class ExecutionSpecsExceptionMapper(ExceptionMapper): - """Translate between EEST exceptions and error strings returned by ExecutionSpecs.""" + """ + Translate between EEST exceptions and error strings returned by + ExecutionSpecs. + """ mapping_substring: ClassVar[Dict[ExceptionBase, str]] = { TransactionException.TYPE_4_EMPTY_AUTHORIZATION_LIST: "EmptyAuthorizationListError", diff --git a/src/ethereum_clis/clis/geth.py b/src/ethereum_clis/clis/geth.py index bf805270805..769315aa4b6 100644 --- a/src/ethereum_clis/clis/geth.py +++ b/src/ethereum_clis/clis/geth.py @@ -200,7 +200,8 @@ def is_fork_supported(self, fork: Fork) -> bool: """ Return True if the fork is supported by the tool. - If the fork is a transition fork, we want to check the fork it transitions to. + If the fork is a transition fork, we want to check the fork it + transitions to. """ return fork.transition_tool_name() in self.help_string @@ -221,8 +222,8 @@ def consume_blockchain_test( """ Consume a single blockchain test. - The `evm blocktest` command takes the `--run` argument which can be used to select a - specific fixture from the fixture file when executing. + The `evm blocktest` command takes the `--run` argument which can be + used to select a specific fixture from the fixture file when executing. """ subcommand = "blocktest" global_options = [] @@ -273,10 +274,10 @@ def consume_state_test_file( """ Consume an entire state test file. - The `evm statetest` will always execute all the tests contained in a file without the - possibility of selecting a single test, so this function is cached in order to only call - the command once and `consume_state_test` can simply select the result that - was requested. + The `evm statetest` will always execute all the tests contained in a + file without the possibility of selecting a single test, so this + function is cached in order to only call the command once and + `consume_state_test` can simply select the result that was requested. """ subcommand = "statetest" global_options: List[str] = [] @@ -316,8 +317,8 @@ def consume_state_test( """ Consume a single state test. - Uses the cached result from `consume_state_test_file` in order to not call the command - every time an select a single result from there. + Uses the cached result from `consume_state_test_file` in order to not + call the command every time an select a single result from there. """ file_results = self.consume_state_test_file( fixture_path=fixture_path, @@ -346,7 +347,10 @@ def consume_fixture( fixture_name: Optional[str] = None, debug_output_path: Optional[Path] = None, ): - """Execute the appropriate geth fixture consumer for the fixture at `fixture_path`.""" + """ + Execute the appropriate geth fixture consumer for the fixture at + `fixture_path`. + """ if fixture_format == BlockchainFixture: self.consume_blockchain_test( fixture_path=fixture_path, diff --git a/src/ethereum_clis/clis/nethermind.py b/src/ethereum_clis/clis/nethermind.py index 13bf2c776f2..51432988a59 100644 --- a/src/ethereum_clis/clis/nethermind.py +++ b/src/ethereum_clis/clis/nethermind.py @@ -96,8 +96,9 @@ def has_eof_support(self) -> bool: """ Return True if the `nethtest` binary supports the `--eofTest` flag. - Currently, nethtest EOF support is only available in nethermind's feature/evm/eof - branch https://github.com/NethermindEth/nethermind/tree/feature/evm/eof + Currently, nethtest EOF support is only available in nethermind's + feature/evm/eof branch + https://github.com/NethermindEth/nethermind/tree/feature/evm/eof """ return "--eofTest" in self.help() @@ -121,7 +122,8 @@ def _build_command_with_options( if fixture_format is BlockchainFixture: command += ["--blockTest", "--filter", f"{re.escape(fixture_name)}"] elif fixture_format is StateFixture: - # TODO: consider using `--filter` here to readily access traces from the output + # TODO: consider using `--filter` here to readily access traces + # from the output pass # no additional options needed elif fixture_format is EOFFixture: command += ["--eofTest"] @@ -144,10 +146,10 @@ def consume_state_test_file( """ Consume an entire state test file. - The `evm statetest` will always execute all the tests contained in a file without the - possibility of selecting a single test, so this function is cached in order to only call - the command once and `consume_state_test` can simply select the result that - was requested. + The `evm statetest` will always execute all the tests contained in a + file without the possibility of selecting a single test, so this + function is cached in order to only call the command once and + `consume_state_test` can simply select the result that was requested. """ result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) @@ -180,8 +182,8 @@ def consume_state_test( """ Consume a single state test. - Uses the cached result from `consume_state_test_file` in order to not call the command - every time an select a single result from there. + Uses the cached result from `consume_state_test_file` in order to not + call the command every time an select a single result from there. """ file_results, stderr = self.consume_state_test_file( fixture_path=fixture_path, @@ -203,9 +205,10 @@ def consume_state_test( for test_result in file_results if test_result["name"].removesuffix(nethtest_suffix) == f"{fixture_name.split('/')[-1]}" - # TODO: the following was required for nethermind's feature/evm/eof branch - # nethtest version: 1.32.0-unstable+025871675bd2e0839f93d2b70416ebae9dbae012 - # == f"{fixture_name.split('.py::')[-1]}" + # TODO: the following was required for nethermind's + # feature/evm/eof branch nethtest version: + # 1.32.0-unstable+025871675bd2e0839f93d2b70416ebae9dbae012 == + # f"{fixture_name.split('.py::')[-1]}" ] assert len(test_result) < 2, f"Multiple test results for {fixture_name}" assert len(test_result) == 1, f"Test result for {fixture_name} missing" @@ -254,7 +257,8 @@ def consume_eof_test_file( pattern = re.compile(r"^(test_.+?)\s+(PASS|FAIL)$", re.MULTILINE) test_results = { - match.group(1): match.group(2) == "PASS" # Convert "PASS" to True and "FAIL" to False + match.group(1): match.group(2) == "PASS" # Convert "PASS" to True + # and "FAIL" to False for match in pattern.finditer(result.stdout) } @@ -297,7 +301,10 @@ def consume_fixture( fixture_name: Optional[str] = None, debug_output_path: Optional[Path] = None, ): - """Execute the appropriate geth fixture consumer for the fixture at `fixture_path`.""" + """ + Execute the appropriate geth fixture consumer for the fixture at + `fixture_path`. + """ command = self._build_command_with_options( fixture_format, fixture_path, fixture_name, debug_output_path ) diff --git a/src/ethereum_clis/clis/nimbus.py b/src/ethereum_clis/clis/nimbus.py index 6c0960774c5..a1f167c363e 100644 --- a/src/ethereum_clis/clis/nimbus.py +++ b/src/ethereum_clis/clis/nimbus.py @@ -57,13 +57,16 @@ def is_fork_supported(self, fork: Fork) -> bool: """ Return True if the fork is supported by the tool. - If the fork is a transition fork, we want to check the fork it transitions to. + If the fork is a transition fork, we want to check the fork it + transitions to. """ return fork.transition_tool_name() in self.help_string class NimbusExceptionMapper(ExceptionMapper): - """Translate between EEST exceptions and error strings returned by Nimbus.""" + """ + Translate between EEST exceptions and error strings returned by Nimbus. + """ mapping_substring: ClassVar[Dict[ExceptionBase, str]] = { TransactionException.TYPE_4_TX_CONTRACT_CREATION: ( diff --git a/src/ethereum_clis/ethereum_cli.py b/src/ethereum_clis/ethereum_cli.py index 7ea060fcc7c..6bdbf646ea7 100644 --- a/src/ethereum_clis/ethereum_cli.py +++ b/src/ethereum_clis/ethereum_cli.py @@ -20,7 +20,9 @@ class UnknownCLIError(Exception): class CLINotFoundInPathError(Exception): - """Exception raised if the specified CLI binary is not found in the path.""" + """ + Exception raised if the specified CLI binary is not found in the path. + """ def __init__(self, message="The CLI binary was not found in the path", binary=None): """Initialize the exception.""" @@ -49,11 +51,14 @@ class EthereumCLI: cached_version: Optional[str] = None def __init__(self, *, binary: Optional[Path] = None): - """Abstract initialization method that all subclasses must implement.""" + """ + Abstract initialization method that all subclasses must implement. + """ if binary is None: binary = self.default_binary else: - # improve behavior of which by resolving the path: ~/relative paths don't work + # improve behavior of which by resolving the path: ~/relative paths + # don't work resolved_path = Path(os.path.expanduser(binary)).resolve() if resolved_path.exists(): binary = resolved_path @@ -75,10 +80,12 @@ def set_default_tool(cls, tool_subclass: Type[Any]): @classmethod def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> Any: """ - Instantiate the appropriate CLI subclass derived from the CLI's `binary_path`. + Instantiate the appropriate CLI subclass derived from the CLI's + `binary_path`. - This method will attempt to detect the CLI version and instantiate the appropriate - subclass based on the version output by running the CLI with the version flag. + This method will attempt to detect the CLI version and instantiate the + appropriate subclass based on the version output by running the CLI + with the version flag. """ assert cls.default_tool is not None, "default CLI implementation was never set" @@ -114,8 +121,8 @@ def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> Any: logger.debug(f"Successfully located the path of the t8n binary: {binary}") binary = Path(binary) - # Group the tools by version flag, so we only have to call the tool once for all the - # classes that share the same version flag + # Group the tools by version flag, so we only have to call the tool + # once for all the classes that share the same version flag for version_flag, subclasses in groupby( cls.registered_tools, key=lambda x: x.version_flag ): @@ -134,7 +141,9 @@ def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> Any: if result.returncode != 0: logger.debug(f"Subprocess returncode is not 0! It is: {result.returncode}") - continue # don't raise exception, you are supposed to keep trying different version flags # noqa: E501 + continue + # don't raise exception, you are supposed to keep + # trying different version flags if result.stderr: logger.debug(f"Stderr detected: {result.stderr}") # type: ignore @@ -143,10 +152,6 @@ def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> Any: binary_output = "" if result.stdout: binary_output = result.stdout.decode().strip() - # e.g. 1.31.10+f62cfede9b4abfb5cd62d6f138240668620a2b0d should be treated as 1.31.10 # noqa: E501 - # if "+" in binary_output: - # binary_output = binary_output.split("+")[0] - logger.debug(f"Stripped subprocess stdout: {binary_output}") for subclass in subclasses: @@ -169,7 +174,10 @@ def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> Any: @classmethod def detect_binary(cls, binary_output: str) -> bool: - """Return True if a CLI's `binary_output` matches the class's expected output.""" + """ + Return True if a CLI's `binary_output` matches the class's expected + output. + """ assert cls.detect_binary_pattern is not None return cls.detect_binary_pattern.match(binary_output) is not None @@ -187,7 +195,10 @@ def is_installed(cls, binary_path: Optional[Path] = None) -> bool: return binary is not None def version(self) -> str: - """Return the name and version of the CLI as reported by the CLI's version flag.""" + """ + Return the name and version of the CLI as reported by the CLI's version + flag. + """ if self.cached_version is None: result = subprocess.run( [str(self.binary), self.version_flag], diff --git a/src/ethereum_clis/fixture_consumer_tool.py b/src/ethereum_clis/fixture_consumer_tool.py index 1f958e2c139..3391c49a9ce 100644 --- a/src/ethereum_clis/fixture_consumer_tool.py +++ b/src/ethereum_clis/fixture_consumer_tool.py @@ -9,8 +9,8 @@ class FixtureConsumerTool(FixtureConsumer, EthereumCLI): """ - Fixture consumer tool abstract base class which should be inherited by all fixture consumer - tool implementations. + Fixture consumer tool abstract base class which should be inherited by all + fixture consumer tool implementations. """ registered_tools: List[Type["FixtureConsumerTool"]] = [] diff --git a/src/ethereum_clis/tests/test_execution_specs.py b/src/ethereum_clis/tests/test_execution_specs.py index 964820dd8a6..a748c9a5b31 100644 --- a/src/ethereum_clis/tests/test_execution_specs.py +++ b/src/ethereum_clis/tests/test_execution_specs.py @@ -22,10 +22,11 @@ @pytest.fixture(autouse=True) def monkeypatch_path_for_entry_points(monkeypatch): """ - Monkeypatch the PATH to add the "bin" directory where entrypoints are installed. + Monkeypatch the PATH to add the "bin" directory where entrypoints are + installed. - This would typically be in the venv in which pytest is running these tests and fill, - which, with uv, is `./.venv/bin`. + This would typically be in the venv in which pytest is running these tests + and fill, which, with uv, is `./.venv/bin`. This is required in order for fill to locate the ethereum-spec-evm-resolver "binary" (entrypoint) when being executed using pytester. @@ -98,7 +99,8 @@ def test_evm_tool_binary_arg(evm_tool, binary_arg): elif binary_arg == "path_type": evm_bin = which(DEFAULT_EVM_T8N_BINARY_NAME) if not evm_bin: - # typing: Path can not take None; but if it is None, we may as well fail explicitly. + # typing: Path can not take None; but if it is None, we may as well + # fail explicitly. raise Exception("Failed to find `{DEFAULT_EVM_T8N_BINARY_NAME}` in the PATH via which") evm_tool(binary=Path(evm_bin)).version() return @@ -143,7 +145,9 @@ def test_evm_t8n( env: Environment, test_dir: str, ) -> None: - """Test the `evaluate` method of the `ExecutionSpecsTransitionTool` class.""" + """ + Test the `evaluate` method of the `ExecutionSpecsTransitionTool` class. + """ expected_path = Path(FIXTURES_ROOT, test_dir, "exp.json") with open(expected_path, "r") as exp: @@ -162,8 +166,9 @@ def test_evm_t8n( ) assert to_json(t8n_output.alloc) == expected.get("alloc") if isinstance(default_t8n, ExecutionSpecsTransitionTool): - # The expected output was generated with geth, instead of deleting any info from - # this expected output, the fields not returned by eels are handled here. + # The expected output was generated with geth, instead of deleting + # any info from this expected output, the fields not returned by + # eels are handled here. missing_receipt_fields = [ "root", "status", diff --git a/src/ethereum_clis/tests/test_transition_tools_support.py b/src/ethereum_clis/tests/test_transition_tools_support.py index 953af15744b..8c6f94278bc 100644 --- a/src/ethereum_clis/tests/test_transition_tools_support.py +++ b/src/ethereum_clis/tests/test_transition_tools_support.py @@ -44,7 +44,9 @@ def test_ci_multi_t8n_support( installed_transition_tool_instances: Dict[str, TransitionTool | Exception], running_in_ci: bool, ): - """Check that the instances of t8n we expect in CI environment were found.""" + """ + Check that the instances of t8n we expect in CI environment were found. + """ names = set(installed_transition_tool_instances.keys()) expected_names = {"ExecutionSpecsTransitionTool"} if running_in_ci: diff --git a/src/ethereum_clis/transition_tool.py b/src/ethereum_clis/transition_tool.py index c3fa04ec278..7d56eb80d5c 100644 --- a/src/ethereum_clis/transition_tool.py +++ b/src/ethereum_clis/transition_tool.py @@ -38,22 +38,24 @@ model_dump_config: Mapping = {"by_alias": True, "exclude_none": True} -# TODO: reduce NORMAL_SERVER_TIMEOUT back down to 20 once BLS timeout issue is resolved: -# https://github.com/ethereum/execution-spec-tests/issues/1894 +# TODO: reduce NORMAL_SERVER_TIMEOUT back down to 20 once BLS timeout issue is +# resolved: https://github.com/ethereum/execution-spec-tests/issues/1894 NORMAL_SERVER_TIMEOUT = 600 SLOW_REQUEST_TIMEOUT = 600 def get_valid_transition_tool_names() -> set[str]: - """Get all valid transition tool names from deployed and development forks.""" + """ + Get all valid transition tool names from deployed and development forks. + """ all_available_forks = get_forks() + get_development_forks() return {fork.transition_tool_name() for fork in all_available_forks} class TransitionTool(EthereumCLI): """ - Transition tool abstract base class which should be inherited by all transition tool - implementations. + Transition tool abstract base class which should be inherited by all + transition tool implementations. """ traces: List[Traces] | None = None @@ -80,7 +82,9 @@ def __init__( binary: Optional[Path] = None, trace: bool = False, ): - """Abstract initialization method that all subclasses must implement.""" + """ + Abstract initialization method that all subclasses must implement. + """ assert exception_mapper is not None self.exception_mapper = exception_mapper super().__init__(binary=binary) @@ -112,7 +116,9 @@ def reset_traces(self): self.traces = None def append_traces(self, new_traces: Traces): - """Append a list of traces of a state transition to the current list.""" + """ + Append a list of traces of a state transition to the current list. + """ if self.traces is None: self.traces = [] self.traces.append(new_traces) @@ -127,7 +133,10 @@ def collect_traces( temp_dir: tempfile.TemporaryDirectory, debug_output_path: str = "", ) -> Traces: - """Collect the traces from the t8n tool output and store them in the traces list.""" + """ + Collect the traces from the t8n tool output and store them in the + traces list. + """ traces: Traces = Traces(root=[]) temp_dir_path = Path(temp_dir.name) for i, r in enumerate(receipts): @@ -194,7 +203,10 @@ def _evaluate_filesystem( t8n_data: TransitionToolData, debug_output_path: str = "", ) -> TransitionToolOutput: - """Execute a transition tool using the filesystem for its inputs and outputs.""" + """ + Execute a transition tool using the filesystem for its inputs and + outputs. + """ temp_dir = tempfile.TemporaryDirectory() os.mkdir(os.path.join(temp_dir.name, "input")) os.mkdir(os.path.join(temp_dir.name, "output")) @@ -256,14 +268,16 @@ def _evaluate_filesystem( t8n_call = t8n_call.replace( os.path.dirname(file_path), os.path.join(debug_output_path, "input") ) - t8n_call = t8n_call.replace( # use a new output path for basedir and outputs + t8n_call = t8n_call.replace( # use a new output path for basedir + # and outputs temp_dir.name, t8n_output_base_dir, ) t8n_script = textwrap.dedent( f"""\ #!/bin/bash - rm -rf {debug_output_path}/t8n.sh.out # hard-coded to avoid surprises + rm -rf {debug_output_path}/t8n.sh.out # hard-coded to avoid + # surprises mkdir -p {debug_output_path}/t8n.sh.out/output {t8n_call} """ @@ -355,7 +369,9 @@ def _evaluate_server( debug_output_path: str = "", timeout: int, ) -> TransitionToolOutput: - """Execute the transition tool sending inputs and outputs via a server.""" + """ + Execute the transition tool sending inputs and outputs via a server. + """ request_data = t8n_data.get_request_data() request_data_json = request_data.model_dump(mode="json", **model_dump_config) @@ -424,7 +440,10 @@ def _evaluate_stream( t8n_data: TransitionToolData, debug_output_path: str = "", ) -> TransitionToolOutput: - """Execute a transition tool using stdin and stdout for its inputs and outputs.""" + """ + Execute a transition tool using stdin and stdout for its inputs and + outputs. + """ temp_dir = tempfile.TemporaryDirectory() args = self.construct_args_stream(t8n_data, temp_dir) @@ -468,7 +487,8 @@ def safe_t8n_args( self, fork_name: str, chain_id: int, reward: int, temp_dir=None ) -> List[str]: """Safely construct t8n arguments with validated inputs.""" - # Validate fork name against actual transition tool names from all available forks + # Validate fork name against actual transition tool names from all + # available forks valid_forks = get_valid_transition_tool_names() if fork_name not in valid_forks: raise ValueError(f"Invalid fork name: {fork_name}") @@ -528,7 +548,9 @@ def dump_debug_stream( args: List[str], result: subprocess.CompletedProcess, ): - """Export debug files if requested when interacting with t8n via streams.""" + """ + Export debug files if requested when interacting with t8n via streams. + """ if not debug_output_path: return @@ -539,8 +561,10 @@ def dump_debug_stream( t8n_script = textwrap.dedent( f"""\ #!/bin/bash - rm -rf {debug_output_path}/t8n.sh.out # hard-coded to avoid surprises - mkdir {debug_output_path}/t8n.sh.out # unused if tracing is not enabled + rm -rf {debug_output_path}/t8n.sh.out # hard-coded to avoid + # surprises + mkdir {debug_output_path}/t8n.sh.out # unused if tracing is not + # enabled {t8n_call} < {debug_output_path}/stdin.txt """ ) diff --git a/src/ethereum_test_base_types/base_types.py b/src/ethereum_test_base_types/base_types.py index d50155ac38a..041df926ca7 100644 --- a/src/ethereum_test_base_types/base_types.py +++ b/src/ethereum_test_base_types/base_types.py @@ -24,15 +24,18 @@ class ToStringSchema: """ - Type converter to add a simple pydantic schema that correctly - parses and serializes the type. + Type converter to add a simple pydantic schema that correctly parses and + serializes the type. """ @staticmethod def __get_pydantic_core_schema__( source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Call the class constructor without info and appends the serialization schema.""" + """ + Call the class constructor without info and appends the serialization + schema. + """ return no_info_plain_validator_function( source_type, serialization=to_string_ser_schema(), @@ -86,7 +89,9 @@ def __new__(cls, input_number: NumberConvertible | Self): @staticmethod def _get_multiplier(unit: str) -> int: - """Return the multiplier for the given unit of wei, handling synonyms.""" + """ + Return the multiplier for the given unit of wei, handling synonyms. + """ match unit: case "wei": return 1 @@ -117,7 +122,10 @@ def __str__(self) -> str: def __get_pydantic_core_schema__( source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Call the class constructor without info and appends the serialization schema.""" + """ + Call the class constructor without info and appends the serialization + schema. + """ return no_info_plain_validator_function( source_type, serialization=to_string_ser_schema(), @@ -143,7 +151,10 @@ def hex(self) -> str: def __get_pydantic_core_schema__( source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Call the class constructor without info and appends the serialization schema.""" + """ + Call the class constructor without info and appends the serialization + schema. + """ return no_info_plain_validator_function( source_type, serialization=to_string_ser_schema(), @@ -197,7 +208,10 @@ def sha256(self) -> "Hash": def __get_pydantic_core_schema__( source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Call the class constructor without info and appends the serialization schema.""" + """ + Call the class constructor without info and appends the serialization + schema. + """ return no_info_plain_validator_function( source_type, serialization=to_string_ser_schema(), @@ -256,7 +270,10 @@ def hex(self) -> str: def __get_pydantic_core_schema__( cls: Type[Self], source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Call the class constructor without info and appends the serialization schema.""" + """ + Call the class constructor without info and appends the serialization + schema. + """ pattern = f"^0x([0-9a-fA-F]{{{cls.byte_length * 2}}})*$" return no_info_plain_validator_function( source_type, @@ -341,7 +358,10 @@ def __ne__(self, other: object) -> bool: def __get_pydantic_core_schema__( cls: Type[Self], source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Call the class constructor without info and appends the serialization schema.""" + """ + Call the class constructor without info and appends the serialization + schema. + """ pattern = f"^0x([0-9a-fA-F]{{{cls.byte_length * 2}}})*$" return no_info_plain_validator_function( source_type, @@ -351,7 +371,9 @@ def __get_pydantic_core_schema__( class ForkHash(FixedSizeBytes[4]): # type: ignore - """Class that helps represent the CRC config hashes and identifiers of a fork.""" + """ + Class that helps represent the CRC config hashes and identifiers of a fork. + """ pass @@ -391,7 +413,8 @@ class StorageKey(FixedSizeBytes[32]): # type: ignore def __new__(cls, value, **kwargs): """Create a new StorageKey with automatic left padding.""" - # Always apply left_padding for storage keys unless explicitly set to False + # Always apply left_padding for storage keys unless explicitly set to + # False if "left_padding" not in kwargs: kwargs["left_padding"] = True return super().__new__(cls, value, **kwargs) diff --git a/src/ethereum_test_base_types/composite_types.py b/src/ethereum_test_base_types/composite_types.py index 035bfb2a88e..1cb76c006a4 100644 --- a/src/ethereum_test_base_types/composite_types.py +++ b/src/ethereum_test_base_types/composite_types.py @@ -36,12 +36,23 @@ class Storage(EthereumTestRootModel[Dict[StorageKeyValueType, StorageKeyValueTyp str | int | bytes | SupportsBytes, str | int | bytes | SupportsBytes ] """ + + + + + + Dictionary type to be used when defining an input to initialize a storage. + + + """ @dataclass(kw_only=True) class InvalidTypeError(Exception): - """Invalid type used when describing test's expected storage key or value.""" + """ + Invalid type used when describing test's expected storage key or value. + """ key_or_value: Any @@ -90,8 +101,8 @@ def __str__(self): @dataclass(kw_only=True) class KeyValueMismatchError(Exception): """ - Test expected a certain value in a storage key but value found - was different. + Test expected a certain value in a storage key but value found was + different. """ address: Address @@ -101,7 +112,10 @@ class KeyValueMismatchError(Exception): hint: str def __init__(self, address: Address, key: int, want: int, got: int, hint: str = "", *args): - """Initialize the exception with the address, key, wanted and got values.""" + """ + Initialize the exception with the address, key, wanted and got + values. + """ super().__init__(args) self.address = address self.key = key @@ -183,14 +197,17 @@ def items(self): return self.root.items() def set_expect_any(self, key: StorageKeyValueTypeConvertible | StorageKeyValueType): - """Mark key to be able to have any expected value when comparing storages.""" + """ + Mark key to be able to have any expected value when comparing storages. + """ self._any_map[StorageKeyValueTypeAdapter.validate_python(key)] = True def store_next( self, value: StorageKeyValueTypeConvertible | StorageKeyValueType | bool, hint: str = "" ) -> StorageKeyValueType: """ - Store a value in the storage and returns the key where the value is stored. + Store a value in the storage and returns the key where the value is + stored. Increments the key counter so the next time this function is called, the next key is used. @@ -208,10 +225,9 @@ def peek_slot(self) -> int: def contains(self, other: "Storage") -> bool: """ - Return True if self contains all keys with equal value as - contained by second storage. - Used for comparison with test expected post state and alloc returned - by the transition tool. + Return True if self contains all keys with equal value as contained by + second storage. Used for comparison with test expected post state and + alloc returned by the transition tool. """ for key in other.keys(): if key not in self: @@ -222,11 +238,10 @@ def contains(self, other: "Storage") -> bool: def must_contain(self, address: Address, other: "Storage"): """ - Succeeds only if self contains all keys with equal value as - contained by second storage. - Used for comparison with test expected post state and alloc returned - by the transition tool. - Raises detailed exception when a difference is found. + Succeeds only if self contains all keys with equal value as contained + by second storage. Used for comparison with test expected post state + and alloc returned by the transition tool. Raises detailed exception + when a difference is found. """ for key in other.keys(): if key not in self: @@ -283,8 +298,9 @@ def must_be_equal(self, address: Address, other: "Storage | None"): def canary(self) -> "Storage": """ - Return a canary storage filled with non-zero values where the current storage expects - zero values, to guarantee that the test overwrites the storage. + Return a canary storage filled with non-zero values where the current + storage expects zero values, to guarantee that the test overwrites the + storage. """ return Storage({key: HashInt(0xBA5E) for key in self.keys() if self[key] == 0}) @@ -294,27 +310,38 @@ class Account(CamelModel): nonce: ZeroPaddedHexNumber = ZeroPaddedHexNumber(0) """ - The scalar value equal to a) the number of transactions sent by - an Externally Owned Account, b) the amount of contracts created by a - contract. + + + + + + + The scalar value equal to a) the number of transactions sent by an + Externally Owned Account, b) the amount of contracts created by a contract. + + + """ balance: ZeroPaddedHexNumber = ZeroPaddedHexNumber(0) - """ - The amount of Wei (10-18 Eth) the account has. - """ + """The amount of Wei (10-18 Eth) the account has.""" code: Bytes = Bytes(b"") - """ - Bytecode contained by the account. - """ + """Bytecode contained by the account.""" storage: Storage = Field(default_factory=Storage) - """ - Storage within a contract. - """ + """Storage within a contract.""" NONEXISTENT: ClassVar[None] = None """ + + + + + + Sentinel object used to specify when an account should not exist in the state. + + + """ @dataclass(kw_only=True) @@ -329,7 +356,9 @@ class NonceMismatchError(Exception): got: int | None def __init__(self, address: Address, want: int | None, got: int | None, *args): - """Initialize the exception with the address, wanted and got values.""" + """ + Initialize the exception with the address, wanted and got values. + """ super().__init__(args) self.address = address self.want = want @@ -348,8 +377,8 @@ def __str__(self): @dataclass(kw_only=True) class BalanceMismatchError(Exception): """ - Test expected a certain balance for an account but a different - value was found. + Test expected a certain balance for an account but a different value + was found. """ address: Address @@ -357,7 +386,9 @@ class BalanceMismatchError(Exception): got: int | None def __init__(self, address: Address, want: int | None, got: int | None, *args): - """Initialize the exception with the address, wanted and got values.""" + """ + Initialize the exception with the address, wanted and got values. + """ super().__init__(args) self.address = address self.want = want @@ -376,8 +407,8 @@ def __str__(self): @dataclass(kw_only=True) class CodeMismatchError(Exception): """ - Test expected a certain bytecode for an account but a different - one was found. + Test expected a certain bytecode for an account but a different one was + found. """ address: Address @@ -385,7 +416,9 @@ class CodeMismatchError(Exception): got: bytes | None def __init__(self, address: Address, want: bytes | None, got: bytes | None, *args): - """Initialize the exception with the address, wanted and got values.""" + """ + Initialize the exception with the address, wanted and got values. + """ super().__init__(args) self.address = address self.want = want diff --git a/src/ethereum_test_base_types/conversions.py b/src/ethereum_test_base_types/conversions.py index e99743ba241..330f46dde06 100644 --- a/src/ethereum_test_base_types/conversions.py +++ b/src/ethereum_test_base_types/conversions.py @@ -60,12 +60,12 @@ def to_fixed_size_bytes( """ Convert multiple types into fixed-size bytes. - :param input_bytes: The input data to convert. - :param size: The size of the output bytes. - :param left_padding: Whether to allow left-padding of the input data bytes using zeros. If the - input data is an integer, padding is always performed. - :param right_padding: Whether to allow right-padding of the input data bytes using zeros. If - the input data is an integer, padding is always performed. + :param input_bytes: The input data to convert. :param size: The size of the + output bytes. :param left_padding: Whether to allow left-padding of the + input data bytes using zeros. If the input data is an integer, padding is + always performed. :param right_padding: Whether to allow right-padding of + the input data bytes using zeros. If the input data is an integer, padding + is always performed. """ if isinstance(input_bytes, int): return int.to_bytes(input_bytes, length=size, byteorder="big", signed=input_bytes < 0) diff --git a/src/ethereum_test_base_types/mixins.py b/src/ethereum_test_base_types/mixins.py index f44eafcaa57..7b09bf5ccfe 100644 --- a/src/ethereum_test_base_types/mixins.py +++ b/src/ethereum_test_base_types/mixins.py @@ -8,10 +8,10 @@ class ModelCustomizationsMixin: """ A mixin that customizes the behavior of pydantic models. Any pydantic - configuration override that must apply to all models - should be placed here. + configuration override that must apply to all models should be placed here. - This mixin is applied to both `EthereumTestBaseModel` and `EthereumTestRootModel`. + This mixin is applied to both `EthereumTestBaseModel` and + `EthereumTestRootModel`. """ def serialize( @@ -23,12 +23,12 @@ def serialize( """ Serialize the model to the specified format with the given parameters. - :param mode: The mode of serialization. - If mode is 'json', the output will only contain JSON serializable types. - If mode is 'python', the output may contain non-JSON-serializable Python objects. - :param by_alias: Whether to use aliases for field names. - :param exclude_none: Whether to exclude fields with None values, default is True. - :return: The serialized representation of the model. + :param mode: The mode of serialization. If mode is 'json', the output + will only contain JSON serializable types. If mode is 'python', the + output may contain non-JSON-serializable Python objects. :param + by_alias: Whether to use aliases for field names. :param exclude_none: + Whether to exclude fields with None values, default is True. :return: + The serialized representation of the model. """ if not hasattr(self, "model_dump"): raise NotImplementedError( @@ -41,35 +41,36 @@ def __repr_args__(self): """ Generate a list of attribute-value pairs for the object representation. - This method serializes the model, retrieves the attribute names, - and constructs a list of tuples containing attribute names and their corresponding values. - Only attributes with non-None values are included in the list. + This method serializes the model, retrieves the attribute names, and + constructs a list of tuples containing attribute names and their + corresponding values. Only attributes with non-None values are included + in the list. - This method is used by the __repr__ method to generate the object representation, - and is used by `gentest` module to generate the test cases. + This method is used by the __repr__ method to generate the object + representation, and is used by `gentest` module to generate the test + cases. - See: - - https://pydantic-docs.helpmanual.io/usage/models/#custom-repr - - https://github.com/ethereum/execution-spec-tests/pull/901#issuecomment-2443296835 - - Returns: - List[Tuple[str, Any]]: A list of tuples where each tuple contains an attribute name - and its corresponding non-None value. + See: - https://pydantic-docs.helpmanual.io/usage/models/#custom-repr - + https://github.com/ethereum/execution-spec-tests/pull/901# + issuecomment-24432968 35 + Returns: List[Tuple[str, Any]]: A list of tuples where each tuple + contains an attribute name and its corresponding non-None value. """ attrs_names = self.serialize(mode="python", by_alias=False).keys() attrs = ((s, getattr(self, s)) for s in attrs_names) - # Convert field values based on their type. - # This ensures consistency between JSON and Python object representations. - # Should a custom `__repr__` be needed for a specific type, it can added in the - # match statement below. - # Otherwise, the default string representation is used. + # Convert field values based on their type. This ensures consistency + # between JSON and Python object representations. Should a custom + # `__repr__` be needed for a specific type, it can added in the match + # statement below. Otherwise, the default string representation is + # used. repr_attrs = [] for a, v in attrs: match v: # Note: The `None` case handles an edge case with transactions - # see: https://github.com/ethereum/execution-spec-tests/pull/901#discussion_r1828491918 # noqa: E501 + # see: https://github.com/ethereum/execution-spec-tests/pull/ + # 901#discussion_r1828491918 case list() | dict() | BaseModel() | None: repr_attrs.append((a, v)) case _: diff --git a/src/ethereum_test_base_types/pydantic.py b/src/ethereum_test_base_types/pydantic.py index 6471fe07fa3..6d58f1fcf95 100644 --- a/src/ethereum_test_base_types/pydantic.py +++ b/src/ethereum_test_base_types/pydantic.py @@ -27,7 +27,9 @@ class CopyValidateModel(EthereumTestBaseModel): """Model that supports copying with validation.""" def copy(self: Self, **kwargs) -> Self: - """Create a copy of the model with the updated fields that are validated.""" + """ + Create a copy of the model with the updated fields that are validated. + """ return self.__class__(**(self.model_dump(exclude_unset=True) | kwargs)) @@ -35,8 +37,8 @@ class CamelModel(CopyValidateModel): """ A base model that converts field names to camel case when serializing. - For example, the field name `current_timestamp` in a Python model will be represented - as `currentTimestamp` when it is serialized to json. + For example, the field name `current_timestamp` in a Python model will be + represented as `currentTimestamp` when it is serialized to json. """ model_config = ConfigDict( diff --git a/src/ethereum_test_base_types/reference_spec/reference_spec.py b/src/ethereum_test_base_types/reference_spec/reference_spec.py index 96a0f493926..edee8e68804 100644 --- a/src/ethereum_test_base_types/reference_spec/reference_spec.py +++ b/src/ethereum_test_base_types/reference_spec/reference_spec.py @@ -36,7 +36,10 @@ def name(self) -> str: @abstractmethod def has_known_version(self) -> bool: - """Return true if the reference spec object is hard-coded with a latest known version.""" + """ + Return true if the reference spec object is hard-coded with a latest + known version. + """ pass @abstractmethod @@ -46,7 +49,9 @@ def known_version(self) -> str: @abstractmethod def api_url(self) -> str: - """Return the URL required to poll the version from an API, if needed.""" + """ + Return the URL required to poll the version from an API, if needed. + """ pass @abstractmethod @@ -64,13 +69,19 @@ def is_outdated(self) -> bool: @abstractmethod def write_info(self, info: Dict[str, Dict[str, Any] | str]): - """Write info about the reference specification used into the output fixture.""" + """ + Write info about the reference specification used into the output + fixture. + """ pass @staticmethod @abstractmethod def parseable_from_module(module_dict: Dict[str, Any]) -> bool: - """Check whether the module's dict contains required reference spec information.""" + """ + Check whether the module's dict contains required reference spec + information. + """ pass @staticmethod @@ -81,9 +92,7 @@ def parse_from_module( """ Parse the module's dict into a reference spec. - Args: - module_dict: Dictionary containing module information - github_token: Optional GitHub token for API authentication - + Args: module_dict: Dictionary containing module information + github_token: Optional GitHub token for API authentication """ pass diff --git a/src/ethereum_test_base_types/serialization.py b/src/ethereum_test_base_types/serialization.py index 35aeaaf233e..f0f18f50848 100644 --- a/src/ethereum_test_base_types/serialization.py +++ b/src/ethereum_test_base_types/serialization.py @@ -36,26 +36,29 @@ class RLPSerializable: def get_rlp_fields(self) -> List[str]: """ - Return an ordered list of field names to be included in RLP serialization. + Return an ordered list of field names to be included in RLP + serialization. Function can be overridden to customize the logic to return the fields. By default, rlp_fields class variable is used. - The list can be nested list up to one extra level to represent nested fields. + The list can be nested list up to one extra level to represent nested + fields. """ return self.rlp_fields def get_rlp_signing_fields(self) -> List[str]: """ - Return an ordered list of field names to be included in the RLP serialization of the object - signature. + Return an ordered list of field names to be included in the RLP + serialization of the object signature. Function can be overridden to customize the logic to return the fields. By default, rlp_signing_fields class variable is used. - The list can be nested list up to one extra level to represent nested fields. + The list can be nested list up to one extra level to represent nested + fields. """ return self.rlp_signing_fields @@ -69,7 +72,8 @@ def get_rlp_prefix(self) -> bytes: def get_rlp_signing_prefix(self) -> bytes: """ - Return a prefix that has to be appended to the serialized signing object. + Return a prefix that has to be appended to the serialized signing + object. By default, an empty string is returned. """ @@ -117,8 +121,9 @@ def to_list(self, signing: bool = False) -> List[Any]: field_list = self.get_rlp_signing_fields() else: if self.signable: - # Automatically sign signable objects during full serialization: - # Ensures nested objects have valid signatures in the final RLP. + # Automatically sign signable objects during full + # serialization: Ensures nested objects have valid signatures + # in the final RLP. self.sign() field_list = self.get_rlp_fields() @@ -136,7 +141,9 @@ def rlp(self) -> Bytes: class SignableRLPSerializable(RLPSerializable): - """Class that adds RLP serialization to another class with signing support.""" + """ + Class that adds RLP serialization to another class with signing support. + """ signable: ClassVar[bool] = True diff --git a/src/ethereum_test_checklists/eip_checklist.py b/src/ethereum_test_checklists/eip_checklist.py index 9a3b0b26cdb..347d52cc3c5 100644 --- a/src/ethereum_test_checklists/eip_checklist.py +++ b/src/ethereum_test_checklists/eip_checklist.py @@ -1,12 +1,12 @@ """ EIP Testing Checklist Enum definitions. -Note: This module includes a companion .pyi stub file that provides mypy type hints -for making EIPChecklist classes callable. The stub file is auto-generated using: - uv run generate_checklist_stubs +Note: This module includes a companion .pyi stub file that provides mypy type +hints for making EIPChecklist classes callable. The stub file is auto-generated +using: uv run generate_checklist_stubs -If you modify the EIPChecklist class structure, regenerate the stub file to maintain -proper type checking support. +If you modify the EIPChecklist class structure, regenerate the stub file to +maintain proper type checking support. """ import re @@ -16,9 +16,11 @@ def camel_to_snake(name: str) -> str: """Convert CamelCase to snake_case.""" - # Insert an underscore before any uppercase letter that follows a lowercase letter + # Insert an underscore before any uppercase letter that follows a lowercase + # letter s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name) - # Insert an underscore before any uppercase letter that follows a lowercase letter or number + # Insert an underscore before any uppercase letter that follows a lowercase + # letter or number return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower() @@ -73,8 +75,8 @@ def __repr__(cls) -> str: def __call__(cls, *args, **kwargs): """Return a pytest mark decorator for the checklist item.""" - # If called with a function as the first argument (direct decorator usage) - # and no other arguments, apply the decorator to the function + # If called with a function as the first argument (direct decorator + # usage) and no other arguments, apply the decorator to the function if len(args) == 1 and len(kwargs) == 0 and callable(args[0]): func = args[0] marker = pytest.mark.eip_checklist(cls._path) @@ -93,21 +95,17 @@ class EIPChecklist: """ Main namespace for EIP testing checklist items. - This class provides a structured way to reference checklist items for EIP testing. - The class structure is automatically converted to callable pytest markers. + This class provides a structured way to reference checklist items for EIP + testing. The class structure is automatically converted to callable pytest + markers. - Note: If you modify this class structure, regenerate the type stub file using: - uv run generate_checklist_stubs + Note: If you modify this class structure, regenerate the type stub file + using: uv run generate_checklist_stubs - Examples: - @EIPChecklist.Opcode.Test.GasUsage.Normal() - def test_normal_gas(): - pass - - @EIPChecklist.Opcode.Test.StackOverflow - def test_stack_overflow(): - pass + Examples: @EIPChecklist.Opcode.Test.GasUsage.Normal() def + test_normal_gas(): pass + @EIPChecklist.Opcode.Test.StackOverflow def test_stack_overflow(): pass """ class General(ChecklistItem): @@ -239,8 +237,9 @@ class Even(ChecklistItem): class DataPortionVariables(ChecklistItem, override_name="data_portion_variables"): """ - If the opcode contains variables in its data portion, for each variable `n` - of the opcode that accesses the nth stack item, test `n` being. + If the opcode contains variables in its data portion, for + each variable `n` of the opcode that accesses the nth stack + item, test `n` being. """ class Top(ChecklistItem): @@ -1688,28 +1687,31 @@ class Test(ChecklistItem): """Test vectors for the new validity constraint.""" class ForkTransition(ChecklistItem): - """Tests for the new transaction validity constraint on fork boundary.""" + """ + Tests for the new transaction validity constraint on fork + boundary. + """ class AcceptedBeforeFork(ChecklistItem): """ - Verify that a block before the activation fork is accepted even when the new - constraint is not met. + Verify that a block before the activation fork is accepted + even when the new constraint is not met. """ pass class AcceptedAfterFork(ChecklistItem): """ - Verify that a block after the activation fork is accepted when the new - validity constraint is met. + Verify that a block after the activation fork is accepted + when the new validity constraint is met. """ pass class RejectedAfterFork(ChecklistItem): """ - Verify that a block after the activation fork is rejected when the new - validity constraint is not met. + Verify that a block after the activation fork is rejected + when the new validity constraint is not met. """ pass @@ -1721,36 +1723,41 @@ class Test(ChecklistItem): """Test vectors for the modified validity constraint.""" class ForkTransition(ChecklistItem): - """Tests for the modified transaction validity constraint on fork boundary.""" + """ + Tests for the modified transaction validity constraint on fork + boundary. + """ class AcceptedBeforeFork(ChecklistItem): """ - Verify that a block before the activation fork is accepted when the existing - constraint is met and, ideally, the new constraint is not met. + Verify that a block before the activation fork is accepted + when the existing constraint is met and, ideally, the new + constraint is not met. """ pass class RejectedBeforeFork(ChecklistItem): """ - Verify that a block before the activation fork is rejected when the existing - constraint is not met and, ideally, the new constraint is met. + Verify that a block before the activation fork is rejected + when the existing constraint is not met and, ideally, the + new constraint is met. """ pass class AcceptedAfterFork(ChecklistItem): """ - Verify that a block after the activation fork is accepted when the new - validity constraint is met. + Verify that a block after the activation fork is accepted + when the new validity constraint is met. """ pass class RejectedAfterFork(ChecklistItem): """ - Verify that a block after the activation fork is rejected when the new - validity constraint is not met. + Verify that a block after the activation fork is rejected + when the new validity constraint is not met. """ pass diff --git a/src/ethereum_test_checklists/eip_checklist.pyi b/src/ethereum_test_checklists/eip_checklist.pyi index 2a0f37d22d1..6dd26539237 100644 --- a/src/ethereum_test_checklists/eip_checklist.pyi +++ b/src/ethereum_test_checklists/eip_checklist.pyi @@ -1,7 +1,8 @@ """ Type stubs for EIP checklist - auto-generated. -DO NOT EDIT MANUALLY - This file is generated by `uv run generate_checklist_stubs` +DO NOT EDIT MANUALLY - +This file is generated by `uv run generate_checklist_stubs` """ from typing import Any, Callable, TypeVar, overload diff --git a/src/ethereum_test_checklists/tests/test_checklist_template_consistency.py b/src/ethereum_test_checklists/tests/test_checklist_template_consistency.py index 69be5f2157a..85a52123ef5 100644 --- a/src/ethereum_test_checklists/tests/test_checklist_template_consistency.py +++ b/src/ethereum_test_checklists/tests/test_checklist_template_consistency.py @@ -32,8 +32,10 @@ def extract_markdown_ids(markdown_content: str) -> Set[str]: return ids -def get_all_checklist_ids(obj) -> Set[str]: - """Recursively extract all checklist IDs from EIPChecklist and its children.""" +def get_all_checklist_ids(obj, current_path="") -> Set[str]: + """ + Recursively extract all checklist IDs from EIPChecklist and its children. + """ ids = set() # Iterate through all attributes of the object @@ -59,7 +61,9 @@ def get_all_checklist_ids(obj) -> Set[str]: def test_checklist_template_consistency(): - """Test that all IDs in markdown template match EIPChecklist class exactly.""" + """ + Test that all IDs in markdown template match EIPChecklist class exactly. + """ # Read the markdown template with open(TEMPLATE_PATH, "r", encoding="utf-8") as f: markdown_content = f.read() @@ -135,7 +139,10 @@ def test_id_extraction_functions(): def test_eip_checklist_decorator_usage(): - """Test EIPChecklist items work correctly as decorators both with and without parentheses.""" + """ + Test EIPChecklist items work correctly as decorators both with and without + parentheses. + """ # Test decorator with parentheses @EIPChecklist.Opcode.Test.StackComplexOperations() @@ -149,7 +156,8 @@ def test_function_with_parens(): assert len(eip_markers) == 1 assert eip_markers[0].args == ("opcode/test/stack_complex_operations",) - # Test decorator without parentheses (direct usage - this is the key fix for issue #1) + # Test decorator without parentheses (direct usage - this is the key fix + # for issue #1) @EIPChecklist.Opcode.Test.StackOverflow def test_function_no_parens(): pass @@ -192,6 +200,7 @@ def test_eip_checklist_pytest_param_usage(): with pytest.raises((TypeError, AssertionError)): pytest.param( "test_value", - marks=EIPChecklist.Opcode.Test.StackOverflow, # Without () should fail + marks=EIPChecklist.Opcode.Test.StackOverflow, # Without () should + # fail id="should_fail", ) diff --git a/src/ethereum_test_exceptions/exception_mapper.py b/src/ethereum_test_exceptions/exception_mapper.py index 43d4d7af667..b750527097a 100644 --- a/src/ethereum_test_exceptions/exception_mapper.py +++ b/src/ethereum_test_exceptions/exception_mapper.py @@ -20,27 +20,39 @@ class ExceptionMapper(ABC): mapping_substring: ClassVar[Dict[ExceptionBase, str]] """ - Mapping of exception to substring that should be present in the error message. - Items in this mapping are used for substring matching (`substring in message`). + + Mapping of exception to substring that should be present in the error + message. + + Items in this mapping are used for substring matching (`substring in + message`). + """ mapping_regex: ClassVar[Dict[ExceptionBase, str]] """ + + Mapping of exception to regex that should be present in the error message. Items in this mapping are compiled into regex patterns for faster matching, and then used for regex matching (`pattern.search(message)`). + """ reliable: ClassVar[bool] = True """ - Whether the exceptions returned by the tool are reliable and can be accurately - mapped to the exceptions in this class. + + + Whether the exceptions returned by the tool are reliable and can be + accurately mapped to the exceptions in this class. + """ def __init__(self) -> None: """Initialize the exception mapper.""" - # Ensure that the subclass has properly defined mapping_substring before accessing it + # Ensure that the subclass has properly defined mapping_substring + # before accessing it assert self.mapping_substring is not None, "mapping_substring must be defined in subclass" assert self.mapping_regex is not None, "mapping_regex must be defined in subclass" self.mapper_name = self.__class__.__name__ @@ -66,8 +78,8 @@ def message_to_exception( class ExceptionWithMessage(BaseModel, Generic[ExceptionBoundTypeVar]): """ - Class that contains the exception along with the verbatim message from the external - tool/client. + Class that contains the exception along with the verbatim message from the + external tool/client. """ exceptions: List[ExceptionBoundTypeVar] @@ -86,8 +98,8 @@ def __str__(self): def mapper_validator(v: str, info: ValidationInfo) -> Dict[str, Any] | UndefinedException | None: """ - Use the exception mapper that must be included in the context to map the exception - from the external tool. + Use the exception mapper that must be included in the context to map the + exception from the external tool. """ if v is None: return v @@ -110,17 +122,17 @@ def mapper_validator(v: str, info: ValidationInfo) -> Dict[str, Any] | Undefined ExceptionMapperValidator = BeforeValidator(mapper_validator) """ -Validator that can be used to annotate a pydantic field in a model that is meant to be -parsed from an external tool or client. - -The annotated type must be an union that can include `None`, `UndefinedException` and a -custom model as: -``` -class BlockExceptionWithMessage(ExceptionWithMessage[BlockException]): - pass -``` -where `BlockException` can be any derivation of `ExceptionBase`. - -The `message` attribute is the verbatim message received from the external tool or client, -and can be used to be printed for extra context information in case of failures. + + +Validator that can be used to annotate a pydantic field in a model that is +meant to be parsed from an external tool or client. + +The annotated type must be an union that can include `None`, +`UndefinedException` and a custom model as: ``` class +BlockExceptionWithMessage(ExceptionWithMessage[BlockException]): pass ``` where +`BlockException` can be any derivation of `ExceptionBase`. + +The `message` attribute is the verbatim message received from the external tool +or client, and can be used to be printed for extra context information in case +of failures. """ diff --git a/src/ethereum_test_exceptions/exceptions.py b/src/ethereum_test_exceptions/exceptions.py index 437b5ad8f25..c900668ec49 100644 --- a/src/ethereum_test_exceptions/exceptions.py +++ b/src/ethereum_test_exceptions/exceptions.py @@ -25,7 +25,10 @@ def __init_subclass__(cls) -> None: def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Call class constructor without info and appends the serialization schema.""" + """ + Call class constructor without info and appends the serialization + schema. + """ return no_info_plain_validator_function( cls.from_str, serialization=to_string_ser_schema(), @@ -104,7 +107,10 @@ def __new__(cls, value: str, *, mapper_name: str | None = None) -> "UndefinedExc def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Call class constructor without info and appends the serialization schema.""" + """ + Call class constructor without info and appends the serialization + schema. + """ return no_info_plain_validator_function( cls, serialization=to_string_ser_schema(), @@ -114,287 +120,230 @@ def __get_pydantic_core_schema__( @unique class TransactionException(ExceptionBase): """ - Exception raised when a transaction is invalid, and thus cannot be executed. + Exception raised when a transaction is invalid, and thus cannot be + executed. - If a transaction with any of these exceptions is included in a block, the block is invalid. + If a transaction with any of these exceptions is included in a block, the + block is invalid. """ TYPE_NOT_SUPPORTED = auto() - """ - Transaction type is not supported on this chain configuration. - """ + """Transaction type is not supported on this chain configuration.""" SENDER_NOT_EOA = auto() - """ - Transaction is coming from address that is not exist anymore. - """ + """Transaction is coming from address that is not exist anymore.""" ADDRESS_TOO_SHORT = auto() - """ - Transaction `to` is not allowed to be less than 20 bytes. - """ + """Transaction `to` is not allowed to be less than 20 bytes.""" ADDRESS_TOO_LONG = auto() - """ - Transaction `to` is not allowed to be more than 20 bytes. - """ + """Transaction `to` is not allowed to be more than 20 bytes.""" NONCE_MISMATCH_TOO_HIGH = auto() - """ - Transaction nonce > sender.nonce. - """ + """Transaction nonce > sender.nonce.""" NONCE_MISMATCH_TOO_LOW = auto() - """ - Transaction nonce < sender.nonce. - """ + """Transaction nonce < sender.nonce.""" NONCE_TOO_BIG = auto() """ - Transaction `nonce` is not allowed to be max_uint64 - 1 (this is probably TransactionTest). + + + Transaction `nonce` is not allowed to be max_uint64 - 1 (this is probably + TransactionTest). + """ NONCE_IS_MAX = auto() """ - Transaction `nonce` is not allowed to be max_uint64 - 1 (this is StateTests). + + + Transaction `nonce` is not allowed to be max_uint64 - 1 (this is + StateTests). + """ NONCE_OVERFLOW = auto() - """ - Transaction `nonce` is not allowed to be more than uint64. - """ + """Transaction `nonce` is not allowed to be more than uint64.""" GASLIMIT_OVERFLOW = auto() - """ - Transaction gaslimit exceeds 2^64-1 maximum value. - """ + """Transaction gaslimit exceeds 2^64-1 maximum value.""" VALUE_OVERFLOW = auto() - """ - Transaction value exceeds 2^256-1 maximum value. - """ + """Transaction value exceeds 2^256-1 maximum value.""" GASPRICE_OVERFLOW = auto() - """ - Transaction gasPrice exceeds 2^256-1 maximum value. - """ + """Transaction gasPrice exceeds 2^256-1 maximum value.""" GASLIMIT_PRICE_PRODUCT_OVERFLOW = auto() - """ - Transaction gasPrice * gasLimit exceeds 2^256-1 maximum value. - """ + """Transaction gasPrice * gasLimit exceeds 2^256-1 maximum value.""" INVALID_SIGNATURE_VRS = auto() - """ - Invalid transaction v, r, s values. - """ + """Invalid transaction v, r, s values.""" RLP_INVALID_SIGNATURE_R = auto() - """ - Error reading transaction signature R value. - """ + """Error reading transaction signature R value.""" RLP_INVALID_SIGNATURE_S = auto() - """ - Error reading transaction signature S value. - """ + """Error reading transaction signature S value.""" RLP_LEADING_ZEROS_GASLIMIT = auto() - """ - Error reading transaction gaslimit field RLP. - """ + """Error reading transaction gaslimit field RLP.""" RLP_LEADING_ZEROS_GASPRICE = auto() - """ - Error reading transaction gasprice field RLP. - """ + """Error reading transaction gasprice field RLP.""" RLP_LEADING_ZEROS_VALUE = auto() - """ - Error reading transaction value field RLP. - """ + """Error reading transaction value field RLP.""" RLP_LEADING_ZEROS_NONCE = auto() - """ - Error reading transaction nonce field RLP. - """ + """Error reading transaction nonce field RLP.""" RLP_LEADING_ZEROS_R = auto() - """ - Error reading transaction signature R field RLP. - """ + """Error reading transaction signature R field RLP.""" RLP_LEADING_ZEROS_S = auto() - """ - Error reading transaction signature S field RLP. - """ + """Error reading transaction signature S field RLP.""" RLP_LEADING_ZEROS_V = auto() - """ - Error reading transaction signature V field RLP. - """ + """Error reading transaction signature V field RLP.""" RLP_LEADING_ZEROS_BASEFEE = auto() - """ - Error reading transaction basefee field RLP. - """ + """Error reading transaction basefee field RLP.""" RLP_LEADING_ZEROS_PRIORITY_FEE = auto() - """ - Error reading transaction priority fee field RLP. - """ + """Error reading transaction priority fee field RLP.""" RLP_LEADING_ZEROS_DATA_SIZE = auto() """ - Error reading transaction data field RLP, (rlp field length has leading zeros). + + + Error reading transaction data field RLP, (rlp field length has leading + zeros). + """ RLP_LEADING_ZEROS_NONCE_SIZE = auto() """ - Error reading transaction nonce field RLP, (rlp field length has leading zeros). + + + Error reading transaction nonce field RLP, (rlp field length has leading + zeros). + """ RLP_TOO_FEW_ELEMENTS = auto() """ - Error reading transaction RLP, structure has too few elements than expected. + + + Error reading transaction RLP, structure has too few elements than + expected. + """ RLP_TOO_MANY_ELEMENTS = auto() """ - Error reading transaction RLP, structure has too many elements than expected. + + + Error reading transaction RLP, structure has too many elements than + expected. + """ RLP_ERROR_EOF = auto() - """ - Error reading transaction RLP, rlp stream unexpectedly finished. - """ + """Error reading transaction RLP, rlp stream unexpectedly finished.""" RLP_ERROR_SIZE = auto() - """ - Error reading transaction RLP, rlp size is invalid. - """ + """Error reading transaction RLP, rlp size is invalid.""" RLP_ERROR_SIZE_LEADING_ZEROS = auto() - """ - Error reading transaction RLP, field size has leading zeros. - """ + """Error reading transaction RLP, field size has leading zeros.""" INVALID_CHAINID = auto() - """ - Transaction chain id encoding is incorrect. - """ + """Transaction chain id encoding is incorrect.""" RLP_INVALID_DATA = auto() - """ - Transaction data field is invalid rlp. - """ + """Transaction data field is invalid rlp.""" RLP_INVALID_GASLIMIT = auto() - """ - Transaction gaslimit field is invalid rlp. - """ + """Transaction gaslimit field is invalid rlp.""" RLP_INVALID_NONCE = auto() - """ - Transaction nonce field is invalid rlp. - """ + """Transaction nonce field is invalid rlp.""" RLP_INVALID_TO = auto() - """ - Transaction to field is invalid rlp. - """ + """Transaction to field is invalid rlp.""" RLP_INVALID_ACCESS_LIST_ADDRESS_TOO_LONG = auto() - """ - Transaction access list address is > 20 bytes. - """ + """Transaction access list address is > 20 bytes.""" RLP_INVALID_ACCESS_LIST_ADDRESS_TOO_SHORT = auto() - """ - Transaction access list address is < 20 bytes. - """ + """Transaction access list address is < 20 bytes.""" RLP_INVALID_ACCESS_LIST_STORAGE_TOO_LONG = auto() - """ - Transaction access list storage hash > 32 bytes. - """ + """Transaction access list storage hash > 32 bytes.""" RLP_INVALID_ACCESS_LIST_STORAGE_TOO_SHORT = auto() - """ - Transaction access list storage hash < 32 bytes. - """ + """Transaction access list storage hash < 32 bytes.""" RLP_INVALID_HEADER = auto() - """ - Transaction failed to read from RLP as rlp header is invalid. - """ + """Transaction failed to read from RLP as rlp header is invalid.""" RLP_INVALID_VALUE = auto() - """ - Transaction value field is invalid rlp/structure. - """ + """Transaction value field is invalid rlp/structure.""" EC_RECOVERY_FAIL = auto() - """ - Transaction has correct signature, but ec recovery failed. - """ + """Transaction has correct signature, but ec recovery failed.""" INSUFFICIENT_ACCOUNT_FUNDS = auto() """ + + Transaction's sender does not have enough funds to pay for the transaction. + """ INSUFFICIENT_MAX_FEE_PER_GAS = auto() - """ - Transaction's max-fee-per-gas is lower than the block base-fee. - """ + """Transaction's max-fee-per-gas is lower than the block base-fee.""" PRIORITY_OVERFLOW = auto() """ + + Transaction's max-priority-fee-per-gas is exceeds 2^256-1 maximum value. + """ PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS = auto() """ + + Transaction's max-priority-fee-per-gas is greater than the max-fee-per-gas. + """ PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS_2 = auto() """ - Transaction's max-priority-fee-per-gas is greater than the max-fee-per-gas (TransactionTests). + + + Transaction's max-priority-fee-per-gas is greater than the max-fee-per-gas + (TransactionTests). + """ INSUFFICIENT_MAX_FEE_PER_BLOB_GAS = auto() """ - Transaction's max-fee-per-blob-gas is lower than the block's blob-gas price. + + + Transaction's max-fee-per-blob-gas is lower than the block's blob-gas + price. + """ INTRINSIC_GAS_TOO_LOW = auto() - """ - Transaction's gas limit is too low. - """ + """Transaction's gas limit is too low.""" INTRINSIC_GAS_BELOW_FLOOR_GAS_COST = auto() - """ - Transaction's gas limit is below the floor gas cost. - """ + """Transaction's gas limit is below the floor gas cost.""" INITCODE_SIZE_EXCEEDED = auto() """ + + Transaction's initcode for a contract-creating transaction is too large. + """ TYPE_3_TX_PRE_FORK = auto() - """ - Transaction type 3 included before activation fork. - """ + """Transaction type 3 included before activation fork.""" TYPE_3_TX_ZERO_BLOBS_PRE_FORK = auto() - """ - Transaction type 3, with zero blobs, included before activation fork. - """ + """Transaction type 3, with zero blobs, included before activation fork.""" TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH = auto() - """ - Transaction contains a blob versioned hash with an invalid version. - """ + """Transaction contains a blob versioned hash with an invalid version.""" TYPE_3_TX_WITH_FULL_BLOBS = auto() - """ - Transaction contains full blobs (network-version of the transaction). - """ + """Transaction contains full blobs (network-version of the transaction).""" TYPE_3_TX_BLOB_COUNT_EXCEEDED = auto() - """ - Transaction contains too many blob versioned hashes. - """ + """Transaction contains too many blob versioned hashes.""" TYPE_3_TX_CONTRACT_CREATION = auto() - """ - Transaction is a type 3 transaction and has an empty `to`. - """ + """Transaction is a type 3 transaction and has an empty `to`.""" TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED = auto() - """ - Transaction causes block to go over blob gas limit. - """ + """Transaction causes block to go over blob gas limit.""" GAS_ALLOWANCE_EXCEEDED = auto() - """ - Transaction causes block to go over blob gas limit. - """ + """Transaction causes block to go over blob gas limit.""" GAS_LIMIT_EXCEEDS_MAXIMUM = auto() """ + + Transaction gas limit exceeds the maximum allowed limit of 30 million. + """ TYPE_3_TX_ZERO_BLOBS = auto() - """ - Transaction is type 3, but has no blobs. - """ + """Transaction is type 3, but has no blobs.""" TYPE_4_EMPTY_AUTHORIZATION_LIST = auto() - """ - Transaction is type 4, but has an empty authorization list. - """ + """Transaction is type 4, but has an empty authorization list.""" TYPE_4_INVALID_AUTHORITY_SIGNATURE = auto() - """ - Transaction authority signature is invalid - """ + """Transaction authority signature is invalid""" TYPE_4_INVALID_AUTHORITY_SIGNATURE_S_TOO_HIGH = auto() - """ - Transaction authority signature is invalid - """ + """Transaction authority signature is invalid""" TYPE_4_TX_CONTRACT_CREATION = auto() - """ - Transaction is a type 4 transaction and has an empty `to`. - """ + """Transaction is a type 4 transaction and has an empty `to`.""" TYPE_4_INVALID_AUTHORIZATION_FORMAT = auto() """ - Transaction is type 4, but contains an authorization that has an invalid format. + + + Transaction is type 4, but contains an authorization that has an invalid + format. + """ TYPE_4_TX_PRE_FORK = auto() - """ - Transaction type 4 included before activation fork. - """ + """Transaction type 4 included before activation fork.""" @unique @@ -402,211 +351,233 @@ class BlockException(ExceptionBase): """ Exception raised when a block is invalid, but not due to a transaction. - E.g. all transactions in the block are valid, and can be applied to the state, but the - block header contains an invalid field. + E.g. all transactions in the block are valid, and can be applied to the + state, but the block header contains an invalid field. """ TOO_MANY_UNCLES = auto() - """ - Block declares too many uncles over the allowed limit. - """ + """Block declares too many uncles over the allowed limit.""" UNCLE_IN_CHAIN = auto() - """ - Block declares uncle header that is already imported into chain. - """ + """Block declares uncle header that is already imported into chain.""" UNCLE_IS_ANCESTOR = auto() - """ - Block declares uncle header that is directly a parent of this block. - """ + """Block declares uncle header that is directly a parent of this block.""" UNCLE_IS_BROTHER = auto() - """ - Block declares two similar uncle headers. - """ + """Block declares two similar uncle headers.""" UNCLE_PARENT_INCORRECT = auto() - """ - Block declares uncle header that is an outdated block to be an uncle. - """ + """Block declares uncle header that is an outdated block to be an uncle.""" EXTRA_DATA_TOO_BIG = auto() - """ - Block header's extra data >32 bytes. - """ + """Block header's extra data >32 bytes.""" EXTRA_DATA_INVALID_DAO = auto() """ + + Block header's extra data after dao fork must be a fixed pre defined hash. + """ UNKNOWN_PARENT = auto() """ - Block header's parent hash does not correspond to any of existing blocks on chain. + + + Block header's parent hash does not correspond to any of existing blocks on + chain. + """ UNCLE_UNKNOWN_PARENT = auto() """ - Uncle header's parent hash does not correspond to any of existing blocks on chain. + + + Uncle header's parent hash does not correspond to any of existing blocks on + chain. + """ UNKNOWN_PARENT_ZERO = auto() - """ - Block header's parent hash is zero hash. - """ + """Block header's parent hash is zero hash.""" GASLIMIT_TOO_BIG = auto() - """ - Block header's gas limit > 0x7fffffffffffffff. - """ + """Block header's gas limit > 0x7fffffffffffffff.""" INVALID_BLOCK_NUMBER = auto() - """ - Block header's number != parent header's number + 1. - """ + """Block header's number != parent header's number + 1.""" INVALID_BLOCK_TIMESTAMP_OLDER_THAN_PARENT = auto() - """ - Block header's timestamp <= parent header's timestamp. - """ + """Block header's timestamp <= parent header's timestamp.""" INVALID_DIFFICULTY = auto() """ - Block header's difficulty does not match the difficulty formula calculated from previous block. + + + Block header's difficulty does not match the difficulty formula calculated + from previous block. + """ INVALID_LOG_BLOOM = auto() """ - Block header's logs bloom hash does not match the actually computed log bloom. + + + Block header's logs bloom hash does not match the actually computed log + bloom. + """ INVALID_STATE_ROOT = auto() """ - Block header's state root hash does not match the actually computed hash of the state. + + + Block header's state root hash does not match the actually computed hash of + the state. + """ INVALID_RECEIPTS_ROOT = auto() """ - Block header's receipts root hash does not match the actually computed hash of receipts. + + + Block header's receipts root hash does not match the actually computed hash + of receipts. + """ INVALID_TRANSACTIONS_ROOT = auto() """ - Block header's transactions root hash does not match the actually computed hash of tx tree. + + + Block header's transactions root hash does not match the actually computed + hash of tx tree. + """ INVALID_UNCLES_HASH = auto() """ - Block header's uncle hash does not match the actually computed hash of block's uncles. + + + Block header's uncle hash does not match the actually computed hash of + block's uncles. + """ GAS_USED_OVERFLOW = auto() - """ - Block transactions consume more gas than block header allow. - """ + """Block transactions consume more gas than block header allow.""" INVALID_GASLIMIT = auto() """ - Block header's gas limit does not match the gas limit formula calculated from previous block. + + + Block header's gas limit does not match the gas limit formula calculated + from previous block. + """ INVALID_BASEFEE_PER_GAS = auto() - """ - Block header's base_fee_per_gas field is calculated incorrect. - """ + """Block header's base_fee_per_gas field is calculated incorrect.""" INVALID_GAS_USED = auto() """ + + Block header's actual gas used does not match the provided header's value + """ INVALID_GAS_USED_ABOVE_LIMIT = auto() - """ - Block header's gas used value is above the gas limit field's value. - """ + """Block header's gas used value is above the gas limit field's value.""" INVALID_WITHDRAWALS_ROOT = auto() """ + + Block header's withdrawals root does not match calculated withdrawals root. + """ INCORRECT_BLOCK_FORMAT = auto() """ - Block's format is incorrect, contains invalid fields, is missing fields, or contains fields of - a fork that is not active yet. + + + Block's format is incorrect, contains invalid fields, is missing fields, or + contains fields of a fork that is not active yet. + """ BLOB_GAS_USED_ABOVE_LIMIT = auto() - """ - Block's blob gas used in header is above the limit. - """ + """Block's blob gas used in header is above the limit.""" INCORRECT_BLOB_GAS_USED = auto() - """ - Block's blob gas used in header is incorrect. - """ + """Block's blob gas used in header is incorrect.""" INCORRECT_EXCESS_BLOB_GAS = auto() - """ - Block's excess blob gas in header is incorrect. - """ + """Block's excess blob gas in header is incorrect.""" INVALID_VERSIONED_HASHES = auto() - """ - Incorrect number of versioned hashes in a payload. - """ + """Incorrect number of versioned hashes in a payload.""" RLP_STRUCTURES_ENCODING = auto() """ + + Block's rlp encoding is valid but ethereum structures in it are invalid. + """ RLP_WITHDRAWALS_NOT_READ = auto() - """ - Block's rlp encoding is missing withdrawals. - """ + """Block's rlp encoding is missing withdrawals.""" RLP_INVALID_FIELD_OVERFLOW_64 = auto() - """ - One of block's fields rlp is overflow 2**64 value. - """ + """One of block's fields rlp is overflow 2**64 value.""" RLP_INVALID_ADDRESS = auto() - """ - Block withdrawals address is rlp of invalid address != 20 bytes. - """ + """Block withdrawals address is rlp of invalid address != 20 bytes.""" RLP_BLOCK_LIMIT_EXCEEDED = auto() - """ - Block's rlp encoding is larger than the allowed limit. - """ + """Block's rlp encoding is larger than the allowed limit.""" INVALID_REQUESTS = auto() - """ - Block's requests are invalid. - """ + """Block's requests are invalid.""" IMPORT_IMPOSSIBLE_LEGACY = auto() - """ - Legacy block import is impossible in this chain configuration. - """ + """Legacy block import is impossible in this chain configuration.""" IMPORT_IMPOSSIBLE_LEGACY_WRONG_PARENT = auto() """ - Legacy block import is impossible, trying to import on top of a block that is not legacy. + + + Legacy block import is impossible, trying to import on top of a block that + is not legacy. + """ IMPORT_IMPOSSIBLE_LONDON_WRONG_PARENT = auto() """ + + Trying to import london (basefee) block on top of block that is not 1559. + """ IMPORT_IMPOSSIBLE_PARIS_WRONG_POW = auto() - """ - Trying to import paris(merge) block with PoW enabled. - """ + """Trying to import paris(merge) block with PoW enabled.""" IMPORT_IMPOSSIBLE_PARIS_WRONG_POS = auto() """ + + Trying to import paris(merge) block with PoS enabled before TTD is reached. + """ IMPORT_IMPOSSIBLE_LONDON_OVER_PARIS = auto() - """ - Trying to import london looking block over paris network (POS). - """ + """Trying to import london looking block over paris network (POS).""" IMPORT_IMPOSSIBLE_PARIS_OVER_SHANGHAI = auto() - """ - Trying to import paris block on top of shanghai block. - """ + """Trying to import paris block on top of shanghai block.""" IMPORT_IMPOSSIBLE_SHANGHAI = auto() - """ - Shanghai block import is impossible in this chain configuration. - """ + """Shanghai block import is impossible in this chain configuration.""" IMPORT_IMPOSSIBLE_UNCLES_OVER_PARIS = auto() """ + + Trying to import a block after paris fork that has not empty uncles hash. + """ IMPORT_IMPOSSIBLE_DIFFICULTY_OVER_PARIS = auto() - """ - Trying to import a block after paris fork that has difficulty != 0. - """ + """Trying to import a block after paris fork that has difficulty != 0.""" SYSTEM_CONTRACT_EMPTY = auto() """ - A system contract address contains no code at the end of fork activation block. + + + A system contract address contains no code at the end of fork activation + block. + """ SYSTEM_CONTRACT_CALL_FAILED = auto() """ - A system contract call at the end of block execution (from the system address) fails. + + + A system contract call at the end of block execution (from the system + address) fails. + """ INVALID_BLOCK_HASH = auto() """ + + Block header's hash does not match the actually computed hash of the block. + """ INVALID_DEPOSIT_EVENT_LAYOUT = auto() """ - Transaction emits a `DepositEvent` in the deposit contract (EIP-6110), but the layout - of the event does not match the required layout. + + + Transaction emits a `DepositEvent` in the deposit contract (EIP-6110), but + the layout of the event does not match the required layout. + """ @@ -615,218 +586,131 @@ class EOFException(ExceptionBase): """Exception raised when an EOF container is invalid.""" DEFAULT_EXCEPTION = auto() - """ - Expect some exception, not yet known. - """ + """Expect some exception, not yet known.""" UNDEFINED_EXCEPTION = auto() - """ - Indicates that exception string is not mapped to an exception enum. - """ + """Indicates that exception string is not mapped to an exception enum.""" UNDEFINED_INSTRUCTION = auto() - """ - EOF container has undefined instruction in it's body code. - """ + """EOF container has undefined instruction in it's body code.""" UNKNOWN_VERSION = auto() - """ - EOF container has an unknown version. - """ + """EOF container has an unknown version.""" INCOMPLETE_MAGIC = auto() - """ - EOF container has not enough bytes to read magic. - """ + """EOF container has not enough bytes to read magic.""" INVALID_MAGIC = auto() - """ - EOF container has not allowed magic version byte. - """ + """EOF container has not allowed magic version byte.""" INVALID_VERSION = auto() - """ - EOF container version bytes mismatch. - """ + """EOF container version bytes mismatch.""" INVALID_NON_RETURNING_FLAG = auto() - """ - EOF container's section has non-returning flag set incorrectly. - """ + """EOF container's section has non-returning flag set incorrectly.""" INVALID_RJUMP_DESTINATION = auto() - """ - Code has RJUMP instruction with invalid parameters. - """ + """Code has RJUMP instruction with invalid parameters.""" MISSING_TYPE_HEADER = auto() - """ - EOF container missing types section. - """ + """EOF container missing types section.""" INVALID_TYPE_SECTION_SIZE = auto() - """ - EOF container types section has wrong size. - """ + """EOF container types section has wrong size.""" INVALID_TYPE_BODY = auto() - """ - EOF container types body section bytes are wrong. - """ + """EOF container types body section bytes are wrong.""" MISSING_CODE_HEADER = auto() - """ - EOF container missing code section. - """ + """EOF container missing code section.""" INVALID_CODE_SECTION = auto() - """ - EOF container code section bytes are incorrect. - """ + """EOF container code section bytes are incorrect.""" INCOMPLETE_CODE_HEADER = auto() - """ - EOF container code header missing bytes. - """ + """EOF container code header missing bytes.""" INCOMPLETE_DATA_HEADER = auto() - """ - EOF container data header missing bytes. - """ + """EOF container data header missing bytes.""" ZERO_SECTION_SIZE = auto() - """ - EOF container data header construction is wrong. - """ + """EOF container data header construction is wrong.""" MISSING_DATA_SECTION = auto() - """ - EOF container missing data section - """ + """EOF container missing data section""" INCOMPLETE_CONTAINER = auto() - """ - EOF container bytes are incomplete. - """ + """EOF container bytes are incomplete.""" INVALID_SECTION_BODIES_SIZE = auto() - """ - Sections bodies does not match sections headers. - """ + """Sections bodies does not match sections headers.""" TRAILING_BYTES = auto() - """ - EOF container has bytes beyond data section. - """ + """EOF container has bytes beyond data section.""" MISSING_TERMINATOR = auto() - """ - EOF container missing terminator bytes between header and body. - """ + """EOF container missing terminator bytes between header and body.""" MISSING_HEADERS_TERMINATOR = auto() - """ - Some type of another exception about missing headers terminator. - """ + """Some type of another exception about missing headers terminator.""" INVALID_FIRST_SECTION_TYPE = auto() - """ - EOF container header does not have types section first. - """ + """EOF container header does not have types section first.""" INCOMPLETE_SECTION_NUMBER = auto() - """ - EOF container header has section that is missing declaration bytes. - """ + """EOF container header has section that is missing declaration bytes.""" INCOMPLETE_SECTION_SIZE = auto() - """ - EOF container header has section that is defined incorrectly. - """ + """EOF container header has section that is defined incorrectly.""" TOO_MANY_CODE_SECTIONS = auto() - """ - EOF container header has too many code sections. - """ + """EOF container header has too many code sections.""" MISSING_STOP_OPCODE = auto() - """ - EOF container's code missing STOP bytecode at it's end. - """ + """EOF container's code missing STOP bytecode at it's end.""" INPUTS_OUTPUTS_NUM_ABOVE_LIMIT = auto() - """ - EOF container code section inputs/outputs number is above the limit - """ + """EOF container code section inputs/outputs number is above the limit""" UNREACHABLE_INSTRUCTIONS = auto() - """ - EOF container's code have instructions that are unreachable. - """ + """EOF container's code have instructions that are unreachable.""" UNREACHABLE_CODE_SECTIONS = auto() - """ - EOF container's body have code sections that are unreachable. - """ + """EOF container's body have code sections that are unreachable.""" STACK_UNDERFLOW = auto() - """ - EOF container's code produces an stack underflow. - """ + """EOF container's code produces an stack underflow.""" STACK_OVERFLOW = auto() - """ - EOF container's code produces an stack overflow. - """ + """EOF container's code produces an stack overflow.""" STACK_HEIGHT_MISMATCH = auto() - """ - EOF container section stack height mismatch. - """ + """EOF container section stack height mismatch.""" MAX_STACK_INCREASE_ABOVE_LIMIT = auto() - """ - EOF container's specified max stack increase is above the limit. - """ + """EOF container's specified max stack increase is above the limit.""" STACK_HIGHER_THAN_OUTPUTS = auto() """ - EOF container section stack height is higher than the outputs. - when returning + + + EOF container section stack height is higher than the outputs. when + returning + """ JUMPF_DESTINATION_INCOMPATIBLE_OUTPUTS = auto() """ - EOF container section JUMPF's to a destination section with incompatible outputs. + + + EOF container section JUMPF's to a destination section with incompatible + outputs. + """ INVALID_MAX_STACK_INCREASE = auto() """ - EOF container section's specified max stack increase does not match the actual stack height. + + + EOF container section's specified max stack increase does not match the + actual stack height. + """ INVALID_DATALOADN_INDEX = auto() - """ - A DATALOADN instruction has out-of-bounds index for the data section. - """ + """A DATALOADN instruction has out-of-bounds index for the data section.""" TRUNCATED_INSTRUCTION = auto() - """ - EOF container's code section has truncated instruction. - """ + """EOF container's code section has truncated instruction.""" TOPLEVEL_CONTAINER_TRUNCATED = auto() - """ - Top-level EOF container has data section truncated - """ + """Top-level EOF container has data section truncated""" ORPHAN_SUBCONTAINER = auto() - """ - EOF container has an unreferenced subcontainer. - '""" + """EOF container has an unreferenced subcontainer. '""" CONTAINER_SIZE_ABOVE_LIMIT = auto() - """ - EOF container is above size limit - """ + """EOF container is above size limit""" INVALID_CONTAINER_SECTION_INDEX = auto() - """ - Instruction references container section that does not exist. - """ + """Instruction references container section that does not exist.""" INCOMPATIBLE_CONTAINER_KIND = auto() - """ - Incompatible instruction found in a container of a specific kind. - """ + """Incompatible instruction found in a container of a specific kind.""" AMBIGUOUS_CONTAINER_KIND = auto() - """ - The kind of a sub-container cannot be uniquely deduced. - """ + """The kind of a sub-container cannot be uniquely deduced.""" TOO_MANY_CONTAINERS = auto() - """ - EOF container header has too many sub-containers. - """ + """EOF container header has too many sub-containers.""" INVALID_CODE_SECTION_INDEX = auto() - """ - CALLF Operation refers to a non-existent code section - """ + """CALLF Operation refers to a non-existent code section""" UNEXPECTED_HEADER_KIND = auto() - """ - Header parsing encountered a section kind it wasn't expecting - """ + """Header parsing encountered a section kind it wasn't expecting""" CALLF_TO_NON_RETURNING = auto() - """ - CALLF instruction targeting a non-returning code section - """ + """CALLF instruction targeting a non-returning code section""" EOFCREATE_WITH_TRUNCATED_CONTAINER = auto() - """ - EOFCREATE with truncated container - """ + """EOFCREATE with truncated container""" -""" -Pydantic Annotated Types -""" +"""Pydantic Annotated Types""" ExceptionInstanceOrList = Annotated[ List[TransactionException | BlockException] | TransactionException | BlockException, diff --git a/src/ethereum_test_exceptions/exceptions/base.py b/src/ethereum_test_exceptions/exceptions/base.py index 96b52929f6c..ebfb0d79e99 100644 --- a/src/ethereum_test_exceptions/exceptions/base.py +++ b/src/ethereum_test_exceptions/exceptions/base.py @@ -25,7 +25,10 @@ def __init_subclass__(cls) -> None: def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Call class constructor without info and appends the serialization schema.""" + """ + Call class constructor without info and appends the serialization + schema. + """ return no_info_plain_validator_function( cls.from_str, serialization=to_string_ser_schema(), @@ -82,7 +85,10 @@ def __new__(cls, value: str, *, mapper_name: str | None = None) -> "UndefinedExc def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Call class constructor without info and appends the serialization schema.""" + """ + Call class constructor without info and appends the serialization + schema. + """ return no_info_plain_validator_function( cls, serialization=to_string_ser_schema(), diff --git a/src/ethereum_test_exceptions/exceptions/block.py b/src/ethereum_test_exceptions/exceptions/block.py index 4053b1938e8..cf9dc2fdb60 100644 --- a/src/ethereum_test_exceptions/exceptions/block.py +++ b/src/ethereum_test_exceptions/exceptions/block.py @@ -10,226 +10,251 @@ class BlockException(ExceptionBase): """ Exception raised when a block is invalid, but not due to a transaction. - E.g. all transactions in the block are valid, and can be applied to the state, but the - block header contains an invalid field. + E.g. all transactions in the block are valid, and can be applied to the + state, but the block header contains an invalid field. """ TOO_MANY_UNCLES = auto() - """ - Block declares too many uncles over the allowed limit. - """ + """Block declares too many uncles over the allowed limit.""" UNCLE_IN_CHAIN = auto() - """ - Block declares uncle header that is already imported into chain. - """ + """Block declares uncle header that is already imported into chain.""" UNCLE_IS_ANCESTOR = auto() - """ - Block declares uncle header that is directly a parent of this block. - """ + """Block declares uncle header that is directly a parent of this block.""" UNCLE_IS_BROTHER = auto() - """ - Block declares two similar uncle headers. - """ + """Block declares two similar uncle headers.""" UNCLE_PARENT_INCORRECT = auto() - """ - Block declares uncle header that is an outdated block to be an uncle. - """ + """Block declares uncle header that is an outdated block to be an uncle.""" EXTRA_DATA_TOO_BIG = auto() - """ - Block header's extra data >32 bytes. - """ + """Block header's extra data >32 bytes.""" EXTRA_DATA_INVALID_DAO = auto() """ + + Block header's extra data after dao fork must be a fixed pre defined hash. + """ UNKNOWN_PARENT = auto() """ - Block header's parent hash does not correspond to any of existing blocks on chain. + + + Block header's parent hash does not correspond to any of existing blocks on + chain. + """ UNCLE_UNKNOWN_PARENT = auto() """ - Uncle header's parent hash does not correspond to any of existing blocks on chain. + + + Uncle header's parent hash does not correspond to any of existing blocks on + chain. + """ UNKNOWN_PARENT_ZERO = auto() - """ - Block header's parent hash is zero hash. - """ + """Block header's parent hash is zero hash.""" GASLIMIT_TOO_BIG = auto() - """ - Block header's gas limit > 0x7fffffffffffffff. - """ + """Block header's gas limit > 0x7fffffffffffffff.""" INVALID_BLOCK_NUMBER = auto() - """ - Block header's number != parent header's number + 1. - """ + """Block header's number != parent header's number + 1.""" INVALID_BLOCK_TIMESTAMP_OLDER_THAN_PARENT = auto() - """ - Block header's timestamp <= parent header's timestamp. - """ + """Block header's timestamp <= parent header's timestamp.""" INVALID_DIFFICULTY = auto() """ - Block header's difficulty does not match the difficulty formula calculated from previous block. + + + Block header's difficulty does not match the difficulty formula calculated + from previous block. + """ INVALID_LOG_BLOOM = auto() """ - Block header's logs bloom hash does not match the actually computed log bloom. + + + Block header's logs bloom hash does not match the actually computed log + bloom. + """ INVALID_STATE_ROOT = auto() """ - Block header's state root hash does not match the actually computed hash of the state. + + + Block header's state root hash does not match the actually computed hash of + the state. + """ INVALID_RECEIPTS_ROOT = auto() """ - Block header's receipts root hash does not match the actually computed hash of receipts. + + + Block header's receipts root hash does not match the actually computed hash + of receipts. + """ INVALID_TRANSACTIONS_ROOT = auto() """ - Block header's transactions root hash does not match the actually computed hash of tx tree. + + + Block header's transactions root hash does not match the actually computed + hash of tx tree. + """ INVALID_UNCLES_HASH = auto() """ - Block header's uncle hash does not match the actually computed hash of block's uncles. + + + Block header's uncle hash does not match the actually computed hash of + block's uncles. + """ GAS_USED_OVERFLOW = auto() - """ - Block transactions consume more gas than block header allow. - """ + """Block transactions consume more gas than block header allow.""" INVALID_GASLIMIT = auto() """ - Block header's gas limit does not match the gas limit formula calculated from previous block. + + + Block header's gas limit does not match the gas limit formula calculated + from previous block. + """ INVALID_BASEFEE_PER_GAS = auto() - """ - Block header's base_fee_per_gas field is calculated incorrect. - """ + """Block header's base_fee_per_gas field is calculated incorrect.""" INVALID_GAS_USED = auto() """ + + Block header's actual gas used does not match the provided header's value + """ INVALID_GAS_USED_ABOVE_LIMIT = auto() - """ - Block header's gas used value is above the gas limit field's value. - """ + """Block header's gas used value is above the gas limit field's value.""" INVALID_WITHDRAWALS_ROOT = auto() """ + + Block header's withdrawals root does not match calculated withdrawals root. + """ INCORRECT_BLOCK_FORMAT = auto() """ - Block's format is incorrect, contains invalid fields, is missing fields, or contains fields of - a fork that is not active yet. + + + Block's format is incorrect, contains invalid fields, is missing fields, or + contains fields of a fork that is not active yet. + """ BLOB_GAS_USED_ABOVE_LIMIT = auto() - """ - Block's blob gas used in header is above the limit. - """ + """Block's blob gas used in header is above the limit.""" INCORRECT_BLOB_GAS_USED = auto() - """ - Block's blob gas used in header is incorrect. - """ + """Block's blob gas used in header is incorrect.""" INCORRECT_EXCESS_BLOB_GAS = auto() - """ - Block's excess blob gas in header is incorrect. - """ + """Block's excess blob gas in header is incorrect.""" INVALID_VERSIONED_HASHES = auto() - """ - Incorrect number of versioned hashes in a payload. - """ + """Incorrect number of versioned hashes in a payload.""" RLP_STRUCTURES_ENCODING = auto() """ + + Block's rlp encoding is valid but ethereum structures in it are invalid. + """ RLP_WITHDRAWALS_NOT_READ = auto() - """ - Block's rlp encoding is missing withdrawals. - """ + """Block's rlp encoding is missing withdrawals.""" RLP_INVALID_FIELD_OVERFLOW_64 = auto() - """ - One of block's fields rlp is overflow 2**64 value. - """ + """One of block's fields rlp is overflow 2**64 value.""" RLP_INVALID_ADDRESS = auto() - """ - Block withdrawals address is rlp of invalid address != 20 bytes. - """ + """Block withdrawals address is rlp of invalid address != 20 bytes.""" RLP_BLOCK_LIMIT_EXCEEDED = auto() - """ - Block's rlp encoding is larger than the allowed limit. - """ + """Block's rlp encoding is larger than the allowed limit.""" INVALID_REQUESTS = auto() - """ - Block's requests are invalid. - """ + """Block's requests are invalid.""" IMPORT_IMPOSSIBLE_LEGACY = auto() - """ - Legacy block import is impossible in this chain configuration. - """ + """Legacy block import is impossible in this chain configuration.""" IMPORT_IMPOSSIBLE_LEGACY_WRONG_PARENT = auto() """ - Legacy block import is impossible, trying to import on top of a block that is not legacy. + + + Legacy block import is impossible, trying to import on top of a block that + is not legacy. + """ IMPORT_IMPOSSIBLE_LONDON_WRONG_PARENT = auto() """ + + Trying to import london (basefee) block on top of block that is not 1559. + """ IMPORT_IMPOSSIBLE_PARIS_WRONG_POW = auto() - """ - Trying to import paris(merge) block with PoW enabled. - """ + """Trying to import paris(merge) block with PoW enabled.""" IMPORT_IMPOSSIBLE_PARIS_WRONG_POS = auto() """ + + Trying to import paris(merge) block with PoS enabled before TTD is reached. + """ IMPORT_IMPOSSIBLE_LONDON_OVER_PARIS = auto() - """ - Trying to import london looking block over paris network (POS). - """ + """Trying to import london looking block over paris network (POS).""" IMPORT_IMPOSSIBLE_PARIS_OVER_SHANGHAI = auto() - """ - Trying to import paris block on top of shanghai block. - """ + """Trying to import paris block on top of shanghai block.""" IMPORT_IMPOSSIBLE_SHANGHAI = auto() - """ - Shanghai block import is impossible in this chain configuration. - """ + """Shanghai block import is impossible in this chain configuration.""" IMPORT_IMPOSSIBLE_UNCLES_OVER_PARIS = auto() """ + + Trying to import a block after paris fork that has not empty uncles hash. + """ IMPORT_IMPOSSIBLE_DIFFICULTY_OVER_PARIS = auto() - """ - Trying to import a block after paris fork that has difficulty != 0. - """ + """Trying to import a block after paris fork that has difficulty != 0.""" SYSTEM_CONTRACT_EMPTY = auto() """ - A system contract address contains no code at the end of fork activation block. + + + A system contract address contains no code at the end of fork activation + block. + """ SYSTEM_CONTRACT_CALL_FAILED = auto() """ - A system contract call at the end of block execution (from the system address) fails. + + + A system contract call at the end of block execution (from the system + address) fails. + """ INVALID_BLOCK_HASH = auto() """ + + Block header's hash does not match the actually computed hash of the block. + """ INVALID_DEPOSIT_EVENT_LAYOUT = auto() """ - Transaction emits a `DepositEvent` in the deposit contract (EIP-6110), but the layout - of the event does not match the required layout. + + + Transaction emits a `DepositEvent` in the deposit contract (EIP-6110), but + the layout of the event does not match the required layout. + """ # --- Block-Level Access Lists (EIP-7928) --- # INVALID_BLOCK_ACCESS_LIST = auto() - """ - Block's access list is invalid. - """ + """Block's access list is invalid.""" INVALID_BAL_HASH = auto() - """ - Block header's BAL hash does not match the computed BAL hash. - """ + """Block header's BAL hash does not match the computed BAL hash.""" INVALID_BAL_EXTRA_ACCOUNT = auto() """ - Block BAL contains an account change that is not present in the computed BAL. + + + Block BAL contains an account change that is not present in the computed + BAL. + """ INVALID_BAL_MISSING_ACCOUNT = auto() """ + + Block BAL is missing an account change that is present in the computed BAL. + """ diff --git a/src/ethereum_test_exceptions/exceptions/eof.py b/src/ethereum_test_exceptions/exceptions/eof.py index 03df7faf649..d17eb033ef3 100644 --- a/src/ethereum_test_exceptions/exceptions/eof.py +++ b/src/ethereum_test_exceptions/exceptions/eof.py @@ -10,210 +10,125 @@ class EOFException(ExceptionBase): """Exception raised when an EOF container is invalid.""" DEFAULT_EXCEPTION = auto() - """ - Expect some exception, not yet known. - """ + """Expect some exception, not yet known.""" UNDEFINED_EXCEPTION = auto() - """ - Indicates that exception string is not mapped to an exception enum. - """ + """Indicates that exception string is not mapped to an exception enum.""" UNDEFINED_INSTRUCTION = auto() - """ - EOF container has undefined instruction in it's body code. - """ + """EOF container has undefined instruction in it's body code.""" UNKNOWN_VERSION = auto() - """ - EOF container has an unknown version. - """ + """EOF container has an unknown version.""" INCOMPLETE_MAGIC = auto() - """ - EOF container has not enough bytes to read magic. - """ + """EOF container has not enough bytes to read magic.""" INVALID_MAGIC = auto() - """ - EOF container has not allowed magic version byte. - """ + """EOF container has not allowed magic version byte.""" INVALID_VERSION = auto() - """ - EOF container version bytes mismatch. - """ + """EOF container version bytes mismatch.""" INVALID_NON_RETURNING_FLAG = auto() - """ - EOF container's section has non-returning flag set incorrectly. - """ + """EOF container's section has non-returning flag set incorrectly.""" INVALID_RJUMP_DESTINATION = auto() - """ - Code has RJUMP instruction with invalid parameters. - """ + """Code has RJUMP instruction with invalid parameters.""" MISSING_TYPE_HEADER = auto() - """ - EOF container missing types section. - """ + """EOF container missing types section.""" INVALID_TYPE_SECTION_SIZE = auto() - """ - EOF container types section has wrong size. - """ + """EOF container types section has wrong size.""" INVALID_TYPE_BODY = auto() - """ - EOF container types body section bytes are wrong. - """ + """EOF container types body section bytes are wrong.""" MISSING_CODE_HEADER = auto() - """ - EOF container missing code section. - """ + """EOF container missing code section.""" INVALID_CODE_SECTION = auto() - """ - EOF container code section bytes are incorrect. - """ + """EOF container code section bytes are incorrect.""" INCOMPLETE_CODE_HEADER = auto() - """ - EOF container code header missing bytes. - """ + """EOF container code header missing bytes.""" INCOMPLETE_DATA_HEADER = auto() - """ - EOF container data header missing bytes. - """ + """EOF container data header missing bytes.""" ZERO_SECTION_SIZE = auto() - """ - EOF container data header construction is wrong. - """ + """EOF container data header construction is wrong.""" MISSING_DATA_SECTION = auto() - """ - EOF container missing data section - """ + """EOF container missing data section""" INCOMPLETE_CONTAINER = auto() - """ - EOF container bytes are incomplete. - """ + """EOF container bytes are incomplete.""" INVALID_SECTION_BODIES_SIZE = auto() - """ - Sections bodies does not match sections headers. - """ + """Sections bodies does not match sections headers.""" TRAILING_BYTES = auto() - """ - EOF container has bytes beyond data section. - """ + """EOF container has bytes beyond data section.""" MISSING_TERMINATOR = auto() - """ - EOF container missing terminator bytes between header and body. - """ + """EOF container missing terminator bytes between header and body.""" MISSING_HEADERS_TERMINATOR = auto() - """ - Some type of another exception about missing headers terminator. - """ + """Some type of another exception about missing headers terminator.""" INVALID_FIRST_SECTION_TYPE = auto() - """ - EOF container header does not have types section first. - """ + """EOF container header does not have types section first.""" INCOMPLETE_SECTION_NUMBER = auto() - """ - EOF container header has section that is missing declaration bytes. - """ + """EOF container header has section that is missing declaration bytes.""" INCOMPLETE_SECTION_SIZE = auto() - """ - EOF container header has section that is defined incorrectly. - """ + """EOF container header has section that is defined incorrectly.""" TOO_MANY_CODE_SECTIONS = auto() - """ - EOF container header has too many code sections. - """ + """EOF container header has too many code sections.""" MISSING_STOP_OPCODE = auto() - """ - EOF container's code missing STOP bytecode at it's end. - """ + """EOF container's code missing STOP bytecode at it's end.""" INPUTS_OUTPUTS_NUM_ABOVE_LIMIT = auto() - """ - EOF container code section inputs/outputs number is above the limit - """ + """EOF container code section inputs/outputs number is above the limit""" UNREACHABLE_INSTRUCTIONS = auto() - """ - EOF container's code have instructions that are unreachable. - """ + """EOF container's code have instructions that are unreachable.""" UNREACHABLE_CODE_SECTIONS = auto() - """ - EOF container's body have code sections that are unreachable. - """ + """EOF container's body have code sections that are unreachable.""" STACK_UNDERFLOW = auto() - """ - EOF container's code produces an stack underflow. - """ + """EOF container's code produces an stack underflow.""" STACK_OVERFLOW = auto() - """ - EOF container's code produces an stack overflow. - """ + """EOF container's code produces an stack overflow.""" STACK_HEIGHT_MISMATCH = auto() - """ - EOF container section stack height mismatch. - """ + """EOF container section stack height mismatch.""" MAX_STACK_INCREASE_ABOVE_LIMIT = auto() - """ - EOF container's specified max stack increase is above the limit. - """ + """EOF container's specified max stack increase is above the limit.""" STACK_HIGHER_THAN_OUTPUTS = auto() """ - EOF container section stack height is higher than the outputs. - when returning + + + EOF container section stack height is higher than the outputs. when + returning + """ JUMPF_DESTINATION_INCOMPATIBLE_OUTPUTS = auto() """ - EOF container section JUMPF's to a destination section with incompatible outputs. + + + EOF container section JUMPF's to a destination section with incompatible + outputs. + """ INVALID_MAX_STACK_INCREASE = auto() """ - EOF container section's specified max stack increase does not match the actual stack height. + + + EOF container section's specified max stack increase does not match the + actual stack height. + """ INVALID_DATALOADN_INDEX = auto() - """ - A DATALOADN instruction has out-of-bounds index for the data section. - """ + """A DATALOADN instruction has out-of-bounds index for the data section.""" TRUNCATED_INSTRUCTION = auto() - """ - EOF container's code section has truncated instruction. - """ + """EOF container's code section has truncated instruction.""" TOPLEVEL_CONTAINER_TRUNCATED = auto() - """ - Top-level EOF container has data section truncated - """ + """Top-level EOF container has data section truncated""" ORPHAN_SUBCONTAINER = auto() - """ - EOF container has an unreferenced subcontainer. - '""" + """EOF container has an unreferenced subcontainer. '""" CONTAINER_SIZE_ABOVE_LIMIT = auto() - """ - EOF container is above size limit - """ + """EOF container is above size limit""" INVALID_CONTAINER_SECTION_INDEX = auto() - """ - Instruction references container section that does not exist. - """ + """Instruction references container section that does not exist.""" INCOMPATIBLE_CONTAINER_KIND = auto() - """ - Incompatible instruction found in a container of a specific kind. - """ + """Incompatible instruction found in a container of a specific kind.""" AMBIGUOUS_CONTAINER_KIND = auto() - """ - The kind of a sub-container cannot be uniquely deduced. - """ + """The kind of a sub-container cannot be uniquely deduced.""" TOO_MANY_CONTAINERS = auto() - """ - EOF container header has too many sub-containers. - """ + """EOF container header has too many sub-containers.""" INVALID_CODE_SECTION_INDEX = auto() - """ - CALLF Operation refers to a non-existent code section - """ + """CALLF Operation refers to a non-existent code section""" UNEXPECTED_HEADER_KIND = auto() - """ - Header parsing encountered a section kind it wasn't expecting - """ + """Header parsing encountered a section kind it wasn't expecting""" CALLF_TO_NON_RETURNING = auto() - """ - CALLF instruction targeting a non-returning code section - """ + """CALLF instruction targeting a non-returning code section""" EOFCREATE_WITH_TRUNCATED_CONTAINER = auto() - """ - EOFCREATE with truncated container - """ + """EOFCREATE with truncated container""" diff --git a/src/ethereum_test_exceptions/exceptions/transaction.py b/src/ethereum_test_exceptions/exceptions/transaction.py index 4d3bbc97b86..3adbb17fb95 100644 --- a/src/ethereum_test_exceptions/exceptions/transaction.py +++ b/src/ethereum_test_exceptions/exceptions/transaction.py @@ -8,284 +8,227 @@ @unique class TransactionException(ExceptionBase): """ - Exception raised when a transaction is invalid, and thus cannot be executed. + Exception raised when a transaction is invalid, and thus cannot be + executed. - If a transaction with any of these exceptions is included in a block, the block is invalid. + If a transaction with any of these exceptions is included in a block, the + block is invalid. """ TYPE_NOT_SUPPORTED = auto() - """ - Transaction type is not supported on this chain configuration. - """ + """Transaction type is not supported on this chain configuration.""" SENDER_NOT_EOA = auto() - """ - Transaction is coming from address that is not exist anymore. - """ + """Transaction is coming from address that is not exist anymore.""" ADDRESS_TOO_SHORT = auto() - """ - Transaction `to` is not allowed to be less than 20 bytes. - """ + """Transaction `to` is not allowed to be less than 20 bytes.""" ADDRESS_TOO_LONG = auto() - """ - Transaction `to` is not allowed to be more than 20 bytes. - """ + """Transaction `to` is not allowed to be more than 20 bytes.""" NONCE_MISMATCH_TOO_HIGH = auto() - """ - Transaction nonce > sender.nonce. - """ + """Transaction nonce > sender.nonce.""" NONCE_MISMATCH_TOO_LOW = auto() - """ - Transaction nonce < sender.nonce. - """ + """Transaction nonce < sender.nonce.""" NONCE_TOO_BIG = auto() """ - Transaction `nonce` is not allowed to be max_uint64 - 1 (this is probably TransactionTest). + + + Transaction `nonce` is not allowed to be max_uint64 - 1 (this is probably + TransactionTest). + """ NONCE_IS_MAX = auto() """ - Transaction `nonce` is not allowed to be max_uint64 - 1 (this is StateTests). + + + Transaction `nonce` is not allowed to be max_uint64 - 1 (this is + StateTests). + """ NONCE_OVERFLOW = auto() - """ - Transaction `nonce` is not allowed to be more than uint64. - """ + """Transaction `nonce` is not allowed to be more than uint64.""" GASLIMIT_OVERFLOW = auto() - """ - Transaction gaslimit exceeds 2^64-1 maximum value. - """ + """Transaction gaslimit exceeds 2^64-1 maximum value.""" VALUE_OVERFLOW = auto() - """ - Transaction value exceeds 2^256-1 maximum value. - """ + """Transaction value exceeds 2^256-1 maximum value.""" GASPRICE_OVERFLOW = auto() - """ - Transaction gasPrice exceeds 2^256-1 maximum value. - """ + """Transaction gasPrice exceeds 2^256-1 maximum value.""" GASLIMIT_PRICE_PRODUCT_OVERFLOW = auto() - """ - Transaction gasPrice * gasLimit exceeds 2^256-1 maximum value. - """ + """Transaction gasPrice * gasLimit exceeds 2^256-1 maximum value.""" INVALID_SIGNATURE_VRS = auto() - """ - Invalid transaction v, r, s values. - """ + """Invalid transaction v, r, s values.""" RLP_INVALID_SIGNATURE_R = auto() - """ - Error reading transaction signature R value. - """ + """Error reading transaction signature R value.""" RLP_INVALID_SIGNATURE_S = auto() - """ - Error reading transaction signature S value. - """ + """Error reading transaction signature S value.""" RLP_LEADING_ZEROS_GASLIMIT = auto() - """ - Error reading transaction gaslimit field RLP. - """ + """Error reading transaction gaslimit field RLP.""" RLP_LEADING_ZEROS_GASPRICE = auto() - """ - Error reading transaction gasprice field RLP. - """ + """Error reading transaction gasprice field RLP.""" RLP_LEADING_ZEROS_VALUE = auto() - """ - Error reading transaction value field RLP. - """ + """Error reading transaction value field RLP.""" RLP_LEADING_ZEROS_NONCE = auto() - """ - Error reading transaction nonce field RLP. - """ + """Error reading transaction nonce field RLP.""" RLP_LEADING_ZEROS_R = auto() - """ - Error reading transaction signature R field RLP. - """ + """Error reading transaction signature R field RLP.""" RLP_LEADING_ZEROS_S = auto() - """ - Error reading transaction signature S field RLP. - """ + """Error reading transaction signature S field RLP.""" RLP_LEADING_ZEROS_V = auto() - """ - Error reading transaction signature V field RLP. - """ + """Error reading transaction signature V field RLP.""" RLP_LEADING_ZEROS_BASEFEE = auto() - """ - Error reading transaction basefee field RLP. - """ + """Error reading transaction basefee field RLP.""" RLP_LEADING_ZEROS_PRIORITY_FEE = auto() - """ - Error reading transaction priority fee field RLP. - """ + """Error reading transaction priority fee field RLP.""" RLP_LEADING_ZEROS_DATA_SIZE = auto() """ - Error reading transaction data field RLP, (rlp field length has leading zeros). + + + Error reading transaction data field RLP, (rlp field length has leading + zeros). + """ RLP_LEADING_ZEROS_NONCE_SIZE = auto() """ - Error reading transaction nonce field RLP, (rlp field length has leading zeros). + + + Error reading transaction nonce field RLP, (rlp field length has leading + zeros). + """ RLP_TOO_FEW_ELEMENTS = auto() """ - Error reading transaction RLP, structure has too few elements than expected. + + + Error reading transaction RLP, structure has too few elements than + expected. + """ RLP_TOO_MANY_ELEMENTS = auto() """ - Error reading transaction RLP, structure has too many elements than expected. + + + Error reading transaction RLP, structure has too many elements than + expected. + """ RLP_ERROR_EOF = auto() - """ - Error reading transaction RLP, rlp stream unexpectedly finished. - """ + """Error reading transaction RLP, rlp stream unexpectedly finished.""" RLP_ERROR_SIZE = auto() - """ - Error reading transaction RLP, rlp size is invalid. - """ + """Error reading transaction RLP, rlp size is invalid.""" RLP_ERROR_SIZE_LEADING_ZEROS = auto() - """ - Error reading transaction RLP, field size has leading zeros. - """ + """Error reading transaction RLP, field size has leading zeros.""" INVALID_CHAINID = auto() - """ - Transaction chain id encoding is incorrect. - """ + """Transaction chain id encoding is incorrect.""" RLP_INVALID_DATA = auto() - """ - Transaction data field is invalid rlp. - """ + """Transaction data field is invalid rlp.""" RLP_INVALID_GASLIMIT = auto() - """ - Transaction gaslimit field is invalid rlp. - """ + """Transaction gaslimit field is invalid rlp.""" RLP_INVALID_NONCE = auto() - """ - Transaction nonce field is invalid rlp. - """ + """Transaction nonce field is invalid rlp.""" RLP_INVALID_TO = auto() - """ - Transaction to field is invalid rlp. - """ + """Transaction to field is invalid rlp.""" RLP_INVALID_ACCESS_LIST_ADDRESS_TOO_LONG = auto() - """ - Transaction access list address is > 20 bytes. - """ + """Transaction access list address is > 20 bytes.""" RLP_INVALID_ACCESS_LIST_ADDRESS_TOO_SHORT = auto() - """ - Transaction access list address is < 20 bytes. - """ + """Transaction access list address is < 20 bytes.""" RLP_INVALID_ACCESS_LIST_STORAGE_TOO_LONG = auto() - """ - Transaction access list storage hash > 32 bytes. - """ + """Transaction access list storage hash > 32 bytes.""" RLP_INVALID_ACCESS_LIST_STORAGE_TOO_SHORT = auto() - """ - Transaction access list storage hash < 32 bytes. - """ + """Transaction access list storage hash < 32 bytes.""" RLP_INVALID_HEADER = auto() - """ - Transaction failed to read from RLP as rlp header is invalid. - """ + """Transaction failed to read from RLP as rlp header is invalid.""" RLP_INVALID_VALUE = auto() - """ - Transaction value field is invalid rlp/structure. - """ + """Transaction value field is invalid rlp/structure.""" EC_RECOVERY_FAIL = auto() - """ - Transaction has correct signature, but ec recovery failed. - """ + """Transaction has correct signature, but ec recovery failed.""" INSUFFICIENT_ACCOUNT_FUNDS = auto() """ + + Transaction's sender does not have enough funds to pay for the transaction. + """ INSUFFICIENT_MAX_FEE_PER_GAS = auto() - """ - Transaction's max-fee-per-gas is lower than the block base-fee. - """ + """Transaction's max-fee-per-gas is lower than the block base-fee.""" PRIORITY_OVERFLOW = auto() """ + + Transaction's max-priority-fee-per-gas is exceeds 2^256-1 maximum value. + """ PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS = auto() """ + + Transaction's max-priority-fee-per-gas is greater than the max-fee-per-gas. + """ PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS_2 = auto() """ - Transaction's max-priority-fee-per-gas is greater than the max-fee-per-gas (TransactionTests). + + + Transaction's max-priority-fee-per-gas is greater than the max-fee-per-gas + (TransactionTests). + """ INSUFFICIENT_MAX_FEE_PER_BLOB_GAS = auto() """ - Transaction's max-fee-per-blob-gas is lower than the block's blob-gas price. + + + Transaction's max-fee-per-blob-gas is lower than the block's blob-gas + price. + """ INTRINSIC_GAS_TOO_LOW = auto() - """ - Transaction's gas limit is too low. - """ + """Transaction's gas limit is too low.""" INTRINSIC_GAS_BELOW_FLOOR_GAS_COST = auto() - """ - Transaction's gas limit is below the floor gas cost. - """ + """Transaction's gas limit is below the floor gas cost.""" INITCODE_SIZE_EXCEEDED = auto() """ + + Transaction's initcode for a contract-creating transaction is too large. + """ TYPE_3_TX_PRE_FORK = auto() - """ - Transaction type 3 included before activation fork. - """ + """Transaction type 3 included before activation fork.""" TYPE_3_TX_ZERO_BLOBS_PRE_FORK = auto() - """ - Transaction type 3, with zero blobs, included before activation fork. - """ + """Transaction type 3, with zero blobs, included before activation fork.""" TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH = auto() - """ - Transaction contains a blob versioned hash with an invalid version. - """ + """Transaction contains a blob versioned hash with an invalid version.""" TYPE_3_TX_WITH_FULL_BLOBS = auto() - """ - Transaction contains full blobs (network-version of the transaction). - """ + """Transaction contains full blobs (network-version of the transaction).""" TYPE_3_TX_BLOB_COUNT_EXCEEDED = auto() - """ - Transaction contains too many blob versioned hashes. - """ + """Transaction contains too many blob versioned hashes.""" TYPE_3_TX_CONTRACT_CREATION = auto() - """ - Transaction is a type 3 transaction and has an empty `to`. - """ + """Transaction is a type 3 transaction and has an empty `to`.""" TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED = auto() - """ - Transaction causes block to go over blob gas limit. - """ + """Transaction causes block to go over blob gas limit.""" GAS_ALLOWANCE_EXCEEDED = auto() - """ - Transaction causes block to go over blob gas limit. - """ + """Transaction causes block to go over blob gas limit.""" GAS_LIMIT_EXCEEDS_MAXIMUM = auto() """ + + Transaction gas limit exceeds the maximum allowed limit of 30 million. + """ TYPE_3_TX_ZERO_BLOBS = auto() - """ - Transaction is type 3, but has no blobs. - """ + """Transaction is type 3, but has no blobs.""" TYPE_4_EMPTY_AUTHORIZATION_LIST = auto() - """ - Transaction is type 4, but has an empty authorization list. - """ + """Transaction is type 4, but has an empty authorization list.""" TYPE_4_INVALID_AUTHORITY_SIGNATURE = auto() - """ - Transaction authority signature is invalid - """ + """Transaction authority signature is invalid""" TYPE_4_INVALID_AUTHORITY_SIGNATURE_S_TOO_HIGH = auto() - """ - Transaction authority signature is invalid - """ + """Transaction authority signature is invalid""" TYPE_4_TX_CONTRACT_CREATION = auto() - """ - Transaction is a type 4 transaction and has an empty `to`. - """ + """Transaction is a type 4 transaction and has an empty `to`.""" TYPE_4_INVALID_AUTHORIZATION_FORMAT = auto() """ - Transaction is type 4, but contains an authorization that has an invalid format. + + + Transaction is type 4, but contains an authorization that has an invalid + format. + """ TYPE_4_TX_PRE_FORK = auto() - """ - Transaction type 4 included before activation fork. - """ + """Transaction type 4 included before activation fork.""" diff --git a/src/ethereum_test_exceptions/tests/test_exceptions.py b/src/ethereum_test_exceptions/tests/test_exceptions.py index 925d76f9c60..a09381be22e 100644 --- a/src/ethereum_test_exceptions/tests/test_exceptions.py +++ b/src/ethereum_test_exceptions/tests/test_exceptions.py @@ -34,7 +34,10 @@ def test_exceptions_string_conversion( exception: BlockException | TransactionException, expected: str ): - """Test that the exceptions are unique and have the correct string representation.""" + """ + Test that the exceptions are unique and have the correct string + representation. + """ assert str(exception) == expected diff --git a/src/ethereum_test_execution/base.py b/src/ethereum_test_execution/base.py index 1bf1d00437c..58a3411443b 100644 --- a/src/ethereum_test_execution/base.py +++ b/src/ethereum_test_execution/base.py @@ -44,8 +44,8 @@ class LabeledExecuteFormat: """ Represents an execution format with a custom label. - This label will be used in the test id and also will be added as a marker to the - generated test case when executing the test. + This label will be used in the test id and also will be added as a marker + to the generated test case when executing the test. """ format: Type[BaseExecute] @@ -85,8 +85,8 @@ def __eq__(self, other: Any) -> bool: """ Check if two labeled execute formats are equal. - If the other object is a ExecuteFormat type, the format of the labeled execute - format will be compared with the format of the other object. + If the other object is a ExecuteFormat type, the format of the labeled + execute format will be compared with the format of the other object. """ if isinstance(other, LabeledExecuteFormat): return self.format == other.format diff --git a/src/ethereum_test_execution/blob_transaction.py b/src/ethereum_test_execution/blob_transaction.py index 6c7f6a90d0d..66c4e3c236e 100644 --- a/src/ethereum_test_execution/blob_transaction.py +++ b/src/ethereum_test_execution/blob_transaction.py @@ -47,8 +47,9 @@ def versioned_hashes_with_blobs_and_proofs( class BlobTransaction(BaseExecute): """ - Represents a test execution format to send blob transactions to the client and then - use `engine_getBlobsV*` end points to validate the proofs generated by the execution client. + Represents a test execution format to send blob transactions to the client + and then use `engine_getBlobsV*` end points to validate the proofs + generated by the execution client. """ format_name: ClassVar[str] = "blob_transaction_test" @@ -94,16 +95,18 @@ def execute( version = fork.engine_get_blobs_version() assert version is not None, "Engine get blobs version is not supported by the fork." - # ensure that clients respond 'null' when they have no access to at least one blob + # ensure that clients respond 'null' when they have no access to at + # least one blob list_versioned_hashes = list(versioned_hashes.keys()) if self.nonexisting_blob_hashes is not None: list_versioned_hashes.extend(self.nonexisting_blob_hashes) blob_response: GetBlobsResponse | None = engine_rpc.get_blobs( list_versioned_hashes, version=version - ) # noqa: E501 + ) - # if non-existing blob hashes were request then the response must be 'null' + # if non-existing blob hashes were request then the response must be + # 'null' if self.nonexisting_blob_hashes is not None: if blob_response is not None: raise ValueError( diff --git a/src/ethereum_test_execution/transaction_post.py b/src/ethereum_test_execution/transaction_post.py index fce6b2bbcb9..5c97eb045bc 100644 --- a/src/ethereum_test_execution/transaction_post.py +++ b/src/ethereum_test_execution/transaction_post.py @@ -14,7 +14,9 @@ class TransactionPost(BaseExecute): - """Represents a simple transaction-send then post-check execution format.""" + """ + Represents a simple transaction-send then post-check execution format. + """ blocks: List[List[Transaction]] post: Alloc diff --git a/src/ethereum_test_fixtures/base.py b/src/ethereum_test_fixtures/base.py index b4531e4580a..e0670b7b34a 100644 --- a/src/ethereum_test_fixtures/base.py +++ b/src/ethereum_test_fixtures/base.py @@ -64,7 +64,10 @@ class BaseFixture(CamelModel): @classmethod def output_base_dir_name(cls) -> str: - """Return name of the subdirectory where this type of fixture should be dumped to.""" + """ + Return name of the subdirectory where this type of fixture should be + dumped to. + """ return cls.format_name.replace("test", "tests") @classmethod @@ -161,7 +164,10 @@ def discard_fixture_format_by_marks( fork: Fork, markers: List[pytest.Mark], ) -> bool: - """Discard a fixture format from filling if the appropriate marker is used.""" + """ + Discard a fixture format from filling if the appropriate marker is + used. + """ return False @@ -169,8 +175,8 @@ class LabeledFixtureFormat: """ Represents a fixture format with a custom label. - This label will be used in the test id and also will be added as a marker to the - generated test case when filling the test. + This label will be used in the test id and also will be added as a marker + to the generated test case when filling the test. """ format: Type[BaseFixture] @@ -210,8 +216,8 @@ def __eq__(self, other: Any) -> bool: """ Check if two labeled fixture formats are equal. - If the other object is a FixtureFormat type, the format of the labeled fixture - format will be compared with the format of the other object. + If the other object is a FixtureFormat type, the format of the labeled + fixture format will be compared with the format of the other object. """ if isinstance(other, LabeledFixtureFormat): return self.format == other.format diff --git a/src/ethereum_test_fixtures/blockchain.py b/src/ethereum_test_fixtures/blockchain.py index 74d60f16bb0..e2983cdb1a0 100644 --- a/src/ethereum_test_fixtures/blockchain.py +++ b/src/ethereum_test_fixtures/blockchain.py @@ -55,10 +55,8 @@ def post_state_validator(alternate_field: str | None = None, mode: str = "after" """ Create a validator to ensure exactly one post-state field is provided. - Args: - alternate_field: Alternative field name to post_state_hash (e.g., 'post_state_diff'). - mode: Pydantic validation mode. - + Args: alternate_field: Alternative field name to post_state_hash (e.g., + 'post_state_diff'). mode: Pydantic validation mode. """ def decorator(cls): @@ -68,10 +66,12 @@ def validate_post_state_fields(self): if mode == "after": # Determine which fields to check if alternate_field: - # For engine x fixtures: check post_state vs post_state_diff + # For engine x fixtures: check post_state vs + # post_state_diff field1_name, field2_name = "post_state", alternate_field else: - # For standard fixtures: check post_state vs post_state_hash + # For standard fixtures: check post_state vs + # post_state_hash field1_name, field2_name = "post_state", "post_state_hash" field1_value = getattr(self, field1_name, None) @@ -93,8 +93,8 @@ def validate_post_state_fields(self): class HeaderForkRequirement(str): """ - Fork requirement class that specifies the name of the method that should be called - to check if the field is required. + Fork requirement class that specifies the name of the method that should be + called to check if the field is required. """ def __new__(cls, value: str) -> "HeaderForkRequirement": @@ -173,7 +173,10 @@ class FixtureHeader(CamelModel): fork: Fork | None = Field(None, exclude=True) def model_post_init(self, __context): - """Model post init method used to check for required fields of a given fork.""" + """ + Model post init method used to check for required fields of a given + fork. + """ super().model_post_init(__context) if self.fork is None: @@ -184,8 +187,9 @@ def model_post_init(self, __context): block_number = self.number timestamp = self.timestamp - # For each field, check if any of the annotations are of type HeaderForkRequirement and - # if so, check if the field is required for the given fork. + # For each field, check if any of the annotations are of type + # HeaderForkRequirement and if so, check if the field is required for + # the given fork. annotated_hints = get_type_hints(self, include_extras=True) for field in self.__class__.model_fields: @@ -244,7 +248,9 @@ def genesis(cls, fork: Fork, env: Environment, state_root: Hash) -> "FixtureHead class FixtureExecutionPayload(CamelModel): - """Representation of an Ethereum execution payload within a test Fixture.""" + """ + Representation of an Ethereum execution payload within a test Fixture. + """ parent_hash: Hash fee_recipient: Address @@ -282,8 +288,8 @@ def from_fixture_header( block_access_list: Bytes | None = None, ) -> "FixtureExecutionPayload": """ - Return FixtureExecutionPayload from a FixtureHeader, a list - of transactions, a list of withdrawals, and an optional block access list. + Return FixtureExecutionPayload from a FixtureHeader, a list of + transactions, a list of withdrawals, and an optional block access list. """ return cls( **header.model_dump(exclude={"rlp"}, exclude_none=True), @@ -303,8 +309,8 @@ def from_fixture_header( ] EngineNewPayloadV5Parameters = EngineNewPayloadV4Parameters -# Important: We check EngineNewPayloadV3Parameters first as it has more fields, and pydantic -# has a weird behavior when the smaller tuple is checked first. +# Important: We check EngineNewPayloadV3Parameters first as it has more fields, +# and pydantic has a weird behavior when the smaller tuple is checked first. EngineNewPayloadParameters = Union[ EngineNewPayloadV5Parameters, EngineNewPayloadV4Parameters, @@ -315,8 +321,8 @@ def from_fixture_header( class FixtureEngineNewPayload(CamelModel): """ - Representation of the `engine_newPayloadVX` information to be - sent using the block information. + Representation of the `engine_newPayloadVX` information to be sent using + the block information. """ params: EngineNewPayloadParameters @@ -445,7 +451,10 @@ def parse_witness_chunks(cls, s: str) -> List["WitnessChunk"]: class FixtureBlockBase(CamelModel): - """Representation of an Ethereum block within a test Fixture without RLP bytes.""" + """ + Representation of an Ethereum block within a test Fixture without RLP + bytes. + """ header: FixtureHeader = Field(..., alias="blockHeader") txs: List[FixtureTransaction] = Field(default_factory=list, alias="transactions") @@ -467,7 +476,8 @@ def with_rlp(self, txs: List[Transaction]) -> "FixtureBlock": block = [ self.header.rlp_encode_list, [tx.serializable_list for tx in txs], - self.ommers, # TODO: This is incorrect, and we probably need to serialize the ommers + self.ommers, # TODO: This is incorrect, and we probably need to + # serialize the ommers ] if self.withdrawals is not None: @@ -519,15 +529,16 @@ class BlockchainFixtureCommon(BaseFixture): pre: Alloc post_state: Alloc | None = Field(None) post_state_hash: Hash | None = Field(None) - last_block_hash: Hash = Field(..., alias="lastblockhash") # FIXME: lastBlockHash + last_block_hash: Hash = Field(..., alias="lastblockhash") # FIXME: + # lastBlockHash config: FixtureConfig @model_validator(mode="before") @classmethod def config_defaults_for_backwards_compatibility(cls, data: Any) -> Any: """ - Check if the config field is populated, otherwise use the root-level field values for - backwards compatibility. + Check if the config field is populated, otherwise use the root-level + field values for backwards compatibility. """ if isinstance(data, dict): if "config" not in data: @@ -566,7 +577,8 @@ class BlockchainEngineFixtureCommon(BaseFixture): fork: Fork = Field(..., alias="network") post_state_hash: Hash | None = Field(None) - last_block_hash: Hash = Field(..., alias="lastblockhash") # FIXME: lastBlockHash + last_block_hash: Hash = Field(..., alias="lastblockhash") # FIXME: + # lastBlockHash config: FixtureConfig def get_fork(self) -> Fork | None: @@ -616,7 +628,13 @@ class BlockchainEngineXFixture(BlockchainEngineFixtureCommon): """Hash of the pre-allocation group this test belongs to.""" post_state_diff: Alloc | None = None - """State difference from genesis after test execution (efficiency optimization).""" + """ + + + State difference from genesis after test execution (efficiency + optimization). + + """ payloads: List[FixtureEngineNewPayload] = Field(..., alias="engineNewPayloads") """Engine API payloads for blockchain execution.""" @@ -626,10 +644,10 @@ class BlockchainEngineSyncFixture(BlockchainEngineFixture): """ Engine Sync specific test fixture information. - This fixture format is specifically designed for sync testing where: - - The client under test receives all payloads - - A sync client attempts to sync from the client under test - - Both client types are parametrized from hive client config + This fixture format is specifically designed for sync testing where: - The + client under test receives all payloads - A sync client attempts to sync + from the client under test - Both client types are parametrized from hive + client config """ format_name: ClassVar[str] = "blockchain_test_sync" diff --git a/src/ethereum_test_fixtures/collector.py b/src/ethereum_test_fixtures/collector.py index e13e043125d..fcf5ae0b2f6 100644 --- a/src/ethereum_test_fixtures/collector.py +++ b/src/ethereum_test_fixtures/collector.py @@ -1,6 +1,6 @@ """ -Fixture collector class used to collect, sort and combine the different types of generated -fixtures. +Fixture collector class used to collect, sort and combine the different types +of generated fixtures. """ import json @@ -23,9 +23,11 @@ class TestInfo: """Contains test information from the current node.""" name: str # pytest: Item.name, e.g. test_paris_one[fork_Paris-state_test] - id: str # pytest: Item.nodeid, e.g. tests/paris/test_module_paris.py::test_paris_one[...] + id: str # pytest: Item.nodeid, e.g. + # tests/paris/test_module_paris.py::test_paris_one[...] original_name: str # pytest: Item.originalname, e.g. test_paris_one - module_path: Path # pytest: Item.path, e.g. .../tests/paris/test_module_paris.py + module_path: Path # pytest: Item.path, e.g. + # .../tests/paris/test_module_paris.py test_prefix: ClassVar[str] = "test_" # Python test prefix filler_suffix: ClassVar[str] = "Filler" # Static test suffix @@ -41,11 +43,11 @@ def strip_test_name(cls, name: str) -> str: def get_name_and_parameters(self) -> Tuple[str, str]: """ - Convert test name to a tuple containing the test name and test parameters. - - Example: - test_push0_key_sstore[fork_Shanghai] -> test_push0_key_sstore, fork_Shanghai + Convert test name to a tuple containing the test name and test + parameters. + Example: test_push0_key_sstore[fork_Shanghai] -> test_push0_key_sstore, + fork_Shanghai """ test_name, parameters = self.name.split("[") return test_name, re.sub(r"[\[\-]", "_", parameters).replace("]", "") @@ -91,9 +93,8 @@ def get_module_relative_output_dir(self, filler_path: Path) -> Path: base ./tests directory) that can be used for output (within the configured fixtures output path or the base_dump_dir directory). - Example: - tests/shanghai/eip3855_push0/test_push0.py -> shanghai/eip3855_push0/test_push0 - + Example: tests/shanghai/eip3855_push0/test_push0.py -> + shanghai/eip3855_push0/test_push0 """ basename = self.module_path.with_suffix("").absolute() basename_relative = basename.relative_to( @@ -122,8 +123,9 @@ def get_fixture_basename(self, info: TestInfo) -> Path: """Return basename of the fixture file for a given test case.""" module_relative_output_dir = info.get_module_relative_output_dir(self.filler_path) - # Each legacy test filler has only 1 test per file if it's a !state test! - # So no need to create directory Add11/add11.json it can be plain add11.json + # Each legacy test filler has only 1 test per file if it's a !state + # test! So no need to create directory Add11/add11.json it can be plain + # add11.json if self.fill_static_tests: return module_relative_output_dir.parent / info.original_name @@ -140,7 +142,9 @@ def add_fixture(self, info: TestInfo, fixture: BaseFixture) -> Path: / fixture.output_base_dir_name() / fixture_basename.with_suffix(fixture.output_file_extension) ) - if fixture_path not in self.all_fixtures.keys(): # relevant when we group by test function + if fixture_path not in self.all_fixtures.keys(): # relevant when we + # group by test + # function self.all_fixtures[fixture_path] = Fixtures(root={}) self.json_path_to_test_item[fixture_path] = info diff --git a/src/ethereum_test_fixtures/consume.py b/src/ethereum_test_fixtures/consume.py index dcec641b3ab..d850b5614f3 100644 --- a/src/ethereum_test_fixtures/consume.py +++ b/src/ethereum_test_fixtures/consume.py @@ -34,7 +34,10 @@ def consume_fixture( fixture_name: str | None = None, debug_output_path: Path | None = None, ): - """Test the client with the specified fixture using its direct consumer interface.""" + """ + Test the client with the specified fixture using its direct consumer + interface. + """ raise NotImplementedError( "The `consume_fixture()` function is not supported by this tool." ) @@ -59,20 +62,29 @@ class TestCaseStream(TestCaseBase): class TestCaseIndexFile(TestCaseBase): - """The test case model used to save/load test cases to/from an index file.""" + """ + The test case model used to save/load test cases to/from an index file. + """ json_path: Path __test__ = False # stop pytest from collecting this class as a test # TODO: add pytest marks """ - ConsumerTypes = Literal["all", "direct", "rlp", "engine"] - @classmethod - def _marks_default(cls): - return {consumer_type: [] for consumer_type in get_args(ConsumerTypes)} - marks: Mapping[ConsumerTypes, List[pytest.MarkDecorator]] = field( - default_factory=lambda: TestCase._marks_default() - ) + + + + + + + ConsumerTypes = Literal["all", "direct", "rlp", "engine"] @classmethod def + _marks_default(cls): return {consumer_type: [] for consumer_type in + get_args(ConsumerTypes)} marks: Mapping[ConsumerTypes, + List[pytest.MarkDecorator]] = field( default_factory=lambda: + TestCase._marks_default() ) + + + """ diff --git a/src/ethereum_test_fixtures/file.py b/src/ethereum_test_fixtures/file.py index 2f74e06b37c..8679cfabcf5 100644 --- a/src/ethereum_test_fixtures/file.py +++ b/src/ethereum_test_fixtures/file.py @@ -15,13 +15,14 @@ class Fixtures(EthereumTestRootModel): """ A base class for defining top-level models that encapsulate multiple test - fixtures. Each fixture is stored in a dictionary, where each key is a string - (typically the fixture name) and its corresponding value is a fixture object. - This is the structure used for blockchain and state JSON fixture files. - - This class implements dunder methods and other common functionality to allow - interaction with the model's fixtures as if they were being accessed directly - from a dictionary. + fixtures. Each fixture is stored in a dictionary, where each key is a + string (typically the fixture name) and its corresponding value is a + fixture object. This is the structure used for blockchain and state JSON + fixture files. + + This class implements dunder methods and other common functionality to + allow interaction with the model's fixtures as if they were being accessed + directly from a dictionary. """ root: Dict[str, SerializeAsAny[BaseFixture]] @@ -54,8 +55,8 @@ def collect_into_file(self, file_path: Path): """ For all formats, we join the fixtures as json into a single file. - Note: We don't use pydantic model_dump_json() on the Fixtures object as we - add the hash to the info field on per-fixture basis. + Note: We don't use pydantic model_dump_json() on the Fixtures object as + we add the hash to the info field on per-fixture basis. """ json_fixtures: Dict[str, Dict[str, Any]] = {} lock_file_path = file_path.with_suffix(".lock") diff --git a/src/ethereum_test_fixtures/pre_alloc_groups.py b/src/ethereum_test_fixtures/pre_alloc_groups.py index c358b757093..378f04e69f4 100644 --- a/src/ethereum_test_fixtures/pre_alloc_groups.py +++ b/src/ethereum_test_fixtures/pre_alloc_groups.py @@ -22,7 +22,8 @@ class PreAllocGroup(CamelModel): pre-allocation group optimization. """ - model_config = {"populate_by_name": True} # Allow both field names and aliases + model_config = {"populate_by_name": True} # Allow both field names and + # aliases test_ids: List[str] = Field(default_factory=list) environment: Environment = Field(..., description="Grouping environment for this test group") @@ -65,9 +66,10 @@ def to_file(self, file: Path) -> None: else: new_account = self.pre[account] if new_account != existing_account: - # This procedure fails during xdist worker's pytest_sessionfinish - # and is not reported to the master thread. - # We signal here that the groups created contain a collision. + # This procedure fails during xdist worker's + # pytest_sessionfinish and is not reported to the + # master thread. We signal here that the groups + # created contain a collision. collision_file_path = file.with_suffix(".fail") collision_exception = Alloc.CollisionError( address=account, @@ -87,7 +89,8 @@ class PreAllocGroups(EthereumTestRootModel): """ Root model mapping pre-allocation group hashes to test groups. - If lazy_load is True, the groups are not loaded from the folder until they are accessed. + If lazy_load is True, the groups are not loaded from the folder until they + are accessed. Iterating will fail if lazy_load is True. """ diff --git a/src/ethereum_test_fixtures/state.py b/src/ethereum_test_fixtures/state.py index 8d389db57f3..3dfb6ba29c4 100644 --- a/src/ethereum_test_fixtures/state.py +++ b/src/ethereum_test_fixtures/state.py @@ -64,7 +64,9 @@ def from_transaction(cls, tx: Transaction) -> "FixtureTransaction": class FixtureForkPostIndexes(BaseModel): - """Type used to describe the indexes of a single post state of a single Fork.""" + """ + Type used to describe the indexes of a single post state of a single Fork. + """ data: int = 0 gas: int = 0 diff --git a/src/ethereum_test_fixtures/tests/test_blockchain.py b/src/ethereum_test_fixtures/tests/test_blockchain.py index c2917a2ccf8..5fcb8274dab 100644 --- a/src/ethereum_test_fixtures/tests/test_blockchain.py +++ b/src/ethereum_test_fixtures/tests/test_blockchain.py @@ -531,8 +531,10 @@ id="invalid_fixture_block_2", ), pytest.param( - False, # Can not be deserialized: A single expect_exception str will not be - # deserialized as a list and therefore will not match the model_instance definition. + False, # Can not be deserialized: A single expect_exception str + # will not be + # deserialized as a list and therefore will not match the + # model_instance definition. InvalidFixtureBlock( rlp="0x00", expect_exception=[TransactionException.INTRINSIC_GAS_TOO_LOW], diff --git a/src/ethereum_test_fixtures/tests/test_state.py b/src/ethereum_test_fixtures/tests/test_state.py index e4b3ab50cef..e7d5b299946 100644 --- a/src/ethereum_test_fixtures/tests/test_state.py +++ b/src/ethereum_test_fixtures/tests/test_state.py @@ -50,8 +50,10 @@ id="state_fixture_fork_post_exception", ), pytest.param( - False, # Can not be deserialized: A single expect_exception str will not be - # deserialized as a list and therefore will not match the model_instance definition. + False, # Can not be deserialized: A single expect_exception str + # will not be + # deserialized as a list and therefore will not match the + # model_instance definition. FixtureForkPost( state_root=0, logs_hash=1, diff --git a/src/ethereum_test_forks/base_fork.py b/src/ethereum_test_forks/base_fork.py index 74840c55e12..750a2c9d694 100644 --- a/src/ethereum_test_forks/base_fork.py +++ b/src/ethereum_test_forks/base_fork.py @@ -26,15 +26,22 @@ class ForkAttribute(Protocol): - """A protocol to get the attribute of a fork at a given block number and timestamp.""" + """ + A protocol to get the attribute of a fork at a given block number and + timestamp. + """ def __call__(self, block_number: int = 0, timestamp: int = 0) -> Any: - """Return value of the attribute at the given block number and timestamp.""" + """ + Return value of the attribute at the given block number and timestamp. + """ pass class MemoryExpansionGasCalculator(Protocol): - """A protocol to calculate the gas cost of memory expansion at a given fork.""" + """ + A protocol to calculate the gas cost of memory expansion at a given fork. + """ def __call__(self, *, new_bytes: int, previous_bytes: int = 0) -> int: """Return gas cost of expanding the memory by the given length.""" @@ -42,7 +49,10 @@ def __call__(self, *, new_bytes: int, previous_bytes: int = 0) -> int: class CalldataGasCalculator(Protocol): - """A protocol to calculate the transaction gas cost of calldata at a given fork.""" + """ + A protocol to calculate the transaction gas cost of calldata at a given + fork. + """ def __call__(self, *, data: BytesConvertible, floor: bool = False) -> int: """Return the transaction gas cost of calldata given its contents.""" @@ -50,7 +60,9 @@ def __call__(self, *, data: BytesConvertible, floor: bool = False) -> int: class TransactionDataFloorCostCalculator(Protocol): - """Calculate the transaction floor cost due to its calldata for a given fork.""" + """ + Calculate the transaction floor cost due to its calldata for a given fork. + """ def __call__(self, *, data: BytesConvertible) -> int: """Return transaction gas cost of calldata given its contents.""" @@ -68,7 +80,10 @@ def __call__( class BaseFeeChangeCalculator(Protocol): - """A protocol to calculate the gas that needs to be used to change the base fee.""" + """ + A protocol to calculate the gas that needs to be used to change the base + fee. + """ def __call__( self, @@ -82,7 +97,10 @@ def __call__( class TransactionIntrinsicCostCalculator(Protocol): - """A protocol to calculate the intrinsic gas cost of a transaction at a given fork.""" + """ + A protocol to calculate the intrinsic gas cost of a transaction at a given + fork. + """ def __call__( self, @@ -96,26 +114,25 @@ def __call__( """ Return the intrinsic gas cost of a transaction given its properties. - Args: - calldata: The data of the transaction. - contract_creation: Whether the transaction creates a contract. - access_list: The list of access lists for the transaction. - authorization_list_or_count: The list of authorizations or the count of authorizations - for the transaction. - return_cost_deducted_prior_execution: If set to False, the returned value is equal to - the minimum gas required for the transaction to be valid. If set to True, the - returned value is equal to the cost that is deducted from the gas limit before - the transaction starts execution. - - Returns: - Gas cost of a transaction + Args: calldata: The data of the transaction. contract_creation: Whether + the transaction creates a contract. access_list: The list of access + lists for the transaction. authorization_list_or_count: The list of + authorizations or the count of authorizations for the transaction. + return_cost_deducted_prior_execution: If set to False, the returned + value is equal to the minimum gas required for the transaction to be + valid. If set to True, the returned value is equal to the cost that is + deducted from the gas limit before the transaction starts execution. + Returns: Gas cost of a transaction """ pass class BlobGasPriceCalculator(Protocol): - """A protocol to calculate the blob gas price given the excess blob gas at a given fork.""" + """ + A protocol to calculate the blob gas price given the excess blob gas at a + given fork. + """ def __call__(self, *, excess_blob_gas: int) -> int: """Return the blob gas price given the excess blob gas.""" @@ -123,7 +140,9 @@ def __call__(self, *, excess_blob_gas: int) -> int: class ExcessBlobGasCalculator(Protocol): - """A protocol to calculate the excess blob gas for a block at a given fork.""" + """ + A protocol to calculate the excess blob gas for a block at a given fork. + """ def __call__( self, @@ -134,7 +153,10 @@ def __call__( parent_blob_count: int | None = None, parent_base_fee_per_gas: int, ) -> int: - """Return the excess blob gas given the parent's excess blob gas and blob gas used.""" + """ + Return the excess blob gas given the parent's excess blob gas and blob + gas used. + """ pass @@ -143,7 +165,10 @@ class BaseForkMeta(ABCMeta): @abstractmethod def name(cls) -> str: - """Return the name of the fork (e.g., Berlin), must be implemented by subclasses.""" + """ + Return the name of the fork (e.g., Berlin), must be implemented by + subclasses. + """ pass def __repr__(cls) -> str: @@ -152,12 +177,18 @@ def __repr__(cls) -> str: @staticmethod def _maybe_transitioned(fork_cls: "BaseForkMeta") -> "BaseForkMeta": - """Return the transitioned fork, if a transition fork, otherwise return `fork_cls`.""" + """ + Return the transitioned fork, if a transition fork, otherwise return + `fork_cls`. + """ return fork_cls.transitions_to() if hasattr(fork_cls, "transitions_to") else fork_cls @staticmethod def _is_subclass_of(a: "BaseForkMeta", b: "BaseForkMeta") -> bool: - """Check if `a` is a subclass of `b`, taking fork transitions into account.""" + """ + Check if `a` is a subclass of `b`, taking fork transitions into + account. + """ a = BaseForkMeta._maybe_transitioned(a) b = BaseForkMeta._maybe_transitioned(b) return issubclass(a, b) @@ -167,7 +198,10 @@ def __gt__(cls, other: "BaseForkMeta") -> bool: return cls is not other and BaseForkMeta._is_subclass_of(cls, other) def __ge__(cls, other: "BaseForkMeta") -> bool: - """Compare if a fork is newer than or equal to some other fork (cls >= other).""" + """ + Compare if a fork is newer than or equal to some other fork (cls >= + other). + """ return cls is other or BaseForkMeta._is_subclass_of(cls, other) def __lt__(cls, other: "BaseForkMeta") -> bool: @@ -176,7 +210,10 @@ def __lt__(cls, other: "BaseForkMeta") -> bool: return cls is not other and BaseForkMeta._is_subclass_of(other, cls) def __le__(cls, other: "BaseForkMeta") -> bool: - """Compare if a fork is older than or equal to some other fork (cls <= other).""" + """ + Compare if a fork is older than or equal to some other fork (cls <= + other). + """ return cls is other or BaseForkMeta._is_subclass_of(other, cls) @@ -209,7 +246,10 @@ def __init_subclass__( ignore: bool = False, bpo_fork: bool = False, ) -> None: - """Initialize new fork with values that don't carry over to subclass forks.""" + """ + Initialize new fork with values that don't carry over to subclass + forks. + """ cls._transition_tool_name = transition_tool_name cls._solc_name = solc_name cls._ignore = ignore @@ -288,7 +328,10 @@ def gas_costs(cls, block_number: int = 0, timestamp: int = 0) -> GasCosts: def memory_expansion_gas_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> MemoryExpansionGasCalculator: - """Return a callable that calculates the gas cost of memory expansion for the fork.""" + """ + Return a callable that calculates the gas cost of memory expansion for + the fork. + """ pass @classmethod @@ -297,8 +340,8 @@ def calldata_gas_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> CalldataGasCalculator: """ - Return callable that calculates the transaction gas cost for its calldata - depending on its contents. + Return callable that calculates the transaction gas cost for its + calldata depending on its contents. """ pass @@ -307,7 +350,9 @@ def calldata_gas_calculator( def base_fee_per_gas_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> BaseFeePerGasCalculator: - """Return a callable that calculates the base fee per gas at a given fork.""" + """ + Return a callable that calculates the base fee per gas at a given fork. + """ pass @classmethod @@ -316,8 +361,8 @@ def base_fee_change_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> BaseFeeChangeCalculator: """ - Return a callable that calculates the gas that needs to be used to change the - base fee. + Return a callable that calculates the gas that needs to be used to + change the base fee. """ pass @@ -344,7 +389,10 @@ def max_refund_quotient(cls) -> int: def transaction_data_floor_cost_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> TransactionDataFloorCostCalculator: - """Return a callable that calculates the transaction floor cost due to its calldata.""" + """ + Return a callable that calculates the transaction floor cost due to its + calldata. + """ pass @classmethod @@ -352,7 +400,10 @@ def transaction_data_floor_cost_calculator( def transaction_intrinsic_cost_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> TransactionIntrinsicCostCalculator: - """Return callable that calculates the intrinsic gas cost of a transaction for the fork.""" + """ + Return callable that calculates the intrinsic gas cost of a transaction + for the fork. + """ pass @classmethod @@ -360,7 +411,9 @@ def transaction_intrinsic_cost_calculator( def blob_gas_price_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> BlobGasPriceCalculator: - """Return a callable that calculates the blob gas price at a given fork.""" + """ + Return a callable that calculates the blob gas price at a given fork. + """ pass @classmethod @@ -368,7 +421,10 @@ def blob_gas_price_calculator( def excess_blob_gas_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> ExcessBlobGasCalculator: - """Return a callable that calculates the excess blob gas for a block at a given fork.""" + """ + Return a callable that calculates the excess blob gas for a block at a + given fork. + """ pass @classmethod @@ -416,7 +472,10 @@ def max_blobs_per_block(cls, block_number: int = 0, timestamp: int = 0) -> int: @classmethod @abstractmethod def blob_reserve_price_active(cls, block_number: int = 0, timestamp: int = 0) -> bool: - """Return whether the fork uses a reserve price mechanism for blobs or not.""" + """ + Return whether the fork uses a reserve price mechanism for blobs or + not. + """ pass @classmethod @@ -428,7 +487,10 @@ def blob_base_cost(cls, block_number: int = 0, timestamp: int = 0) -> int: @classmethod @abstractmethod def full_blob_tx_wrapper_version(cls, block_number: int = 0, timestamp: int = 0) -> int | None: - """Return the version of the full blob transaction wrapper at a given fork.""" + """ + Return the version of the full blob transaction wrapper at a given + fork. + """ pass @classmethod @@ -455,19 +517,27 @@ def tx_types(cls, block_number: int = 0, timestamp: int = 0) -> List[int]: @classmethod @abstractmethod def contract_creating_tx_types(cls, block_number: int = 0, timestamp: int = 0) -> List[int]: - """Return list of the transaction types supported by the fork that can create contracts.""" + """ + Return list of the transaction types supported by the fork that can + create contracts. + """ pass @classmethod @abstractmethod def transaction_gas_limit_cap(cls, block_number: int = 0, timestamp: int = 0) -> int | None: - """Return the transaction gas limit cap, or None if no limit is imposed.""" + """ + Return the transaction gas limit cap, or None if no limit is imposed. + """ pass @classmethod @abstractmethod def block_rlp_size_limit(cls, block_number: int = 0, timestamp: int = 0) -> int | None: - """Return the maximum RLP size of a block in bytes, or None if no limit is imposed.""" + """ + Return the maximum RLP size of a block in bytes, or None if no limit is + imposed. + """ pass @classmethod @@ -489,8 +559,9 @@ def pre_allocation(cls) -> Mapping: """ Return required pre-allocation of accounts for any kind of test. - This method must always call the `fork_to` method when transitioning, because the - allocation can only be set at genesis, and thus cannot be changed at transition time. + This method must always call the `fork_to` method when transitioning, + because the allocation can only be set at genesis, and thus cannot be + changed at transition time. """ pass @@ -501,8 +572,9 @@ def pre_allocation_blockchain(cls) -> Mapping: """ Return required pre-allocation of accounts for any blockchain tests. - This method must always call the `fork_to` method when transitioning, because the - allocation can only be set at genesis, and thus cannot be changed at transition time. + This method must always call the `fork_to` method when transitioning, + because the allocation can only be set at genesis, and thus cannot be + changed at transition time. """ pass @@ -513,8 +585,8 @@ def engine_new_payload_version( cls, block_number: int = 0, timestamp: int = 0 ) -> Optional[int]: """ - Return `None` if this fork's payloads cannot be sent over the engine API, - or the payload version if it can. + Return `None` if this fork's payloads cannot be sent over the engine + API, or the payload version if it can. """ pass @@ -522,8 +594,8 @@ def engine_new_payload_version( @abstractmethod def engine_new_payload_blob_hashes(cls, block_number: int = 0, timestamp: int = 0) -> bool: """ - Return true if the engine api version requires new payload calls to include - blob hashes. + Return true if the engine api version requires new payload calls to + include blob hashes. """ pass @@ -531,15 +603,18 @@ def engine_new_payload_blob_hashes(cls, block_number: int = 0, timestamp: int = @abstractmethod def engine_new_payload_beacon_root(cls, block_number: int = 0, timestamp: int = 0) -> bool: """ - Return true if the engine api version requires new payload calls to include a parent - beacon block root. + Return true if the engine api version requires new payload calls to + include a parent beacon block root. """ pass @classmethod @abstractmethod def engine_new_payload_requests(cls, block_number: int = 0, timestamp: int = 0) -> bool: - """Return true if the engine api version requires new payload calls to include requests.""" + """ + Return true if the engine api version requires new payload calls to + include requests. + """ pass @classmethod @@ -548,8 +623,8 @@ def engine_new_payload_target_blobs_per_block( cls, block_number: int = 0, timestamp: int = 0 ) -> bool: """ - Return true if the engine api version requires new payload calls to include - target blobs per block. + Return true if the engine api version requires new payload calls to + include target blobs per block. """ pass @@ -559,8 +634,8 @@ def engine_execution_payload_block_access_list( cls, block_number: int = 0, timestamp: int = 0 ) -> bool: """ - Return `True` if the engine api version requires execution payload to include a - `block_access_list`. + Return `True` if the engine api version requires execution payload to + include a `block_access_list`. """ pass @@ -569,7 +644,10 @@ def engine_execution_payload_block_access_list( def engine_payload_attribute_target_blobs_per_block( cls, block_number: int = 0, timestamp: int = 0 ) -> bool: - """Return true if the payload attributes include the target blobs per block.""" + """ + Return true if the payload attributes include the target blobs per + block. + """ pass @classmethod @@ -577,7 +655,9 @@ def engine_payload_attribute_target_blobs_per_block( def engine_payload_attribute_max_blobs_per_block( cls, block_number: int = 0, timestamp: int = 0 ) -> bool: - """Return true if the payload attributes include the max blobs per block.""" + """ + Return true if the payload attributes include the max blobs per block. + """ pass @classmethod @@ -585,7 +665,10 @@ def engine_payload_attribute_max_blobs_per_block( def engine_forkchoice_updated_version( cls, block_number: int = 0, timestamp: int = 0 ) -> Optional[int]: - """Return `None` if the forks canonical chain cannot be set using the forkchoice method.""" + """ + Return `None` if the forks canonical chain cannot be set using the + forkchoice method. + """ pass @classmethod @@ -594,15 +677,18 @@ def engine_get_payload_version( cls, block_number: int = 0, timestamp: int = 0 ) -> Optional[int]: """ - Return `None` if the forks canonical chain cannot build a payload using the engine - API. + Return `None` if the forks canonical chain cannot build a payload using + the engine API. """ pass @classmethod @abstractmethod def engine_get_blobs_version(cls, block_number: int = 0, timestamp: int = 0) -> Optional[int]: - """Return `None` if the fork does not support the engine get blobs version.""" + """ + Return `None` if the fork does not support the engine get blobs + version. + """ pass # EVM information abstract methods @@ -615,7 +701,10 @@ def evm_code_types(cls, block_number: int = 0, timestamp: int = 0) -> List[EVMCo @classmethod @abstractmethod def max_code_size(cls) -> int: - """Return the maximum code size allowed to be deployed in a contract creation.""" + """ + Return the maximum code size allowed to be deployed in a contract + creation. + """ pass @classmethod @@ -627,7 +716,10 @@ def max_stack_height(cls) -> int: @classmethod @abstractmethod def max_initcode_size(cls) -> int: - """Return the maximum initcode size allowed to be used in a contract creation.""" + """ + Return the maximum initcode size allowed to be used in a contract + creation. + """ pass @classmethod @@ -635,7 +727,10 @@ def max_initcode_size(cls) -> int: def call_opcodes( cls, block_number: int = 0, timestamp: int = 0 ) -> List[Tuple[Opcodes, EVMCodeType]]: - """Return list of tuples with the call opcodes and its corresponding EVM code type.""" + """ + Return list of tuples with the call opcodes and its corresponding EVM + code type. + """ pass @classmethod @@ -651,7 +746,10 @@ def valid_opcodes( def create_opcodes( cls, block_number: int = 0, timestamp: int = 0 ) -> List[Tuple[Opcodes, EVMCodeType]]: - """Return list of tuples with the create opcodes and its corresponding EVM code type.""" + """ + Return list of tuples with the create opcodes and its corresponding EVM + code type. + """ pass @classmethod @@ -669,15 +767,18 @@ def name(cls) -> str: @classmethod def fork_at(cls, block_number: int = 0, timestamp: int = 0) -> Type["BaseFork"]: """ - Return fork at the given block number and timestamp. - Useful only for transition forks, and it's a no-op for normal forks. + Return fork at the given block number and timestamp. Useful only for + transition forks, and it's a no-op for normal forks. """ return cls @classmethod @abstractmethod def transition_tool_name(cls, block_number: int = 0, timestamp: int = 0) -> str: - """Return fork name as it's meant to be passed to the transition tool for execution.""" + """ + Return fork name as it's meant to be passed to the transition tool for + execution. + """ pass @classmethod diff --git a/src/ethereum_test_forks/forks/forks.py b/src/ethereum_test_forks/forks/forks.py index c40484a34dd..83ae639747a 100644 --- a/src/ethereum_test_forks/forks/forks.py +++ b/src/ethereum_test_forks/forks/forks.py @@ -34,7 +34,10 @@ class Frontier(BaseFork, solc_name="homestead"): @classmethod def transition_tool_name(cls, block_number: int = 0, timestamp: int = 0) -> str: - """Return fork name as it's meant to be passed to the transition tool for execution.""" + """ + Return fork name as it's meant to be passed to the transition tool for + execution. + """ if cls._transition_tool_name is not None: return cls._transition_tool_name return cls.name() @@ -78,7 +81,9 @@ def header_blob_gas_used_required(cls, block_number: int = 0, timestamp: int = 0 @classmethod def gas_costs(cls, block_number: int = 0, timestamp: int = 0) -> GasCosts: - """Return dataclass with the defined gas costs constants for genesis.""" + """ + Return dataclass with the defined gas costs constants for genesis. + """ return GasCosts( G_JUMPDEST=1, G_BASE=2, @@ -126,7 +131,10 @@ def gas_costs(cls, block_number: int = 0, timestamp: int = 0) -> GasCosts: def memory_expansion_gas_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> MemoryExpansionGasCalculator: - """Return callable that calculates the gas cost of memory expansion for the fork.""" + """ + Return callable that calculates the gas cost of memory expansion for + the fork. + """ gas_costs = cls.gas_costs(block_number, timestamp) def fn(*, new_bytes: int, previous_bytes: int = 0) -> int: @@ -147,8 +155,8 @@ def calldata_gas_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> CalldataGasCalculator: """ - Return callable that calculates the transaction gas cost for its calldata - depending on its contents. + Return callable that calculates the transaction gas cost for its + calldata depending on its contents. """ gas_costs = cls.gas_costs(block_number, timestamp) @@ -169,7 +177,9 @@ def fn(*, data: BytesConvertible, floor: bool = False) -> int: def base_fee_per_gas_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> BaseFeePerGasCalculator: - """Return a callable that calculates the base fee per gas at a given fork.""" + """ + Return a callable that calculates the base fee per gas at a given fork. + """ raise NotImplementedError(f"Base fee per gas calculator is not supported in {cls.name()}") @classmethod @@ -177,8 +187,8 @@ def base_fee_change_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> BaseFeeChangeCalculator: """ - Return a callable that calculates the gas that needs to be used to change the - base fee. + Return a callable that calculates the gas that needs to be used to + change the base fee. """ raise NotImplementedError(f"Base fee change calculator is not supported in {cls.name()}") @@ -212,7 +222,10 @@ def fn(*, data: BytesConvertible) -> int: def transaction_intrinsic_cost_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> TransactionIntrinsicCostCalculator: - """Return callable that calculates the intrinsic gas cost of a transaction for the fork.""" + """ + Return callable that calculates the intrinsic gas cost of a transaction + for the fork. + """ gas_costs = cls.gas_costs(block_number, timestamp) calldata_gas_calculator = cls.calldata_gas_calculator(block_number, timestamp) @@ -246,14 +259,19 @@ def fn( def blob_gas_price_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> BlobGasPriceCalculator: - """Return a callable that calculates the blob gas price at a given fork.""" + """ + Return a callable that calculates the blob gas price at a given fork. + """ raise NotImplementedError(f"Blob gas price calculator is not supported in {cls.name()}") @classmethod def excess_blob_gas_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> ExcessBlobGasCalculator: - """Return a callable that calculates the excess blob gas for a block at a given fork.""" + """ + Return a callable that calculates the excess blob gas for a block at a + given fork. + """ raise NotImplementedError(f"Excess blob gas calculator is not supported in {cls.name()}") @classmethod @@ -290,7 +308,10 @@ def max_blobs_per_block(cls, block_number: int = 0, timestamp: int = 0) -> int: @classmethod def blob_reserve_price_active(cls, block_number: int = 0, timestamp: int = 0) -> bool: - """Return whether the fork uses a reserve price mechanism for blobs or not.""" + """ + Return whether the fork uses a reserve price mechanism for blobs or + not. + """ raise NotImplementedError(f"Blob reserve price is not supported in {cls.name()}") @classmethod @@ -372,21 +393,28 @@ def engine_new_payload_target_blobs_per_block( def engine_payload_attribute_target_blobs_per_block( cls, block_number: int = 0, timestamp: int = 0 ) -> bool: - """At genesis, payload attributes do not include the target blobs per block.""" + """ + At genesis, payload attributes do not include the target blobs per + block. + """ return False @classmethod def engine_payload_attribute_max_blobs_per_block( cls, block_number: int = 0, timestamp: int = 0 ) -> bool: - """At genesis, payload attributes do not include the max blobs per block.""" + """ + At genesis, payload attributes do not include the max blobs per block. + """ return False @classmethod def engine_forkchoice_updated_version( cls, block_number: int = 0, timestamp: int = 0 ) -> Optional[int]: - """At genesis, forkchoice updates cannot be sent through the engine API.""" + """ + At genesis, forkchoice updates cannot be sent through the engine API. + """ return cls.engine_new_payload_version(block_number, timestamp) @classmethod @@ -446,8 +474,16 @@ def evm_code_types(cls, block_number: int = 0, timestamp: int = 0) -> List[EVMCo @classmethod def max_code_size(cls) -> int: - """At genesis, there is no upper bound for code size (bounded by block gas limit).""" - """However, the default is set to the limit of EIP-170 (Spurious Dragon)""" + """ + At genesis, there is no upper bound for code size (bounded by block gas + limit). + """ + """ + + + However, the default is set to the limit of EIP-170 (Spurious Dragon) + + """ return 0x6000 @classmethod @@ -738,17 +774,17 @@ class Byzantium(Homestead): @classmethod def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int: """ - At Byzantium, the block reward is reduced to - 3_000_000_000_000_000_000 wei. + At Byzantium, the block reward is reduced to 3_000_000_000_000_000_000 + wei. """ return 3_000_000_000_000_000_000 @classmethod def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]: """ - At Byzantium, pre-compiles for bigint modular exponentiation, addition and scalar - multiplication on elliptic curve alt_bn128, and optimal ate pairing check on - elliptic curve alt_bn128 are introduced. + At Byzantium, pre-compiles for bigint modular exponentiation, addition + and scalar multiplication on elliptic curve alt_bn128, and optimal ate + pairing check on elliptic curve alt_bn128 are introduced. """ return [ Address(5, label="MODEXP"), @@ -759,8 +795,12 @@ def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address] @classmethod def max_code_size(cls) -> int: - # NOTE: Move this to Spurious Dragon once this fork is introduced. See EIP-170. - """At Spurious Dragon, an upper bound was introduced for max contract code size.""" + # NOTE: Move this to Spurious Dragon once this fork is introduced. See + # EIP-170. + """ + At Spurious Dragon, an upper bound was introduced for max contract code + size. + """ return 0x6000 @classmethod @@ -845,8 +885,8 @@ def valid_opcodes( @classmethod def gas_costs(cls, block_number: int = 0, timestamp: int = 0) -> GasCosts: """ - On Istanbul, the non-zero transaction data byte cost is reduced to 16 due to - EIP-2028. + On Istanbul, the non-zero transaction data byte cost is reduced to 16 + due to EIP-2028. """ return replace( super(Istanbul, cls).gas_costs(block_number, timestamp), @@ -878,7 +918,10 @@ def contract_creating_tx_types(cls, block_number: int = 0, timestamp: int = 0) - def transaction_intrinsic_cost_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> TransactionIntrinsicCostCalculator: - """At Berlin, the transaction intrinsic cost needs to take the access list into account.""" + """ + At Berlin, the transaction intrinsic cost needs to take the access list + into account. + """ super_fn = super(Berlin, cls).transaction_intrinsic_cost_calculator( block_number, timestamp ) @@ -958,25 +1001,18 @@ def base_fee_per_gas_calculator( EIP-1559 block validation pseudo code: - if INITIAL_FORK_BLOCK_NUMBER == block.number: - expected_base_fee_per_gas = INITIAL_BASE_FEE - elif parent_gas_used == parent_gas_target: - expected_base_fee_per_gas = parent_base_fee_per_gas - elif parent_gas_used > parent_gas_target: - gas_used_delta = parent_gas_used - parent_gas_target - base_fee_per_gas_delta = max( - parent_base_fee_per_gas * gas_used_delta // parent_gas_target \ - // BASE_FEE_MAX_CHANGE_DENOMINATOR, - 1, - ) - expected_base_fee_per_gas = parent_base_fee_per_gas + base_fee_per_gas_delta - else: - gas_used_delta = parent_gas_target - parent_gas_used - base_fee_per_gas_delta = ( - parent_base_fee_per_gas * gas_used_delta // \ - parent_gas_target // BASE_FEE_MAX_CHANGE_DENOMINATOR - ) - expected_base_fee_per_gas = parent_base_fee_per_gas - base_fee_per_gas_delta + if INITIAL_FORK_BLOCK_NUMBER == block.number: expected_base_fee_per_gas + = INITIAL_BASE_FEE elif parent_gas_used == parent_gas_target: + expected_base_fee_per_gas = parent_base_fee_per_gas elif + parent_gas_used > parent_gas_target: gas_used_delta = parent_gas_used - + parent_gas_target base_fee_per_gas_delta = max( parent_base_fee_per_gas + * gas_used_delta // parent_gas_target // + BASE_FEE_MAX_CHANGE_DENOMINATOR, 1, ) expected_base_fee_per_gas = + parent_base_fee_per_gas + base_fee_per_gas_delta else: gas_used_delta = + parent_gas_target - parent_gas_used base_fee_per_gas_delta = ( + parent_base_fee_per_gas * gas_used_delta // parent_gas_target // + BASE_FEE_MAX_CHANGE_DENOMINATOR ) expected_base_fee_per_gas = + parent_base_fee_per_gas - base_fee_per_gas_delta """ base_fee_max_change_denominator = cls.base_fee_max_change_denominator( block_number, timestamp @@ -1016,8 +1052,8 @@ def base_fee_change_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> BaseFeeChangeCalculator: """ - Return a callable that calculates the gas that needs to be used to change the - base fee. + Return a callable that calculates the gas that needs to be used to + change the base fee. """ base_fee_max_change_denominator = cls.base_fee_max_change_denominator( block_number, timestamp @@ -1150,8 +1186,12 @@ class Cancun(Shanghai): "FIELD_ELEMENTS_PER_BLOB": 4096, "BYTES_PER_FIELD_ELEMENT": 32, "CELL_LENGTH": 2048, - "BLS_MODULUS": 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001, # EIP-2537: Main subgroup order = q, due to this BLS_MODULUS every blob byte (uint256) must be smaller than 116 # noqa: E501 - # https://github.com/ethereum/consensus-specs/blob/cc6996c22692d70e41b7a453d925172ee4b719ad/specs/deneb/polynomial-commitments.md?plain=1#L78 + # EIP-2537: Main subgroup order = q, due to this BLS_MODULUS + # every blob byte (uint256) must be smaller than 116 + "BLS_MODULUS": 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001, + # https://github.com/ethereum/consensus-specs/blob/ + # cc6996c22692d70e41b7a453d925172ee4b719ad/specs/deneb/ + # polynomial-commitments.md?plain=1#L78 "BYTES_PER_PROOF": 48, "BYTES_PER_COMMITMENT": 48, "KZG_ENDIANNESS": "big", @@ -1203,7 +1243,10 @@ def fn(*, excess_blob_gas) -> int: def excess_blob_gas_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> ExcessBlobGasCalculator: - """Return a callable that calculates the excess blob gas for a block at Cancun.""" + """ + Return a callable that calculates the excess blob gas for a block at + Cancun. + """ target_blobs_per_block = cls.target_blobs_per_block(block_number, timestamp) blob_gas_per_blob = cls.blob_gas_per_blob(block_number, timestamp) target_blob_gas_per_block = target_blobs_per_block * blob_gas_per_blob @@ -1214,7 +1257,8 @@ def fn( parent_excess_blobs: int | None = None, parent_blob_gas_used: int | None = None, parent_blob_count: int | None = None, - parent_base_fee_per_gas: int, # Required for Osaka as using this as base + parent_base_fee_per_gas: int, # Required for Osaka as using this + # as base ) -> int: del parent_base_fee_per_gas @@ -1253,12 +1297,18 @@ def supports_blobs(cls, block_number: int = 0, timestamp: int = 0) -> bool: @classmethod def target_blobs_per_block(cls, block_number: int = 0, timestamp: int = 0) -> int: - """Blobs are enabled starting from Cancun, with a static target of 3 blobs per block.""" + """ + Blobs are enabled starting from Cancun, with a static target of 3 blobs + per block. + """ return 3 @classmethod def max_blobs_per_block(cls, block_number: int = 0, timestamp: int = 0) -> int: - """Blobs are enabled starting from Cancun, with a static max of 6 blobs per block.""" + """ + Blobs are enabled starting from Cancun, with a static max of 6 blobs + per block. + """ return 6 @classmethod @@ -1268,12 +1318,18 @@ def blob_reserve_price_active(cls, block_number: int = 0, timestamp: int = 0) -> @classmethod def full_blob_tx_wrapper_version(cls, block_number: int = 0, timestamp: int = 0) -> int | None: - """Pre-Osaka forks don't use tx wrapper versions for full blob transactions.""" + """ + Pre-Osaka forks don't use tx wrapper versions for full blob + transactions. + """ return None @classmethod def max_blobs_per_tx(cls, block_number: int = 0, timestamp: int = 0) -> int: - """Blobs are enabled starting from Cancun, with a static max equal to the max per block.""" + """ + Blobs are enabled starting from Cancun, with a static max equal to the + max per block. + """ return cls.max_blobs_per_block(block_number, timestamp) @classmethod @@ -1313,8 +1369,8 @@ def system_contracts(cls, block_number: int = 0, timestamp: int = 0) -> List[Add @classmethod def pre_allocation_blockchain(cls) -> Mapping: """ - Cancun requires pre-allocation of the beacon root contract for EIP-4788 on blockchain - type tests. + Cancun requires pre-allocation of the beacon root contract for EIP-4788 + on blockchain type tests. """ new_allocation = { 0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02: { @@ -1380,12 +1436,8 @@ def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address] """ At Prague, pre-compile for BLS operations are added. - BLS12_G1ADD = 0x0B - BLS12_G1MSM = 0x0C - BLS12_G2ADD = 0x0D - BLS12_G2MSM = 0x0E - BLS12_PAIRING_CHECK = 0x0F - BLS12_MAP_FP_TO_G1 = 0x10 + BLS12_G1ADD = 0x0B BLS12_G1MSM = 0x0C BLS12_G2ADD = 0x0D BLS12_G2MSM = + 0x0E BLS12_PAIRING_CHECK = 0x0F BLS12_MAP_FP_TO_G1 = 0x10 BLS12_MAP_FP2_TO_G2 = 0x11 """ return [ @@ -1406,8 +1458,8 @@ def tx_types(cls, block_number: int = 0, timestamp: int = 0) -> List[int]: @classmethod def gas_costs(cls, block_number: int = 0, timestamp: int = 0) -> GasCosts: """ - On Prague, the standard token cost and the floor token costs are introduced due to - EIP-7623. + On Prague, the standard token cost and the floor token costs are + introduced due to EIP-7623. """ return replace( super(Prague, cls).gas_costs(block_number, timestamp), @@ -1419,7 +1471,10 @@ def gas_costs(cls, block_number: int = 0, timestamp: int = 0) -> GasCosts: @classmethod def system_contracts(cls, block_number: int = 0, timestamp: int = 0) -> List[Address]: - """Prague introduces the system contracts for EIP-6110, EIP-7002, EIP-7251 and EIP-2935.""" + """ + Prague introduces the system contracts for EIP-6110, EIP-7002, EIP-7251 + and EIP-2935. + """ return [ Address( 0x00000000219AB540356CBB839CBE05303D7705FA, @@ -1441,7 +1496,10 @@ def system_contracts(cls, block_number: int = 0, timestamp: int = 0) -> List[Add @classmethod def max_request_type(cls, block_number: int = 0, timestamp: int = 0) -> int: - """At Prague, three request types are introduced, hence the max request type is 2.""" + """ + At Prague, three request types are introduced, hence the max request + type is 2. + """ return 2 @classmethod @@ -1449,8 +1507,8 @@ def calldata_gas_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> CalldataGasCalculator: """ - Return a callable that calculates the transaction gas cost for its calldata - depending on its contents. + Return a callable that calculates the transaction gas cost for its + calldata depending on its contents. """ gas_costs = cls.gas_costs(block_number, timestamp) @@ -1471,7 +1529,10 @@ def fn(*, data: BytesConvertible, floor: bool = False) -> int: def transaction_data_floor_cost_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> TransactionDataFloorCostCalculator: - """On Prague, due to EIP-7623, the transaction data floor cost is introduced.""" + """ + On Prague, due to EIP-7623, the transaction data floor cost is + introduced. + """ calldata_gas_calculator = cls.calldata_gas_calculator(block_number, timestamp) gas_costs = cls.gas_costs(block_number, timestamp) @@ -1541,8 +1602,9 @@ def max_blobs_per_block(cls, block_number: int = 0, timestamp: int = 0) -> int: @classmethod def pre_allocation_blockchain(cls) -> Mapping: """ - Prague requires pre-allocation of the beacon chain deposit contract for EIP-6110, - the exits contract for EIP-7002, and the history storage contract for EIP-2935. + Prague requires pre-allocation of the beacon chain deposit contract for + EIP-6110, the exits contract for EIP-7002, and the history storage + contract for EIP-2935. """ new_allocation = {} @@ -1610,7 +1672,9 @@ def header_requests_required(cls, block_number: int = 0, timestamp: int = 0) -> @classmethod def engine_new_payload_requests(cls, block_number: int = 0, timestamp: int = 0) -> bool: - """From Prague, new payloads include the requests hash as a parameter.""" + """ + From Prague, new payloads include the requests hash as a parameter. + """ return True @classmethod @@ -1624,7 +1688,9 @@ def engine_new_payload_version( def engine_forkchoice_updated_version( cls, block_number: int = 0, timestamp: int = 0 ) -> Optional[int]: - """At Prague, version number of NewPayload and ForkchoiceUpdated diverge.""" + """ + At Prague, version number of NewPayload and ForkchoiceUpdated diverge. + """ return 3 @@ -1698,7 +1764,9 @@ def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address] def excess_blob_gas_calculator( cls, block_number: int = 0, timestamp: int = 0 ) -> ExcessBlobGasCalculator: - """Return a callable that calculates the excess blob gas for a block.""" + """ + Return a callable that calculates the excess blob gas for a block. + """ target_blobs_per_block = cls.target_blobs_per_block(block_number, timestamp) blob_gas_per_blob = cls.blob_gas_per_blob(block_number, timestamp) target_blob_gas_per_block = target_blobs_per_block * blob_gas_per_blob @@ -1722,7 +1790,8 @@ def fn( if parent_excess_blob_gas + parent_blob_gas_used < target_blob_gas_per_block: return 0 - # EIP-7918: Apply reserve price when execution costs dominate blob costs + # EIP-7918: Apply reserve price when execution costs dominate blob + # costs current_blob_base_fee = cls.blob_gas_price_calculator()( excess_blob_gas=parent_excess_blob_gas ) @@ -1745,7 +1814,10 @@ def fn( @classmethod def max_blobs_per_tx(cls, block_number: int = 0, timestamp: int = 0) -> int: - """Blobs in Osaka, have a static max of 6 blobs per tx. Differs from the max per block.""" + """ + Blobs in Osaka, have a static max of 6 blobs per tx. Differs from the + max per block. + """ return 6 @classmethod @@ -1836,7 +1908,10 @@ def max_blobs_per_block(cls, block_number: int = 0, timestamp: int = 0) -> int: class BPO5(BPO4, bpo_fork=True): - """BPO5 fork - Blob Parameter Only fork 5 (Required to parse Fusaka devnet genesis files).""" + """ + BPO5 fork - Blob Parameter Only fork 5 (Required to parse Fusaka devnet + genesis files). + """ pass @@ -1846,7 +1921,9 @@ class Amsterdam(Osaka): @classmethod def header_bal_hash_required(cls, block_number: int = 0, timestamp: int = 0) -> bool: - """From Amsterdam, header must contain block access list hash (EIP-7928).""" + """ + From Amsterdam, header must contain block access list hash (EIP-7928). + """ return True @classmethod @@ -1866,8 +1943,8 @@ def engine_execution_payload_block_access_list( cls, block_number: int = 0, timestamp: int = 0 ) -> bool: """ - From Amsterdam, engine execution payload includes `block_access_list` as - a parameter. + From Amsterdam, engine execution payload includes `block_access_list` + as a parameter. """ return True diff --git a/src/ethereum_test_forks/helpers.py b/src/ethereum_test_forks/helpers.py index 62796f3f530..53890b7b5a3 100644 --- a/src/ethereum_test_forks/helpers.py +++ b/src/ethereum_test_forks/helpers.py @@ -20,7 +20,10 @@ class InvalidForkError(Exception): - """Invalid fork error raised when the fork specified is not found or incompatible.""" + """ + Invalid fork error raised when the fork specified is not found or + incompatible. + """ def __init__(self, message): """Initialize the InvalidForkError exception.""" @@ -54,8 +57,8 @@ def __init__(self, message): def get_forks() -> List[Type[BaseFork]]: """ - Return list of all the fork classes implemented by - `ethereum_test_forks` ordered chronologically by deployment. + Return list of all the fork classes implemented by `ethereum_test_forks` + ordered chronologically by deployment. """ return all_forks[:] @@ -177,8 +180,8 @@ def get_selected_fork_set( transition_forks: bool = True, ) -> Set[Type[BaseFork]]: """ - Process sets derived from `--fork`, `--until` and `--from` to return an unified fork - set. + Process sets derived from `--fork`, `--until` and `--from` to return an + unified fork set. """ selected_fork_set = set() if single_fork: @@ -200,8 +203,7 @@ def transition_fork_from_to( fork_from: Type[BaseFork], fork_to: Type[BaseFork] ) -> Type[BaseFork] | None: """ - Return transition fork that transitions to and from the specified - forks. + Return transition fork that transitions to and from the specified forks. """ for transition_fork in get_transition_forks(): if not issubclass(transition_fork, TransitionBaseClass): @@ -231,8 +233,8 @@ def forks_from_until( fork_from: Type[BaseFork], fork_until: Type[BaseFork] ) -> List[Type[BaseFork]]: """ - Return specified fork and all forks after it until and including the - second specified fork. + Return specified fork and all forks after it until and including the second + specified fork. """ prev_fork = fork_until @@ -266,13 +268,13 @@ def get_relative_fork_markers( """ Return a list of marker names for a given fork. - For a base fork (e.g. `Shanghai`), return [ `Shanghai` ]. - For a transition fork (e.g. `ShanghaiToCancunAtTime15k` which transitions to `Cancun`), + For a base fork (e.g. `Shanghai`), return [ `Shanghai` ]. For a transition + fork (e.g. `ShanghaiToCancunAtTime15k` which transitions to `Cancun`), return [ `ShanghaiToCancunAtTime15k`, `Cancun` ]. - If `strict_mode` is set to `True`, raise an `InvalidForkError` if the fork is not found, - otherwise, simply return the provided (str) `fork_identifier` (this is required to run - `consume` with forks that are unknown to EEST). + If `strict_mode` is set to `True`, raise an `InvalidForkError` if the fork + is not found, otherwise, simply return the provided (str) `fork_identifier` + (this is required to run `consume` with forks that are unknown to EEST). """ all_forks = set(get_forks()) | set(get_transition_forks()) if isinstance(fork_identifier, str): @@ -302,7 +304,10 @@ def get_fork_by_name(fork_name: str) -> Type[BaseFork] | None: class ForkRangeDescriptor(BaseModel): - """Fork descriptor parsed from string normally contained in ethereum/tests fillers.""" + """ + Fork descriptor parsed from string normally contained in ethereum/tests + fillers. + """ greater_equal: Type[BaseFork] | None = None less_than: Type[BaseFork] | None = None @@ -322,10 +327,9 @@ def validate_fork_range_descriptor(cls, v: Any, handler: ValidatorFunctionWrapHa """ Validate the fork range descriptor from a string. - Examples: - - ">=Osaka" validates to {greater_equal=Osaka, less_than=None} - - ">=Prague=Osaka" validates to {greater_equal=Osaka, + less_than=None} - ">=PragueB, when filling, and given the from/until markers, - we expect the following logic: + E.g. given transition fork A->B, when filling, and given the from/until + markers, we expect the following logic: - Marker Comparison A->B Included - --------- ------------ --------------- - From A fork >= A True - Until A fork <= A False - From B fork >= B True - Until B fork <= B True + Marker Comparison A->B Included --------- ------------ --------------- + From A fork >= A True Until A fork <= A False From B fork >= + B True Until B fork <= B True """ assert BerlinToLondonAt5 >= Berlin assert not BerlinToLondonAt5 <= Berlin assert BerlinToLondonAt5 >= London assert BerlinToLondonAt5 <= London - # Comparisons between transition forks is done against the `transitions_to` fork + # Comparisons between transition forks is done against the `transitions_to` + # fork assert BerlinToLondonAt5 < ParisToShanghaiAtTime15k assert ParisToShanghaiAtTime15k > BerlinToLondonAt5 assert BerlinToLondonAt5 == BerlinToLondonAt5 @@ -353,8 +352,9 @@ class FutureFork(Osaka): """ Dummy fork used for testing. - Contains no changes to the blob parameters from the parent fork in order to confirm that - it's added to the blob schedule even if it doesn't have any changes. + Contains no changes to the blob parameters from the parent fork in order to + confirm that it's added to the blob schedule even if it doesn't have any + changes. """ pass diff --git a/src/ethereum_test_forks/transition_base_fork.py b/src/ethereum_test_forks/transition_base_fork.py index 81c3e3f6576..60b43b63a9b 100644 --- a/src/ethereum_test_forks/transition_base_fork.py +++ b/src/ethereum_test_forks/transition_base_fork.py @@ -24,7 +24,9 @@ def transitions_from(cls) -> Type[BaseFork]: def base_fork_abstract_methods() -> List[str]: - """Return list of all abstract methods that must be implemented by a fork.""" + """ + Return list of all abstract methods that must be implemented by a fork. + """ return list(BaseFork.__abstractmethods__) diff --git a/src/ethereum_test_rpc/__init__.py b/src/ethereum_test_rpc/__init__.py index 85e533d89bd..888cdf3c633 100644 --- a/src/ethereum_test_rpc/__init__.py +++ b/src/ethereum_test_rpc/__init__.py @@ -1,4 +1,6 @@ -"""JSON-RPC methods and helper functions for EEST consume based hive simulators.""" +""" +JSON-RPC methods and helper functions for EEST consume based hive simulators. +""" from .rpc import ( AdminRPC, diff --git a/src/ethereum_test_rpc/rpc.py b/src/ethereum_test_rpc/rpc.py index 1f289b628ff..a09055ba123 100644 --- a/src/ethereum_test_rpc/rpc.py +++ b/src/ethereum_test_rpc/rpc.py @@ -1,4 +1,6 @@ -"""JSON-RPC methods and helper functions for EEST consume based hive simulators.""" +""" +JSON-RPC methods and helper functions for EEST consume based hive simulators. +""" import time from itertools import count @@ -30,13 +32,18 @@ class SendTransactionExceptionError(Exception): - """Represent an exception that is raised when a transaction fails to be sent.""" + """ + Represent an exception that is raised when a transaction fails to be sent. + """ tx: Transaction | None = None tx_rlp: Bytes | None = None def __init__(self, *args, tx: Transaction | None = None, tx_rlp: Bytes | None = None): - """Initialize SendTransactionExceptionError class with the given transaction.""" + """ + Initialize SendTransactionExceptionError class with the given + transaction. + """ super().__init__(*args) self.tx = tx self.tx_rlp = tx_rlp @@ -51,7 +58,10 @@ def __str__(self): class BaseRPC: - """Represents a base RPC class for every RPC call used within EEST based hive simulators.""" + """ + Represents a base RPC class for every RPC call used within EEST based hive + simulators. + """ namespace: ClassVar[str] response_validation_context: Any | None @@ -68,7 +78,9 @@ def __init__( self.response_validation_context = response_validation_context def __init_subclass__(cls, namespace: str | None = None) -> None: - """Set namespace of the RPC class to the lowercase of the class name.""" + """ + Set namespace of the RPC class to the lowercase of the class name. + """ if namespace is None: namespace = cls.__name__ if namespace.endswith("RPC"): @@ -85,7 +97,10 @@ def post_request( request_id: int | str | None = None, timeout: int | None = None, ) -> Any: - """Send JSON-RPC POST request to the client RPC server at port defined in the url.""" + """ + Send JSON-RPC POST request to the client RPC server at port defined in + the url. + """ if extra_headers is None: extra_headers = {} if params is None: @@ -123,8 +138,8 @@ def post_request( class EthRPC(BaseRPC): """ - Represents an `eth_X` RPC class for every default ethereum RPC method used within EEST based - hive simulators. + Represents an `eth_X` RPC class for every default ethereum RPC method used + within EEST based hive simulators. """ transaction_wait_timeout: int = 60 @@ -137,12 +152,18 @@ def __init__( transaction_wait_timeout: int = 60, **kwargs, ): - """Initialize EthRPC class with the given url and transaction wait timeout.""" + """ + Initialize EthRPC class with the given url and transaction wait + timeout. + """ super().__init__(*args, **kwargs) self.transaction_wait_timeout = transaction_wait_timeout def config(self, timeout: int | None = None): - """`eth_config`: Returns information about a fork configuration of the client.""" + """ + `eth_config`: Returns information about a fork configuration of the + client. + """ try: response = self.post_request(method="config", timeout=timeout) if response is None: @@ -165,7 +186,10 @@ def chain_id(self) -> int: return int(response, 16) def get_block_by_number(self, block_number: BlockNumberType = "latest", full_txs: bool = True): - """`eth_getBlockByNumber`: Returns information about a block by block number.""" + """ + `eth_getBlockByNumber`: Returns information about a block by block + number. + """ block = hex(block_number) if isinstance(block_number, int) else block_number params = [block, full_txs] response = self.post_request(method="getBlockByNumber", params=params) @@ -180,7 +204,9 @@ def get_block_by_hash(self, block_hash: Hash, full_txs: bool = True): return response def get_balance(self, address: Address, block_number: BlockNumberType = "latest") -> int: - """`eth_getBalance`: Returns the balance of the account of given address.""" + """ + `eth_getBalance`: Returns the balance of the account of given address. + """ block = hex(block_number) if isinstance(block_number, int) else block_number params = [f"{address}", block] @@ -200,7 +226,10 @@ def get_code(self, address: Address, block_number: BlockNumberType = "latest") - def get_transaction_count( self, address: Address, block_number: BlockNumberType = "latest" ) -> int: - """`eth_getTransactionCount`: Returns the number of transactions sent from an address.""" + """ + `eth_getTransactionCount`: Returns the number of transactions sent from + an address. + """ block = hex(block_number) if isinstance(block_number, int) else block_number params = [f"{address}", block] @@ -226,7 +255,10 @@ def get_transaction_by_hash(self, transaction_hash: Hash) -> TransactionByHashRe def get_storage_at( self, address: Address, position: Hash, block_number: BlockNumberType = "latest" ) -> Hash: - """`eth_getStorageAt`: Returns the value from a storage position at a given address.""" + """ + `eth_getStorageAt`: Returns the value from a storage position at a + given address. + """ block = hex(block_number) if isinstance(block_number, int) else block_number params = [f"{address}", f"{position}", block] @@ -234,7 +266,10 @@ def get_storage_at( return Hash(response) def gas_price(self) -> int: - """`eth_gasPrice`: Returns the number of transactions sent from an address.""" + """ + `eth_gasPrice`: Returns the number of transactions sent from an + address. + """ response = self.post_request(method="gasPrice") return int(response, 16) @@ -247,7 +282,7 @@ def send_raw_transaction( response = self.post_request( method="sendRawTransaction", params=[transaction_rlp.hex()], - request_id=request_id, # noqa: E501 + request_id=request_id, ) result_hash = Hash(response) @@ -263,7 +298,7 @@ def send_transaction(self, transaction: Transaction) -> Hash: response = self.post_request( method="sendRawTransaction", params=[transaction.rlp().hex()], - request_id=transaction.metadata_string(), # noqa: E501 + request_id=transaction.metadata_string(), ) result_hash = Hash(response) @@ -274,15 +309,18 @@ def send_transaction(self, transaction: Transaction) -> Hash: raise SendTransactionExceptionError(str(e), tx=transaction) from e def send_transactions(self, transactions: List[Transaction]) -> List[Hash]: - """Use `eth_sendRawTransaction` to send a list of transactions to the client.""" + """ + Use `eth_sendRawTransaction` to send a list of transactions to the + client. + """ return [self.send_transaction(tx) for tx in transactions] def storage_at_keys( self, account: Address, keys: List[Hash], block_number: BlockNumberType = "latest" ) -> Dict[Hash, Hash]: """ - Retrieve the storage values for the specified keys at a given address and block - number. + Retrieve the storage values for the specified keys at a given address + and block number. """ results: Dict[Hash, Hash] = {} for key in keys: @@ -291,7 +329,10 @@ def storage_at_keys( return results def wait_for_transaction(self, transaction: Transaction) -> TransactionByHashResponse: - """Use `eth_getTransactionByHash` to wait until a transaction is included in a block.""" + """ + Use `eth_getTransactionByHash` to wait until a transaction is included + in a block. + """ tx_hash = transaction.hash start_time = time.time() while True: @@ -310,8 +351,8 @@ def wait_for_transactions( self, transactions: List[Transaction] ) -> List[TransactionByHashResponse]: """ - Use `eth_getTransactionByHash` to wait until all transactions in list are included in a - block. + Use `eth_getTransactionByHash` to wait until all transactions in list + are included in a block. """ tx_hashes = [tx.hash for tx in transactions] responses: List[TransactionByHashResponse] = [] @@ -345,15 +386,18 @@ def send_wait_transaction(self, transaction: Transaction): return self.wait_for_transaction(transaction) def send_wait_transactions(self, transactions: List[Transaction]): - """Send list of transactions and waits until all of them are included in a block.""" + """ + Send list of transactions and waits until all of them are included in a + block. + """ self.send_transactions(transactions) return self.wait_for_transactions(transactions) class DebugRPC(EthRPC): """ - Represents an `debug_X` RPC class for every default ethereum RPC method used within EEST based - hive simulators. + Represents an `debug_X` RPC class for every default ethereum RPC method + used within EEST based hive simulators. """ def trace_call(self, tr: dict[str, str], block_number: str): @@ -364,8 +408,8 @@ def trace_call(self, tr: dict[str, str], block_number: str): class EngineRPC(BaseRPC): """ - Represents an Engine API RPC class for every Engine API method used within EEST based hive - simulators. + Represents an Engine API RPC class for every Engine API method used within + EEST based hive simulators. """ jwt_secret: bytes @@ -389,7 +433,10 @@ def post_request( request_id: int | str | None = None, timeout: int | None = None, ) -> Any: - """Send JSON-RPC POST request to the client RPC server at port defined in the url.""" + """ + Send JSON-RPC POST request to the client RPC server at port defined in + the url. + """ if extra_headers is None: extra_headers = {} jwt_token = encode( @@ -410,7 +457,10 @@ def post_request( ) def new_payload(self, *params: Any, version: int) -> PayloadStatus: - """`engine_newPayloadVX`: Attempts to execute the given payload on an execution client.""" + """ + `engine_newPayloadVX`: Attempts to execute the given payload on an + execution client. + """ method = f"newPayloadV{version}" params_list = [to_json(param) for param in params] @@ -426,7 +476,10 @@ def forkchoice_updated( *, version: int, ) -> ForkchoiceUpdateResponse: - """`engine_forkchoiceUpdatedVX`: Updates the forkchoice state of the execution client.""" + """ + `engine_forkchoiceUpdatedVX`: Updates the forkchoice state of the + execution client. + """ method = f"forkchoiceUpdatedV{version}" if payload_attributes is None: @@ -468,7 +521,9 @@ def get_blobs( *, version: int, ) -> GetBlobsResponse | None: - """`engine_getBlobsVX`: Retrieves blobs from an execution layers tx pool.""" + """ + `engine_getBlobsVX`: Retrieves blobs from an execution layers tx pool. + """ method = f"getBlobsV{version}" params = [f"{h}" for h in versioned_hashes] diff --git a/src/ethereum_test_rpc/rpc_types.py b/src/ethereum_test_rpc/rpc_types.py index 8d874d07fb6..d904d441cc6 100644 --- a/src/ethereum_test_rpc/rpc_types.py +++ b/src/ethereum_test_rpc/rpc_types.py @@ -55,7 +55,8 @@ class TransactionByHashResponse(Transaction): transaction_hash: Hash = Field(..., alias="hash") sender: EOA | None = Field(None, alias="from") - # The to field can have different names in different clients, so we use AliasChoices. + # The to field can have different names in different clients, so we use + # AliasChoices. to: Address | None = Field(..., validation_alias=AliasChoices("to_address", "to", "toAddress")) v: HexNumber = Field(0, validation_alias=AliasChoices("v", "yParity")) # type: ignore @@ -64,8 +65,8 @@ class TransactionByHashResponse(Transaction): @classmethod def adapt_clients_response(cls, data: Any) -> Any: """ - Perform modifications necessary to adapt the response returned by clients - so it can be parsed by our model. + Perform modifications necessary to adapt the response returned by + clients so it can be parsed by our model. """ if isinstance(data, dict): if "gasPrice" in data and "maxFeePerGas" in data: @@ -75,8 +76,8 @@ def adapt_clients_response(cls, data: Any) -> Any: def model_post_init(self, __context): """ - Check that the transaction hash returned by the client matches the one calculated by - us. + Check that the transaction hash returned by the client matches the one + calculated by us. """ Transaction.model_post_init(self, __context) assert self.transaction_hash == self.hash diff --git a/src/ethereum_test_rpc/tests/test_types.py b/src/ethereum_test_rpc/tests/test_types.py index c0a6892e9af..0a42a078b35 100644 --- a/src/ethereum_test_rpc/tests/test_types.py +++ b/src/ethereum_test_rpc/tests/test_types.py @@ -99,7 +99,9 @@ @pytest.fixture def eth_config_response() -> EthConfigResponse: - """Get the `eth_config` response from the client to be verified by all tests.""" + """ + Get the `eth_config` response from the client to be verified by all tests. + """ return EthConfigResponse.model_validate(eth_config_dict) diff --git a/src/ethereum_test_specs/base.py b/src/ethereum_test_specs/base.py index a82c0d94568..3fee6ba4bc1 100644 --- a/src/ethereum_test_specs/base.py +++ b/src/ethereum_test_specs/base.py @@ -1,4 +1,6 @@ -"""Base test class and helper functions for Ethereum state and blockchain tests.""" +""" +Base test class and helper functions for Ethereum state and blockchain tests. +""" import hashlib from abc import abstractmethod @@ -43,8 +45,8 @@ def __str__(self): def verify_result(result: Result, env: Environment): """ - Verify that values in the t8n result match the expected values. - Raises exception on unexpected values. + Verify that values in the t8n result match the expected values. Raises + exception on unexpected values. """ if env.withdrawals is not None: assert result.withdrawals_root == to_hex(Withdrawal.list_root(env.withdrawals)) @@ -61,7 +63,9 @@ class OpMode(StrEnum): class BaseTest(BaseModel): - """Represents a base Ethereum test which must return a single test fixture.""" + """ + Represents a base Ethereum test which must return a single test fixture. + """ model_config = ConfigDict(extra="forbid") @@ -93,7 +97,10 @@ def discard_fixture_format_by_marks( fork: Fork, markers: List[pytest.Mark], ) -> bool: - """Discard a fixture format from filling if the appropriate marker is used.""" + """ + Discard a fixture format from filling if the appropriate marker is + used. + """ return False @classmethod @@ -132,7 +139,10 @@ def discard_execute_format_by_marks( fork: Fork, markers: List[pytest.Mark], ) -> bool: - """Discard an execute format from executing if the appropriate marker is used.""" + """ + Discard an execute format from executing if the appropriate marker is + used. + """ return False @abstractmethod @@ -189,10 +199,11 @@ def is_tx_gas_heavy_test(self) -> bool: def is_exception_test(self) -> bool | None: """ - Check if the test is an exception test (invalid block, invalid transaction). + Check if the test is an exception test (invalid block, invalid + transaction). - `None` is returned if it's not possible to determine if the test is negative or not. - This is the case when the test is not run in pytest. + `None` is returned if it's not possible to determine if the test is + negative or not. This is the case when the test is not run in pytest. """ if self._request is not None and hasattr(self._request, "node"): return self._request.node.get_closest_marker("exception_test") is not None @@ -231,7 +242,8 @@ def get_genesis_environment(self, fork: Fork) -> Environment: """ Get the genesis environment for pre-allocation groups. - Must be implemented by subclasses to provide the appropriate environment. + Must be implemented by subclasses to provide the appropriate + environment. """ raise NotImplementedError( f"{self.__class__.__name__} must implement genesis environment access for use with " @@ -241,7 +253,10 @@ def get_genesis_environment(self, fork: Fork) -> Environment: def update_pre_alloc_groups( self, pre_alloc_groups: PreAllocGroups, fork: Fork, test_id: str ) -> PreAllocGroups: - """Create or update the pre-allocation group with the pre from the current spec.""" + """ + Create or update the pre-allocation group with the pre from the current + spec. + """ if not hasattr(self, "pre"): raise AttributeError( f"{self.__class__.__name__} does not have a 'pre' field. Pre-allocation groups " @@ -261,7 +276,8 @@ def update_pre_alloc_groups( group.test_ids.append(str(test_id)) pre_alloc_groups[pre_alloc_hash] = group else: - # Create new group - use Environment instead of expensive genesis generation + # Create new group - use Environment instead of expensive genesis + # generation genesis_env = self.get_genesis_environment(fork) pre_alloc = Alloc.merge( Alloc.model_validate(fork.pre_allocation_blockchain()), diff --git a/src/ethereum_test_specs/base_static.py b/src/ethereum_test_specs/base_static.py index cdd60d6164a..c4c6323d84d 100644 --- a/src/ethereum_test_specs/base_static.py +++ b/src/ethereum_test_specs/base_static.py @@ -25,8 +25,8 @@ class BaseStaticTest(BaseModel): @classmethod def __pydantic_init_subclass__(cls, **kwargs): """ - Register all subclasses of BaseStaticTest with a static test format name set - as possible static test format. + Register all subclasses of BaseStaticTest with a static test format + name set as possible static test format. """ if cls.format_name: # Register the new fixture format @@ -50,72 +50,45 @@ def _parse_into_subclass( @abstractmethod def fill_function(self) -> Callable: - """ + ''' Return the test function that can be used to fill the test. This method should be implemented by the subclasses. - The function returned can be optionally decorated with the `@pytest.mark.parametrize` - decorator to parametrize the test with the number of sub test cases. + The function returned can be optionally decorated with the + `@pytest.mark.parametrize` decorator to parametrize the test with the + number of sub test cases. - Example: - ``` - @pytest.mark.parametrize("n", [1]) + Example: ``` @pytest.mark.parametrize("n", [1]) @pytest.mark.parametrize("m", [1, 2]) - @pytest.mark.valid_from("Homestead") - def test_state_filler( - state_test: StateTestFiller, - fork: Fork, - pre: Alloc, - n: int, - m: int, - ): - \"\"\"Generate a test from a static state filler.\"\"\" - assert n == 1 - assert m in [1, 2] - env = Environment(**self.env.model_dump()) - sender = pre.fund_eoa() - tx = Transaction( - ty=0x0, - nonce=0, - to=Address(0x1000), - gas_limit=500000, - protected=False if fork in [Frontier, Homestead] else True, - data="", - sender=sender, - ) - state_test(env=env, pre=pre, post={}, tx=tx) - - return test_state_filler - ``` - - To aid the generation of the test, the function can be defined and then the decorator be - applied after defining the function: - - ``` - def test_state_filler( - state_test: StateTestFiller, - fork: Fork, - pre: Alloc, - n: int, - m: int, - ): - ... - test_state_filler = pytest.mark.parametrize("n", [1])(test_state_filler) - test_state_filler = pytest.mark.parametrize("m", [1, 2])(test_state_filler) - if self.valid_from: - test_state_filler = pytest.mark.valid_from(self.valid_from)(test_state_filler) - if self.valid_until: - test_state_filler = pytest.mark.valid_until(self.valid_until)(test_state_filler) - return test_state_filler - ``` - - The function can contain the following parameters on top of the spec type parameter - (`state_test` in the example above): - - `fork`: The fork for which the test is currently being filled. - - `pre`: The pre-state of the test. - - """ + @pytest.mark.valid_from("Homestead") def test_state_filler( state_test: + StateTestFiller, fork: Fork, pre: Alloc, n: int, m: int, ): """Generate + a test from a static state filler.""" assert n == 1 assert m in [1, 2] + env = Environment(**self.env.model_dump()) sender = pre.fund_eoa() tx = + Transaction( ty=0x0, nonce=0, to=Address(0x1000), gas_limit=500000, + protected=False if fork in [Frontier, Homestead] else True, data="", + sender=sender, ) state_test(env=env, pre=pre, post={}, tx=tx) + + return test_state_filler ``` + + To aid the generation of the test, the function can be defined and then + the decorator be applied after defining the function: + + ``` def test_state_filler( state_test: StateTestFiller, fork: Fork, + pre: Alloc, n: int, m: int, ): ... test_state_filler = + pytest.mark.parametrize("n", [1])(test_state_filler) test_state_filler + = pytest.mark.parametrize("m", [1, 2])(test_state_filler) if + self.valid_from: test_state_filler = + pytest.mark.valid_from(self.valid_from)(test_state_filler) if + self.valid_until: test_state_filler = + pytest.mark.valid_until(self.valid_until)(test_state_filler) return + test_state_filler ``` + + The function can contain the following parameters on top of the spec + type parameter (`state_test` in the example above): - `fork`: The fork + for which the test is currently being filled. - `pre`: The pre-state of + the test. + ''' raise NotImplementedError @staticmethod @@ -143,8 +116,8 @@ def remove_comments_from_model(cls, data: Any) -> Any: def remove_comments(v: str) -> str: """ - Split by line and then remove the comments (starting with #) at the end of each line if - any. + Split by line and then remove the comments (starting with #) at the end of + each line if any. """ return "\n".join([line.split("#")[0].strip() for line in v.splitlines()]) diff --git a/src/ethereum_test_specs/blockchain.py b/src/ethereum_test_specs/blockchain.py index 796a34ce4df..29f662f6a60 100644 --- a/src/ethereum_test_specs/blockchain.py +++ b/src/ethereum_test_specs/blockchain.py @@ -126,31 +126,44 @@ class Header(CamelModel): REMOVE_FIELD: ClassVar[Removable] = Removable() """ + + + + + + Sentinel object used to specify that a header field should be removed. + + + """ EMPTY_FIELD: ClassVar[Removable] = Removable() """ - Sentinel object used to specify that a header field must be empty during verification. - This can be used in a test to explicitly skip a field in a block's RLP encoding. - included in the (json) output when the model is serialized. For example: - ``` - header_modifier = Header( - excess_blob_gas=Header.REMOVE_FIELD, - ) - block = Block( - timestamp=TIMESTAMP, - rlp_modifier=header_modifier, - exception=BlockException.INCORRECT_BLOCK_FORMAT, - engine_api_error_code=EngineAPIError.InvalidParams, - ) - ``` + + + + + + Sentinel object used to specify that a header field must be empty during + verification. + + This can be used in a test to explicitly skip a field in a block's RLP + encoding. included in the (json) output when the model is serialized. For + example: ``` header_modifier = Header( excess_blob_gas=Header.REMOVE_FIELD, + ) block = Block( timestamp=TIMESTAMP, rlp_modifier=header_modifier, + exception=BlockException.INCORRECT_BLOCK_FORMAT, + engine_api_error_code=EngineAPIError.InvalidParams, ) ``` + + + """ model_config = ConfigDict( arbitrary_types_allowed=True, - # explicitly set Removable items to None so they are not included in the serialization - # (in combination with exclude_None=True in model.dump()). + # explicitly set Removable items to None so they are not included in + # the serialization (in combination with exclude_None=True in + # model.dump()). json_encoders={ Removable: lambda x: None, }, @@ -165,7 +178,9 @@ def validate_withdrawals_root(cls, value): return value def apply(self, target: FixtureHeader) -> FixtureHeader: - """Produce a fixture header copy with the set values from the modifier.""" + """ + Produce a fixture header copy with the set values from the modifier. + """ return target.copy( **{ k: (v if v is not Header.REMOVE_FIELD else None) @@ -201,55 +216,88 @@ class Block(Header): header_verify: Header | None = None """ + + + + + + If set, the block header will be verified against the specified values. + + + """ rlp_modifier: Header | None = None """ + + + + + + An RLP modifying header which values would be used to override the ones returned by the `ethereum_clis.TransitionTool`. + + + """ expected_block_access_list: BlockAccessListExpectation | None = None """ - If set, the block access list will be verified and potentially corrupted for invalid tests. + + + + + + + If set, the block access list will be verified and potentially corrupted + for invalid tests. + + + """ exception: BLOCK_EXCEPTION_TYPE = None - """ - If set, the block is expected to be rejected by the client. - """ + """If set, the block is expected to be rejected by the client.""" skip_exception_verification: bool = False """ - Skip verifying that the exception is returned by the transition tool. - This could be because the exception is inserted in the block after the transition tool - evaluates it. + + + + + + + Skip verifying that the exception is returned by the transition tool. This + could be because the exception is inserted in the block after the + transition tool evaluates it. + + + """ engine_api_error_code: EngineAPIError | None = None """ - If set, the block is expected to produce an error response from the Engine API. + + + + + + + If set, the block is expected to produce an error response from the Engine + API. + + + """ txs: List[Transaction] = Field(default_factory=list) - """ - List of transactions included in the block. - """ + """List of transactions included in the block.""" ommers: List[Header] | None = None - """ - List of ommer headers included in the block. - """ + """List of ommer headers included in the block.""" withdrawals: List[Withdrawal] | None = None - """ - List of withdrawals to perform for this block. - """ + """List of withdrawals to perform for this block.""" requests: List[Bytes] | None = None - """ - Custom list of requests to embed in this block. - """ + """Custom list of requests to embed in this block.""" expected_post_state: Alloc | None = None - """ - Post state for verification after block execution in BlockchainTest - """ + """Post state for verification after block execution in BlockchainTest""" block_access_list: Bytes | None = Field(None) - """ - EIP-7928: Block-level access lists (serialized). - """ + """EIP-7928: Block-level access lists (serialized).""" def set_environment(self, env: Environment) -> Environment: """ @@ -259,8 +307,17 @@ def set_environment(self, env: Environment) -> Environment: new_env_values: Dict[str, Any] = {} """ - Values that need to be set in the environment and are `None` for - this block need to be set to their defaults. + + + + + + + Values that need to be set in the environment and are `None` for this + block need to be set to their defaults. + + + """ new_env_values["difficulty"] = self.difficulty new_env_values["prev_randao"] = self.prev_randao @@ -288,8 +345,17 @@ def set_environment(self, env: Environment) -> Environment: ): new_env_values["block_access_list"] = self.block_access_list """ + + + + + + These values are required, but they depend on the previous environment, so they can be calculated here. + + + """ if self.number is not None: new_env_values["number"] = self.number @@ -310,10 +376,7 @@ def set_environment(self, env: Environment) -> Environment: class BuiltBlock(CamelModel): - """ - Model that contains all properties to build a full block or - payload. - """ + """Model that contains all properties to build a full block or payload.""" header: FixtureHeader env: Environment @@ -414,7 +477,14 @@ def verify_block_exception(self, transition_tool_exceptions_reliable: bool): "prev_randao": 0, } """ -Default values for the genesis environment that are used to create all genesis headers. + + + + + + +Default values for the genesis environment that are used to create all genesis +headers. """ @@ -428,8 +498,17 @@ class BlockchainTest(BaseTest): chain_id: int = 1 exclude_full_post_state_in_output: bool = False """ - Exclude the post state from the fixture output. - In this case, the state verification is only performed based on the state root. + + + + + + + Exclude the post state from the fixture output. In this case, the state + verification is only performed based on the state root. + + + """ supported_fixture_formats: ClassVar[Sequence[FixtureFormat | LabeledFixtureFormat]] = [ @@ -458,7 +537,10 @@ def discard_fixture_format_by_marks( fork: Fork, markers: List[pytest.Mark], ) -> bool: - """Discard a fixture format from filling if the appropriate marker is used.""" + """ + Discard a fixture format from filling if the appropriate marker is + used. + """ marker_names = [m.name for m in markers] if fixture_format != BlockchainFixture and "blockchain_test_only" in marker_names: return True @@ -516,7 +598,9 @@ def generate_block_data( previous_alloc: Alloc, last_block: bool, ) -> BuiltBlock: - """Generate common block data for both make_fixture and make_hive_fixture.""" + """ + Generate common block data for both make_fixture and make_hive_fixture. + """ env = block.set_environment(previous_env) env = env.set_fork_requirements(fork) txs = [tx.with_signature_and_sender() for tx in block.txs] @@ -546,10 +630,11 @@ def generate_block_data( slow_request=self.is_tx_gas_heavy_test(), ) - # One special case of the invalid transactions is the blob gas used, since this value - # is not included in the transition tool result, but it is included in the block header, - # and some clients check it before executing the block by simply counting the type-3 txs, - # we need to set the correct value by default. + # One special case of the invalid transactions is the blob gas used, + # since this value is not included in the transition tool result, but + # it is included in the block header, and some clients check it before + # executing the block by simply counting the type-3 txs, we need to set + # the correct value by default. blob_gas_used: int | None = None if (blob_gas_per_blob := fork.blob_gas_per_blob(env.number, env.timestamp)) > 0: blob_gas_used = blob_gas_per_blob * count_blobs(txs) @@ -628,7 +713,8 @@ def generate_block_data( header = block.rlp_modifier.apply(header) header.fork = fork # Deleted during `apply` because `exclude=True` - # Process block access list - apply transformer if present for invalid tests + # Process block access list - apply transformer if present for invalid + # tests t8n_bal = transition_tool_output.result.block_access_list bal = t8n_bal if block.expected_block_access_list is not None and t8n_bal is not None: @@ -668,15 +754,14 @@ def generate_block_data( and block.expected_block_access_list._modifier is not None ) ): - # Only verify block level exception if: - # - No transaction exception was raised, because these are not - # reported as block exceptions. - # - No RLP modifier was specified, because the modifier is what - # normally produces the block exception. - # - No requests were specified, because modified requests are also - # what normally produces the block exception. - # - No BAL modifier was specified, because modified BAL also - # produces block exceptions. + # Only verify block level exception if: - No transaction + # exception was raised, because these are not reported as block + # exceptions. - No RLP modifier was specified, because the + # modifier is what normally produces the block exception. - No + # requests were specified, because modified requests are also + # what normally produces the block exception. - No BAL modifier + # was specified, because modified BAL also produces block + # exceptions. built_block.verify_block_exception( transition_tool_exceptions_reliable=t8n.exception_mapper.reliable, ) @@ -739,7 +824,8 @@ def make_fixture( ) fixture_blocks.append(built_block.get_fixture_block()) - # BAL verification already done in to_fixture_bal() if expected_block_access_list set + # BAL verification already done in to_fixture_bal() if + # expected_block_access_list set if block.exception is None: # Update env, alloc and last block hash for the next block. @@ -838,8 +924,8 @@ def make_hive_fixture( # Add format-specific fields if fixture_format == BlockchainEngineXFixture: - # For Engine X format, exclude pre (will be provided via shared state) - # and prepare for state diff optimization + # For Engine X format, exclude pre (will be provided via shared + # state) and prepare for state diff optimization fixture_data.update( { "post_state": alloc if not self.exclude_full_post_state_in_output else None, @@ -852,9 +938,9 @@ def make_hive_fixture( assert genesis.header.block_hash != head_hash, ( "Invalid payload tests negative test via sync is not supported yet." ) - # Most clients require the header to start the sync process, so we create an empty - # block on top of the last block of the test to send it as new payload and trigger the - # sync process. + # Most clients require the header to start the sync process, so we + # create an empty block on top of the last block of the test to + # send it as new payload and trigger the sync process. sync_built_block = self.generate_block_data( t8n=t8n, fork=fork, diff --git a/src/ethereum_test_specs/eof.py b/src/ethereum_test_specs/eof.py index 35f58984897..44d3cd29f75 100644 --- a/src/ethereum_test_specs/eof.py +++ b/src/ethereum_test_specs/eof.py @@ -53,7 +53,9 @@ def __init__(self, message): @staticmethod def format_code(code: Bytes, max_length=60) -> str: - """Avoid printing long bytecode strings in the terminal upon test failure.""" + """ + Avoid printing long bytecode strings in the terminal upon test failure. + """ if len(code) > max_length: half_length = max_length // 2 - 5 # Floor; adjust for ellipsis return f"{code[:half_length].hex()}...{code[-half_length:].hex()}" @@ -84,7 +86,10 @@ class ExpectedEOFExceptionError(EOFBaseExceptionError): """ def __init__(self, *, code: Bytes, expected: str): - """Initialize the exception with the code and the expected exception message.""" + """ + Initialize the exception with the code and the expected exception + message. + """ message = ( "Expected EOF code to be invalid, but no exception was raised:\n" f" Code: {self.format_code(code)}\n" @@ -95,10 +100,15 @@ def __init__(self, *, code: Bytes, expected: str): class EOFExceptionMismatchError(EOFBaseExceptionError): - """Exception used when the actual EOF exception differs from the expected one.""" + """ + Exception used when the actual EOF exception differs from the expected one. + """ def __init__(self, code: Bytes, expected: str, got: str): - """Initialize the exception with the code, the expected/actual exception message.""" + """ + Initialize the exception with the code, the expected/actual exception + message. + """ message = ( "EOF code raised a different exception than expected:\n" f" Code: {self.format_code(code)}\n" @@ -166,88 +176,155 @@ class EOFTest(BaseTest): """ Filler type that generates a test for EOF container validation. - A state test is also automatically generated where the container is wrapped in a - contract-creating transaction to test deployment/validation on the instantiated blockchain. + A state test is also automatically generated where the container is wrapped + in a contract-creating transaction to test deployment/validation on the + instantiated blockchain. """ container: Container """ + + + + + + EOF container that will be tested for validity. - The only supported type at the moment is `ethereum_test_types.eof.v1.Container`. + The only supported type at the moment is + `ethereum_test_types.eof.v1.Container`. + + If an invalid container needs to be tested, and it cannot be generated + using the Container class features, the `raw_bytes` field can be used to + provide the raw container bytes. + + - If an invalid container needs to be tested, and it cannot be generated using the - Container class features, the `raw_bytes` field can be used to provide the raw - container bytes. """ expect_exception: EOFExceptionInstanceOrList | None = None """ - Expected exception that the container should raise when parsed by an EOF parser. - Can be a single exception or a list of exceptions that the container is expected to raise, - in which case the test will pass if any of the exceptions are raised. - The list of supported exceptions can be found in the `ethereum_test_exceptions.EOFException` - class. + + + + + Expected exception that the container should raise when parsed by an EOF + parser. + + Can be a single exception or a list of exceptions that the container is + expected to raise, in which case the test will pass if any of the + exceptions are raised. + + The list of supported exceptions can be found in the + `ethereum_test_exceptions.EOFException` class. + + + """ container_kind: ContainerKind = ContainerKind.RUNTIME """ + + + + + + Container kind type that the container should be treated as. - The container kind can be one of the following: - - `ContainerKind.INITCODE`: The container is an initcode container. - - `ContainerKind.RUNTIME`: The container is a runtime container. + The container kind can be one of the following: - `ContainerKind.INITCODE`: + The container is an initcode container. - `ContainerKind.RUNTIME`: The + container is a runtime container. The default value is `ContainerKind.RUNTIME`. + + + """ deployed_container: Container | None = None """ - To be used when the container is an initcode container and the expected deployed container is - known. - - The value is only used when a State Test is generated from this EOF test to set the expected - deployed container that should be found in the post state. - - If this field is not set, and the container is valid: - - If the container kind is `ContainerKind.RUNTIME`, the deployed container is assumed to be - the container itself, and an initcode container that wraps the container is generated - automatically. - - If the container kind is `ContainerKind.INITCODE`, `model_post_init` will attempt to infer - the deployed container from the sections of the init-container, and the first - container-type section will be used. An error will be raised if the deployed container - cannot be inferred. - - If the value is set to `None`, it is assumed that the container is invalid and the test will - expect that no contract is created. - - It is considered an error if: - - The `deployed_container` field is set and the `container_kind` field is not set to - `ContainerKind.INITCODE`. - - The `deployed_container` field is set and the `expect_exception` is not `None`. - - The deployed container is **not** executed at any point during the EOF validation test nor - the generated State Test. For container runtime testing use the `EOFStateTest` class. + + + + + + + To be used when the container is an initcode container and the expected + deployed container is known. + + The value is only used when a State Test is generated from this EOF test to + set the expected deployed container that should be found in the post state. + + If this field is not set, and the container is valid: - If the container + kind is `ContainerKind.RUNTIME`, the deployed container is assumed to be + the container itself, and an initcode container that wraps the container is + generated automatically. - If the container kind is + `ContainerKind.INITCODE`, `model_post_init` will attempt to infer the + deployed container from the sections of the init-container, and the first + container-type section will be used. An error will be raised if the + deployed container cannot be inferred. + + If the value is set to `None`, it is assumed that the container is invalid + and the test will expect that no contract is created. + + It is considered an error if: - The `deployed_container` field is set and + the `container_kind` field is not set to `ContainerKind.INITCODE`. - The + `deployed_container` field is set and the `expect_exception` is not `None`. + + The deployed container is **not** executed at any point during the EOF + validation test nor the generated State Test. For container runtime testing + use the `EOFStateTest` class. + + + """ pre: Alloc | None = None """ + + + + + + Pre alloc object that is used during State Test generation. - This field is automatically set by the test filler when generating a State Test from this EOF - test and should otherwise be left unset. + This field is automatically set by the test filler when generating a State + Test from this EOF test and should otherwise be left unset. + + + """ post: Alloc | None = None """ + + + + + + Post alloc object that is used during State Test generation. - This field is automatically set by the test filler when generating a State Test from this EOF - test and is normally not set by the user. + This field is automatically set by the test filler when generating a State + Test from this EOF test and is normally not set by the user. + + + """ sender: EOA | None = None """ + + + + + + Sender EOA object that is used during State Test generation. - This field is automatically set by the `model_post_init` method and should otherwise be left - unset. + This field is automatically set by the `model_post_init` method and should + otherwise be left unset. + + + """ supported_fixture_formats: ClassVar[Sequence[FixtureFormat | LabeledFixtureFormat]] = [ @@ -281,7 +358,10 @@ def discard_fixture_format_by_marks( fork: Fork, markers: List[pytest.Mark], ) -> bool: - """Discard a fixture format from filling if the appropriate marker is used.""" + """ + Discard a fixture format from filling if the appropriate marker is + used. + """ if "eof_test_only" in [m.name for m in markers]: return fixture_format != EOFFixture return False @@ -369,7 +449,9 @@ def make_eof_test_fixture( return fixture def verify_result(self, result: CompletedProcess, expected_result: Result, code: Bytes): - """Check that the reported exception string matches the expected error.""" + """ + Check that the reported exception string matches the expected error. + """ evmone_exception_mapper = EvmoneExceptionMapper() actual_exception_str = result.stdout.strip() actual_exception: EOFExceptionWithMessage | UndefinedException | None = None @@ -409,12 +491,13 @@ def generate_eof_contract_create_transaction(self) -> Transaction: if self.container_kind == ContainerKind.INITCODE: initcode = self.container if "deployed_container" in self.model_fields_set: - # In the case of an initcontainer where we know the deployed container, - # we can use the initcontainer as-is. + # In the case of an initcontainer where we know the deployed + # container, we can use the initcontainer as-is. deployed_container = self.deployed_container elif self.expect_exception is None: - # We have a valid init-container, but we don't know the deployed container. - # Try to infer the deployed container from the sections of the init-container. + # We have a valid init-container, but we don't know the + # deployed container. Try to infer the deployed container from + # the sections of the init-container. assert self.container.raw_bytes is None, ( "deployed_container must be set for initcode containers with raw_bytes." ) @@ -505,34 +588,28 @@ def execute( class EOFStateTest(EOFTest, Transaction): """ - Filler type that generates an EOF test for container validation, and also tests the container - during runtime using a state test (and blockchain test). + Filler type that generates an EOF test for container validation, and also + tests the container during runtime using a state test (and blockchain + test). - In the state or blockchain test, the container is first deployed to the pre-allocation and - then a transaction is sent to the deployed container. + In the state or blockchain test, the container is first deployed to the + pre-allocation and then a transaction is sent to the deployed container. - Container deployment/validation is **not** tested like in the `EOFTest` unless the container - under test is an initcode container. + Container deployment/validation is **not** tested like in the `EOFTest` + unless the container under test is an initcode container. - All fields from `ethereum_test_types.Transaction` are available for use in the test. + All fields from `ethereum_test_types.Transaction` are available for use in + the test. """ gas_limit: HexNumber = Field(HexNumber(10_000_000), serialization_alias="gas") - """ - Gas limit for the transaction that deploys the container. - """ + """Gas limit for the transaction that deploys the container.""" tx_sender_funding_amount: int = 1_000_000_000_000_000_000_000 - """ - Amount of funds to send to the sender EOA before the transaction. - """ + """Amount of funds to send to the sender EOA before the transaction.""" env: Environment = Field(default_factory=Environment) - """ - Environment object that is used during State Test generation. - """ + """Environment object that is used during State Test generation.""" container_post: Account = Field(default_factory=Account) - """ - Account object used to verify the container post state. - """ + """Account object used to verify the container post state.""" supported_fixture_formats: ClassVar[Sequence[FixtureFormat | LabeledFixtureFormat]] = [ EOFFixture @@ -580,7 +657,8 @@ def model_post_init(self, __context): # Run transaction model validation Transaction.model_post_init(self, __context) - self.post[compute_eofcreate_address(self.to, 0)] = None # Expect failure. + self.post[compute_eofcreate_address(self.to, 0)] = None # Expect + # failure. elif self.expect_exception is not None and self.container_kind == ContainerKind.INITCODE: # Invalid EOF initcode self.to = self.pre.deploy_contract( @@ -591,7 +669,8 @@ def model_post_init(self, __context): # Run transaction model validation Transaction.model_post_init(self, __context) - self.post[compute_eofcreate_address(self.to, 0)] = None # Expect failure. + self.post[compute_eofcreate_address(self.to, 0)] = None # Expect + # failure. elif self.container_kind == ContainerKind.INITCODE: self.to = self.pre.deploy_contract( Op.TXCREATE(tx_initcode_hash=self.container.hash) + Op.STOP @@ -634,8 +713,8 @@ def generate( """Generate the BlockchainTest fixture.""" if fixture_format == EOFFixture: if Bytes(self.container) in existing_tests: - # Gracefully skip duplicate tests because one EOFStateTest can generate multiple - # state fixtures with the same data. + # Gracefully skip duplicate tests because one EOFStateTest can + # generate multiple state fixtures with the same data. pytest.skip(f"Duplicate EOF container on EOFStateTest: {self.node_id()}") return self.make_eof_test_fixture(fork=fork) elif fixture_format in StateTest.supported_fixture_formats: diff --git a/src/ethereum_test_specs/helpers.py b/src/ethereum_test_specs/helpers.py index 1f877f21d30..27b0979310d 100644 --- a/src/ethereum_test_specs/helpers.py +++ b/src/ethereum_test_specs/helpers.py @@ -23,7 +23,9 @@ class ExecutionContext(StrEnum): class UnexpectedExecutionSuccessError(Exception): - """Exception used when the transaction expected to fail succeeded instead.""" + """ + Exception used when the transaction expected to fail succeeded instead. + """ def __init__(self, execution_context: ExecutionContext, **kwargs): """Initialize the unexpected success exception.""" @@ -35,7 +37,9 @@ def __init__(self, execution_context: ExecutionContext, **kwargs): class UnexpectedExecutionFailError(Exception): - """Exception used when a transaction/block expected to succeed failed instead.""" + """ + Exception used when a transaction/block expected to succeed failed instead. + """ def __init__( self, @@ -54,7 +58,10 @@ def __init__( class UndefinedExecutionExceptionError(Exception): - """Exception used when a client's exception message isn't present in its `ExceptionMapper`.""" + """ + Exception used when a client's exception message isn't present in its + `ExceptionMapper`. + """ def __init__( self, @@ -100,7 +107,10 @@ def __init__( class TransactionReceiptMismatchError(Exception): - """Exception used when the actual transaction receipt differs from the expected one.""" + """ + Exception used when the actual transaction receipt differs from the + expected one. + """ def __init__( self, @@ -259,9 +269,9 @@ def verify_transactions( transition_tool_exceptions_reliable: bool, ) -> List[int]: """ - Verify accepted and rejected (if any) transactions against the expected outcome. - Raises exception on unexpected rejections, unexpected successful txs, or successful txs with - unexpected receipt values. + Verify accepted and rejected (if any) transactions against the expected + outcome. Raises exception on unexpected rejections, unexpected successful + txs, or successful txs with unexpected receipt values. """ rejected_txs: Dict[int, ExceptionWithMessage | UndefinedException] = { rejected_tx.index: rejected_tx.error for rejected_tx in result.rejected_transactions diff --git a/src/ethereum_test_specs/state.py b/src/ethereum_test_specs/state.py index b368b41298c..0d073347472 100644 --- a/src/ethereum_test_specs/state.py +++ b/src/ethereum_test_specs/state.py @@ -46,7 +46,9 @@ class StateTest(BaseTest): - """Filler type that tests transactions over the period of a single block.""" + """ + Filler type that tests transactions over the period of a single block. + """ env: Environment = Field(default_factory=Environment) pre: Alloc @@ -70,7 +72,8 @@ class StateTest(BaseTest): f"A {fixture_format.format_name} generated from a state_test", ) for fixture_format in BlockchainTest.supported_fixture_formats - # Exclude sync fixtures from state tests - they don't make sense for state tests + # Exclude sync fixtures from state tests - they don't make sense for + # state tests if not ( (hasattr(fixture_format, "__name__") and "Sync" in fixture_format.__name__) or (hasattr(fixture_format, "format") and "Sync" in fixture_format.format.__name__) @@ -173,26 +176,31 @@ def discard_fixture_format_by_marks( fork: Fork, markers: List[pytest.Mark], ) -> bool: - """Discard a fixture format from filling if the appropriate marker is used.""" + """ + Discard a fixture format from filling if the appropriate marker is + used. + """ if "state_test_only" in [m.name for m in markers]: return fixture_format != StateFixture return False def _generate_blockchain_genesis_environment(self, *, fork: Fork) -> Environment: - """Generate the genesis environment for the BlockchainTest formatted test.""" + """ + Generate the genesis environment for the BlockchainTest formatted test. + """ assert self.env.number >= 1, ( "genesis block number cannot be negative, set state test env.number to at least 1" ) assert self.env.timestamp >= 1, ( "genesis timestamp cannot be negative, set state test env.timestamp to at least 1" ) - # There's only a handful of values that we need to set in the genesis for the - # environment values at block 1 to make sense: - # - Number: Needs to be N minus 1 - # - Timestamp: Needs to be zero, because the subsequent block can come at any time. - # - Gas Limit: Changes from parent to child, needs to be set in genesis - # - Base Fee Per Gas: Block's base fee depends on the parent's value - # - Excess Blob Gas: Block's excess blob gas value depends on the parent's value + # There's only a handful of values that we need to set in the genesis + # for the environment values at block 1 to make sense: - Number: Needs + # to be N minus 1 - Timestamp: Needs to be zero, because the subsequent + # block can come at any time. - Gas Limit: Changes from parent to + # child, needs to be set in genesis - Base Fee Per Gas: Block's base + # fee depends on the parent's value - Excess Blob Gas: Block's excess + # blob gas value depends on the parent's value kwargs: Dict[str, Any] = { "number": self.env.number - 1, "timestamp": 0, @@ -208,11 +216,13 @@ def _generate_blockchain_genesis_environment(self, *, fork: Fork) -> Environment ) if self.env.excess_blob_gas: - # The excess blob gas environment value means the value of the context (block header) - # where the transaction is executed. In a blockchain test, we need to indirectly - # set the excess blob gas by setting the excess blob gas of the genesis block - # to the expected value plus the TARGET_BLOB_GAS_PER_BLOCK, which is the value - # that will be subtracted from the excess blob gas when the first block is mined. + # The excess blob gas environment value means the value of the + # context (block header) where the transaction is executed. In a + # blockchain test, we need to indirectly set the excess blob gas by + # setting the excess blob gas of the genesis block to the expected + # value plus the TARGET_BLOB_GAS_PER_BLOCK, which is the value that + # will be subtracted from the excess blob gas when the first block + # is mined. kwargs["excess_blob_gas"] = self.env.excess_blob_gas + ( fork.target_blobs_per_block() * fork.blob_gas_per_blob() ) @@ -220,7 +230,10 @@ def _generate_blockchain_genesis_environment(self, *, fork: Fork) -> Environment return Environment(**kwargs) def _generate_blockchain_blocks(self, *, fork: Fork) -> List[Block]: - """Generate the single block that represents this state test in a BlockchainTest format.""" + """ + Generate the single block that represents this state test in a + BlockchainTest format. + """ kwargs = { "number": self.env.number, "timestamp": self.env.timestamp, @@ -261,7 +274,8 @@ def make_state_test_fixture( ) -> StateFixture: """Create a fixture from the state test definition.""" # We can't generate a state test fixture that names a transition fork, - # so we get the fork at the block number and timestamp of the state test + # so we get the fork at the block number and timestamp of the state + # test fork = fork.fork_at(self.env.number, self.env.timestamp) env = self.env.set_fork_requirements(fork) @@ -315,8 +329,9 @@ def make_state_test_fixture( assert base_tool_output.result.traces is not None, "Traces not found." - # First try reducing the gas limit only by one, if the validation fails, it means - # that the traces change even with the slightest modification to the gas. + # First try reducing the gas limit only by one, if the validation + # fails, it means that the traces change even with the slightest + # modification to the gas. if self.verify_modified_gas_limit( t8n=t8n, base_tool_output=base_tool_output, diff --git a/src/ethereum_test_specs/static_state/account.py b/src/ethereum_test_specs/static_state/account.py index 81f16cdee1f..978312f9b21 100644 --- a/src/ethereum_test_specs/static_state/account.py +++ b/src/ethereum_test_specs/static_state/account.py @@ -169,7 +169,8 @@ def setup(self, pre: Alloc, all_dependencies: Dict[str, Tag]) -> TagDict: # Step 3: Get topological order resolution_order = self._topological_sort(dep_graph) - # Step 4: Pre-deploy all contract tags and pre-fund EOAs to get addresses + # Step 4: Pre-deploy all contract tags and pre-fund EOAs to get + # addresses for tag_name in resolution_order: if tag_name in tag_to_address: tag = tag_to_address[tag_name] @@ -181,7 +182,8 @@ def setup(self, pre: Alloc, all_dependencies: Dict[str, Tag]) -> TagDict: ) resolved_accounts[tag_name] = deployed_address elif isinstance(tag, SenderTag): - # Create EOA to get address - use amount=1 to ensure account is created + # Create EOA to get address - use amount=1 to ensure + # account is created eoa = pre.fund_eoa(amount=1, label=tag_name) # Store the EOA object for SenderKeyTag resolution resolved_accounts[tag_name] = eoa @@ -247,7 +249,8 @@ def setup(self, pre: Alloc, all_dependencies: Dict[str, Tag]) -> TagDict: if all_dependencies[extra_dependency].type != "eoa": raise ValueError(f"Contract dependency {extra_dependency} not found in pre") - # Create new EOA - this will have a dynamically generated key and address + # Create new EOA - this will have a dynamically generated key + # and address eoa = pre.fund_eoa(amount=0, label=extra_dependency) resolved_accounts[extra_dependency] = eoa diff --git a/src/ethereum_test_specs/static_state/common/common.py b/src/ethereum_test_specs/static_state/common/common.py index 340f08971d8..3d706cf14e8 100644 --- a/src/ethereum_test_specs/static_state/common/common.py +++ b/src/ethereum_test_specs/static_state/common/common.py @@ -69,7 +69,8 @@ def validate_from_string(cls, code: Any) -> Any: """Validate from string, separating label from code source.""" if isinstance(code, str): label_marker = ":label" - # Only look for label at the beginning of the string (possibly after whitespace) + # Only look for label at the beginning of the string (possibly + # after whitespace) stripped_code = code.lstrip() # Parse :label into code options @@ -123,7 +124,8 @@ def replace_tags(raw_code, keep_prefix: bool) -> str: substitution_address = f"{tag.resolve(tags)}" if not keep_prefix and substitution_address.startswith("0x"): substitution_address = substitution_address[2:] - # Use the original string if available, otherwise construct a pattern + # Use the original string if available, otherwise construct a + # pattern if hasattr(tag, "original_string") and tag.original_string: raw_code = raw_code.replace(tag.original_string, substitution_address) else: @@ -192,9 +194,13 @@ def replace_tags(raw_code, keep_prefix: bool) -> str: [parameter_str], [ [ - int(t.lower(), 0) & ((1 << 256) - 1) # treat big ints as 256bits + int(t.lower(), 0) & ((1 << 256) - 1) # treat + # big + # ints as + # 256bits if parameter_types[t_index] == "uint" - else int(t.lower(), 0) > 0 # treat positive values as True + else int(t.lower(), 0) > 0 # treat positive + # values as True if parameter_types[t_index] == "bool" else False and ValueError("unhandled parameter_types") for t_index, t in enumerate(tokens[1:]) @@ -217,16 +223,12 @@ def replace_tags(raw_code, keep_prefix: bool) -> str: # - using lllc result = subprocess.run(["lllc", tmp_path], capture_output=True, text=True) - # - using docker: - # If the running machine does not have lllc installed, we can use docker to - # run lllc, but we need to start a container first, and the process is generally - # slower. - # from .docker import get_lllc_container_id - # result = subprocess.run( - # ["docker", "exec", get_lllc_container_id(), "lllc", tmp_path[5:]], - # capture_output=True, - # text=True, - # ) + # - using docker: If the running machine does not have lllc + # installed, we can use docker to run lllc, but we need to + # start a container first, and the process is generally slower. + # from .docker import get_lllc_container_id result = + # subprocess.run( ["docker", "exec", get_lllc_container_id(), + # "lllc", tmp_path[5:]], capture_output=True, text=True, ) compiled_code = "".join(result.stdout.splitlines()) else: @@ -244,16 +246,15 @@ def tag_dependencies(self) -> Mapping[str, Tag]: class AddressTag: """ - Represents an address tag like: - - . - - . - - . + Represents an address tag like: - . - + . - . """ def __init__(self, tag_type: str, tag_name: str, original_string: str): """Initialize address tag.""" self.tag_type = tag_type # "eoa", "contract", or "coinbase" - self.tag_name = tag_name # e.g., "sender", "target", or address for 2-part tags + self.tag_name = tag_name # e.g., "sender", "target", or address for + # 2-part tags self.original_string = original_string def __str__(self) -> str: @@ -317,8 +318,8 @@ def parse_address_or_tag(value: Any) -> Union[Address, AddressTag]: def parse_address_or_tag_for_access_list(value: Any) -> Union[Address, str]: """ - Parse either a regular address or an address tag, keeping tags as strings for later - resolution. + Parse either a regular address or an address tag, keeping tags as strings + for later resolution. """ if not isinstance(value, str): # Non-string values should be converted to Address normally @@ -344,7 +345,9 @@ def parse_address_or_tag_for_access_list(value: Any) -> Union[Address, str]: class AccessListInFiller(CamelModel, TagDependentData): - """Access List for transactions in fillers that can contain address tags.""" + """ + Access List for transactions in fillers that can contain address tags. + """ address: AddressOrTagInFiller storage_keys: List[Hash] = Field(default_factory=list) diff --git a/src/ethereum_test_specs/static_state/common/compile_yul.py b/src/ethereum_test_specs/static_state/common/compile_yul.py index 6e548d46b26..c4b6ec41854 100644 --- a/src/ethereum_test_specs/static_state/common/compile_yul.py +++ b/src/ethereum_test_specs/static_state/common/compile_yul.py @@ -51,19 +51,17 @@ def safe_solc_command( def compile_yul(source_file: str, evm_version: str | None = None, optimize: str | None = None): """ - Compiles a Yul source file using solc and returns the binary representation. + Compiles a Yul source file using solc and returns the binary + representation. - Parameters_: - source_file (str): Path to the Yul source file. - evm_version (str, optional): The EVM version to use (e.g., 'istanbul'). Defaults to None. - optimize (any, optional): If provided (non-None), optimization flags are not added. - If None, additional optimization flags will be included. + Parameters_: source_file (str): Path to the Yul source file. evm_version + (str, optional): The EVM version to use (e.g., 'istanbul'). Defaults to + None. optimize (any, optional): If provided (non-None), optimization flags + are not added. If None, additional optimization flags will be included. - Returns_: - str: The binary representation prefixed with "0x". + Returns_: str: The binary representation prefixed with "0x". - Raises_: - Exception: If the solc output contains an error message. + Raises_: Exception: If the solc output contains an error message. """ cmd = safe_solc_command(source_file, evm_version, optimize) @@ -77,7 +75,8 @@ def compile_yul(source_file: str, evm_version: str | None = None, optimize: str if "Error" in out: raise Exception(f"Yul compilation error:\n{out}") - # Search for the "Binary representation:" line and get the following line as the binary + # Search for the "Binary representation:" line and get the following line + # as the binary lines = out.splitlines() binary_line = "" for i, line in enumerate(lines): diff --git a/src/ethereum_test_specs/static_state/common/tags.py b/src/ethereum_test_specs/static_state/common/tags.py index d1c75dc8885..9d7e11f9972 100644 --- a/src/ethereum_test_specs/static_state/common/tags.py +++ b/src/ethereum_test_specs/static_state/common/tags.py @@ -20,7 +20,8 @@ class Tag(BaseModel, Generic[T]): name: str type: ClassVar[str] = "" regex_pattern: ClassVar[re.Pattern] = re.compile(r"<\w+:(\w+)(:[^>]+)?") - original_string: str | None = None # Store the original tag string for replacement + original_string: str | None = None # Store the original tag string for + # replacement def __hash__(self) -> int: """Hash based on original string for use as dict key.""" @@ -64,12 +65,16 @@ class ContractTag(AddressTag): type: ClassVar[str] = "contract" regex_pattern: ClassVar[re.Pattern] = re.compile(r"]+)(?::(0x[a-fA-F0-9]+))?>") - debug_address: Address | None = None # Optional hard-coded address for debugging + debug_address: Address | None = None # Optional hard-coded address for + # debugging @model_validator(mode="before") @classmethod def validate_from_string(cls, data: Any) -> Any: - """Validate the contract tag from string: or .""" + """ + Validate the contract tag from string: or + . + """ if isinstance(data, str): if m := cls.regex_pattern.match(data): name_or_addr = m.group(1) @@ -77,8 +82,9 @@ def validate_from_string(cls, data: Any) -> Any: # Check if it's a 2-part format with an address if name_or_addr.startswith("0x") and len(name_or_addr) == 42: - # For 2-part format, use the full address as the name - # This ensures all references to the same address get the same tag name + # For 2-part format, use the full address as the name This + # ensures all references to the same address get the same + # tag name return { "name": name_or_addr, "debug_address": Address(name_or_addr), @@ -146,7 +152,8 @@ class SenderTag(AddressTag): type: ClassVar[str] = "eoa" regex_pattern: ClassVar[re.Pattern] = re.compile(r"") - debug_address: Address | None = None # Optional hard-coded address for debugging + debug_address: Address | None = None # Optional hard-coded address for + # debugging @model_validator(mode="before") @classmethod diff --git a/src/ethereum_test_specs/static_state/expect_section.py b/src/ethereum_test_specs/static_state/expect_section.py index 226b3311bec..ccd7f7aa45d 100644 --- a/src/ethereum_test_specs/static_state/expect_section.py +++ b/src/ethereum_test_specs/static_state/expect_section.py @@ -106,7 +106,10 @@ class AccountInExpectSection(BaseModel, TagDependentData): @model_validator(mode="wrap") @classmethod def validate_should_not_exist(cls, v: Any, handler: ValidatorFunctionWrapHandler): - """Validate the "shouldnotexist" field, which makes this validator return `None`.""" + """ + Validate the "shouldnotexist" field, which makes this validator return + `None`. + """ if isinstance(v, dict): if "shouldnotexist" in v: return None @@ -251,8 +254,8 @@ class ResultInFiller(EthereumTestRootModel, TagDependentData): """ Post section in state test filler. - A value of `None` for an address means that the account should not be in the state trie - at the end of the test. + A value of `None` for an address means that the account should not be in + the state trie at the end of the test. """ root: Dict[AddressOrCreateTagInFiller, AccountInExpectSection | None] diff --git a/src/ethereum_test_specs/static_state/general_transaction.py b/src/ethereum_test_specs/static_state/general_transaction.py index e3e44be62ea..cafec7778c3 100644 --- a/src/ethereum_test_specs/static_state/general_transaction.py +++ b/src/ethereum_test_specs/static_state/general_transaction.py @@ -86,7 +86,9 @@ def __getitem__(self, label_or_index: int | str): raise KeyError(f"Label/index {label_or_index} not found in data indexes") def __contains__(self, label_or_index: int | str): - """Return True if the LabeledDataList contains the given label/index.""" + """ + Return True if the LabeledDataList contains the given label/index. + """ if isinstance(label_or_index, int): return label_or_index < len(self.root) if isinstance(label_or_index, str): diff --git a/src/ethereum_test_specs/static_state/state_static.py b/src/ethereum_test_specs/static_state/state_static.py index 7801d404b91..322691b4cf6 100644 --- a/src/ethereum_test_specs/static_state/state_static.py +++ b/src/ethereum_test_specs/static_state/state_static.py @@ -69,7 +69,9 @@ def parse_indexes( indexes: Union[int, str, list[Union[int, str]], list[str], list[int]], do_hint: bool = False, ) -> List[int] | int: - """Parse indexes and replace all ranges and labels into tx indexes.""" + """ + Parse indexes and replace all ranges and labels into tx indexes. + """ result: List[int] | int = [] if do_hint: @@ -129,8 +131,9 @@ def fill_function(self) -> Callable: for expect in self.expect: if expect.has_index(d.index, g, v) and expect.expect_exception is not None: exception_test = True - # TODO: This does not take into account exceptions that only happen on - # specific forks, but this requires a covariant parametrize + # TODO: This does not take into account exceptions that + # only happen on specific forks, but this requires a + # covariant parametrize marks = [pytest.mark.exception_test] if exception_test else [] id_label = "" if len(self.transaction.data) > 1 or d.label is not None: diff --git a/src/ethereum_test_specs/tests/test_expect.py b/src/ethereum_test_specs/tests/test_expect.py index 9f2b00acafc..0009064fc12 100644 --- a/src/ethereum_test_specs/tests/test_expect.py +++ b/src/ethereum_test_specs/tests/test_expect.py @@ -118,7 +118,10 @@ def state_test( # noqa: D103 indirect=["pre", "post"], ) def test_post_storage_value_mismatch(expected_exception, state_test, default_t8n, fork): - """Test post state `Account.storage` exceptions during state test fixture generation.""" + """ + Test post state `Account.storage` exceptions during state test fixture + generation. + """ with pytest.raises(Storage.KeyValueMismatchError) as e_info: state_test.generate(t8n=default_t8n, fork=fork, fixture_format=StateFixture) assert e_info.value == expected_exception @@ -136,8 +139,8 @@ def test_post_storage_value_mismatch(expected_exception, state_test, default_t8n ) def test_post_nonce_value_mismatch(pre: Alloc, post: Alloc, state_test, default_t8n, fork): """ - Test post state `Account.nonce` verification and exceptions during state test - fixture generation. + Test post state `Account.nonce` verification and exceptions during state + test fixture generation. """ pre_account = pre[ADDRESS_UNDER_TEST] post_account = post[ADDRESS_UNDER_TEST] @@ -167,8 +170,8 @@ def test_post_nonce_value_mismatch(pre: Alloc, post: Alloc, state_test, default_ ) def test_post_code_value_mismatch(pre: Alloc, post: Alloc, state_test, default_t8n, fork): """ - Test post state `Account.code` verification and exceptions during state test - fixture generation. + Test post state `Account.code` verification and exceptions during state + test fixture generation. """ pre_account = pre[ADDRESS_UNDER_TEST] post_account = post[ADDRESS_UNDER_TEST] @@ -198,8 +201,8 @@ def test_post_code_value_mismatch(pre: Alloc, post: Alloc, state_test, default_t ) def test_post_balance_value_mismatch(pre: Alloc, post: Alloc, state_test, default_t8n, fork): """ - Test post state `Account.balance` verification and exceptions during state test - fixture generation. + Test post state `Account.balance` verification and exceptions during state + test fixture generation. """ pre_account = pre[ADDRESS_UNDER_TEST] post_account = post[ADDRESS_UNDER_TEST] @@ -332,8 +335,8 @@ def test_transaction_expectation( fixture_format: FixtureFormat, ): """ - Test a transaction that has an unexpected error, expected error, or expected a specific - value in its receipt. + Test a transaction that has an unexpected error, expected error, or + expected a specific value in its receipt. """ if ( exception_type == ExecutionExceptionMismatchError diff --git a/src/ethereum_test_specs/tests/test_fixtures.py b/src/ethereum_test_specs/tests/test_fixtures.py index 665b37b0675..45afb3864cd 100644 --- a/src/ethereum_test_specs/tests/test_fixtures.py +++ b/src/ethereum_test_specs/tests/test_fixtures.py @@ -42,8 +42,8 @@ def fixture_hash(fork: Fork) -> bytes: def test_check_helper_fixtures(): """ Test that the framework's pydantic models serialization and deserialization - work correctly and that they are compatible with the helper fixtures defined - in ./fixtures/ by using the check_fixtures.py script. + work correctly and that they are compatible with the helper fixtures + defined in ./fixtures/ by using the check_fixtures.py script. """ runner = CliRunner() args = [ diff --git a/src/ethereum_test_specs/transaction.py b/src/ethereum_test_specs/transaction.py index 0dbf927201c..0511891e579 100644 --- a/src/ethereum_test_specs/transaction.py +++ b/src/ethereum_test_specs/transaction.py @@ -23,7 +23,9 @@ class TransactionTest(BaseTest): - """Filler type that tests the transaction over the period of a single block.""" + """ + Filler type that tests the transaction over the period of a single block. + """ tx: Transaction pre: Alloc | None = None diff --git a/src/ethereum_test_tools/tests/test_code.py b/src/ethereum_test_tools/tests/test_code.py index 40d47821421..37040cfbb28 100644 --- a/src/ethereum_test_tools/tests/test_code.py +++ b/src/ethereum_test_tools/tests/test_code.py @@ -185,7 +185,9 @@ def test_initcode(initcode: Initcode, bytecode: bytes): # noqa: D103 ], ) def test_opcodes_if(conditional_bytecode: bytes, expected: bytes): - """Test that the if opcode macro is transformed into bytecode as expected.""" + """ + Test that the if opcode macro is transformed into bytecode as expected. + """ assert bytes(conditional_bytecode) == expected @@ -514,7 +516,9 @@ def test_opcodes_if(conditional_bytecode: bytes, expected: bytes): def test_switch( tx_data: bytes, switch_bytecode: bytes, expected_storage: Mapping, default_t8n: TransitionTool ): - """Test that the switch opcode macro gets executed as using the t8n tool.""" + """ + Test that the switch opcode macro gets executed as using the t8n tool. + """ code_address = Address(0x1000) pre = Alloc( { diff --git a/src/ethereum_test_tools/tools_code/generators.py b/src/ethereum_test_tools/tools_code/generators.py index 7af682ab6c4..7b2baa03f81 100644 --- a/src/ethereum_test_tools/tools_code/generators.py +++ b/src/ethereum_test_tools/tools_code/generators.py @@ -18,12 +18,11 @@ class Initcode(Bytecode): The execution gas cost of the initcode is calculated, and also the deployment gas costs for the deployed code. - The initcode can be padded to a certain length if necessary, which - does not affect the deployed code. + The initcode can be padded to a certain length if necessary, which does not + affect the deployed code. - Other costs such as the CREATE2 hashing costs or the initcode_word_cost - of EIP-3860 are *not* taken into account by any of these calculated - costs. + Other costs such as the CREATE2 hashing costs or the initcode_word_cost of + EIP-3860 are *not* taken into account by any of these calculated costs. """ deploy_code: SupportsBytes | Bytes @@ -131,8 +130,8 @@ class CodeGasMeasure(Bytecode): """ Helper class used to generate bytecode that measures gas usage of a bytecode, taking into account and subtracting any extra overhead gas costs - required to execute. - By default, the result gas calculation is saved to storage key 0. + required to execute. By default, the result gas calculation is saved to + storage key 0. """ code: Bytecode @@ -199,8 +198,8 @@ def __new__( ): """ Assemble the conditional bytecode by generating the necessary jump and - jumpdest opcodes surrounding the condition and the two possible execution - paths. + jumpdest opcodes surrounding the condition and the two possible + execution paths. In the future, PC usage should be replaced by using RJUMP and RJUMPI """ @@ -213,15 +212,16 @@ def __new__( # First we append a jumpdest to the start of the true branch if_true = Op.JUMPDEST + if_true - # Then we append the unconditional jump to the end of the false branch, used to skip - # the true branch + # Then we append the unconditional jump to the end of the false + # branch, used to skip the true branch if_false += Op.JUMP(Op.ADD(Op.PC, len(if_true) + 3)) - # Then we need to do the conditional jump by skipping the false branch + # Then we need to do the conditional jump by skipping the false + # branch condition = Op.JUMPI(Op.ADD(Op.PC, len(if_false) + 3), condition) - # Finally we append the condition, false and true branches, plus the jumpdest at the - # very end + # Finally we append the condition, false and true branches, plus + # the jumpdest at the very end bytecode = condition + if_false + if_true + Op.JUMPDEST elif evm_code_type == EVMCodeType.EOF_V1: @@ -284,8 +284,8 @@ def is_terminating(self) -> bool: class CalldataCase(Case): """ - Small helper class to represent a single case whose condition depends - on the value of the contract's calldata in a Switch case statement. + Small helper class to represent a single case whose condition depends on + the value of the contract's calldata in a Switch case statement. By default the calldata is read from position zero, but this can be overridden using `position`. @@ -304,13 +304,11 @@ class Switch(Bytecode): """ Helper class used to generate switch-case expressions in EVM bytecode. - Switch-case behavior: - - If no condition is met in the list of BytecodeCases conditions, - the `default_action` bytecode is executed. - - If multiple conditions are met, the action from the first valid - condition is the only one executed. - - There is no fall through; it is not possible to execute multiple - actions. + Switch-case behavior: - If no condition is met in the list of BytecodeCases + conditions, the `default_action` bytecode is executed. - If multiple + conditions are met, the action from the first valid condition is the only + one executed. - There is no fall through; it is not possible to execute + multiple actions. """ default_action: Bytecode | Op | None @@ -338,54 +336,49 @@ def __new__( evm_code_type: EVMCodeType = EVMCodeType.LEGACY, ): """ - Assemble the bytecode by looping over the list of cases and adding - the necessary [R]JUMPI and JUMPDEST opcodes in order to replicate + Assemble the bytecode by looping over the list of cases and adding the + necessary [R]JUMPI and JUMPDEST opcodes in order to replicate switch-case behavior. """ - # The length required to jump over subsequent actions to the final JUMPDEST at the end - # of the switch-case block: - # - add 6 per case for the length of the JUMPDEST and JUMP(ADD(PC, action_jump_length)) - # bytecode - # - add 3 to the total to account for this action's JUMP; the PC within the call - # requires a "correction" of 3. + # The length required to jump over subsequent actions to the final + # JUMPDEST at the end of the switch-case block: - add 6 per case for + # the length of the JUMPDEST and JUMP(ADD(PC, action_jump_length)) + # bytecode - add 3 to the total to account for this action's JUMP; the + # PC within the call requires a "correction" of 3. bytecode = Bytecode() - # All conditions get prepended to this bytecode; if none are met, we reach the default + # All conditions get prepended to this bytecode; if none are met, we + # reach the default if evm_code_type == EVMCodeType.LEGACY: action_jump_length = sum(len(case.action) + 6 for case in cases) + 3 bytecode = default_action + Op.JUMP(Op.ADD(Op.PC, action_jump_length)) - # The length required to jump over the default action and its JUMP bytecode + # The length required to jump over the default action and its JUMP + # bytecode condition_jump_length = len(bytecode) + 3 elif evm_code_type == EVMCodeType.EOF_V1: action_jump_length = sum( len(case.action) + (len(Op.RJUMP[0]) if not case.is_terminating else 0) for case in cases - # On not terminating cases, we need to add 3 bytes for the RJUMP + # On not terminating cases, we need to add 3 bytes for the + # RJUMP ) bytecode = default_action + Op.RJUMP[action_jump_length] - # The length required to jump over the default action and its JUMP bytecode + # The length required to jump over the default action and its JUMP + # bytecode condition_jump_length = len(bytecode) - # Reversed: first case in the list has priority; it will become the outer-most onion layer. - # We build up layers around the default_action, after 1 iteration of the loop, a simplified - # representation of the bytecode is: - # - # JUMPI(case[n-1].condition) - # + default_action + JUMP() - # + JUMPDEST + case[n-1].action + JUMP() - # + # Reversed: first case in the list has priority; it will become the + # outer-most onion layer. We build up layers around the default_action, + # after 1 iteration of the loop, a simplified representation of the + # bytecode is: + # JUMPI(case[n-1].condition) + default_action + JUMP() + JUMPDEST + + # case[n-1].action + JUMP() # and after n=len(cases) iterations: - # - # JUMPI(case[0].condition) - # + JUMPI(case[1].condition) - # ... - # + JUMPI(case[n-1].condition) - # + default_action + JUMP() - # + JUMPDEST + case[n-1].action + JUMP() - # + ... - # + JUMPDEST + case[1].action + JUMP() - # + JUMPDEST + case[0].action + JUMP() + # JUMPI(case[0].condition) + JUMPI(case[1].condition) ... + + # JUMPI(case[n-1].condition) + default_action + JUMP() + JUMPDEST + + # case[n-1].action + JUMP() + ... + JUMPDEST + case[1].action + JUMP() + # + JUMPDEST + case[0].action + JUMP() # for case in reversed(cases): action = case.action diff --git a/src/ethereum_test_tools/utility/generators.py b/src/ethereum_test_tools/utility/generators.py index 95c9094e91c..142898466bc 100644 --- a/src/ethereum_test_tools/utility/generators.py +++ b/src/ethereum_test_tools/utility/generators.py @@ -43,7 +43,10 @@ def param(self): class ContractAddressHasBalance(StrEnum): - """Represents whether the target deployment test has a balance before deployment.""" + """ + Represents whether the target deployment test has a balance before + deployment. + """ ZERO_BALANCE = "zero_balance" NONZERO_BALANCE = "nonzero_balance" @@ -51,8 +54,8 @@ class ContractAddressHasBalance(StrEnum): class SystemContractDeployTestFunction(Protocol): """ - Represents a function to be decorated with the `generate_system_contract_deploy_test` - decorator. + Represents a function to be decorated with the + `generate_system_contract_deploy_test` decorator. """ def __call__( @@ -64,17 +67,15 @@ def __call__( test_type: DeploymentTestType, ) -> Generator[Block, None, None]: """ - Args: - fork (Fork): The fork to test. - pre (Alloc): The pre state of the blockchain. - post (Alloc): The post state of the blockchain. - test_type (DeploymentTestType): The type of deployment test currently being filled. - - Yields: - Block: To add after the block where the contract was deployed (e.g. can contain extra - transactions to execute after the system contract has been deployed, and/or a header - object to verify that the headers are correct). - + Args: fork (Fork): The fork to test. pre (Alloc): The pre state of the + blockchain. post (Alloc): The post state of the blockchain. test_type + (DeploymentTestType): The type of deployment test currently being + filled. + + Yields: Block: To add after the block where the contract was deployed + (e.g. can contain extra transactions to execute after the system + contract has been deployed, and/or a header object to verify that the + headers are correct). """ ... @@ -92,28 +93,28 @@ def generate_system_contract_deploy_test( Generates following test cases: - | before/after fork | fail on | invalid block | - | | empty block | | - --------------------------------------|-------------------|-------------|---------------| - `deploy_before_fork-nonzero_balance` | before | False | False | - `deploy_before_fork-zero_balance` | before | True | False | - `deploy_on_fork_block-nonzero_balance`| on fork block | False | False | - `deploy_on_fork_block-zero_balance` | on fork block | True | False | - `deploy_after_fork-nonzero_balance` | after | False | False | - `deploy_after_fork-zero_balance` | after | True | True | - - The `has balance` parametrization does not have an effect on the expectation of the test. - - Args: - fork (Fork): The fork to test. - tx_json_path (Path): Path to the JSON file with the transaction to deploy the system - contract. - Providing a JSON file is useful to copy-paste the transaction from the EIP. - expected_deploy_address (Address): The expected address of the deployed contract. - fail_on_empty_code (bool): If True, the test is expected to fail on empty code. - expected_system_contract_storage (Dict | None): The expected storage of the system - contract. - + | before/after fork | fail on | invalid block | | | + empty block | | + --------------------------------------|-------------------|-------------|------ + ---------| `deploy_before_fork-nonzero_balance` | before | + False | False | `deploy_before_fork-zero_balance` | + before | True | False | + `deploy_on_fork_block-nonzero_balance`| on fork block | False | + False | `deploy_on_fork_block-zero_balance` | on fork block | + True | False | `deploy_after_fork-nonzero_balance` | after + | False | False | `deploy_after_fork-zero_balance` | + after | True | True | + + The `has balance` parametrization does not have an effect on the + expectation of the test. + + Args: fork (Fork): The fork to test. tx_json_path (Path): Path to the JSON + file with the transaction to deploy the system contract. Providing a JSON + file is useful to copy-paste the transaction from the EIP. + expected_deploy_address (Address): The expected address of the deployed + contract. fail_on_empty_code (bool): If True, the test is expected to fail + on empty code. expected_system_contract_storage (Dict | None): The expected + storage of the system contract. """ with open(tx_json_path, mode="r") as f: tx_json = json.loads(f.read()) @@ -213,7 +214,8 @@ def wrapper( ) balance = 1 if has_balance == ContractAddressHasBalance.NONZERO_BALANCE else 0 pre[expected_deploy_address] = Account( - code=b"", # Remove the code that is automatically allocated on the fork + code=b"", # Remove the code that is automatically allocated on + # the fork nonce=0, balance=balance, ) @@ -227,7 +229,8 @@ def wrapper( fork_pre_allocation = fork.pre_allocation_blockchain() assert expected_deploy_address_int in fork_pre_allocation expected_code = fork_pre_allocation[expected_deploy_address_int]["code"] - # Note: balance check is omitted; it may be modified by the underlying, decorated test + # Note: balance check is omitted; it may be modified by the + # underlying, decorated test account_kwargs = { "code": expected_code, "nonce": 1, @@ -240,8 +243,8 @@ def wrapper( nonce=1, ) - # Extra blocks (if any) returned by the decorated function to add after the - # contract is deployed. + # Extra blocks (if any) returned by the decorated function to add + # after the contract is deployed. if test_type != DeploymentTestType.DEPLOY_AFTER_FORK or not fail_on_empty_code: # Only fill more blocks if the deploy block does not fail. blocks += list(func(fork=fork, pre=pre, post=post, test_type=test_type)) @@ -265,15 +268,15 @@ def generate_system_contract_error_test( max_gas_limit: int, ): """ - Generate a test that verifies the correct behavior when a system contract fails execution. - - Parametrizations required: - - system_contract (Address): The address of the system contract to deploy. - - valid_from (Fork): The fork from which the test is valid. + Generate a test that verifies the correct behavior when a system contract + fails execution. - Args: - max_gas_limit (int): The maximum gas limit for the system transaction. + Parametrizations required: - system_contract (Address): The address of the + system contract to deploy. - valid_from (Fork): The fork from which the + test is valid. + Args: max_gas_limit (int): The maximum gas limit for the system + transaction. """ def decorator(func: SystemContractDeployTestFunction): @@ -288,25 +291,27 @@ def wrapper( ): modified_system_contract_code = Bytecode() - # Depending on the test case, we need to modify the system contract code accordingly. + # Depending on the test case, we need to modify the system contract + # code accordingly. if ( test_type == SystemContractTestType.GAS_LIMIT or test_type == SystemContractTestType.OUT_OF_GAS_ERROR ): # Run code so that it reaches the gas limit. gas_costs = fork.gas_costs() - # The code works by storing N values to storage, and N is calculated based on the - # gas costs for the given fork. - # This code will only work once, so if the system contract is re-executed - # in a subsequent block, it will consume less gas. + # The code works by storing N values to storage, and N is + # calculated based on the gas costs for the given fork. This + # code will only work once, so if the system contract is re- + # executed in a subsequent block, it will consume less gas. gas_used_per_storage = ( gas_costs.G_STORAGE_SET + gas_costs.G_COLD_SLOAD + (gas_costs.G_VERY_LOW * 2) ) modified_system_contract_code += sum( Op.SSTORE(i, 1) for i in range(max_gas_limit // gas_used_per_storage) ) - # If the gas limit is not divisible by the gas used per storage, we need to add - # some NO-OP (JUMPDEST) to the code that each consume 1 gas. + # If the gas limit is not divisible by the gas used per + # storage, we need to add some NO-OP (JUMPDEST) to the code + # that each consume 1 gas. assert gas_costs.G_JUMPDEST == 1, ( f"JUMPDEST gas cost should be 1, but got {gas_costs.G_JUMPDEST}. " "Generator `generate_system_contract_error_test` needs to be updated." @@ -316,8 +321,9 @@ def wrapper( ) if test_type == SystemContractTestType.OUT_OF_GAS_ERROR: - # If the test type is OUT_OF_GAS_ERROR, we need to add a JUMPDEST to the code - # to ensure that we go over the limit by one gas. + # If the test type is OUT_OF_GAS_ERROR, we need to add a + # JUMPDEST to the code to ensure that we go over the limit + # by one gas. modified_system_contract_code += Op.JUMPDEST modified_system_contract_code += Op.STOP elif test_type == SystemContractTestType.REVERT_ERROR: @@ -335,7 +341,8 @@ def wrapper( balance=0, ) - # Simple test transaction to verify the block failed to modify the state. + # Simple test transaction to verify the block failed to modify the + # state. value_receiver = pre.fund_eoa(amount=0) test_tx = Transaction( to=value_receiver, diff --git a/src/ethereum_test_tools/utility/pytest.py b/src/ethereum_test_tools/utility/pytest.py index 4e01a6cd4a7..241ac40dc0f 100644 --- a/src/ethereum_test_tools/utility/pytest.py +++ b/src/ethereum_test_tools/utility/pytest.py @@ -8,8 +8,8 @@ class UnknownParameterInCasesError(Exception): """ - Exception raised when a test case contains parameters - that are not present in the defaults. + Exception raised when a test case contains parameters that are not present + in the defaults. """ def __init__(self) -> None: @@ -34,84 +34,50 @@ def extend_with_defaults( The function returns a dictionary that can be directly unpacked and passed to the `@pytest.mark.parametrize` decorator. - Args: - defaults (Dict[str, Any]): A dictionary of default parameter names and - their values. These values will be added to each case unless the case - already defines a value for each parameter. - cases (List[ParameterSet]): A list of `pytest.param` objects representing - different test cases. Its first argument must be a dictionary defining - parameter names and values. - parametrize_kwargs (Any): Additional keyword arguments to be passed to - `@pytest.mark.parametrize`. These arguments are not modified by this - function and are passed through unchanged. - - Returns: - Dict[str, Any]: A dictionary with the following structure: - `argnames`: A list of parameter names. - `argvalues`: A list of test cases with modified parameter values. - `parametrize_kwargs`: Additional keyword arguments passed through unchanged. - - - Example: - ```python - @pytest.mark.parametrize(**extend_with_defaults( - defaults=dict( - min_value=0, # default minimum value is 0 - max_value=100, # default maximum value is 100 - average=50, # default average value is 50 - ), - cases=[ - pytest.param( - dict(), # use default values - id='default_case', - ), - pytest.param( - dict(min_value=10), # override with min_value=10 - id='min_value_10', - ), - pytest.param( - dict(max_value=200), # override with max_value=200 - id='max_value_200', - ), - pytest.param( - dict(min_value=-10, max_value=50), # override both min_value - # and max_value - id='min_-10_max_50', - ), - pytest.param( - dict(min_value=20, max_value=80, average=50), # all defaults - # are overridden - id="min_20_max_80_avg_50", - ), - pytest.param( - dict(min_value=100, max_value=0), # invalid range - id='invalid_range', - marks=pytest.mark.xfail(reason='invalid range'), - ) - ], - )) - def test_range(min_value, max_value, average): - assert min_value <= max_value - assert min_value <= average <= max_value - ``` + Args: defaults (Dict[str, Any]): A dictionary of default parameter names + and their values. These values will be added to each case unless the case + already defines a value for each parameter. cases (List[ParameterSet]): A + list of `pytest.param` objects representing different test cases. Its first + argument must be a dictionary defining parameter names and values. + parametrize_kwargs (Any): Additional keyword arguments to be passed to + `@pytest.mark.parametrize`. These arguments are not modified by this + function and are passed through unchanged. + + Returns: Dict[str, Any]: A dictionary with the following structure: + `argnames`: A list of parameter names. `argvalues`: A list of test cases + with modified parameter values. `parametrize_kwargs`: Additional keyword + arguments passed through unchanged. + + + + Example: ```python @pytest.mark.parametrize(**extend_with_defaults( + defaults=dict( min_value=0, # default minimum value is 0 max_value=100, # + default maximum value is 100 average=50, # default average value is 50 ), + cases=[ pytest.param( dict(), # use default values id='default_case', ), + pytest.param( dict(min_value=10), # override with min_value=10 + id='min_value_10', ), pytest.param( dict(max_value=200), # override with + max_value=200 id='max_value_200', ), pytest.param( dict(min_value=-10, + max_value=50), # override both min_value # and max_value + id='min_-10_max_50', ), pytest.param( dict(min_value=20, max_value=80, + average=50), # all defaults # are overridden id="min_20_max_80_avg_50", ), + pytest.param( dict(min_value=100, max_value=0), # invalid range + id='invalid_range', marks=pytest.mark.xfail(reason='invalid range'), ) ], + )) def test_range(min_value, max_value, average): assert min_value <= + max_value assert min_value <= average <= max_value ``` The above test will execute with the following sets of parameters: - ```python - "default_case": {"min_value": 0, "max_value": 100, "average": 50} + ```python "default_case": {"min_value": 0, "max_value": 100, "average": 50} "min_value_10": {"min_value": 10, "max_value": 100, "average": 50} "max_value_200": {"min_value": 0, "max_value": 200, "average": 50} "min_-10_max_50": {"min_value": -10, "max_value": 50, "average": 50} "min_20_max_80_avg_50": {"min_value": 20, "max_value": 80, "average": 50} - "invalid_range": {"min_value": 100, "max_value": 0, "average": 50} # expected to fail - ``` - - Notes: - - Each case in `cases` must contain exactly one value, which is a dictionary - of parameter values. - - The function performs an in-place update of the `cases` list, so the - original `cases` list is modified. + "invalid_range": {"min_value": 100, "max_value": 0, "average": 50} # + expected to fail ``` + Notes: - Each case in `cases` must contain exactly one value, which is a + dictionary of parameter values. - The function performs an in-place update + of the `cases` list, so the original `cases` list is modified. """ for i, case in enumerate(cases): if not (len(case.values) == 1 and isinstance(case.values[0], dict)): @@ -120,7 +86,8 @@ def test_range(min_value, max_value, average): ) if set(case.values[0].keys()) - set(defaults.keys()): raise UnknownParameterInCasesError() - # Overwrite values in defaults if the parameter is present in the test case values + # Overwrite values in defaults if the parameter is present in the test + # case values merged_params = {**defaults, **case.values[0]} # type: ignore cases[i] = pytest.param(*merged_params.values(), id=case.id, marks=case.marks) diff --git a/src/ethereum_test_tools/utility/tests/test_pytest.py b/src/ethereum_test_tools/utility/tests/test_pytest.py index f8f242c92f2..edc12d05f70 100644 --- a/src/ethereum_test_tools/utility/tests/test_pytest.py +++ b/src/ethereum_test_tools/utility/tests/test_pytest.py @@ -6,7 +6,8 @@ from ethereum_test_tools.utility.pytest import UnknownParameterInCasesError -# TODO: This is from the docstring in extend_with_defaults; should be tested automatically +# TODO: This is from the docstring in extend_with_defaults; should be tested +# automatically @pytest.mark.parametrize( **extend_with_defaults( defaults={ @@ -33,7 +34,8 @@ id="min_-10_max_50", ), pytest.param( - {"min_value": 20, "max_value": 80, "average": 50}, # all defaults + {"min_value": 20, "max_value": 80, "average": 50}, # all + # defaults # are overridden id="min_20_max_80_avg_50", ), diff --git a/src/ethereum_test_tools/utility/versioning.py b/src/ethereum_test_tools/utility/versioning.py index 1d0578fd94e..d98ac31c7ef 100644 --- a/src/ethereum_test_tools/utility/versioning.py +++ b/src/ethereum_test_tools/utility/versioning.py @@ -9,10 +9,9 @@ def get_current_commit_hash_or_tag(repo_path=".", shorten_hash=False): """ Get the latest commit tag or commit hash from the repository. - If a tag points to the current commit, return the tag name. - If no tag exists: - - If shorten_hash is True, return the first 8 characters of the commit hash. - - Otherwise, return the full commit hash. + If a tag points to the current commit, return the tag name. If no tag + exists: - If shorten_hash is True, return the first 8 characters of the + commit hash. - Otherwise, return the full commit hash. """ try: repo = Repo(repo_path) diff --git a/src/ethereum_test_types/account_types.py b/src/ethereum_test_types/account_types.py index 53befb4592e..51a17ebe15d 100644 --- a/src/ethereum_test_types/account_types.py +++ b/src/ethereum_test_types/account_types.py @@ -50,8 +50,8 @@ class State: def set_account(state: State, address: Bytes20, account: Optional[FrontierAccount]) -> None: """ - Set the `Account` object at an address. Setting to `None` deletes - the account (but not its storage, see `destroy_account()`). + Set the `Account` object at an address. Setting to `None` deletes the + account (but not its storage, see `destroy_account()`). """ trie_set(state._main_trie, address, account) @@ -93,9 +93,11 @@ def get_storage_root(address: Bytes20) -> Bytes32: class EOA(Address): """ - An Externally Owned Account (EOA) is an account controlled by a private key. + An Externally Owned Account (EOA) is an account controlled by a private + key. - The EOA is defined by its address and (optionally) by its corresponding private key. + The EOA is defined by its address and (optionally) by its corresponding + private key. """ key: Hash | None @@ -354,7 +356,10 @@ def fund_eoa( delegation: Address | Literal["Self"] | None = None, nonce: NumberConvertible | None = None, ) -> EOA: - """Add a previously unused EOA to the pre-alloc with the balance specified by `amount`.""" + """ + Add a previously unused EOA to the pre-alloc with the balance specified + by `amount`. + """ raise NotImplementedError("fund_eoa is not implemented in the base class") def fund_address(self, address: Address, amount: NumberConvertible): @@ -370,7 +375,7 @@ def empty_account(self) -> Address: """ Return a previously unused account guaranteed to be empty. - This ensures the account has zero balance, zero nonce, no code, and no storage. - The account is not a precompile or a system contract. + This ensures the account has zero balance, zero nonce, no code, and no + storage. The account is not a precompile or a system contract. """ raise NotImplementedError("empty_account is not implemented in the base class") diff --git a/src/ethereum_test_types/blob_types.py b/src/ethereum_test_types/blob_types.py index 3adc860c860..a5c82c9944f 100644 --- a/src/ethereum_test_types/blob_types.py +++ b/src/ethereum_test_types/blob_types.py @@ -50,7 +50,8 @@ class Blob(CamelModel): data: Bytes commitment: Bytes proof: List[Bytes] | Bytes # Bytes < Osaka, List[Bytes] >= Osaka - cells: List[Bytes] | None # None (in json: null) < Osaka, List[Bytes] >= Osaka + cells: List[Bytes] | None # None (in json: null) < Osaka, List[Bytes] >= + # Osaka versioned_hash: Hash name: str @@ -72,13 +73,18 @@ def trusted_setup(cls): @staticmethod def get_filename(fork: Fork, seed: int) -> str: - """Return filename this blob would have as string (with .json extension).""" + """ + Return filename this blob would have as string (with .json extension). + """ amount_cell_proofs: int = cast(int, fork.get_blob_constant("AMOUNT_CELL_PROOFS")) return "blob_" + str(seed) + "_cell_proofs_" + str(amount_cell_proofs) + ".json" @staticmethod def get_filepath(fork: Fork, seed: int): - """Return the Path to the blob that would be created with these parameters.""" + """ + Return the Path to the blob that would be created with these + parameters. + """ # determine amount of cell proofs for this fork (0 or 128) would_be_filename: str = Blob.get_filename(fork, seed) @@ -87,7 +93,10 @@ def get_filepath(fork: Fork, seed: int): @staticmethod def from_fork(fork: Fork, seed: int = 0, timestamp: int = 0) -> "Blob": - """Construct Blob instances. Fork logic is encapsulated within nested functions.""" + """ + Construct Blob instances. Fork logic is encapsulated within nested + functions. + """ def generate_blob_data(rng_seed: int = 0) -> Bytes: """Calculate blob data deterministically via provided seed.""" @@ -139,12 +148,16 @@ def get_commitment(data: Bytes) -> Bytes: return commitment def get_proof(fork: Fork, data: Bytes) -> List[Bytes] | Bytes: - # determine whether this fork is = osaka by looking at amount of cell_proofs + # determine whether this fork is = osaka by looking at + # amount of cell_proofs amount_cell_proofs = fork.get_blob_constant("AMOUNT_CELL_PROOFS") # cancun, prague if amount_cell_proofs == 0: - z = 2 # 2 is one of many possible valid field elements z (https://github.com/ethereum/consensus-specs/blob/ad884507f7a1d5962cd3dfb5f7b3e41aab728c55/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py#L58-L66) + z = 2 # 2 is one of many possible valid field elements z + # https://github.com/ethereum/consensus-specs/blob/ad884507f + # 7a1d5962cd3dfb5f7b3e41aab728c55/tests/core/pyspec/eth2spec/ + # test/utils/kzg_tests.py#L58-L66) z_valid_size: bytes = z.to_bytes( cast(int, fork.get_blob_constant("BYTES_PER_FIELD_ELEMENT")), byteorder="big" ) @@ -164,7 +177,8 @@ def get_proof(fork: Fork, data: Bytes) -> List[Bytes] | Bytes: ) def get_cells(fork: Fork, data: Bytes) -> List[Bytes] | None: - # determine whether this fork is = osaka by looking at amount of cell_proofs + # determine whether this fork is = osaka by looking at + # amount of cell_proofs amount_cell_proofs = fork.get_blob_constant("AMOUNT_CELL_PROOFS") # cancun, prague @@ -189,8 +203,8 @@ def get_cells(fork: Fork, data: Bytes) -> List[Bytes] | None: parents=True, exist_ok=True ) # create all necessary dirs on the way - # handle transition forks - # (blob related constants are needed and only available for normal forks) + # handle transition forks (blob related constants are needed and only + # available for normal forks) fork = fork.fork_at(timestamp=timestamp) # if this blob already exists then load from file. use lock @@ -224,7 +238,8 @@ def get_cells(fork: Fork, data: Bytes) -> List[Bytes] | None: seed=seed, timestamp=timestamp, ) - # for most effective caching temporarily persist every blob that is created in cache + # for most effective caching temporarily persist every blob that is + # created in cache blob.write_to_file() return blob @@ -234,7 +249,8 @@ def from_file(file_name: str) -> "Blob": """ Read a .json file and reconstruct object it represents. - You can load a blob only via its filename (with or without .json extension). + You can load a blob only via its filename (with or without .json + extension). """ # ensure filename was passed assert file_name.startswith("blob_"), ( @@ -272,11 +288,15 @@ def write_to_file(self): if output_location.exists(): logger.debug(f"Blob {output_location} already exists. It will be overwritten.") - with open(output_location, "w", encoding="utf-8") as f: # overwrite existing + with open(output_location, "w", encoding="utf-8") as f: # overwrite + # existing f.write(json_str) def verify_cell_kzg_proof_batch(self, cell_indices: list) -> bool: - """Check whether all cell proofs are valid and returns True only if that is the case.""" + """ + Check whether all cell proofs are valid and returns True only if that + is the case. + """ amount_cell_proofs: int = cast(int, self.fork.get_blob_constant("AMOUNT_CELL_PROOFS")) assert amount_cell_proofs > 0, ( @@ -303,12 +323,14 @@ def delete_cells_then_recover_them(self, deletion_indices: list[int]): """ Simulate the cell recovery process in user-specified scenario. - Note: Requirement for successful reconstruction is having at least N of the 2N cells. + Note: Requirement for successful reconstruction is having at least N of + the 2N cells. - Theoretical Usage: You pass a cell list with to 128 elements to this function - along with a list of deletion indices. These cells will be deleted and then - the ckzg recovery mechanism is used to repair the missing cells. - If no assertion is triggered the reconstruction was successful. + Theoretical Usage: You pass a cell list with to 128 elements to this + function along with a list of deletion indices. These cells will be + deleted and then the ckzg recovery mechanism is used to repair the + missing cells. If no assertion is triggered the reconstruction was + successful. """ amount_cell_proofs: int = cast(int, self.fork.get_blob_constant("AMOUNT_CELL_PROOFS")) @@ -370,7 +392,8 @@ class ProofCorruptionMode(Enum): """ Define what the proof corruption modes do. - For Osaka and later each Bytes object in the list is manipulated this way. + For Osaka and later each Bytes object in the list is manipulated this + way. """ CORRUPT_FIRST_BYTE = 1 # corrupts a single byte (index 0) @@ -382,7 +405,9 @@ def corrupt_proof(self, mode: ProofCorruptionMode): """Corrupt the proof field, supports different corruption modes.""" def corrupt_byte(b: bytes) -> Bytes: - """Bit-flip all bits of provided byte using XOR to guarantee change.""" + """ + Bit-flip all bits of provided byte using XOR to guarantee change. + """ if len(b) != 1: raise ValueError("Input must be a single byte") return Bytes(bytes([b[0] ^ 0xFF])) diff --git a/src/ethereum_test_types/block_access_list/__init__.py b/src/ethereum_test_types/block_access_list/__init__.py index 6544bc71083..03cad90aae0 100644 --- a/src/ethereum_test_types/block_access_list/__init__.py +++ b/src/ethereum_test_types/block_access_list/__init__.py @@ -1,8 +1,9 @@ """ Block Access List (BAL) models for EIP-7928. -Following the established pattern in the codebase (AccessList, AuthorizationTuple), -these are simple data classes that can be composed together. +Following the established pattern in the codebase (AccessList, +AuthorizationTuple), these are simple data classes that can be composed +together. """ from .account_absent_values import BalAccountAbsentValues diff --git a/src/ethereum_test_types/block_access_list/modifiers.py b/src/ethereum_test_types/block_access_list/modifiers.py index a9df449d152..d873de9e7dd 100644 --- a/src/ethereum_test_types/block_access_list/modifiers.py +++ b/src/ethereum_test_types/block_access_list/modifiers.py @@ -1,9 +1,9 @@ """ BAL modifier functions for invalid test cases. -This module provides modifier functions that can be used to modify Block Access Lists -in various ways for testing invalid block scenarios. They are composable and can be -combined to create complex modifications. +This module provides modifier functions that can be used to modify Block Access +Lists in various ways for testing invalid block scenarios. They are composable +and can be combined to create complex modifications. """ from typing import Any, Callable, List, Optional @@ -60,7 +60,10 @@ def _modify_field_value( nested: bool = False, slot: Optional[int] = None, ) -> Callable[[BlockAccessList], BlockAccessList]: - """Abstracted helper to modify a field value for a specific account and transaction.""" + """ + Abstracted helper to modify a field value for a specific account and + transaction. + """ found_address = False def transform(bal: BlockAccessList) -> BlockAccessList: @@ -154,7 +157,9 @@ def modify_nonce( def modify_balance( address: Address, tx_index: int, balance: int ) -> Callable[[BlockAccessList], BlockAccessList]: - """Set an incorrect balance value for a specific account and transaction.""" + """ + Set an incorrect balance value for a specific account and transaction. + """ return _modify_field_value( address, tx_index, "balance_changes", BalBalanceChange, balance, "post_balance" ) @@ -163,7 +168,10 @@ def modify_balance( def modify_storage( address: Address, tx_index: int, slot: int, value: int ) -> Callable[[BlockAccessList], BlockAccessList]: - """Set an incorrect storage value for a specific account, transaction, and slot.""" + """ + Set an incorrect storage value for a specific account, transaction, and + slot. + """ return _modify_field_value( address, tx_index, @@ -227,7 +235,8 @@ def transform(bal: BlockAccessList) -> BlockAccessList: balance_indices[tx2] = True storage_change.tx_index = HexNumber(tx1) - # Note: storage_reads is just a list of StorageKey, no tx_index to swap + # Note: storage_reads is just a list of StorageKey, no tx_index to + # swap # Swap in code changes if new_account.code_changes: diff --git a/src/ethereum_test_types/block_types.py b/src/ethereum_test_types/block_types.py index 268296f49a1..8e7977a3b12 100644 --- a/src/ethereum_test_types/block_types.py +++ b/src/ethereum_test_types/block_types.py @@ -38,7 +38,10 @@ class EnvironmentDefaults: class WithdrawalGeneric(CamelModel, Generic[NumberBoundTypeVar]): - """Withdrawal generic type, used as a parent class for `Withdrawal` and `FixtureWithdrawal`.""" + """ + Withdrawal generic type, used as a parent class for `Withdrawal` and + `FixtureWithdrawal`. + """ index: NumberBoundTypeVar validator_index: NumberBoundTypeVar @@ -47,8 +50,8 @@ class WithdrawalGeneric(CamelModel, Generic[NumberBoundTypeVar]): def to_serializable_list(self) -> List[Any]: """ - Return list of the withdrawal's attributes in the order they should - be serialized. + Return list of the withdrawal's attributes in the order they should be + serialized. """ return [ Uint(self.index), @@ -98,8 +101,8 @@ class EnvironmentGeneric(CamelModel, Generic[NumberBoundTypeVar]): class Environment(EnvironmentGeneric[ZeroPaddedHexNumber]): """ - Structure used to keep track of the context in which a block - must be executed. + Structure used to keep track of the context in which a block must be + executed. """ blob_gas_used: ZeroPaddedHexNumber | None = Field(None, alias="currentBlobGasUsed") diff --git a/src/ethereum_test_types/chain_config_types.py b/src/ethereum_test_types/chain_config_types.py index a8c7b2e484e..d9ece600f1a 100644 --- a/src/ethereum_test_types/chain_config_types.py +++ b/src/ethereum_test_types/chain_config_types.py @@ -9,7 +9,8 @@ class ChainConfigDefaults: """ Default values for the chain configuration. - Can be modified by modules that import this module and want to override the default values. + Can be modified by modules that import this module and want to override the + default values. """ chain_id: int = 1 diff --git a/src/ethereum_test_types/eof/constants.py b/src/ethereum_test_types/eof/constants.py index fbc6e88a6d1..b4e61705d69 100644 --- a/src/ethereum_test_types/eof/constants.py +++ b/src/ethereum_test_types/eof/constants.py @@ -1,29 +1,24 @@ -""" -EVM Object Format generic constants. -Applicable to all EOF versions. -""" +"""EVM Object Format generic constants. Applicable to all EOF versions.""" EOF_MAGIC = b"\xef\x00" """ + + The second byte found on every EOF formatted contract, which was chosen to avoid clashes with three contracts which were deployed on Mainnet. """ EOF_HEADER_TERMINATOR = b"\x00" -""" -Byte that terminates the header of the EOF format. -""" +"""Byte that terminates the header of the EOF format.""" LATEST_EOF_VERSION = 1 -""" -Latest existing EOF version. -""" +"""Latest existing EOF version.""" VERSION_BYTE_LENGTH = 1 -""" -Length of the version byte. -""" +"""Length of the version byte.""" MAX_RUNTIME_STACK_HEIGHT = 1024 """ -Maximum height of the EVM runtime operand stack. -Exceeding this value during execution will result in the stack overflow exception. -This value applies to both legacy EVM and EOF. + + +Maximum height of the EVM runtime operand stack. Exceeding this value during +execution will result in the stack overflow exception. This value applies to +both legacy EVM and EOF. """ diff --git a/src/ethereum_test_types/eof/v1/__init__.py b/src/ethereum_test_types/eof/v1/__init__.py index 0a7385cad9c..a52f32656a5 100644 --- a/src/ethereum_test_types/eof/v1/__init__.py +++ b/src/ethereum_test_types/eof/v1/__init__.py @@ -1,4 +1,6 @@ -"""EVM Object Format Version 1 Library to generate bytecode for testing purposes.""" +""" +EVM Object Format Version 1 Library to generate bytecode for testing purposes. +""" from dataclasses import dataclass from enum import Enum, IntEnum, auto @@ -56,7 +58,10 @@ class ContainerKind(Enum): def __get_pydantic_core_schema__( source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Call class constructor without info and appends the serialization schema.""" + """ + Call class constructor without info and appends the serialization + schema. + """ return no_info_plain_validator_function( source_type.from_str, serialization=to_string_ser_schema(), @@ -105,67 +110,138 @@ class Section(CopyValidateModel): data: Bytes = Bytes(b"") """ - Data to be contained by this section. - Can be SupportsBytes, another EOF container or any other abstract data. + + + + + + + Data to be contained by this section. Can be SupportsBytes, another EOF + container or any other abstract data. + + + """ custom_size: int = 0 """ - Custom size value to be used in the header. - If unset, the header is built with length of the data. + + + + + + + Custom size value to be used in the header. If unset, the header is built + with length of the data. + + + """ kind: SectionKind | int """ - Kind of section that is represented by this object. - Can be any `int` outside of the values defined by `SectionKind` - for testing purposes. + + + + + + + Kind of section that is represented by this object. Can be any `int` + outside of the values defined by `SectionKind` for testing purposes. + + + """ force_type_listing: bool = False """ + + + + + + Forces this section to appear in the TYPE section at the beginning of the container. + + + """ code_inputs: int = 0 - """ - Data stack items consumed by this code section (function) - """ + """Data stack items consumed by this code section (function)""" code_outputs: int = NON_RETURNING_SECTION """ + + + + + + Data stack items produced by or expected at the end of this code section (function) + + + """ max_stack_increase: int | None = None - """ - Maximum operand stack height increase above the code section inputs. - """ + """Maximum operand stack height increase above the code section inputs.""" max_stack_height: int | None = None - """ - Maximum height data stack reaches during execution of code section. - """ + """Maximum height data stack reaches during execution of code section.""" auto_max_stack_height: bool = False """ + + + + + + Whether to automatically compute the best suggestion for the max_stack_height value for this code section. + + + """ auto_code_inputs_outputs: bool = False """ + + + + + + Whether to automatically compute the best suggestion for the code_inputs, code_outputs values for this code section. + + + """ skip_header_listing: bool = False - """ - Skip section from listing in the header - """ + """Skip section from listing in the header""" skip_body_listing: bool = False - """ - Skip section from listing in the body - """ + """Skip section from listing in the body""" skip_types_body_listing: bool = False """ + + + + + + Skip section from listing in the types body (input, output, stack) bytes + + + """ skip_types_header_listing: bool = False """ - Skip section from listing in the types header (not calculating input, output, stack size) + + + + + + + Skip section from listing in the types header (not calculating input, + output, stack size) + + + """ @cached_property @@ -219,27 +295,27 @@ def type_definition(self) -> bytes: def with_max_stack_height(self, max_stack_height) -> "Section": """ - Create copy of the section with `max_stack_height` set to the - specified value. + Create copy of the section with `max_stack_height` set to the specified + value. """ return self.copy(max_stack_height=max_stack_height) def with_auto_max_stack_height(self) -> "Section": - """Create copy of the section with `auto_max_stack_height` set to True.""" + """ + Create copy of the section with `auto_max_stack_height` set to True. + """ return self.copy(auto_max_stack_height=True) def with_auto_code_inputs_outputs(self) -> "Section": """ - Create copy of the section with `auto_code_inputs_outputs` set to - True. + Create copy of the section with `auto_code_inputs_outputs` set to True. """ return self.copy(auto_code_inputs_outputs=True) @staticmethod def list_header(sections: List["Section"]) -> bytes: """ - Create single code header for all code sections contained in - the list. + Create single code header for all code sections contained in the list. """ # Allow 'types section' to use skip_header_listing flag if sections[0].skip_header_listing: @@ -250,7 +326,8 @@ def list_header(sections: List["Section"]) -> bytes: h = sections[0].kind.to_bytes(HEADER_SECTION_KIND_BYTE_LENGTH, "big") - # Count only those sections that are not marked to be skipped for header calculation + # Count only those sections that are not marked to be skipped for + # header calculation header_registered_sections = 0 for cs in sections: if not cs.skip_header_listing: @@ -258,7 +335,8 @@ def list_header(sections: List["Section"]) -> bytes: h += header_registered_sections.to_bytes(HEADER_SECTION_COUNT_BYTE_LENGTH, "big") for cs in sections: - # If section is marked to skip the header calculation, don't make header for it + # If section is marked to skip the header calculation, don't make + # header for it if cs.skip_header_listing: continue size = cs.custom_size if "custom_size" in cs.model_fields_set else len(cs.data) @@ -307,73 +385,119 @@ class Container(CopyValidateModel): """Class that represents an EOF V1 container.""" name: Optional[str] = None - """ - Name of the container - """ + """Name of the container""" sections: List[Section] = Field(default_factory=list) - """ - List of sections in the container - """ + """List of sections in the container""" magic: Bytes = Bytes(EOF_MAGIC) """ + + + + + + Custom magic value used to override the mandatory EOF value for testing purposes. + + + """ version: Bytes = Bytes(VERSION_NUMBER_BYTES) """ - Custom version value used to override the mandatory EOF V1 value - for testing purposes. + + + + + + + Custom version value used to override the mandatory EOF V1 value for + testing purposes. + + + """ header_terminator: Bytes = Bytes(EOF_HEADER_TERMINATOR) - """ - Bytes used to terminate the header. - """ + """Bytes used to terminate the header.""" extra: Bytes = Bytes(b"") """ - Extra data to be appended at the end of the container, which will - not be considered part of any of the sections, for testing purposes. + + + + + + + Extra data to be appended at the end of the container, which will not be + considered part of any of the sections, for testing purposes. + + + """ auto_type_section: AutoSection = AutoSection.AUTO """ - Automatically generate a `TYPE` section based on the - included `CODE` kind sections. + + + + + + + Automatically generate a `TYPE` section based on the included `CODE` kind + sections. + + + """ auto_data_section: bool = True - """ - Automatically generate a `DATA` section. - """ + """Automatically generate a `DATA` section.""" auto_sort_sections: AutoSection = AutoSection.AUTO """ - Automatically sort sections for the header and body: - Headers: type section first, all code sections, container sections, last - data section(s) - Body: type section first, all code sections, data section(s), last - container sections + + + + + + + Automatically sort sections for the header and body: Headers: type section + first, all code sections, container sections, last data section(s) Body: + type section first, all code sections, data section(s), last container + sections + + + """ skip_join_concurrent_sections_in_header: bool = False - """ - Skip joining concurrent sections in the header (code and container) - """ + """Skip joining concurrent sections in the header (code and container)""" validity_error: EOFExceptionInstanceOrList | str | None = None - """ - Optional error expected for the container. - - TODO: Remove str - """ + """Optional error expected for the container. TODO: Remove str""" kind: ContainerKind = ContainerKind.RUNTIME - """ - Kind type of the container. - """ + """Kind type of the container.""" raw_bytes: Optional[Bytes] = None """ - Optional raw bytes that represent the container. - Used to have a cohesive type among all test cases, even those that do not - resemble a valid EOF V1 container. + + + + + + + Optional raw bytes that represent the container. Used to have a cohesive + type among all test cases, even those that do not resemble a valid EOF V1 + container. + + + """ expected_bytecode: Optional[Bytes] = None """ - Optional raw bytes of the expected constructed bytecode. - This allows confirming that raw EOF and Container() representations are identical. + + + + + + + Optional raw bytes of the expected constructed bytecode. This allows + confirming that raw EOF and Container() representations are identical. + + + """ @cached_property @@ -419,7 +543,8 @@ def bytecode(self) -> bytes: # Add headers if header_sections: - # Join headers of the same kind in a list of lists, only if they are next to each other + # Join headers of the same kind in a list of lists, only if they + # are next to each other concurrent_sections: List[List[Section]] = [[header_sections[0]]] for s in header_sections[1:]: if ( @@ -469,7 +594,9 @@ def Init( # noqa: N802 deploy_container: "Container", initcode_prefix: Optional[Bytecode] = None, ) -> "Container": - """Create simple init container that deploys the specified container.""" + """ + Create simple init container that deploys the specified container. + """ if initcode_prefix is None: initcode_prefix = Bytecode() return cls( @@ -498,8 +625,8 @@ def __len__(self) -> int: def __str__(self) -> str: """ - Return name of the container if available, otherwise the bytecode of the container - as a string. + Return name of the container if available, otherwise the bytecode of + the container as a string. """ if self.name: return self.name @@ -514,13 +641,9 @@ class Initcode(Bytecode): """ name: str = "EOF V1 Initcode" - """ - Name used to identify the initcode. - """ + """Name used to identify the initcode.""" deploy_container: Container - """ - Container to be deployed. - """ + """Container to be deployed.""" @cached_property def init_container(self) -> Container: @@ -539,7 +662,9 @@ def init_container(self) -> Container: @cached_property def bytecode(self) -> bytes: - """Generate an EOF container performs `EOFCREATE` with the specified code.""" + """ + Generate an EOF container performs `EOFCREATE` with the specified code. + """ initcode = Container( sections=[ Section.Code( diff --git a/src/ethereum_test_types/helpers.py b/src/ethereum_test_types/helpers.py index 802adfced2b..4378dc292b3 100644 --- a/src/ethereum_test_types/helpers.py +++ b/src/ethereum_test_types/helpers.py @@ -19,8 +19,8 @@ def ceiling_division(a: int, b: int) -> int: """ - Calculate ceil without using floating point. - Used by many of the EVM's formulas. + Calculate ceil without using floating point. Used by many of the EVM's + formulas. """ return -(a // -b) @@ -34,8 +34,8 @@ def compute_create_address( opcode: Op = Op.CREATE, ) -> Address: """ - Compute address of the resulting contract created using a transaction - or the `CREATE` opcode. + Compute address of the resulting contract created using a transaction or + the `CREATE` opcode. """ if opcode == Op.CREATE: if isinstance(address, EOA): @@ -68,7 +68,10 @@ def compute_create2_address( def compute_eofcreate_address( address: FixedSizeBytesConvertible, salt: FixedSizeBytesConvertible ) -> Address: - """Compute address of the resulting contract created using the `EOFCREATE` opcode.""" + """ + Compute address of the resulting contract created using the `EOFCREATE` + opcode. + """ hash_bytes = Bytes(b"\xff" + b"\x00" * 12 + Address(address) + Hash(salt)).keccak256() return Address(hash_bytes[-20:]) @@ -106,13 +109,14 @@ class TestParameterGroup(BaseModel): def __repr__(self): """ - Generate repr string, intended to be used as a test id, based on the class - name and the values of the non-default optional fields. + Generate repr string, intended to be used as a test id, based on the + class name and the values of the non-default optional fields. """ class_name = self.__class__.__name__ field_strings = [ f"{field}_{value}" - # Include the field only if it is not optional or not set to its default value + # Include the field only if it is not optional or not set to its + # default value for field, value in self.model_dump(exclude_defaults=True, exclude_unset=True).items() ] diff --git a/src/ethereum_test_types/request_types.py b/src/ethereum_test_types/request_types.py index e56ed231484..298055cddbc 100644 --- a/src/ethereum_test_types/request_types.py +++ b/src/ethereum_test_types/request_types.py @@ -30,26 +30,21 @@ class DepositRequest(RequestBase, CamelModel): """Deposit Request type.""" pubkey: BLSPublicKey - """ - The public key of the beacon chain validator. - """ + """The public key of the beacon chain validator.""" withdrawal_credentials: Hash - """ - The withdrawal credentials of the beacon chain validator. - """ + """The withdrawal credentials of the beacon chain validator.""" amount: HexNumber - """ - The amount in gwei of the deposit. - """ + """The amount in gwei of the deposit.""" signature: BLSSignature """ - The signature of the deposit using the validator's private key that matches the - `pubkey`. + + + The signature of the deposit using the validator's private key that matches + the `pubkey`. + """ index: HexNumber - """ - The index of the deposit. - """ + """The index of the deposit.""" type: ClassVar[int] = 0 @@ -69,16 +64,22 @@ class WithdrawalRequest(RequestBase, CamelModel): source_address: Address = Address(0) """ - The address of the execution layer account that made the withdrawal request. + + + The address of the execution layer account that made the withdrawal + request. + """ validator_pubkey: BLSPublicKey """ - The current public key of the validator as it currently is in the beacon state. + + + The current public key of the validator as it currently is in the beacon + state. + """ amount: HexNumber - """ - The amount in gwei to be withdrawn on the beacon chain. - """ + """The amount in gwei to be withdrawn on the beacon chain.""" type: ClassVar[int] = 1 @@ -96,15 +97,27 @@ class ConsolidationRequest(RequestBase, CamelModel): source_address: Address = Address(0) """ - The address of the execution layer account that made the consolidation request. + + + The address of the execution layer account that made the consolidation + request. + """ source_pubkey: BLSPublicKey """ - The public key of the source validator as it currently is in the beacon state. + + + The public key of the source validator as it currently is in the beacon + state. + """ target_pubkey: BLSPublicKey """ - The public key of the target validator as it currently is in the beacon state. + + + The public key of the target validator as it currently is in the beacon + state. + """ type: ClassVar[int] = 2 diff --git a/src/ethereum_test_types/tests/test_blob_types.py b/src/ethereum_test_types/tests/test_blob_types.py index 4aefc61a912..26448b80ecb 100644 --- a/src/ethereum_test_types/tests/test_blob_types.py +++ b/src/ethereum_test_types/tests/test_blob_types.py @@ -24,14 +24,14 @@ def increment_counter(timeout: float = 10): """ Increment counter in file, creating if doesn't exist. - This is needed because we require the unit test 'test_transition_fork_blobs' to run - at the end without having to include another dependency for ordering tests. - That test has to run at the end because it assumes that no json blobs not created - by itself are created while it is running. - - The hardcoded counter value in the test above has to be updated if any new blob_related - unit tests that create json blobs are added in the future. - + This is needed because we require the unit test + 'test_transition_fork_blobs' to run at the end without having to include + another dependency for ordering tests. That test has to run at the end + because it assumes that no json blobs not created by itself are created + while it is running. + + The hardcoded counter value in the test above has to be updated if any new + blob_related unit tests that create json blobs are added in the future. """ file_path = CACHED_BLOBS_DIRECTORY / "blob_unit_test_counter.txt" lock_file = file_path.with_suffix(".lock") @@ -62,7 +62,8 @@ def wait_until_counter_reached(target: int, poll_interval: float = 0.1): try: current_value = int(file_path.read_text().strip()) if current_value == target: - # file_path.unlink() # get rid to effectively reset counter to 0 + # file_path.unlink() # get rid to effectively reset + # counter to 0 return current_value elif current_value > target: pytest.fail( @@ -86,8 +87,8 @@ def test_blob_creation_and_writing_and_reading( fork, ): # noqa: F811 """ - Generates blobs for different forks and ensures writing to file - and reading from file works as expected. + Generates blobs for different forks and ensures writing to file and reading + from file works as expected. """ timestamp = 100 b = Blob.from_fork(fork=fork, seed=seed, timestamp=timestamp) @@ -145,15 +146,20 @@ def test_transition_fork_blobs( fork, timestamp, ): - """Generates blobs for transition forks (time 14999 is old fork, time 15000 is new fork).""" - # line below guarantees that this test runs only after the other blob unit tests are done + """ + Generates blobs for transition forks (time 14999 is old fork, time 15000 is + new fork). + """ + # line below guarantees that this test runs only after the other blob unit + # tests are done wait_until_counter_reached(21) clear_blob_cache(CACHED_BLOBS_DIRECTORY) print(f"Original fork: {fork}, Timestamp: {timestamp}") pre_transition_fork = fork.transitions_from() - post_transition_fork_at_15k = fork.transitions_to() # only reached if timestamp >= 15000 + post_transition_fork_at_15k = fork.transitions_to() # only reached if + # timestamp >= 15000 if not pre_transition_fork.supports_blobs() and timestamp < 15000: print( @@ -178,6 +184,7 @@ def test_transition_fork_blobs( f"transitioned to {post_transition_fork_at_15k.name()} but is still at {b.fork.name()}" ) - # delete counter at last iteration (otherwise re-running all unit tests will fail) + # delete counter at last iteration (otherwise re-running all unit tests + # will fail) if timestamp == 15_000 and pre_transition_fork == Prague: (CACHED_BLOBS_DIRECTORY / "blob_unit_test_counter.txt").unlink() diff --git a/src/ethereum_test_types/tests/test_block_access_lists.py b/src/ethereum_test_types/tests/test_block_access_lists.py index e8a36d73213..9174202605c 100644 --- a/src/ethereum_test_types/tests/test_block_access_lists.py +++ b/src/ethereum_test_types/tests/test_block_access_lists.py @@ -143,7 +143,8 @@ def test_partial_validation(): account_expectations={ alice: BalAccountExpectation( nonce_changes=[BalNonceChange(tx_index=1, post_nonce=1)], - # balance_changes and storage_reads not set and won't be validated + # balance_changes and storage_reads not set and won't be + # validated ), } ) @@ -338,8 +339,8 @@ def test_expected_addresses_auto_sorted(): """ Test that expected addresses are automatically sorted before comparison. - The BAL *Expectation address order should not matter for the dict. - We DO, however, validate that the actual BAL (from t8n) is sorted correctly. + The BAL *Expectation address order should not matter for the dict. We DO, + however, validate that the actual BAL (from t8n) is sorted correctly. """ alice = Address(0xA) bob = Address(0xB) diff --git a/src/ethereum_test_types/tests/test_eof_v1.py b/src/ethereum_test_types/tests/test_eof_v1.py index 21c1b8b196b..1c454ab870f 100644 --- a/src/ethereum_test_types/tests/test_eof_v1.py +++ b/src/ethereum_test_types/tests/test_eof_v1.py @@ -867,7 +867,8 @@ def remove_comments_from_string(input_string): # Find the index of the first '#' character comment_start = line.find("#") - # If a '#' is found, slice up to that point; otherwise, take the whole line + # If a '#' is found, slice up to that point; otherwise, take the whole + # line if comment_start != -1: cleaned_line = line[:comment_start].rstrip() else: diff --git a/src/ethereum_test_types/tests/test_post_alloc.py b/src/ethereum_test_types/tests/test_post_alloc.py index c9639b7e543..45111760fc7 100644 --- a/src/ethereum_test_types/tests/test_post_alloc.py +++ b/src/ethereum_test_types/tests/test_post_alloc.py @@ -10,13 +10,17 @@ @pytest.fixture() def post(request: pytest.FixtureRequest) -> Alloc: - """Post state: Set from the test's indirectly parametrized `post` parameter.""" + """ + Post state: Set from the test's indirectly parametrized `post` parameter. + """ return Alloc.model_validate(request.param) @pytest.fixture() def alloc(request: pytest.FixtureRequest) -> Alloc: - """Alloc state: Set from the test's indirectly parametrized `alloc` parameter.""" + """ + Alloc state: Set from the test's indirectly parametrized `alloc` parameter. + """ return Alloc.model_validate(request.param) diff --git a/src/ethereum_test_types/transaction_types.py b/src/ethereum_test_types/transaction_types.py index 4ffe706bb02..4d798801248 100644 --- a/src/ethereum_test_types/transaction_types.py +++ b/src/ethereum_test_types/transaction_types.py @@ -81,7 +81,8 @@ class AuthorizationTupleGeneric(CamelModel, Generic[NumberBoundTypeVar], Signabl def get_rlp_signing_prefix(self) -> bytes: """ - Return a prefix that has to be appended to the serialized signing object. + Return a prefix that has to be appended to the serialized signing + object. By default, an empty string is returned. """ @@ -107,7 +108,10 @@ class AuthorizationTuple(AuthorizationTupleGeneric[HexNumber]): secret_key: Hash | None = None def model_post_init(self, __context: Any) -> None: - """Automatically signs the authorization tuple if a secret key or sender are provided.""" + """ + Automatically signs the authorization tuple if a secret key or sender + are provided. + """ super().model_post_init(__context) self.sign() @@ -198,7 +202,9 @@ class TransactionValidateToAsEmptyString(CamelModel): @model_validator(mode="before") @classmethod def validate_to_as_empty_string(cls, data: Any) -> Any: - """If the `to` field is an empty string, set the model value to None.""" + """ + If the `to` field is an empty string, set the model value to None. + """ if ( isinstance(data, dict) and "to" in data @@ -210,11 +216,16 @@ def validate_to_as_empty_string(cls, data: Any) -> Any: class TransactionFixtureConverter(TransactionValidateToAsEmptyString): - """Handler for serializing and validating the `to` field as an empty string.""" + """ + Handler for serializing and validating the `to` field as an empty string. + """ @model_serializer(mode="wrap", when_used="json-unless-none") def serialize_to_as_empty_string(self, serializer): - """Serialize the `to` field as the empty string if the model value is None.""" + """ + Serialize the `to` field as the empty string if the model value is + None. + """ default = serializer(self) if default is not None and "to" not in default: default["to"] = "" @@ -222,16 +233,18 @@ def serialize_to_as_empty_string(self, serializer): class TransactionTransitionToolConverter(TransactionValidateToAsEmptyString): - """Handler for serializing and validating the `to` field as an empty string.""" + """ + Handler for serializing and validating the `to` field as an empty string. + """ @model_serializer(mode="wrap", when_used="json-unless-none") def serialize_to_as_none(self, serializer): """ Serialize the `to` field as `None` if the model value is None. - This is required as we use `exclude_none=True` when serializing, but the - t8n tool explicitly requires a value of `None` (respectively null), for - if the `to` field should be unset (contract creation). + This is required as we use `exclude_none=True` when serializing, but + the t8n tool explicitly requires a value of `None` (respectively null), + for if the `to` field should be unset (contract creation). """ default = serializer(self) if default is not None and "to" not in default: @@ -250,8 +263,8 @@ class TransactionTestMetadata(CamelModel): def to_json(self) -> str: """ - Convert the transaction metadata into json string for it to be embedded in the - request id. + Convert the transaction metadata into json string for it to be embedded + in the request id. """ return self.model_dump_json(exclude_none=True, by_alias=True) @@ -291,8 +304,8 @@ def __str__(self): class InvalidSignaturePrivateKeyError(Exception): """ - Transaction describes both the signature and private key of - source account. + Transaction describes both the signature and private key of source + account. """ def __str__(self): @@ -522,8 +535,8 @@ def with_signature_and_sender(self, *, keep_secret_key: bool = False) -> "Transa def get_rlp_signing_fields(self) -> List[str]: """ - Return the list of values included in the envelope used for signing depending on - the transaction type. + Return the list of values included in the envelope used for signing + depending on the transaction type. """ field_list: List[str] if self.ty == 6: @@ -611,8 +624,8 @@ def get_rlp_signing_fields(self) -> List[str]: def get_rlp_fields(self) -> List[str]: """ - Return the list of values included in the list used for rlp encoding depending on - the transaction type. + Return the list of values included in the list used for rlp encoding + depending on the transaction type. """ fields = self.get_rlp_signing_fields() if self.ty == 0 and self.protected: @@ -621,8 +634,8 @@ def get_rlp_fields(self) -> List[str]: def get_rlp_prefix(self) -> bytes: """ - Return the transaction type as bytes to be appended at the beginning of the - serialized transaction if type is not 0. + Return the transaction type as bytes to be appended at the beginning of + the serialized transaction if type is not 0. """ if self.ty > 0: return bytes([self.ty]) @@ -630,8 +643,8 @@ def get_rlp_prefix(self) -> bytes: def get_rlp_signing_prefix(self) -> bytes: """ - Return the transaction type as bytes to be appended at the beginning of the - serialized transaction signing envelope if type is not 0. + Return the transaction type as bytes to be appended at the beginning of + the serialized transaction signing envelope if type is not 0. """ if self.ty > 0: return bytes([self.ty]) @@ -650,7 +663,10 @@ def hash(self) -> Hash: @cached_property def serializable_list(self) -> Any: - """Return list of values included in the transaction as a serializable object.""" + """ + Return list of values included in the transaction as a serializable + object. + """ return self.rlp() if self.ty > 0 else self.to_list(signing=False) @staticmethod @@ -663,7 +679,9 @@ def list_root(input_txs: List["Transaction"]) -> Hash: @staticmethod def list_blob_versioned_hashes(input_txs: List["Transaction"]) -> List[Hash]: - """Get list of ordered blob versioned hashes from a list of transactions.""" + """ + Get list of ordered blob versioned hashes from a list of transactions. + """ return [ blob_versioned_hash for tx in input_txs @@ -687,11 +705,11 @@ class NetworkWrappedTransaction(CamelModel, RLPSerializable): Network wrapped transaction as defined in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#networking). - < Osaka: - rlp([tx_payload_body, blobs, commitments, proofs]) + < Osaka: rlp([tx_payload_body, blobs, commitments, + proofs]) - >= Osaka: - rlp([tx_payload_body, wrapper_version, blobs, commitments, cell_proofs]) + >= Osaka: rlp([tx_payload_body, wrapper_version, blobs, commitments, + cell_proofs]) """ tx: Transaction @@ -740,15 +758,18 @@ def cell_proofs(self) -> Sequence[Bytes] | None: def get_rlp_fields(self) -> List[str]: """ - Return an ordered list of field names to be included in RLP serialization. + Return an ordered list of field names to be included in RLP + serialization. Function can be overridden to customize the logic to return the fields. By default, rlp_fields class variable is used. - The list can be nested list up to one extra level to represent nested fields. + The list can be nested list up to one extra level to represent nested + fields. """ - # only put a wrapper_version field for >=osaka (value 1), otherwise omit field + # only put a wrapper_version field for >=osaka (value 1), otherwise + # omit field wrapper = [] if self.wrapper_version is not None: wrapper = ["wrapper_version"] @@ -761,11 +782,11 @@ def get_rlp_fields(self) -> List[str]: if self.cell_proofs is not None: rlp_cell_proofs = ["cell_proofs"] - rlp_fields: List[ - str - ] = [ # structure explained in https://eips.ethereum.org/EIPS/eip-7594#Networking + rlp_fields: List[str] = [ # structure explained in + # https://eips.ethereum.org/EIPS/eip-7594#Networking "tx", # tx_payload_body - *wrapper, # wrapper_version, which is always 1 for osaka (was non-existing before) + *wrapper, # wrapper_version, which is always 1 for osaka (was non- + # existing before) "blobs", # Blob.data "commitments", *rlp_proofs, @@ -782,8 +803,8 @@ def get_rlp_fields(self) -> List[str]: def get_rlp_prefix(self) -> bytes: """ - Return the transaction type as bytes to be appended at the beginning of the - serialized transaction if type is not 0. + Return the transaction type as bytes to be appended at the beginning of + the serialized transaction if type is not 0. """ if self.tx.ty > 0: return bytes([self.tx.ty]) diff --git a/src/ethereum_test_types/trie.py b/src/ethereum_test_types/trie.py index 8c97e519568..171f3daff38 100644 --- a/src/ethereum_test_types/trie.py +++ b/src/ethereum_test_types/trie.py @@ -58,17 +58,11 @@ def encode_account(raw_account_data: FrontierAccount, storage_root: Bytes) -> By # note: an empty trie (regardless of whether it is secured) has root: -# -# keccak256(RLP(b'')) -# == -# 56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421 # noqa: E501,SC10 -# +# keccak256(RLP(b'')) == +# 56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421 # also: -# -# keccak256(RLP(())) -# == -# 1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347 # noqa: E501,SC10 -# +# keccak256(RLP(())) == +# 1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347 # which is the sha3Uncles hash in block header with no uncles EMPTY_TRIE_ROOT = Bytes32( bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") @@ -138,8 +132,8 @@ class BranchNode: def encode_internal_node(node: Optional[InternalNode]) -> Extended: """ Encode a Merkle Trie node into its RLP form. The RLP will then be - serialized into a `Bytes` and hashed unless it is less that 32 bytes - when serialized. + serialized into a `Bytes` and hashed unless it is less that 32 bytes when + serialized. This function also accepts `None`, representing the absence of a node, which is encoded to `b""`. @@ -211,7 +205,6 @@ def trie_set(trie: Trie[K, V], key: K, value: V) -> None: This method deletes the key if `value == trie.default`, because the Merkle Trie represents the default value by omitting it from the trie. - """ if value == trie.default: if key in trie._data: @@ -225,7 +218,6 @@ def trie_get(trie: Trie[K, V], key: K) -> V: Get an item from the Merkle Trie. This method returns `trie.default` if the key is missing. - """ return trie._data.get(key, trie.default) @@ -248,10 +240,15 @@ def nibble_list_to_compact(x: Bytes, is_leaf: bool) -> Bytes: Highest nibble:: - +---+---+----------+--------+ - | _ | _ | is_leaf | parity | - +---+---+----------+--------+ - 3 2 1 0 + +---+---+----------+--------+ | _ | _ | is_leaf | parity | + +---+---+----------+--------+ 3 2 1 0 + + + + + + + The lowest bit of the nibble encodes the parity of the length of the @@ -274,7 +271,9 @@ def nibble_list_to_compact(x: Bytes, is_leaf: bool) -> Bytes: def bytes_to_nibble_list(bytes_: Bytes) -> Bytes: - """Convert a `Bytes` into to a sequence of nibbles (bytes with value < 16).""" + """ + Convert a `Bytes` into to a sequence of nibbles (bytes with value < 16). + """ nibble_list = bytearray(2 * len(bytes_)) for byte_index, byte in enumerate(bytes_): nibble_list[byte_index * 2] = (byte & 0xF0) >> 4 diff --git a/src/ethereum_test_vm/bytecode.py b/src/ethereum_test_vm/bytecode.py index 5eea5b0cce3..a0298f01df0 100644 --- a/src/ethereum_test_vm/bytecode.py +++ b/src/ethereum_test_vm/bytecode.py @@ -16,17 +16,15 @@ class Bytecode: """ Base class to represent EVM bytecode. - Stack calculations are automatically done after an addition operation between two bytecode - objects. The stack height is not guaranteed to be correct, so the user must take this into - consideration. - - Parameters - ---------- - - popped_stack_items: number of items the bytecode pops from the stack - - pushed_stack_items: number of items the bytecode pushes to the stack - - min_stack_height: minimum stack height required by the bytecode - - max_stack_height: maximum stack height reached by the bytecode - + Stack calculations are automatically done after an addition operation + between two bytecode objects. The stack height is not guaranteed to be + correct, so the user must take this into consideration. + + Parameters ---------- - popped_stack_items: number of items the bytecode + pops from the stack - pushed_stack_items: number of items the bytecode + pushes to the stack - min_stack_height: minimum stack height required by + the bytecode - max_stack_height: maximum stack height reached by the + bytecode """ _name_: str = "" @@ -63,8 +61,8 @@ def __new__( return instance if isinstance(bytes_or_byte_code_base, Bytecode): - # Required because Enum class calls the base class with the instantiated object as - # parameter. + # Required because Enum class calls the base class with the + # instantiated object as parameter. obj = super().__new__(cls) obj._bytes_ = bytes_or_byte_code_base._bytes_ obj.popped_stack_items = bytes_or_byte_code_base.popped_stack_items @@ -112,10 +110,8 @@ def __eq__(self, other): """ Allow comparison between Bytecode instances and bytes objects. - Raises: - - NotImplementedError: if the comparison is not between an Bytecode - or a bytes object. - + Raises: - NotImplementedError: if the comparison is not between an + Bytecode or a bytes object. """ if isinstance(other, Bytecode): return ( @@ -142,7 +138,9 @@ def __hash__(self): ) def __add__(self, other: "Bytecode | bytes | int | None") -> "Bytecode": - """Concatenate the bytecode representation with another bytecode object.""" + """ + Concatenate the bytecode representation with another bytecode object. + """ if other is None or (isinstance(other, int) and other == 0): # Edge case for sum() function return self @@ -160,33 +158,40 @@ def __add__(self, other: "Bytecode | bytes | int | None") -> "Bytecode": b_pop, b_push = other.popped_stack_items, other.pushed_stack_items b_min, b_max = other.min_stack_height, other.max_stack_height - # NOTE: "_pop" is understood as the number of elements required by an instruction or - # bytecode to be popped off the stack before it starts returning (pushing). + # NOTE: "_pop" is understood as the number of elements required by an + # instruction or bytecode to be popped off the stack before it starts + # returning (pushing). - # Auxiliary variables representing "stages" of the execution of `c = a + b` bytecode: - # Assume starting point 0 as reference: + # Auxiliary variables representing "stages" of the execution of `c = a + # + b` bytecode: Assume starting point 0 as reference: a_start = 0 - # A (potentially) pops some elements and reaches its "bottom", might be negative: + # A (potentially) pops some elements and reaches its "bottom", might be + # negative: a_bottom = a_start - a_pop - # After this A pushes some elements, then B pops and reaches its "bottom": + # After this A pushes some elements, then B pops and reaches its + # "bottom": b_bottom = a_bottom + a_push - b_pop # C's bottom is either at the bottom of A or B: c_bottom = min(a_bottom, b_bottom) if c_bottom == a_bottom: - # C pops the same as A to reach its bottom, then the rest of A and B are C's "push" + # C pops the same as A to reach its bottom, then the rest of A and + # B are C's "push" c_pop = a_pop c_push = a_push - b_pop + b_push else: - # A and B are C's "pop" to reach its bottom, then pushes the same as B + # A and B are C's "pop" to reach its bottom, then pushes the same + # as B c_pop = a_pop - a_push + b_pop c_push = b_push - # C's minimum required stack is either A's or B's shifted by the net stack balance of A + # C's minimum required stack is either A's or B's shifted by the net + # stack balance of A c_min = max(a_min, b_min + a_pop - a_push) - # C starts from c_min, then reaches max either in the spot where A reached a_max or in the - # spot where B reached b_max, after A had completed. + # C starts from c_min, then reaches max either in the spot where A + # reached a_max or in the spot where B reached b_max, after A had + # completed. c_max = max(c_min + a_max - a_min, c_min - a_pop + a_push + b_max - b_min) return Bytecode( @@ -199,7 +204,9 @@ def __add__(self, other: "Bytecode | bytes | int | None") -> "Bytecode": ) def __radd__(self, other: "Bytecode | int | None") -> "Bytecode": - """Concatenate the opcode byte representation with another bytes object.""" + """ + Concatenate the opcode byte representation with another bytes object. + """ if other is None or (isinstance(other, int) and other == 0): # Edge case for sum() function return self @@ -207,7 +214,9 @@ def __radd__(self, other: "Bytecode | int | None") -> "Bytecode": return other.__add__(self) def __mul__(self, other: int) -> "Bytecode": - """Concatenate another bytes object with the opcode byte representation.""" + """ + Concatenate another bytes object with the opcode byte representation. + """ if other < 0: raise ValueError("Cannot multiply by a negative number") if other == 0: @@ -218,7 +227,10 @@ def __mul__(self, other: int) -> "Bytecode": return output def hex(self) -> str: - """Return the hexadecimal representation of the opcode byte representation.""" + """ + Return the hexadecimal representation of the opcode byte + representation. + """ return bytes(self).hex() def keccak256(self) -> Hash: diff --git a/src/ethereum_test_vm/evm_types.py b/src/ethereum_test_vm/evm_types.py index bb7fe296dc6..992f580e89b 100644 --- a/src/ethereum_test_vm/evm_types.py +++ b/src/ethereum_test_vm/evm_types.py @@ -4,7 +4,9 @@ class EVMCodeType(str, Enum): - """Enum representing the type of EVM code that is supported in a given fork.""" + """ + Enum representing the type of EVM code that is supported in a given fork. + """ LEGACY = "legacy" EOF_V1 = "eof_v1" diff --git a/src/ethereum_test_vm/opcodes.py b/src/ethereum_test_vm/opcodes.py index 5f2aef894ba..126344abc2e 100644 --- a/src/ethereum_test_vm/opcodes.py +++ b/src/ethereum_test_vm/opcodes.py @@ -1,10 +1,11 @@ """ Ethereum Virtual Machine opcode definitions. -Acknowledgments: The individual opcode documentation below is due to the work by -[smlXL](https://github.com/smlxl) on [evm.codes](https://www.evm.codes/), available as open -source [github.com/smlxl/evm.codes](https://github.com/smlxl/evm.codes) - thank you! And thanks -to @ThreeHrSleep for integrating it in the docstrings. +Acknowledgments: The individual opcode documentation below is due to the work +by [smlXL](https://github.com/smlxl) on [evm.codes](https://www.evm.codes/), +available as open source +[github.com/smlxl/evm.codes](https://github.com/smlxl/evm.codes) - thank you! +And thanks to @ThreeHrSleep for integrating it in the docstrings. """ from enum import Enum @@ -18,7 +19,8 @@ def _get_int_size(n: int) -> int: """Return size of an integer in bytes.""" if n < 0: - # Negative numbers in the EVM are represented as two's complement of 32 bytes + # Negative numbers in the EVM are represented as two's complement of 32 + # bytes return 32 byte_count = 0 while n: @@ -45,7 +47,8 @@ def _stack_argument_to_bytecode( if data_size > 32: raise ValueError("Opcode stack data must be less than 32 bytes") elif data_size == 0: - # Pushing 0 is done with the PUSH1 opcode for compatibility reasons. + # Pushing 0 is done with the PUSH1 opcode for compatibility + # reasons. data_size = 1 arg = arg.to_bytes( length=data_size, @@ -55,7 +58,8 @@ def _stack_argument_to_bytecode( else: arg = to_bytes(arg).lstrip(b"\0") # type: ignore if arg == b"": - # Pushing 0 is done with the PUSH1 opcode for compatibility reasons. + # Pushing 0 is done with the PUSH1 opcode for compatibility + # reasons. arg = b"\x00" data_size = len(arg) @@ -67,21 +71,18 @@ def _stack_argument_to_bytecode( class Opcode(Bytecode): """ - Represents a single Opcode instruction in the EVM, with extra metadata useful to parametrize - tests. - - Parameters - ---------- - - data_portion_length: number of bytes after the opcode in the bytecode - that represent data - - data_portion_formatter: function to format the data portion of the opcode, if any - - stack_properties_modifier: function to modify the stack properties of the opcode after the - data portion has been processed - - kwargs: list of keyword arguments that can be passed to the opcode, in the order they are - meant to be placed in the stack - - kwargs_defaults: default values for the keyword arguments if any, otherwise 0 - - unchecked_stack: whether the bytecode should ignore stack checks when being called + Represents a single Opcode instruction in the EVM, with extra metadata + useful to parametrize tests. + Parameters ---------- - data_portion_length: number of bytes after the + opcode in the bytecode that represent data - data_portion_formatter: + function to format the data portion of the opcode, if any - + stack_properties_modifier: function to modify the stack properties of the + opcode after the data portion has been processed - kwargs: list of keyword + arguments that can be passed to the opcode, in the order they are meant to + be placed in the stack - kwargs_defaults: default values for the keyword + arguments if any, otherwise 0 - unchecked_stack: whether the bytecode + should ignore stack checks when being called """ data_portion_length: int @@ -111,8 +112,8 @@ def __new__( if kwargs_defaults is None: kwargs_defaults = {} if type(opcode_or_byte) is Opcode: - # Required because Enum class calls the base class with the instantiated object as - # parameter. + # Required because Enum class calls the base class with the + # instantiated object as parameter. return opcode_or_byte elif isinstance(opcode_or_byte, int) or isinstance(opcode_or_byte, bytes): obj_bytes = ( @@ -147,8 +148,8 @@ def __new__( def __getitem__(self, *args: "int | bytes | str | Iterable[int]") -> "Opcode": """ - Initialize a new instance of the opcode with the data portion set, and also clear - the data portion variables to avoid reusing them. + Initialize a new instance of the opcode with the data portion set, and + also clear the data portion variables to avoid reusing them. """ if self.data_portion_formatter is None and self.data_portion_length == 0: raise ValueError("Opcode does not have a data portion or has already been set") @@ -160,8 +161,8 @@ def __getitem__(self, *args: "int | bytes | str | Iterable[int]") -> "Opcode": else: data_portion = self.data_portion_formatter(*args) elif self.data_portion_length > 0: - # For opcodes with a data portion, the first argument is the data and the rest of the - # arguments form the stack. + # For opcodes with a data portion, the first argument is the data + # and the rest of the arguments form the stack. assert len(args) == 1, "Opcode with data portion requires exactly one argument" data = args[0] if isinstance(data, bytes) or isinstance(data, SupportsBytes) or isinstance(data, str): @@ -222,26 +223,28 @@ def __call__( **kwargs: "int | bytes | str | Opcode | Bytecode", ) -> Bytecode: """ - Make all opcode instances callable to return formatted bytecode, which constitutes a data - portion, that is located after the opcode byte, and pre-opcode bytecode, which is normally - used to set up the stack. + Make all opcode instances callable to return formatted bytecode, which + constitutes a data portion, that is located after the opcode byte, and + pre-opcode bytecode, which is normally used to set up the stack. - This useful to automatically format, e.g., call opcodes and their stack arguments as - `Opcodes.CALL(Opcodes.GAS, 0x1234, 0x0, 0x0, 0x0, 0x0, 0x0)`. + This useful to automatically format, e.g., call opcodes and their stack + arguments as `Opcodes.CALL(Opcodes.GAS, 0x1234, 0x0, 0x0, 0x0, 0x0, + 0x0)`. - Data sign is automatically detected but for this reason the range of the input must be: - `[-2^(data_portion_bits-1), 2^(data_portion_bits)]` where: `data_portion_bits == - data_portion_length * 8` + Data sign is automatically detected but for this reason the range of + the input must be: `[-2^(data_portion_bits-1), 2^(data_portion_bits)]` + where: `data_portion_bits == data_portion_length * 8` - For the stack, the arguments are set up in the opposite order they are given, so the first - argument is the last item pushed to the stack. + For the stack, the arguments are set up in the opposite order they are + given, so the first argument is the last item pushed to the stack. - The resulting stack arrangement does not take into account opcode stack element - consumption, so the stack height is not guaranteed to be correct and the user must take - this into consideration. + The resulting stack arrangement does not take into account opcode stack + element consumption, so the stack height is not guaranteed to be + correct and the user must take this into consideration. - Integers can also be used as stack elements, in which case they are automatically converted - to PUSH operations, and negative numbers always use a PUSH32 operation. + Integers can also be used as stack elements, in which case they are + automatically converted to PUSH operations, and negative numbers always + use a PUSH32 operation. Hex-strings will be automatically converted to bytes. """ @@ -317,8 +320,8 @@ def __new__( if macro_or_bytes is None: macro_or_bytes = Bytecode() if isinstance(macro_or_bytes, Macro): - # Required because Enum class calls the base class with the instantiated object as - # parameter. + # Required because Enum class calls the base class with the + # instantiated object as parameter. return macro_or_bytes else: instance = super().__new__(cls, macro_or_bytes) @@ -342,9 +345,9 @@ def __call__(self, *args_t: OpcodeCallArg, **kwargs) -> Bytecode: RJUMPV_BRANCH_OFFSET_BYTE_LENGTH = 2 -# TODO: Allowing Iterable here is a hacky way to support `range`, because Python 3.11+ will allow -# `Op.RJUMPV[*range(5)]`. This is a temporary solution until Python 3.11+ is the minimum required -# version. +# TODO: Allowing Iterable here is a hacky way to support `range`, because +# Python 3.11+ will allow `Op.RJUMPV[*range(5)]`. This is a temporary solution +# until Python 3.11+ is the minimum required version. def _rjumpv_encoder(*args: int | bytes | Iterable[int]) -> bytes: @@ -419,4672 +422,4257 @@ class Opcodes(Opcode, Enum): Contains deprecated and not yet implemented opcodes. - This enum is !! NOT !! meant to be iterated over by the tests. Instead, create a list with - cherry-picked opcodes from this Enum within the test if iteration is needed. + This enum is !! NOT !! meant to be iterated over by the tests. Instead, + create a list with cherry-picked opcodes from this Enum within the test if + iteration is needed. Do !! NOT !! remove or modify existing opcodes from this list. """ STOP = Opcode(0x00, terminating=True) """ - STOP() - ---- - Description - ---- - Stop execution - Inputs - ---- - - None - Outputs - ---- - - None - Fork - ---- - Frontier - Gas - ---- - 0 - Source: [evm.codes/#00](https://www.evm.codes/#00) - """ + STOP() ---- - ADD = Opcode(0x01, popped_stack_items=2, pushed_stack_items=1) - """ - ADD(a, b) = c - ---- + Description ---- Stop execution + + Inputs ---- - None - Description - ---- - Addition operation + Outputs ---- - None - Inputs - ---- - - a: first integer value to add - - b: second integer value to add + Fork ---- Frontier - Outputs - ---- - - c: integer result of the addition modulo 2**256 + Gas ---- 0 + + Source: [evm.codes/#00](https://www.evm.codes/#00) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#01](https://www.evm.codes/#01) """ - MUL = Opcode(0x02, popped_stack_items=2, pushed_stack_items=1) + ADD = Opcode(0x01, popped_stack_items=2, pushed_stack_items=1) """ - MUL(a, b) = c - ---- - Description - ---- - Multiplication operation - Inputs - ---- - - a: first integer value to multiply - - b: second integer value to multiply - Outputs - ---- - - c: integer result of the multiplication modulo 2**256 - Fork - ---- - Frontier - Gas - ---- - 5 - Source: [evm.codes/#02](https://www.evm.codes/#02) - """ + ADD(a, b) = c ---- - SUB = Opcode(0x03, popped_stack_items=2, pushed_stack_items=1) - """ - SUB(a, b) = c - ---- + Description ---- Addition operation + + Inputs ---- - a: first integer value to add - b: second integer value to + add - Description - ---- - Subtraction operation + Outputs ---- - c: integer result of the addition modulo 2**256 - Inputs - ---- - - a: first integer value - - b: second integer value + Fork ---- Frontier - Outputs - ---- - - c: integer result of the subtraction modulo 2**256 + Gas ---- 3 + + Source: [evm.codes/#01](https://www.evm.codes/#01) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#03](https://www.evm.codes/#03) """ - DIV = Opcode(0x04, popped_stack_items=2, pushed_stack_items=1) + MUL = Opcode(0x02, popped_stack_items=2, pushed_stack_items=1) """ - DIV(a, b) = c - ---- - Description - ---- - Division operation - Inputs - ---- - - a: numerator - - b: denominator (must be non-zero) - Outputs - ---- - - c: integer result of the division - Fork - ---- - Frontier - Gas - ---- - 5 - Source: [evm.codes/#04](https://www.evm.codes/#04) - """ + MUL(a, b) = c ---- - SDIV = Opcode(0x05, popped_stack_items=2, pushed_stack_items=1) - """ - SDIV(a, b) = c - ---- + Description ---- Multiplication operation + + Inputs ---- - a: first integer value to multiply - b: second integer value + to multiply - Description - ---- - Signed division operation + Outputs ---- - c: integer result of the multiplication modulo 2**256 - Inputs - ---- - - a: signed numerator - - b: signed denominator + Fork ---- Frontier - Outputs - ---- - - c: signed integer result of the division. If the denominator is 0, the result will be 0 - ---- + Gas ---- 5 + + Source: [evm.codes/#02](https://www.evm.codes/#02) - Fork - ---- - Frontier - Gas - ---- - 5 - Source: [evm.codes/#05](https://www.evm.codes/#05) """ - MOD = Opcode(0x06, popped_stack_items=2, pushed_stack_items=1) + SUB = Opcode(0x03, popped_stack_items=2, pushed_stack_items=1) """ - MOD(a, b) = c - ---- - Description - ---- - Modulo operation - Inputs - ---- - - a: integer numerator - - b: integer denominator - Outputs - ---- - - a % b: integer result of the integer modulo. If the denominator is 0, the result will be 0 - Fork - ---- - Frontier - Gas - ---- - 5 - Source: [evm.codes/#06](https://www.evm.codes/#06) - """ + SUB(a, b) = c ---- - SMOD = Opcode(0x07, popped_stack_items=2, pushed_stack_items=1) - """ - SMOD(a, b) = c - ---- + Description ---- Subtraction operation + + Inputs ---- - a: first integer value - b: second integer value - Description - ---- - Signed modulo remainder operation + Outputs ---- - c: integer result of the subtraction modulo 2**256 - Inputs - ---- - - a: integer numerator - - b: integer denominator + Fork ---- Frontier - Outputs - ---- - - a % b: integer result of the signed integer modulo. If the denominator is 0, the result will - be 0 + Gas ---- 3 + + Source: [evm.codes/#03](https://www.evm.codes/#03) - Fork - ---- - Frontier - Gas - ---- - 5 - Source: [evm.codes/#07](https://www.evm.codes/#07) """ - ADDMOD = Opcode(0x08, popped_stack_items=3, pushed_stack_items=1) + DIV = Opcode(0x04, popped_stack_items=2, pushed_stack_items=1) """ - ADDMOD(a, b, c) = d - ---- - Description - ---- - Modular addition operation with overflow check - Inputs - ---- - - a: first integer value - - b: second integer value - - c: integer denominator - Outputs - ---- - - (a + b) % N: integer result of the addition followed by a modulo. If the denominator is 0, - the result will be 0 - Fork - ---- - Frontier - Gas - ---- - 8 - Source: [evm.codes/#08](https://www.evm.codes/#08) - """ + DIV(a, b) = c ---- - MULMOD = Opcode(0x09, popped_stack_items=3, pushed_stack_items=1) - """ - MULMOD(a, b, N) = d - ---- + Description ---- Division operation + + Inputs ---- - a: numerator - b: denominator (must be non-zero) - Description - ---- - Modulo multiplication operation + Outputs ---- - c: integer result of the division - Inputs - ---- - - a: first integer value to multiply - - b: second integer value to multiply - - N: integer denominator + Fork ---- Frontier - Outputs - ---- - - (a * b) % N: integer result of the multiplication followed by a modulo. If the denominator - is 0, the result will be 0 + Gas ---- 5 + + Source: [evm.codes/#04](https://www.evm.codes/#04) - Fork - ---- - Frontier - Gas - ---- - 8 - Source: [evm.codes/#09](https://www.evm.codes/#09) """ - EXP = Opcode(0x0A, popped_stack_items=2, pushed_stack_items=1) + SDIV = Opcode(0x05, popped_stack_items=2, pushed_stack_items=1) """ - EXP(a, exponent) = a ** exponent - ---- - Description - ---- - Exponential operation - Inputs - ---- - - a: integer base - - exponent: integer exponent - Outputs - ---- - - a ** exponent: integer result of the exponential operation modulo 2**256 - Fork - ---- - Frontier - Gas - ---- - - static_gas = 10 - - dynamic_gas = 50 * exponent_byte_size - Source: [evm.codes/#0A](https://www.evm.codes/#0A) - """ + SDIV(a, b) = c ---- - SIGNEXTEND = Opcode(0x0B, popped_stack_items=2, pushed_stack_items=1) - """ - SIGNEXTEND(b, x) = y - ---- + Description ---- Signed division operation + + Inputs ---- - a: signed numerator - b: signed denominator - Description - ---- - Sign extension operation + Outputs ---- - c: signed integer result of the division. If the denominator + is 0, the result will be 0 ---- - Inputs - ---- - - b: size in byte - 1 of the integer to sign extend - - x: integer value to sign extend + Fork ---- Frontier - Outputs - ---- - - y: integer result of the sign extend + Gas ---- 5 + + Source: [evm.codes/#05](https://www.evm.codes/#05) - Fork - ---- - Frontier - Gas - ---- - 5 - Source: [evm.codes/#0B](https://www.evm.codes/#0B) """ - LT = Opcode(0x10, popped_stack_items=2, pushed_stack_items=1) + MOD = Opcode(0x06, popped_stack_items=2, pushed_stack_items=1) """ - LT(a, b) = a < b - ---- - Description - ---- - Less-than comparison - Inputs - ---- - - a: left side integer value - - b: right side integer value - Outputs - ---- - - a < b: 1 if the left side is smaller, 0 otherwise - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#10](https://www.evm.codes/#10) - """ + MOD(a, b) = c ---- - GT = Opcode(0x11, popped_stack_items=2, pushed_stack_items=1) - """ - GT(a, b) = a > b - ---- + Description ---- Modulo operation + + Inputs ---- - a: integer numerator - b: integer denominator - Description - ---- - Greater-than comparison + Outputs ---- - a % b: integer result of the integer modulo. If the + denominator is 0, the result will be 0 - Inputs - ---- - - a: left side integer - - b: right side integer + Fork ---- Frontier - Outputs - ---- - - a > b: 1 if the left side is bigger, 0 otherwise + Gas ---- 5 + + Source: [evm.codes/#06](https://www.evm.codes/#06) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#11](https://www.evm.codes/#11) """ - SLT = Opcode(0x12, popped_stack_items=2, pushed_stack_items=1) + SMOD = Opcode(0x07, popped_stack_items=2, pushed_stack_items=1) """ - SLT(a, b) = a < b - ---- - Description - ---- - Signed less-than comparison - Inputs - ---- - - a: left side signed integer - - b: right side signed integer - Outputs - ---- - - a < b: 1 if the left side is smaller, 0 otherwise - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#12](https://www.evm.codes/#12) - """ + SMOD(a, b) = c ---- - SGT = Opcode(0x13, popped_stack_items=2, pushed_stack_items=1) - """ - SGT(a, b) = a > b - ---- + Description ---- Signed modulo remainder operation + + Inputs ---- - a: integer numerator - b: integer denominator - Description - ---- - Signed greater-than comparison + Outputs ---- - a % b: integer result of the signed integer modulo. If the + denominator is 0, the result will be 0 - Inputs - ---- - - a: left side signed integer - - b: right side signed integer + Fork ---- Frontier - Outputs - ---- - - a > b: 1 if the left side is bigger, 0 otherwise + Gas ---- 5 + + Source: [evm.codes/#07](https://www.evm.codes/#07) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#13](https://www.evm.codes/#13) """ - EQ = Opcode(0x14, popped_stack_items=2, pushed_stack_items=1) + ADDMOD = Opcode(0x08, popped_stack_items=3, pushed_stack_items=1) """ - EQ(a, b) = a == b - ---- - Description - ---- - Equality comparison - Inputs - ---- - - a: left side integer - - b: right side integer - Outputs - ---- - - a == b: 1 if the left side is equal to the right side, 0 otherwise - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#14](https://www.evm.codes/#14) - """ + ADDMOD(a, b, c) = d ---- - ISZERO = Opcode(0x15, popped_stack_items=1, pushed_stack_items=1) - """ - ISZERO(a) = a == 0 - ---- + Description ---- Modular addition operation with overflow check + + Inputs ---- - a: first integer value - b: second integer value - c: integer + denominator - Description - ---- - Is-zero comparison + Outputs ---- - (a + b) % N: integer result of the addition followed by a + modulo. If the denominator is 0, the result will be 0 - Inputs - ---- - - a: integer + Fork ---- Frontier - Outputs - ---- - - a == 0: 1 if a is 0, 0 otherwise + Gas ---- 8 + + Source: [evm.codes/#08](https://www.evm.codes/#08) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#15](https://www.evm.codes/#15) """ - AND = Opcode(0x16, popped_stack_items=2, pushed_stack_items=1) + MULMOD = Opcode(0x09, popped_stack_items=3, pushed_stack_items=1) """ - AND(a, b) = a & b - ---- - Description - ---- - Bitwise AND operation - Inputs - ---- - - a: first binary value - - b: second binary value - Outputs - ---- - - a & b: the bitwise AND result - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#16](https://www.evm.codes/#16) - """ + MULMOD(a, b, N) = d ---- - OR = Opcode(0x17, popped_stack_items=2, pushed_stack_items=1) - """ - OR(a, b) = a | b - ---- + Description ---- Modulo multiplication operation + + Inputs ---- - a: first integer value to multiply - b: second integer value + to multiply - N: integer denominator - Description - ---- - Bitwise OR operation + Outputs ---- - (a * b) % N: integer result of the multiplication followed + by a modulo. If the denominator is 0, the result will be 0 - Inputs - ---- - - a: first binary value - - b: second binary value + Fork ---- Frontier - Outputs - ---- - - a | b: the bitwise OR result + Gas ---- 8 + + Source: [evm.codes/#09](https://www.evm.codes/#09) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#17](https://www.evm.codes/#17) """ - XOR = Opcode(0x18, popped_stack_items=2, pushed_stack_items=1) + EXP = Opcode(0x0A, popped_stack_items=2, pushed_stack_items=1) """ - XOR(a, b) = a ^ b - ---- - Description - ---- - Bitwise XOR operation - Inputs - ---- - - a: first binary value - - b: second binary value - Outputs - ---- - - a ^ b: the bitwise XOR result - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#18](https://www.evm.codes/#18) - """ + EXP(a, exponent) = a ** exponent ---- - NOT = Opcode(0x19, popped_stack_items=1, pushed_stack_items=1) - """ - NOT(a) = ~a - ---- + Description ---- Exponential operation + + Inputs ---- - a: integer base - exponent: integer exponent - Description - ---- - Bitwise NOT operation + Outputs ---- - a ** exponent: integer result of the exponential operation + modulo 2**256 - Inputs - ---- - - a: binary value + Fork ---- Frontier - Outputs - ---- - - ~a: the bitwise NOT result + Gas ---- - static_gas = 10 - dynamic_gas = 50 * exponent_byte_size + + Source: [evm.codes/#0A](https://www.evm.codes/#0A) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#19](https://www.evm.codes/#19) """ - BYTE = Opcode(0x1A, popped_stack_items=2, pushed_stack_items=1) + SIGNEXTEND = Opcode(0x0B, popped_stack_items=2, pushed_stack_items=1) """ - BYTE(i, x) = y - ---- - Description - ---- - Extract a byte from the given position in the value - Inputs - ---- - - i: byte offset starting from the most significant byte - - x: 32-byte value - Outputs - ---- - - y: the indicated byte at the least significant position. If the byte offset is out of range, - the result is 0 - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#1A](https://www.evm.codes/#1A) - """ + SIGNEXTEND(b, x) = y ---- - SHL = Opcode(0x1B, popped_stack_items=2, pushed_stack_items=1) - """ - SHL(shift, value) = value << shift - ---- + Description ---- Sign extension operation + + Inputs ---- - b: size in byte - 1 of the integer to sign extend - x: + integer value to sign extend - Description - ---- - Shift left operation + Outputs ---- - y: integer result of the sign extend - Inputs - ---- - - shift: number of bits to shift to the left - - value: 32 bytes to shift + Fork ---- Frontier - Outputs - ---- - - value << shift: the shifted value. If shift is bigger than 255, returns 0 + Gas ---- 5 + + Source: [evm.codes/#0B](https://www.evm.codes/#0B) - Fork - ---- - Constantinople - Gas - ---- - 3 - Source: [evm.codes/#1B](https://www.evm.codes/#1B) """ - SHR = Opcode(0x1C, popped_stack_items=2, pushed_stack_items=1) + LT = Opcode(0x10, popped_stack_items=2, pushed_stack_items=1) """ - SHR(shift, value) = value >> shift - ---- - Description - ---- - Logical shift right operation - Inputs - ---- - - shift: number of bits to shift to the right. - - value: 32 bytes to shift - Outputs - ---- - - value >> shift: the shifted value. If shift is bigger than 255, returns 0 - Fork - ---- - Constantinople - Gas - ---- - 3 - Source: [evm.codes/#1C](https://www.evm.codes/#1C) - """ + LT(a, b) = a < b ---- - SAR = Opcode(0x1D, popped_stack_items=2, pushed_stack_items=1) - """ - SAR(shift, value) = value >> shift - ---- + Description ---- Less-than comparison + + Inputs ---- - a: left side integer value - b: right side integer value - Description - ---- - Arithmetic shift right operation + Outputs ---- - a < b: 1 if the left side is smaller, 0 otherwise - Inputs - ---- - - shift: number of bits to shift to the right - - value: integer to shift + Fork ---- Frontier - Outputs - ---- - - value >> shift: the shifted value + Gas ---- 3 + + Source: [evm.codes/#10](https://www.evm.codes/#10) - Fork - ---- - Constantinople - Gas - ---- - 3 - Source: [evm.codes/#1D](https://www.evm.codes/#1D) """ - CLZ = Opcode(0x1E, popped_stack_items=1, pushed_stack_items=1) + GT = Opcode(0x11, popped_stack_items=2, pushed_stack_items=1) """ - CLZ(value) = count_leading_zeros(value) - ---- - Description - ---- - Counts leading zeros (bitwise). - Inputs - ---- - - value: integer to count zeros on - Outputs - ---- - - zeros: leading zero bits - Fork - ---- - Osaka - Gas - ---- - 3 - Source: [evm.codes/#1E](https://www.evm.codes/#1E) - """ + GT(a, b) = a > b ---- - SHA3 = Opcode(0x20, popped_stack_items=2, pushed_stack_items=1, kwargs=["offset", "size"]) - """ - SHA3(offset, size) = hash - ---- + Description ---- Greater-than comparison + + Inputs ---- - a: left side integer - b: right side integer - Description - ---- - Compute Keccak-256 hash + Outputs ---- - a > b: 1 if the left side is bigger, 0 otherwise - Inputs - ---- - - offset: byte offset in the memory - - size: byte size to read in the memory + Fork ---- Frontier - Outputs - ---- - - hash: Keccak-256 hash of the given data in memory + Gas ---- 3 + + Source: [evm.codes/#11](https://www.evm.codes/#11) - Fork - ---- - Frontier - Gas - ---- - - minimum_word_size = (size + 31) / 32 - - static_gas = 30 - - dynamic_gas = 6 * minimum_word_size + memory_expansion_cost - Source: [evm.codes/#20](https://www.evm.codes/#20) """ - ADDRESS = Opcode(0x30, pushed_stack_items=1) + SLT = Opcode(0x12, popped_stack_items=2, pushed_stack_items=1) """ - ADDRESS() = address - ---- - Description - ---- - Get address of currently executing account - Inputs - ---- - - None - Outputs - ---- - - address: the 20-byte address of the current account - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#30](https://www.evm.codes/#30) - """ + SLT(a, b) = a < b ---- - BALANCE = Opcode(0x31, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) - """ - BALANCE(address) = balance - ---- + Description ---- Signed less-than comparison + + Inputs ---- - a: left side signed integer - b: right side signed integer - Description - ---- - Get the balance of the specified account + Outputs ---- - a < b: 1 if the left side is smaller, 0 otherwise - Inputs - ---- - - address: 20-byte address of the account to check + Fork ---- Frontier - Outputs - ---- - - balance: balance of the given account in wei. Returns 0 if the account doesn't exist + Gas ---- 3 + + Source: [evm.codes/#12](https://www.evm.codes/#12) - Fork - ---- - Frontier - Gas - ---- - - static_gas = 0 - - dynamic_gas = 100 if warm_address, 2600 if cold_address - Source: [evm.codes/#31](https://www.evm.codes/#31) """ - ORIGIN = Opcode(0x32, pushed_stack_items=1) + SGT = Opcode(0x13, popped_stack_items=2, pushed_stack_items=1) """ - ORIGIN() = address - ---- - Description - ---- - Get execution origination address - Inputs - ---- - - None - Outputs - ---- - - address: the 20-byte address of the sender of the transaction. It can only be an account - without code - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#32](https://www.evm.codes/#32) - """ + SGT(a, b) = a > b ---- - CALLER = Opcode(0x33, pushed_stack_items=1) - """ - CALLER() = address - ---- + Description ---- Signed greater-than comparison + + Inputs ---- - a: left side signed integer - b: right side signed integer - Description - ---- - Get caller address + Outputs ---- - a > b: 1 if the left side is bigger, 0 otherwise - Inputs - ---- - - None + Fork ---- Frontier - Outputs - ---- - - address: the 20-byte address of the caller account. This is the account that did the last - call (except delegate call) + Gas ---- 3 + + Source: [evm.codes/#13](https://www.evm.codes/#13) - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#33](https://www.evm.codes/#33) """ - CALLVALUE = Opcode(0x34, pushed_stack_items=1) + EQ = Opcode(0x14, popped_stack_items=2, pushed_stack_items=1) """ - CALLVALUE() = value - ---- - Description - ---- - Get deposited value by the instruction/transaction responsible for this execution - Inputs - ---- - - None - Outputs - ---- - - value: the value of the current call in wei - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#34](https://www.evm.codes/#34) - """ + EQ(a, b) = a == b ---- - CALLDATALOAD = Opcode(0x35, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) - """ - CALLDATALOAD(offset) = data[offset] - ---- + Description ---- Equality comparison + + Inputs ---- - a: left side integer - b: right side integer - Description - ---- - Get input data of current environment + Outputs ---- - a == b: 1 if the left side is equal to the right side, 0 + otherwise - Inputs - ---- - - offset: byte offset in the calldata + Fork ---- Frontier - Outputs - ---- - - data[offset]: 32-byte value starting from the given offset of the calldata. All bytes after - the end of the calldata are set to 0 + Gas ---- 3 + + Source: [evm.codes/#14](https://www.evm.codes/#14) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#35](https://www.evm.codes/#35) """ - CALLDATASIZE = Opcode(0x36, pushed_stack_items=1) + ISZERO = Opcode(0x15, popped_stack_items=1, pushed_stack_items=1) """ - CALLDATASIZE() = size - ---- - Description - ---- - Get size of input data in current environment - Inputs - ---- - - None - Outputs - ---- - - size: byte size of the calldata - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#36](https://www.evm.codes/#36) - """ + ISZERO(a) = a == 0 ---- - CALLDATACOPY = Opcode(0x37, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) - """ - CALLDATACOPY(dest_offset, offset, size) - ---- + Description ---- Is-zero comparison + + Inputs ---- - a: integer - Description - ---- - Copy input data in current environment to memory + Outputs ---- - a == 0: 1 if a is 0, 0 otherwise - Inputs - ---- - - dest_offset: byte offset in the memory where the result will be copied - - offset: byte offset in the calldata to copy - - size: byte size to copy + Fork ---- Frontier - Outputs - ---- - - None + Gas ---- 3 + + Source: [evm.codes/#15](https://www.evm.codes/#15) - Fork - ---- - Frontier - Gas - ---- - - minimum_word_size = (size + 31) / 32 - - static_gas = 3 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost - Source: [evm.codes/#37](https://www.evm.codes/#37) """ - CODESIZE = Opcode(0x38, pushed_stack_items=1) + AND = Opcode(0x16, popped_stack_items=2, pushed_stack_items=1) """ - CODESIZE() = size - ---- - Description - ---- - Get size of code running in current environment - Inputs - ---- - - None - Outputs - ---- - - size: byte size of the code - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#38](https://www.evm.codes/#38) - """ + AND(a, b) = a & b ---- - CODECOPY = Opcode(0x39, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) - """ - CODECOPY(dest_offset, offset, size) - ---- + Description ---- Bitwise AND operation - Description - ---- - Copy code running in current environment to memory + Inputs ---- - a: first binary value - b: second binary value - Inputs - ---- - - dest_offset: byte offset in the memory where the result will be copied. - - offset: byte offset in the code to copy. - - size: byte size to copy + Outputs ---- - a & b: the bitwise AND result + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#16](https://www.evm.codes/#16) - Fork - ---- - Frontier - Gas - ---- - - minimum_word_size = (size + 31) / 32 - - static_gas = 3 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost - Source: [evm.codes/#39](https://www.evm.codes/#39) """ - GASPRICE = Opcode(0x3A, pushed_stack_items=1) + OR = Opcode(0x17, popped_stack_items=2, pushed_stack_items=1) """ - GASPRICE() = price - ---- - Description - ---- - Get price of gas in current environment - Outputs - ---- - - price: gas price in wei per gas - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#3A](https://www.evm.codes/#3A) - """ - EXTCODESIZE = Opcode(0x3B, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) - """ - EXTCODESIZE(address) = size - ---- + OR(a, b) = a | b ---- - Description - ---- - Get size of an account's code + Description ---- Bitwise OR operation - Inputs - ---- - - address: 20-byte address of the contract to query + Inputs ---- - a: first binary value - b: second binary value - Outputs - ---- - - size: byte size of the code + Outputs ---- - a | b: the bitwise OR result - Fork - ---- - Frontier + Fork ---- Frontier - Gas - ---- - - static_gas = 0 - - dynamic_gas = 100 if warm_address, 2600 if cold_address + Gas ---- 3 - Source: [evm.codes/#3B](https://www.evm.codes/#3B) - """ + Source: [evm.codes/#17](https://www.evm.codes/#17) - EXTCODECOPY = Opcode( - 0x3C, popped_stack_items=4, kwargs=["address", "dest_offset", "offset", "size"] - ) - """ - EXTCODECOPY(address, dest_offset, offset, size) - ---- - Description - ---- - Copy an account's code to memory - Inputs - ---- - - address: 20-byte address of the contract to query - - dest_offset: byte offset in the memory where the result will be copied - - offset: byte offset in the code to copy - - size: byte size to copy + """ - Outputs - ---- - - None + XOR = Opcode(0x18, popped_stack_items=2, pushed_stack_items=1) + """ - Fork - ---- - Frontier - Gas - ---- - - minimum_word_size = (size + 31) / 32 - - static_gas = 0 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + address_access_cost - Source: [evm.codes/#3C](https://www.evm.codes/#3C) - """ - RETURNDATASIZE = Opcode(0x3D, pushed_stack_items=1) - """ - RETURNDATASIZE() = size - ---- - Description - ---- - Get size of output data from the previous call from the current environment - Outputs - ---- - - size: byte size of the return data from the last executed sub context + XOR(a, b) = a ^ b ---- - Fork - ---- - Byzantium + Description ---- Bitwise XOR operation - Gas - ---- - 2 + Inputs ---- - a: first binary value - b: second binary value - Source: [evm.codes/#3D](https://www.evm.codes/#3D) - """ + Outputs ---- - a ^ b: the bitwise XOR result - RETURNDATACOPY = Opcode(0x3E, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) - """ - RETURNDATACOPY(dest_offset, offset, size) - ---- + Fork ---- Frontier - Description - ---- - Copy output data from the previous call to memory + Gas ---- 3 - Inputs - ---- - - dest_offset: byte offset in the memory where the result will be copied - - offset: byte offset in the return data from the last executed sub context to copy - - size: byte size to copy + Source: [evm.codes/#18](https://www.evm.codes/#18) - Fork - ---- - Byzantium - Gas - ---- - - minimum_word_size = (size + 31) / 32 - - static_gas = 3 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost - Source: [evm.codes/#3E](https://www.evm.codes/#3E) """ - EXTCODEHASH = Opcode(0x3F, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) + NOT = Opcode(0x19, popped_stack_items=1, pushed_stack_items=1) """ - EXTCODEHASH(address) = hash - ---- - Description - ---- - Get hash of an account's code - Inputs - ---- - - address: 20-byte address of the account - Outputs - ---- - - hash: hash of the chosen account's code, the empty hash (0xc5d24601...) if the account has no - code, or 0 if the account does not exist or has been destroyed - Fork - ---- - Constantinople - Gas - ---- - - static_gas = 0 - - dynamic_gas = 100 if warm_address, 2600 if cold_address - Source: [evm.codes/#3F](https://www.evm.codes/#3F) - """ + NOT(a) = ~a ---- - BLOCKHASH = Opcode(0x40, popped_stack_items=1, pushed_stack_items=1, kwargs=["block_number"]) - """ - BLOCKHASH(block_number) = hash - ---- + Description ---- Bitwise NOT operation - Description - ---- - Get the hash of one of the 256 most recent complete blocks + Inputs ---- - a: binary value - Inputs - ---- - - blockNumber: block number to get the hash from. Valid range is the last 256 blocks (not - including the current one). Current block number can be queried with NUMBER + Outputs ---- - ~a: the bitwise NOT result - Outputs - ---- - - hash: hash of the chosen block, or 0 if the block number is not in the valid range + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#19](https://www.evm.codes/#19) - Fork - ---- - Frontier - Gas - ---- - 20 - Source: [evm.codes/#40](https://www.evm.codes/#40) """ - COINBASE = Opcode(0x41, pushed_stack_items=1) + BYTE = Opcode(0x1A, popped_stack_items=2, pushed_stack_items=1) """ - COINBASE() = address - ---- - Description - ---- - Get the block's beneficiary address - Inputs - ---- - - None - Outputs - ---- - - address: miner's 20-byte address - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#41](https://www.evm.codes/#41) - """ + BYTE(i, x) = y ---- - TIMESTAMP = Opcode(0x42, pushed_stack_items=1) - """ - TIMESTAMP() = timestamp - ---- + Description ---- Extract a byte from the given position in the value - Description - ---- - Get the block's timestamp + Inputs ---- - i: byte offset starting from the most significant byte - x: + 32-byte value - Inputs - ---- - - None + Outputs ---- - y: the indicated byte at the least significant position. If + the byte offset is out of range, the result is 0 - Outputs - ---- - - timestamp: unix timestamp of the current block + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#1A](https://www.evm.codes/#1A) - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#42](https://www.evm.codes/#42) """ - NUMBER = Opcode(0x43, pushed_stack_items=1) + SHL = Opcode(0x1B, popped_stack_items=2, pushed_stack_items=1) """ - NUMBER() = blockNumber - ---- - Description - ---- - Get the block's number - Inputs - ---- - - None - Outputs - ---- - - blockNumber: current block number - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#43](https://www.evm.codes/#43) - """ + SHL(shift, value) = value << shift ---- - PREVRANDAO = Opcode(0x44, pushed_stack_items=1) - """ - PREVRANDAO() = prevRandao - ---- + Description ---- Shift left operation - Description - ---- - Get the previous block's RANDAO mix + Inputs ---- - shift: number of bits to shift to the left - value: 32 bytes + to shift - Inputs - ---- - - None + Outputs ---- - value << shift: the shifted value. If shift is bigger than + 255, returns 0 - Outputs - ---- - - prevRandao: previous block's RANDAO mix + Fork ---- Constantinople + + Gas ---- 3 + + Source: [evm.codes/#1B](https://www.evm.codes/#1B) - Fork - ---- - Merge - Gas - ---- - 2 - Source: [evm.codes/#44](https://www.evm.codes/#44) """ - GASLIMIT = Opcode(0x45, pushed_stack_items=1) + SHR = Opcode(0x1C, popped_stack_items=2, pushed_stack_items=1) """ - GASLIMIT() = gasLimit - ---- - Description - ---- - Get the block's gas limit - Inputs - ---- - - None - Outputs - ---- - - gasLimit: gas limit - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#45](https://www.evm.codes/#45) - """ + SHR(shift, value) = value >> shift ---- - CHAINID = Opcode(0x46, pushed_stack_items=1) - """ - CHAINID() = chainId - ---- + Description ---- Logical shift right operation - Description - ---- - Get the chain ID + Inputs ---- - shift: number of bits to shift to the right. - value: 32 + bytes to shift - Inputs - ---- - - None + Outputs ---- - value >> shift: the shifted value. If shift is bigger than + 255, returns 0 - Outputs - ---- - - chainId: chain id of the network + Fork ---- Constantinople + + Gas ---- 3 + + Source: [evm.codes/#1C](https://www.evm.codes/#1C) - Fork - ---- - Istanbul - Gas - ---- - 2 - Source: [evm.codes/#46](https://www.evm.codes/#46) """ - SELFBALANCE = Opcode(0x47, pushed_stack_items=1) + SAR = Opcode(0x1D, popped_stack_items=2, pushed_stack_items=1) """ - SELFBALANCE() = balance - ---- - Description - ---- - Get balance of currently executing account - Inputs - ---- - - None - Outputs - ---- - - balance: balance of the current account in wei - Fork - ---- - Istanbul - Gas - ---- - 5 - Source: [evm.codes/#47](https://www.evm.codes/#47) - """ + SAR(shift, value) = value >> shift ---- - BASEFEE = Opcode(0x48, pushed_stack_items=1) - """ - BASEFEE() = baseFee - ---- + Description ---- Arithmetic shift right operation - Description - ---- - Get the base fee + Inputs ---- - shift: number of bits to shift to the right - value: integer + to shift - Outputs - ---- - - baseFee: base fee in wei + Outputs ---- - value >> shift: the shifted value + + Fork ---- Constantinople + + Gas ---- 3 + + Source: [evm.codes/#1D](https://www.evm.codes/#1D) - Fork - ---- - London - Gas - ---- - 2 - Source: [evm.codes/#48](https://www.evm.codes/#48) """ - BLOBHASH = Opcode(0x49, popped_stack_items=1, pushed_stack_items=1, kwargs=["index"]) + CLZ = Opcode(0x1E, popped_stack_items=1, pushed_stack_items=1) """ - BLOBHASH(index) = versionedHash - ---- - Description - ---- - Returns the versioned hash of a single blob contained in the type-3 transaction - Inputs - ---- - - index: index of the blob - Outputs - ---- - - versionedHash: versioned hash of the blob - Fork - ---- - Cancun - Gas - ---- - 3 - Source: [eips.ethereum.org/EIPS/eip-4844](https://eips.ethereum.org/EIPS/eip-4844) - """ + CLZ(value) = count_leading_zeros(value) ---- - BLOBBASEFEE = Opcode(0x4A, popped_stack_items=0, pushed_stack_items=1) - """ - BLOBBASEFEE() = fee - ---- + Description ---- Counts leading zeros (bitwise). - Description - ---- - Returns the value of the blob base fee of the block it is executing in + Inputs ---- - value: integer to count zeros on - Inputs - ---- - - None + Outputs ---- - zeros: leading zero bits - Outputs - ---- - - baseFeePerBlobGas: base fee for the blob gas in wei + Fork ---- Osaka + + Gas ---- 3 + + Source: [evm.codes/#1E](https://www.evm.codes/#1E) - Fork - ---- - Cancun - Gas - ---- - 2 - Source: [eips.ethereum.org/EIPS/eip-7516](https://eips.ethereum.org/EIPS/eip-7516) """ - POP = Opcode(0x50, popped_stack_items=1) + SHA3 = Opcode(0x20, popped_stack_items=2, pushed_stack_items=1, kwargs=["offset", "size"]) """ - POP() - ---- - Description - ---- - Remove item from stack - Inputs - ---- - - None - Outputs - ---- - - None - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#50](https://www.evm.codes/#50) - """ + SHA3(offset, size) = hash ---- - MLOAD = Opcode(0x51, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) - """ - MLOAD(offset) = value - ---- + Description ---- Compute Keccak-256 hash + + Inputs ---- - offset: byte offset in the memory - size: byte size to read + in the memory - Description - ---- - Load word from memory + Outputs ---- - hash: Keccak-256 hash of the given data in memory - Inputs - ---- - - offset: offset in the memory in bytes + Fork ---- Frontier - Outputs - ---- - - value: the 32 bytes in memory starting at that offset. If it goes beyond its current size - (see MSIZE), writes 0s + Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 30 - + dynamic_gas = 6 * minimum_word_size + memory_expansion_cost + + Source: [evm.codes/#20](https://www.evm.codes/#20) - Fork - ---- - Frontier - Gas - ---- - - static_gas = 3 - - dynamic_gas = memory_expansion_cost - Source: [evm.codes/#51](https://www.evm.codes/#51) """ - MSTORE = Opcode(0x52, popped_stack_items=2, kwargs=["offset", "value"]) + ADDRESS = Opcode(0x30, pushed_stack_items=1) """ - MSTORE(offset, value) - ---- - Description - ---- - Save word to memory - Inputs - ---- - - offset: offset in the memory in bytes - - value: 32-byte value to write in the memory - Outputs - ---- - - None - Fork - ---- - Frontier - Gas - ---- - - static_gas = 3 - - dynamic_gas = memory_expansion_cost - Source: [evm.codes/#52](https://www.evm.codes/#52) - """ + ADDRESS() = address ---- - MSTORE8 = Opcode(0x53, popped_stack_items=2, kwargs=["offset", "value"]) - """ - MSTORE8(offset, value) - ---- + Description ---- Get address of currently executing account - Description - ---- - Save byte to memory + Inputs ---- - None - Inputs - ---- - - offset: offset in the memory in bytes - - value: 1-byte value to write in the memory (the least significant byte of the 32-byte stack - value) + Outputs ---- - address: the 20-byte address of the current account + + Fork ---- Frontier + + Gas ---- 2 + + Source: [evm.codes/#30](https://www.evm.codes/#30) - Fork - ---- - Frontier - Gas - ---- - - static_gas = 3 - - dynamic_gas = memory_expansion_cost - Source: [evm.codes/#53](https://www.evm.codes/#53) """ - SLOAD = Opcode(0x54, popped_stack_items=1, pushed_stack_items=1, kwargs=["key"]) + BALANCE = Opcode(0x31, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) """ - SLOAD(key) = value - ---- - Description - ---- - Load word from storage - Inputs - ---- - - key: 32-byte key in storage - Outputs - ---- - - value: 32-byte value corresponding to that key. 0 if that key was never written before - Fork - ---- - Frontier - Gas - ---- - - static_gas = 0 - - dynamic_gas = 100 if warm_address, 2600 if cold_address - Source: [evm.codes/#54](https://www.evm.codes/#54) - """ + BALANCE(address) = balance ---- - SSTORE = Opcode(0x55, popped_stack_items=2, kwargs=["key", "value"]) - """ - SSTORE(key, value) - ---- + Description ---- Get the balance of the specified account - Description - ---- - Save word to storage + Inputs ---- - address: 20-byte address of the account to check - Inputs - ---- - - key: 32-byte key in storage - - value: 32-byte value to store + Outputs ---- - balance: balance of the given account in wei. Returns 0 if + the account doesn't exist - Outputs - ---- - - None + Fork ---- Frontier + + Gas ---- - static_gas = 0 - dynamic_gas = 100 if warm_address, 2600 if + cold_address + + Source: [evm.codes/#31](https://www.evm.codes/#31) - Fork - ---- - Frontier - Gas - ---- - ``` - static_gas = 0 - - if value == current_value - if key is warm - base_dynamic_gas = 100 - else - base_dynamic_gas = 100 - else if current_value == original_value - if original_value == 0 - base_dynamic_gas = 20000 - else - base_dynamic_gas = 2900 - else - base_dynamic_gas = 100 - - if key is cold: - base_dynamic_gas += 2100 - ``` - Source: [evm.codes/#55](https://www.evm.codes/#55) """ - JUMP = Opcode(0x56, popped_stack_items=1, kwargs=["pc"]) + ORIGIN = Opcode(0x32, pushed_stack_items=1) """ - JUMP(pc) - ---- - Description - ---- - Alter the program counter - Inputs - ---- - - pc: byte offset in the deployed code where execution will continue from. Must be a - JUMPDEST instruction - Outputs - ---- - - None - Fork - ---- - Frontier - Gas - ---- - 8 - Source: [evm.codes/#56](https://www.evm.codes/#56) - """ + ORIGIN() = address ---- - JUMPI = Opcode(0x57, popped_stack_items=2, kwargs=["pc", "condition"]) - """ - JUMPI(pc, condition) - ---- + Description ---- Get execution origination address - Description - ---- - Conditionally alter the program counter + Inputs ---- - None - Inputs - ---- - - pc: byte offset in the deployed code where execution will continue from. Must be a - JUMPDEST instruction - - condition: the program counter will be altered with the new value only if this value is - different from 0. Otherwise, the program counter is simply incremented and the next - instruction will be executed + Outputs ---- - address: the 20-byte address of the sender of the + transaction. It can only be an account without code + + Fork ---- Frontier + + Gas ---- 2 + + Source: [evm.codes/#32](https://www.evm.codes/#32) - Fork - ---- - Frontier - Gas - ---- - 10 - Source: [evm.codes/#57](https://www.evm.codes/#57) """ - PC = Opcode(0x58, pushed_stack_items=1) + CALLER = Opcode(0x33, pushed_stack_items=1) """ - PC() = counter - ---- - Description - ---- - Get the value of the program counter prior to the increment corresponding to this instruction - Inputs - ---- - - None - Outputs - ---- - - counter: PC of this instruction in the current program. - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#58](https://www.evm.codes/#58) - """ + CALLER() = address ---- - MSIZE = Opcode(0x59, pushed_stack_items=1) - """ - MSIZE() = size - ---- + Description ---- Get caller address - Description - ---- - Get the size of active memory in bytes + Inputs ---- - None - Outputs - ---- - - size: current memory size in bytes (higher offset accessed until now + 1) + Outputs ---- - address: the 20-byte address of the caller account. This is + the account that did the last call (except delegate call) + + Fork ---- Frontier + + Gas ---- 2 + + Source: [evm.codes/#33](https://www.evm.codes/#33) - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#59](https://www.evm.codes/#59) """ - GAS = Opcode(0x5A, pushed_stack_items=1) + CALLVALUE = Opcode(0x34, pushed_stack_items=1) """ - GAS() = gas_remaining - ---- - Description - ---- - Get the amount of available gas, including the corresponding reduction for the cost of this - instruction - Inputs - ---- - - None - Outputs - ---- - - gas: remaining gas (after this instruction) - Fork - ---- - Frontier - Gas - ---- - 2 - Source: [evm.codes/#5A](https://www.evm.codes/#5A) - """ + CALLVALUE() = value ---- - JUMPDEST = Opcode(0x5B) - """ - JUMPDEST() - ---- + Description ---- Get deposited value by the instruction/transaction + responsible for this execution - Description - ---- - Mark a valid destination for jumps + Inputs ---- - None - Inputs - ---- - - None + Outputs ---- - value: the value of the current call in wei - Outputs - ---- - - None + Fork ---- Frontier + + Gas ---- 2 + + Source: [evm.codes/#34](https://www.evm.codes/#34) - Fork - ---- - Frontier - Gas - ---- - 1 - Source: [evm.codes/#5B](https://www.evm.codes/#5B) """ - NOOP = Opcode(0x5B) + CALLDATALOAD = Opcode(0x35, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) """ - NOOP() - ---- - Description - ---- - Synonym for JUMPDEST. Performs no operation. - Inputs - ---- - - None - Outputs - ---- - - None - Fork - ---- - Frontier - Gas - ---- - 1 - Source: [evm.codes/#5B](https://www.evm.codes/#5B) - """ + CALLDATALOAD(offset) = data[offset] ---- - TLOAD = Opcode(0x5C, popped_stack_items=1, pushed_stack_items=1, kwargs=["key"]) - """ - TLOAD(key) = value - ---- + Description ---- Get input data of current environment + + Inputs ---- - offset: byte offset in the calldata + + Outputs ---- - data[offset]: 32-byte value starting from the given offset + of the calldata. All bytes after the end of the calldata are set to 0 - Description - ---- - Load word from transient storage + Fork ---- Frontier - Inputs - ---- - - key: 32-byte key in transient storage + Gas ---- 3 - Outputs - ---- - - value: 32-byte value corresponding to that key. 0 if that key was never written + Source: [evm.codes/#35](https://www.evm.codes/#35) - Fork - ---- - Cancun - Gas - ---- - 100 - Source: [eips.ethereum.org/EIPS/eip-1153](https://eips.ethereum.org/EIPS/eip-1153) """ - TSTORE = Opcode(0x5D, popped_stack_items=2, kwargs=["key", "value"]) + CALLDATASIZE = Opcode(0x36, pushed_stack_items=1) """ - TSTORE(key, value) - ---- - Description - ---- - Save word to transient storage - Inputs - ---- - - key: 32-byte key in transient storage - - value: 32-byte value to store - Fork - ---- - Cancun - Gas - ---- - 100 - Source: [eips.ethereum.org/EIPS/eip-1153](https://eips.ethereum.org/EIPS/eip-1153) - """ - MCOPY = Opcode(0x5E, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) - """ - MCOPY(dest_offset, offset, size) - ---- + CALLDATASIZE() = size ---- + + Description ---- Get size of input data in current environment + + Inputs ---- - None - Description - ---- - Copies areas in memory + Outputs ---- - size: byte size of the calldata - Inputs - ---- - - dest_offset: byte offset in the memory where the result will be copied - - offset: byte offset in the calldata to copy - - size: byte size to copy + Fork ---- Frontier - Outputs - ---- - - None + Gas ---- 2 + + Source: [evm.codes/#36](https://www.evm.codes/#36) - Fork - ---- - Cancun - Gas - ---- - - minimum_word_size = (size + 31) / 32 - - static_gas = 3 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost - Source: [eips.ethereum.org/EIPS/eip-5656](https://eips.ethereum.org/EIPS/eip-5656) """ - PUSH0 = Opcode(0x5F, pushed_stack_items=1) + CALLDATACOPY = Opcode(0x37, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) """ - PUSH0() = value - ---- - Description - ---- - Place value 0 on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, equal to 0 - Fork - ---- - Shanghai - Gas - ---- - 2 - Source: [evm.codes/#5F](https://www.evm.codes/#5F) - """ + CALLDATACOPY(dest_offset, offset, size) ---- - PUSH1 = Opcode(0x60, pushed_stack_items=1, data_portion_length=1) - """ - PUSH1() = value - ---- + Description ---- Copy input data in current environment to memory - Description - ---- - Place 1 byte item on stack + Inputs ---- - dest_offset: byte offset in the memory where the result will + be copied - offset: byte offset in the calldata to copy - size: byte size + to copy - Inputs - ---- - - None + Outputs ---- - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Fork ---- Frontier + + Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 3 - + dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + + Source: [evm.codes/#37](https://www.evm.codes/#37) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#60](https://www.evm.codes/#60) """ - PUSH2 = Opcode(0x61, pushed_stack_items=1, data_portion_length=2) + CODESIZE = Opcode(0x38, pushed_stack_items=1) """ - PUSH2() = value - ---- - Description - ---- - Place 2 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#61](https://www.evm.codes/#61) - """ + CODESIZE() = size ---- - PUSH3 = Opcode(0x62, pushed_stack_items=1, data_portion_length=3) - """ - PUSH3() = value - ---- + Description ---- Get size of code running in current environment - Description - ---- - Place 3 byte item on stack + Inputs ---- - None - Inputs - ---- - - None + Outputs ---- - size: byte size of the code - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Fork ---- Frontier + + Gas ---- 2 + + Source: [evm.codes/#38](https://www.evm.codes/#38) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#62](https://www.evm.codes/#62) """ - PUSH4 = Opcode(0x63, pushed_stack_items=1, data_portion_length=4) + CODECOPY = Opcode(0x39, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) """ - PUSH4() = value - ---- - Description - ---- - Place 4 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#63](https://www.evm.codes/#63) - """ + CODECOPY(dest_offset, offset, size) ---- - PUSH5 = Opcode(0x64, pushed_stack_items=1, data_portion_length=5) - """ - PUSH5() = value - ---- + Description ---- Copy code running in current environment to memory - Description - ---- - Place 5 byte item on stack + Inputs ---- - dest_offset: byte offset in the memory where the result will + be copied. - offset: byte offset in the code to copy. - size: byte size to + copy - Inputs - ---- - - None + Fork ---- Frontier - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 3 - + dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + + Source: [evm.codes/#39](https://www.evm.codes/#39) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#64](https://www.evm.codes/#64) """ - PUSH6 = Opcode(0x65, pushed_stack_items=1, data_portion_length=6) + GASPRICE = Opcode(0x3A, pushed_stack_items=1) """ - PUSH6() = value - ---- - Description - ---- - Place 6 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#65](https://www.evm.codes/#65) - """ + GASPRICE() = price ---- - PUSH7 = Opcode(0x66, pushed_stack_items=1, data_portion_length=7) - """ - PUSH7() = value - ---- + Description ---- Get price of gas in current environment + + Outputs ---- - price: gas price in wei per gas - Description - ---- - Place 7 byte item on stack + Fork ---- Frontier - Inputs - ---- - - None + Gas ---- 2 - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Source: [evm.codes/#3A](https://www.evm.codes/#3A) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#66](https://www.evm.codes/#66) """ - PUSH8 = Opcode(0x67, pushed_stack_items=1, data_portion_length=8) + EXTCODESIZE = Opcode(0x3B, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) """ - PUSH8() = value - ---- - Description - ---- - Place 8 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#67](https://www.evm.codes/#67) - """ + EXTCODESIZE(address) = size ---- - PUSH9 = Opcode(0x68, pushed_stack_items=1, data_portion_length=9) - """ - PUSH9() = value - ---- + Description ---- Get size of an account's code - Description - ---- - Place 9 byte item on stack + Inputs ---- - address: 20-byte address of the contract to query - Inputs - ---- - - None + Outputs ---- - size: byte size of the code - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Fork ---- Frontier + + Gas ---- - static_gas = 0 - dynamic_gas = 100 if warm_address, 2600 if + cold_address + + Source: [evm.codes/#3B](https://www.evm.codes/#3B) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#68](https://www.evm.codes/#68) """ - PUSH10 = Opcode(0x69, pushed_stack_items=1, data_portion_length=10) + EXTCODECOPY = Opcode( + 0x3C, popped_stack_items=4, kwargs=["address", "dest_offset", "offset", "size"] + ) """ - PUSH10() = value - ---- - Description - ---- - Place 10 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#69](https://www.evm.codes/#69) - """ + EXTCODECOPY(address, dest_offset, offset, size) ---- - PUSH11 = Opcode(0x6A, pushed_stack_items=1, data_portion_length=11) - """ - PUSH11() = value - ---- + Description ---- Copy an account's code to memory - Description - ---- - Place 11 byte item on stack + Inputs ---- - address: 20-byte address of the contract to query - + dest_offset: byte offset in the memory where the result will be copied - + offset: byte offset in the code to copy - size: byte size to copy - Inputs - ---- - - None + Outputs ---- - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Fork ---- Frontier + + Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 0 - + dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + + address_access_cost + + Source: [evm.codes/#3C](https://www.evm.codes/#3C) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#6A](https://www.evm.codes/#6A) """ - PUSH12 = Opcode(0x6B, pushed_stack_items=1, data_portion_length=12) + RETURNDATASIZE = Opcode(0x3D, pushed_stack_items=1) """ - PUSH12() = value - ---- - Description - ---- - Place 12 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#6B](https://www.evm.codes/#6B) - """ + RETURNDATASIZE() = size ---- - PUSH13 = Opcode(0x6C, pushed_stack_items=1, data_portion_length=13) - """ - PUSH13() = value - ---- + Description ---- Get size of output data from the previous call from the + current environment - Description - ---- - Place 13 byte item on stack + Outputs ---- - size: byte size of the return data from the last executed + sub context - Inputs - ---- - - None + Fork ---- Byzantium - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Gas ---- 2 + + Source: [evm.codes/#3D](https://www.evm.codes/#3D) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#6C](https://www.evm.codes/#6C) """ - PUSH14 = Opcode(0x6D, pushed_stack_items=1, data_portion_length=14) + RETURNDATACOPY = Opcode(0x3E, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) """ - PUSH14() = value - ---- - Description - ---- - Place 14 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 + RETURNDATACOPY(dest_offset, offset, size) ---- - Source: [evm.codes/#6D](https://www.evm.codes/#6D) - """ + Description ---- Copy output data from the previous call to memory - PUSH15 = Opcode(0x6E, pushed_stack_items=1, data_portion_length=15) - """ - PUSH15() = value - ---- + Inputs ---- - dest_offset: byte offset in the memory where the result will + be copied - offset: byte offset in the return data from the last executed + sub context to copy - size: byte size to copy - Description - ---- - Place 15 byte item on stack + Fork ---- Byzantium - Inputs - ---- - - None + Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 3 - + dynamic_gas = 3 * minimum_word_size + memory_expansion_cost - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Source: [evm.codes/#3E](https://www.evm.codes/#3E) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#6E](https://www.evm.codes/#6E) """ - PUSH16 = Opcode(0x6F, pushed_stack_items=1, data_portion_length=16) + EXTCODEHASH = Opcode(0x3F, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) """ - PUSH16() = value - ---- - Description - ---- - Place 16 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#6F](https://www.evm.codes/#6F) - """ + EXTCODEHASH(address) = hash ---- - PUSH17 = Opcode(0x70, pushed_stack_items=1, data_portion_length=17) - """ - PUSH17() = value - ---- + Description ---- Get hash of an account's code + + Inputs ---- - address: 20-byte address of the account - Description - ---- - Place 17 byte item on stack + Outputs ---- - hash: hash of the chosen account's code, the empty hash + (0xc5d24601...) if the account has no code, or 0 if the account does not + exist or has been destroyed - Inputs - ---- - - None + Fork ---- Constantinople - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Gas ---- - static_gas = 0 - dynamic_gas = 100 if warm_address, 2600 if + cold_address + + Source: [evm.codes/#3F](https://www.evm.codes/#3F) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#70](https://www.evm.codes/#70) """ - PUSH18 = Opcode(0x71, pushed_stack_items=1, data_portion_length=18) + BLOCKHASH = Opcode(0x40, popped_stack_items=1, pushed_stack_items=1, kwargs=["block_number"]) """ - PUSH18() = value - ---- - Description - ---- - Place 18 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#71](https://www.evm.codes/#71) - """ + BLOCKHASH(block_number) = hash ---- - PUSH19 = Opcode(0x72, pushed_stack_items=1, data_portion_length=19) - """ - PUSH19() = value - ---- + Description ---- Get the hash of one of the 256 most recent complete blocks + + Inputs ---- - blockNumber: block number to get the hash from. Valid range + is the last 256 blocks (not including the current one). Current block + number can be queried with NUMBER - Description - ---- - Place 19 byte item on stack + Outputs ---- - hash: hash of the chosen block, or 0 if the block number is + not in the valid range - Inputs - ---- - - None + Fork ---- Frontier - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Gas ---- 20 + + Source: [evm.codes/#40](https://www.evm.codes/#40) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#72](https://www.evm.codes/#72) """ - PUSH20 = Opcode(0x73, pushed_stack_items=1, data_portion_length=20) + COINBASE = Opcode(0x41, pushed_stack_items=1) """ - PUSH20() = value - ---- - Description - ---- - Place 20 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#73](https://www.evm.codes/#73) - """ + COINBASE() = address ---- - PUSH21 = Opcode(0x74, pushed_stack_items=1, data_portion_length=21) - """ - PUSH21() = value - ---- + Description ---- Get the block's beneficiary address + + Inputs ---- - None - Description - ---- - Place 21 byte item on stack + Outputs ---- - address: miner's 20-byte address - Inputs - ---- - - None + Fork ---- Frontier - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Gas ---- 2 + + Source: [evm.codes/#41](https://www.evm.codes/#41) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#74](https://www.evm.codes/#74) """ - PUSH22 = Opcode(0x75, pushed_stack_items=1, data_portion_length=22) + TIMESTAMP = Opcode(0x42, pushed_stack_items=1) """ - PUSH22() = value - ---- - Description - ---- - Place 22 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#75](https://www.evm.codes/#75) - """ + TIMESTAMP() = timestamp ---- - PUSH23 = Opcode(0x76, pushed_stack_items=1, data_portion_length=23) - """ - PUSH23() = value - ---- + Description ---- Get the block's timestamp + + Inputs ---- - None - Description - ---- - Place 23 byte item on stack + Outputs ---- - timestamp: unix timestamp of the current block - Inputs - ---- - - None + Fork ---- Frontier - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Gas ---- 2 + + Source: [evm.codes/#42](https://www.evm.codes/#42) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#76](https://www.evm.codes/#76) """ - PUSH24 = Opcode(0x77, pushed_stack_items=1, data_portion_length=24) + NUMBER = Opcode(0x43, pushed_stack_items=1) """ - PUSH24() = value - ---- - Description - ---- - Place 24 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#77](https://www.evm.codes/#77) - """ + NUMBER() = blockNumber ---- - PUSH25 = Opcode(0x78, pushed_stack_items=1, data_portion_length=25) - """ - PUSH25() = value - ---- + Description ---- Get the block's number + + Inputs ---- - None - Description - ---- - Place 25 byte item on stack + Outputs ---- - blockNumber: current block number - Inputs - ---- - - None + Fork ---- Frontier - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Gas ---- 2 + + Source: [evm.codes/#43](https://www.evm.codes/#43) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#78](https://www.evm.codes/#78) """ - PUSH26 = Opcode(0x79, pushed_stack_items=1, data_portion_length=26) + PREVRANDAO = Opcode(0x44, pushed_stack_items=1) """ - PUSH26() = value - ---- - Description - ---- - Place 26 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#79](https://www.evm.codes/#79) - """ + PREVRANDAO() = prevRandao ---- - PUSH27 = Opcode(0x7A, pushed_stack_items=1, data_portion_length=27) - """ - PUSH27() = value - ---- + Description ---- Get the previous block's RANDAO mix + + Inputs ---- - None - Description - ---- - Place 27 byte item on stack + Outputs ---- - prevRandao: previous block's RANDAO mix - Inputs - ---- - - None + Fork ---- Merge - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Gas ---- 2 + + Source: [evm.codes/#44](https://www.evm.codes/#44) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#7A](https://www.evm.codes/#7A) """ - PUSH28 = Opcode(0x7B, pushed_stack_items=1, data_portion_length=28) + GASLIMIT = Opcode(0x45, pushed_stack_items=1) """ - PUSH28() = value - ---- - Description - ---- - Place 28 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#7B](https://www.evm.codes/#7B) - """ + GASLIMIT() = gasLimit ---- - PUSH29 = Opcode(0x7C, pushed_stack_items=1, data_portion_length=29) - """ - PUSH29() = value - ---- + Description ---- Get the block's gas limit + + Inputs ---- - None - Description - ---- - Place 29 byte item on stack + Outputs ---- - gasLimit: gas limit - Inputs - ---- - - None + Fork ---- Frontier - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Gas ---- 2 + + Source: [evm.codes/#45](https://www.evm.codes/#45) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#7C](https://www.evm.codes/#7C) """ - PUSH30 = Opcode(0x7D, pushed_stack_items=1, data_portion_length=30) + CHAINID = Opcode(0x46, pushed_stack_items=1) """ - PUSH30() = value - ---- - Description - ---- - Place 30 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#7D](https://www.evm.codes/#7D) - """ + CHAINID() = chainId ---- - PUSH31 = Opcode(0x7E, pushed_stack_items=1, data_portion_length=31) - """ - PUSH31() = value - ---- + Description ---- Get the chain ID - Description - ---- - Place 31 byte item on stack + Inputs ---- - None - Inputs - ---- - - None + Outputs ---- - chainId: chain id of the network - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) + Fork ---- Istanbul + + Gas ---- 2 + + Source: [evm.codes/#46](https://www.evm.codes/#46) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#7E](https://www.evm.codes/#7E) """ - PUSH32 = Opcode(0x7F, pushed_stack_items=1, data_portion_length=32) + SELFBALANCE = Opcode(0x47, pushed_stack_items=1) """ - PUSH32() = value - ---- - Description - ---- - Place 32 byte item on stack - Inputs - ---- - - None - Outputs - ---- - - value: pushed value, aligned to the right (put in the lowest significant bytes) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#7F](https://www.evm.codes/#7F) - """ + SELFBALANCE() = balance ---- - DUP1 = Opcode(0x80, pushed_stack_items=1, min_stack_height=1) - """ - DUP1(value) = value, value - ---- + Description ---- Get balance of currently executing account + + Inputs ---- - None - Description - ---- - Duplicate 1st stack item + Outputs ---- - balance: balance of the current account in wei - Inputs - ---- - - value: value to duplicate + Fork ---- Istanbul - Outputs - ---- - - value: duplicated value - - value: original value + Gas ---- 5 + + Source: [evm.codes/#47](https://www.evm.codes/#47) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#80](https://www.evm.codes/#80) """ - DUP2 = Opcode(0x81, pushed_stack_items=1, min_stack_height=2) + BASEFEE = Opcode(0x48, pushed_stack_items=1) """ - DUP2(v1, v2) = v2, v1, v2 - ---- - Description - ---- - Duplicate 2nd stack item - Inputs - ---- - - v1: ignored value - - v2: value to duplicate - Outputs - ---- - - v2: duplicated value - - v1: ignored value - - v2: original value - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#81](https://www.evm.codes/#81) - """ + BASEFEE() = baseFee ---- - DUP3 = Opcode(0x82, pushed_stack_items=1, min_stack_height=3) - """ - DUP3(v1, v2, v3) = v3, v1, v2, v3 - ---- + Description ---- Get the base fee - Description - ---- - Duplicate 3rd stack item + Outputs ---- - baseFee: base fee in wei - Inputs - ---- - - v1: ignored value - - v2: ignored value - - v3: value to duplicate + Fork ---- London - Outputs - ---- - - v3: duplicated value - - v1: ignored value - - v2: ignored value - - v3: original value + Gas ---- 2 + + Source: [evm.codes/#48](https://www.evm.codes/#48) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#82](https://www.evm.codes/#82) """ - DUP4 = Opcode(0x83, pushed_stack_items=1, min_stack_height=4) + BLOBHASH = Opcode(0x49, popped_stack_items=1, pushed_stack_items=1, kwargs=["index"]) """ - DUP4(v1, v2, v3, v4) = v4, v1, v2, v3, v4 - ---- - Description - ---- - Duplicate 4th stack item - Inputs - ---- - - v1: ignored value - - v2: ignored value - - v3: ignored value - - v4: value to duplicate - Outputs - ---- - - v4: duplicated value - - v1: ignored value - - v2: ignored value - - v3: ignored value - - v4: original value - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#83](https://www.evm.codes/#83) - """ + BLOBHASH(index) = versionedHash ---- - DUP5 = Opcode(0x84, pushed_stack_items=1, min_stack_height=5) - """ - DUP5(v1, v2, v3, v4, v5) = v5, v1, v2, v3, v4, v5 - ---- - - Description - ---- - Duplicate 5th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - v3: ignored value - - v4: ignored value - - v5: value to duplicate - - Outputs - ---- - - v5: duplicated value - - v1: ignored value - - v2: ignored value - - v3: ignored value - - v4: ignored value - - v5: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 + Description ---- Returns the versioned hash of a single blob contained in + the type-3 transaction - Source: [evm.codes/#84](https://www.evm.codes/#84) - """ + Inputs ---- - index: index of the blob - DUP6 = Opcode(0x85, pushed_stack_items=1, min_stack_height=6) - """ - DUP6(v1, v2, ..., v5, v6) = v6, v1, v2, ..., v5, v6 - ---- - - Description - ---- - Duplicate 6th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - ... - - v5: ignored value - - v6: value to duplicate - - Outputs - ---- - - v6: duplicated value - - v1: ignored value - - v2: ignored value - - ... - - v5: ignored value - - v6: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 + Outputs ---- - versionedHash: versioned hash of the blob - Source: [evm.codes/#85](https://www.evm.codes/#85) - """ + Fork ---- Cancun - DUP7 = Opcode(0x86, pushed_stack_items=1, min_stack_height=7) - """ - DUP7(v1, v2, ..., v6, v7) = v7, v1, v2, ..., v6, v7 - ---- - - Description - ---- - Duplicate 7th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - ... - - v6: ignored value - - v7: value to duplicate - - Outputs - ---- - - v7: duplicated value - - v1: ignored value - - v2: ignored value - - ... - - v6: ignored value - - v7: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 + Gas ---- 3 - Source: [evm.codes/#86](https://www.evm.codes/#86) - """ + Source: + [eips.ethereum.org/EIPS/eip-4844](https://eips.ethereum.org/EIPS/eip-4844) - DUP8 = Opcode(0x87, pushed_stack_items=1, min_stack_height=8) - """ - DUP8(v1, v2, ..., v7, v8) = v8, v1, v2, ..., v7, v8 - ---- - - Description - ---- - Duplicate 8th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - ... - - v7: ignored value - - v8: value to duplicate - - Outputs - ---- - - v8: duplicated value - - v1: ignored value - - v2: ignored value - - ... - - v7: ignored value - - v8: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#87](https://www.evm.codes/#87) - """ - DUP9 = Opcode(0x88, pushed_stack_items=1, min_stack_height=9) """ - DUP9(v1, v2, ..., v8, v9) = v9, v1, v2, ..., v8, v9 - ---- - - Description - ---- - Duplicate 9th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - ... - - v8: ignored value - - v9: value to duplicate - - Outputs - ---- - - v9: duplicated value - - v1: ignored value - - v2: ignored value - - ... - - v8: ignored value - - v9: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#88](https://www.evm.codes/#88) - """ - DUP10 = Opcode(0x89, pushed_stack_items=1, min_stack_height=10) + BLOBBASEFEE = Opcode(0x4A, popped_stack_items=0, pushed_stack_items=1) """ - DUP10(v1, v2, ..., v9, v10) = v10, v1, v2, ..., v9, v10 - ---- - - Description - ---- - Duplicate 10th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - ... - - v9: ignored value - - v10: value to duplicate - - Outputs - ---- - - v10: duplicated value - - v1: ignored value - - v2: ignored value - - ... - - v9: ignored value - - v10: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#89](https://www.evm.codes/#89) - """ - DUP11 = Opcode(0x8A, pushed_stack_items=1, min_stack_height=11) - """ - DUP11(v1, v2, ..., v10, v11) = v11, v1, v2, ..., v10, v11 - ---- - - Description - ---- - Duplicate 11th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - ... - - v10: ignored value - - v11: value to duplicate - - Outputs - ---- - - v11: duplicated value - - v1: ignored value - - v2: ignored value - - ... - - v10: ignored value - - v11: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#8A](https://www.evm.codes/#8A) - """ - DUP12 = Opcode(0x8B, pushed_stack_items=1, min_stack_height=12) - """ - DUP12(v1, v2, ..., v11, v12) = v12, v1, v2, ..., v11, v12 - ---- - - Description - ---- - Duplicate 12th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - ... - - v11: ignored value - - v12: value to duplicate - - Outputs - ---- - - v12: duplicated value - - v1: ignored value - - v2: ignored value - - ... - - v11: ignored value - - v12: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#8B](https://www.evm.codes/#8B) - """ - DUP13 = Opcode(0x8C, pushed_stack_items=1, min_stack_height=13) - """ - DUP13(v1, v2, ..., v12, v13) = v13, v1, v2, ..., v12, v13 - ---- - - Description - ---- - Duplicate 13th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - ... - - v12: ignored value - - v13: value to duplicate - - Outputs - ---- - - v13: duplicated value - - v1: ignored value - - v2: ignored value - - ... - - v12: ignored value - - v13: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 + BLOBBASEFEE() = fee ---- - Source: [evm.codes/#8C](https://www.evm.codes/#8C) - """ + Description ---- Returns the value of the blob base fee of the block it is + executing in - DUP14 = Opcode(0x8D, pushed_stack_items=1, min_stack_height=14) - """ - DUP14(v1, v2, ..., v13, v14) = v14, v1, v2, ..., v13, v14 - ---- - - Description - ---- - Duplicate 14th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - ... - - v13: ignored value - - v14: value to duplicate - - Outputs - ---- - - v14: duplicated value - - v1: ignored value - - v2: ignored value - - ... - - v13: ignored value - - v14: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 + Inputs ---- - None - Source: [evm.codes/#8D](https://www.evm.codes/#8D) - """ + Outputs ---- - baseFeePerBlobGas: base fee for the blob gas in wei - DUP15 = Opcode(0x8E, pushed_stack_items=1, min_stack_height=15) - """ - DUP15(v1, v2, ..., v14, v15) = v15, v1, v2, ..., v14, v15 - ---- - - Description - ---- - Duplicate 15th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - ... - - v14: ignored value - - v15: value to duplicate - - Outputs - ---- - - v15: duplicated value - - v1: ignored value - - v2: ignored value - - ... - - v14: ignored value - - v15: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 + Fork ---- Cancun + + Gas ---- 2 + + Source: + [eips.ethereum.org/EIPS/eip-7516](https://eips.ethereum.org/EIPS/eip-7516) - Source: [evm.codes/#8E](https://www.evm.codes/#8E) - """ - DUP16 = Opcode(0x8F, pushed_stack_items=1, min_stack_height=16) - """ - DUP16(v1, v2, ..., v15, v16) = v16, v1, v2, ..., v15, v16 - ---- - - Description - ---- - Duplicate 16th stack item - - Inputs - ---- - - v1: ignored value - - v2: ignored value - - ... - - v15: ignored value - - v16: value to duplicate - - Outputs - ---- - - v16: duplicated value - - v1: ignored value - - v2: ignored value - - ... - - v15: ignored value - - v16: original value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#8F](https://www.evm.codes/#8F) """ - SWAP1 = Opcode(0x90, min_stack_height=2) + POP = Opcode(0x50, popped_stack_items=1) """ - SWAP1(v1, v2) = v2, v1 - ---- - Description - ---- - Exchange the top stack item with the second stack item. - Inputs - ---- - - v1: value to swap - - v2: value to swap - Outputs - ---- - - v1: swapped value - - v2: swapped value - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#90](https://www.evm.codes/#90) - """ + POP() ---- - SWAP2 = Opcode(0x91, min_stack_height=3) - """ - SWAP2(v1, v2, v3) = v3, v2, v1 - ---- + Description ---- Remove item from stack + + Inputs ---- - None - Description - ---- - Exchange 1st and 3rd stack items + Outputs ---- - None - Inputs - ---- - - v1: value to swap - - v2: ignored value - - v3: value to swap + Fork ---- Frontier - Outputs - ---- - - v3: swapped value - - v2: ignored value - - v1: swapped value + Gas ---- 2 + + Source: [evm.codes/#50](https://www.evm.codes/#50) - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#91](https://www.evm.codes/#91) """ - SWAP3 = Opcode(0x92, min_stack_height=4) + MLOAD = Opcode(0x51, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) """ - SWAP3(v1, v2, v3, v4) = v4, v2, v3, v1 - ---- - Description - ---- - Exchange 1st and 4th stack items - Inputs - ---- - - v1: value to swap - - v2: ignored value - - v3: ignored value - - v4: value to swap - Outputs - ---- - - v4: swapped value - - v2: ignored value - - v3: ignored value - - v1: swapped value - Fork - ---- - Frontier - Gas - ---- - 3 - Source: [evm.codes/#92](https://www.evm.codes/#92) - """ + MLOAD(offset) = value ---- - SWAP4 = Opcode(0x93, min_stack_height=5) - """ - SWAP4(v1, v2, ..., v4, v5) = v5, v2, ..., v4, v1 - ---- - - Description - ---- - Exchange 1st and 5th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v4: ignored value - - v5: value to swap - - Outputs - ---- - - v5: swapped value - - v2: ignored value - - ... - - v4: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 + Description ---- Load word from memory - Source: [evm.codes/#93](https://www.evm.codes/#93) - """ + Inputs ---- - offset: offset in the memory in bytes - SWAP5 = Opcode(0x94, min_stack_height=6) - """ - SWAP5(v1, v2, ..., v5, v6) = v6, v2, ..., v5, v1 - ---- - - Description - ---- - Exchange 1st and 6th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v5: ignored value - - v6: value to swap - - Outputs - ---- - - v6: swapped value - - v2: ignored value - - ... - - v5: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 + Outputs ---- - value: the 32 bytes in memory starting at that offset. If it + goes beyond its current size (see MSIZE), writes 0s - Source: [evm.codes/#94](https://www.evm.codes/#94) - """ + Fork ---- Frontier - SWAP6 = Opcode(0x95, min_stack_height=7) - """ - SWAP6(v1, v2, ..., v6, v7) = v7, v2, ..., v6, v1 - ---- - - Description - ---- - Exchange 1st and 7th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v6: ignored value - - v7: value to swap - - Outputs - ---- - - v7: swapped value - - v2: ignored value - - ... - - v6: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 + Gas ---- - static_gas = 3 - dynamic_gas = memory_expansion_cost - Source: [evm.codes/#95](https://www.evm.codes/#95) - """ + Source: [evm.codes/#51](https://www.evm.codes/#51) - SWAP7 = Opcode(0x96, min_stack_height=8) - """ - SWAP7(v1, v2, ..., v7, v8) = v8, v2, ..., v7, v1 - ---- - - Description - ---- - Exchange 1st and 8th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v7: ignored value - - v8: value to swap - - Outputs - ---- - - v8: swapped value - - v2: ignored value - - ... - - v7: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#96](https://www.evm.codes/#96) - """ - SWAP8 = Opcode(0x97, min_stack_height=9) """ - SWAP8(v1, v2, ..., v8, v9) = v9, v2, ..., v8, v1 - ---- - - Description - ---- - Exchange 1st and 9th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v8: ignored value - - v9: value to swap - - Outputs - ---- - - v9: swapped value - - v2: ignored value - - ... - - v8: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#97](https://www.evm.codes/#97) + MSTORE = Opcode(0x52, popped_stack_items=2, kwargs=["offset", "value"]) """ - SWAP9 = Opcode(0x98, min_stack_height=10) - """ - SWAP9(v1, v2, ..., v9, v10) = v10, v2, ..., v9, v1 - ---- - - Description - ---- - Exchange 1st and 10th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v9: ignored value - - v10: value to swap - - Outputs - ---- - - v10: swapped value - - v2: ignored value - - ... - - v9: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#98](https://www.evm.codes/#98) - """ - SWAP10 = Opcode(0x99, min_stack_height=11) - """ - SWAP10(v1, v2, ..., v10, v11) = v11, v2, ..., v10, v1 - ---- - - Description - ---- - Exchange 1st and 11th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v10: ignored value - - v11: value to swap - - Outputs - ---- - - v11: swapped value - - v2: ignored value - - ... - - v10: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#99](https://www.evm.codes/#99) - """ - SWAP11 = Opcode(0x9A, min_stack_height=12) - """ - SWAP11(v1, v2, ..., v11, v12) = v12, v2, ..., v11, v1 - ---- - - Description - ---- - Exchange 1st and 12th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v11: ignored value - - v12: value to swap - - Outputs - ---- - - v12: swapped value - - v2: ignored value - - ... - - v11: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#9A](https://www.evm.codes/#9A) - """ + MSTORE(offset, value) ---- - SWAP12 = Opcode(0x9B, min_stack_height=13) - """ - SWAP12(v1, v2, ..., v12, v13) = v13, v2, ..., v12, v1 - ---- - - Description - ---- - Exchange 1st and 13th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v12: ignored value - - v13: value to swap - - Outputs - ---- - - v13: swapped value - - v2: ignored value - - ... - - v12: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 + Description ---- Save word to memory - Source: [evm.codes/#9B](https://www.evm.codes/#9B) - """ + Inputs ---- - offset: offset in the memory in bytes - value: 32-byte value + to write in the memory - SWAP13 = Opcode(0x9C, min_stack_height=14) - """ - SWAP13(v1, v2, ..., v13, v14) = v14, v2, ..., v13, v1 - ---- - - Description - ---- - Exchange 1st and 14th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v13: ignored value - - v14: value to swap - - Outputs - ---- - - v14: swapped value - - v2: ignored value - - ... - - v13: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 + Outputs ---- - None - Source: [evm.codes/#9C](https://www.evm.codes/#9C) - """ + Fork ---- Frontier - SWAP14 = Opcode(0x9D, min_stack_height=15) - """ - SWAP14(v1, v2, ..., v14, v15) = v15, v2, ..., v14, v1 - ---- - - Description - ---- - Exchange 1st and 15th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v14: ignored value - - v15: value to swap - - Outputs - ---- - - v15: swapped value - - v2: ignored value - - ... - - v14: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 + Gas ---- - static_gas = 3 - dynamic_gas = memory_expansion_cost - Source: [evm.codes/#9D](https://www.evm.codes/#9D) - """ + Source: [evm.codes/#52](https://www.evm.codes/#52) - SWAP15 = Opcode(0x9E, min_stack_height=16) - """ - SWAP15(v1, v2, ..., v15, v16) = v16, v2, ..., v15, v1 - ---- - - Description - ---- - Exchange 1st and 16th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v15: ignored value - - v16: value to swap - - Outputs - ---- - - v16: swapped value - - v2: ignored value - - ... - - v15: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#9E](https://www.evm.codes/#9E) - """ - SWAP16 = Opcode(0x9F, min_stack_height=17) """ - SWAP16(v1, v2, ..., v16, v17) = v17, v2, ..., v16, v1 - ---- - - Description - ---- - Exchange 1st and 17th stack items - - Inputs - ---- - - v1: value to swap - - v2: ignored value - - ... - - v16: ignored value - - v17: value to swap - - Outputs - ---- - - v17: swapped value - - v2: ignored value - - ... - - v16: ignored value - - v1: swapped value - - Fork - ---- - Frontier - - Gas - ---- - 3 - Source: [evm.codes/#9F](https://www.evm.codes/#9F) + MSTORE8 = Opcode(0x53, popped_stack_items=2, kwargs=["offset", "value"]) """ - LOG0 = Opcode(0xA0, popped_stack_items=2, kwargs=["offset", "size"]) - """ - LOG0(offset, size) - ---- - Description - ---- - Append log record with no topics - Inputs - ---- - - offset: byte offset in the memory in bytes - - size: byte size to copy - Outputs - ---- - - None - Fork - ---- - Frontier - Gas - ---- - - static_gas = 375 - - dynamic_gas = 375 * topic_count + 8 * size + memory_expansion_cost + MSTORE8(offset, value) ---- - Source: [evm.codes/#A0](https://www.evm.codes/#A0) - """ + Description ---- Save byte to memory - LOG1 = Opcode(0xA1, popped_stack_items=3, kwargs=["offset", "size", "topic_1"]) - """ - LOG1(offset, size, topic_1) - ---- + Inputs ---- - offset: offset in the memory in bytes - value: 1-byte value + to write in the memory (the least significant byte of the 32-byte stack + value) - Description - ---- - Append log record with one topic + Fork ---- Frontier - Inputs - ---- - - offset: byte offset in the memory in bytes - - size: byte size to copy - - topic_1: 32-byte value + Gas ---- - static_gas = 3 - dynamic_gas = memory_expansion_cost - Outputs - ---- - - None + Source: [evm.codes/#53](https://www.evm.codes/#53) - Fork - ---- - Frontier - Gas - ---- - - static_gas = 375 - - dynamic_gas = 375 * topic_count + 8 * size + memory_expansion_cost - Source: [evm.codes/#A1](https://www.evm.codes/#A1) """ - LOG2 = Opcode(0xA2, popped_stack_items=4, kwargs=["offset", "size", "topic_1", "topic_2"]) + SLOAD = Opcode(0x54, popped_stack_items=1, pushed_stack_items=1, kwargs=["key"]) """ - LOG2(offset, size, topic_1, topic_2) - ---- - Description - ---- - Append log record with two topics - Inputs - ---- - - offset: byte offset in the memory in bytes - - size: byte size to copy - - topic_1: 32-byte value - - topic_2: 32-byte value - Outputs - ---- - - None - Fork - ---- - Frontier - Gas - ---- - - static_gas = 375 - - dynamic_gas = 375 * topic_count + 8 * size + memory_expansion_cost - Source: [evm.codes/#A2](https://www.evm.codes/#A2) - """ + SLOAD(key) = value ---- - LOG3 = Opcode( - 0xA3, popped_stack_items=5, kwargs=["offset", "size", "topic_1", "topic_2", "topic_3"] - ) - """ - LOG3(offset, size, topic_1, topic_2, topic_3) - ---- + Description ---- Load word from storage + + Inputs ---- - key: 32-byte key in storage - Description - ---- - Append log record with three topics + Outputs ---- - value: 32-byte value corresponding to that key. 0 if that + key was never written before - Inputs - ---- - - offset: byte offset in the memory in bytes - - size: byte size to copy - - topic_1: 32-byte value - - topic_2: 32-byte value - - topic_3: 32-byte value + Fork ---- Frontier - Outputs - ---- - - None + Gas ---- - static_gas = 0 - dynamic_gas = 100 if warm_address, 2600 if + cold_address + + Source: [evm.codes/#54](https://www.evm.codes/#54) - Fork - ---- - Frontier - Gas - ---- - - static_gas = 375 - - dynamic_gas = 375 * topic_count + 8 * size + memory_expansion_cost - Source: [evm.codes/#A3](https://www.evm.codes/#A3) """ - LOG4 = Opcode( - 0xA4, - popped_stack_items=6, - kwargs=["offset", "size", "topic_1", "topic_2", "topic_3", "topic_4"], - ) + SSTORE = Opcode(0x55, popped_stack_items=2, kwargs=["key", "value"]) """ - LOG4(offset, size, topic_1, topic_2, topic_3, topic_4) - ---- - Description - ---- - Append log record with four topics - Inputs - ---- - - offset: byte offset in the memory in bytes - - size: byte size to copy - - topic_1: 32-byte value - - topic_2: 32-byte value - - topic_3: 32-byte value - - topic_4: 32-byte value - Outputs - ---- - - None - Fork - ---- - Frontier - Gas - ---- - - static_gas = 375 - - dynamic_gas = 375 * topic_count + 8 * size + memory_expansion_cost - Source: [evm.codes/#A4](https://www.evm.codes/#A4) - """ + SSTORE(key, value) ---- - RJUMP = Opcode(0xE0, data_portion_length=2) - """ - !!! Note: This opcode is under development + Description ---- Save word to storage + + Inputs ---- - key: 32-byte key in storage - value: 32-byte value to store + + Outputs ---- - None - RJUMP() - ---- + Fork ---- Frontier - Description - ---- + Gas ---- ``` static_gas = 0 - Inputs - ---- + if value == current_value if key is warm base_dynamic_gas = 100 else + base_dynamic_gas = 100 else if current_value == original_value if + original_value == 0 base_dynamic_gas = 20000 else base_dynamic_gas = 2900 + else base_dynamic_gas = 100 - Outputs - ---- + if key is cold: base_dynamic_gas += 2100 ``` + + Source: [evm.codes/#55](https://www.evm.codes/#55) - Fork - ---- - EOF Fork - Gas - ---- - Source: [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/eip-4200) """ - DATALOAD = Opcode(0xD0, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) + JUMP = Opcode(0x56, popped_stack_items=1, kwargs=["pc"]) """ - !!! Note: This opcode is under development - DATALOAD(offset) - ---- - Description - ---- - Reads 32 bytes of data at offset onto the stack - Inputs - ---- - - offset: offset within the data section to start copying - Outputs - ---- - none - Fork - ---- - EOF Fork - Gas - ---- - 4 + JUMP(pc) ---- + + Description ---- Alter the program counter + + Inputs ---- - pc: byte offset in the deployed code where execution will + continue from. Must be a JUMPDEST instruction + + Outputs ---- - None + + Fork ---- Frontier + + Gas ---- 8 + + Source: [evm.codes/#56](https://www.evm.codes/#56) + + - Source: [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) """ - DATALOADN = Opcode(0xD1, pushed_stack_items=1, data_portion_length=2) + JUMPI = Opcode(0x57, popped_stack_items=2, kwargs=["pc", "condition"]) """ - !!! Note: This opcode is under development - DATALOADN() - ---- - Description - ---- - Reads 32 bytes of data at offset onto the stack - Immediates - ---- - 2 bytes forming a UInt16, which is the offset into the data section. - Inputs - ---- - none - Outputs - ---- - none - Fork - ---- - EOF Fork + JUMPI(pc, condition) ---- + + Description ---- Conditionally alter the program counter + + Inputs ---- - pc: byte offset in the deployed code where execution will + continue from. Must be a JUMPDEST instruction - condition: the program + counter will be altered with the new value only if this value is different + from 0. Otherwise, the program counter is simply incremented and the next + instruction will be executed + + Fork ---- Frontier + + Gas ---- 10 + + Source: [evm.codes/#57](https://www.evm.codes/#57) + - Gas - ---- - 3 - Source: [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) """ - DATASIZE = Opcode(0xD2, pushed_stack_items=1) + PC = Opcode(0x58, pushed_stack_items=1) """ - !!! Note: This opcode is under development - DATASIZE() - ---- - Description - ---- - Returns the size of the data section - Inputs - ---- - Outputs - ---- - The size of the data section. If there is no data section, returns 0. - Fork - ---- - EOF Fork - Gas - ---- - 2 + PC() = counter ---- - Source: [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) - """ + Description ---- Get the value of the program counter prior to the + increment corresponding to this instruction - DATACOPY = Opcode(0xD3, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) - """ - !!! Note: This opcode is under development + Inputs ---- - None - DATACOPY(dest_offset, offset, size) - ---- + Outputs ---- - counter: PC of this instruction in the current program. - Description - ---- - Copies data from the data section into call frame memory + Fork ---- Frontier - Inputs - ---- - - dest_offset: The offset within the memory section to start copying to - - offset: The offset within the data section to start copying from - - size: The number of bytes to copy + Gas ---- 2 - Outputs - ---- - none + Source: [evm.codes/#58](https://www.evm.codes/#58) - Fork - ---- - EOF Fork - Gas - ---- - - minimum_word_size = (size + 31) / 32 - - static_gas = 3 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost - Source: [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) """ - RJUMPI = Opcode(0xE1, popped_stack_items=1, data_portion_length=2) + MSIZE = Opcode(0x59, pushed_stack_items=1) """ - !!! Note: This opcode is under development - RJUMPI() - ---- - Description - ---- - Inputs - ---- - Outputs - ---- - Fork - ---- - EOF Fork - Gas - ---- + MSIZE() = size ---- + + Description ---- Get the size of active memory in bytes + + Outputs ---- - size: current memory size in bytes (higher offset accessed + until now + 1) + + Fork ---- Frontier + + Gas ---- 2 + + Source: [evm.codes/#59](https://www.evm.codes/#59) + + - Source: [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/eip-4200) """ - RJUMPV = Opcode( - 0xE2, - popped_stack_items=1, - data_portion_formatter=_rjumpv_encoder, - ) + GAS = Opcode(0x5A, pushed_stack_items=1) """ - !!! Note: This opcode is under development - RJUMPV() - ---- - Description - ---- - Relative jump with variable offset. - When calling this opcode to generate bytecode, the first argument is used to format the data - portion of the opcode, and it can be either of two types: - - A bytes type, and in this instance the bytes are used verbatim as the data portion. - - An integer iterable, list or tuple or any other iterable, where each element is a - jump offset. - Inputs - ---- - Outputs - ---- - Fork - ---- - EOF Fork + GAS() = gas_remaining ---- + + Description ---- Get the amount of available gas, including the + corresponding reduction for the cost of this instruction + + Inputs ---- - None + + Outputs ---- - gas: remaining gas (after this instruction) + + Fork ---- Frontier + + Gas ---- 2 + + Source: [evm.codes/#5A](https://www.evm.codes/#5A) + - Gas - ---- - Source: [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/eip-4200) """ - CALLF = Opcode(0xE3, data_portion_length=2, unchecked_stack=True) + JUMPDEST = Opcode(0x5B) """ - !!! Note: This opcode is under development - CALLF() - ---- - Description - ---- - - deduct 5 gas - - read uint16 operand idx - - if 1024 < len(stack) + types[idx].max_stack_height - types[idx].inputs, execution results in - an exceptional halt - - if 1024 <= len(return_stack), execution results in an exceptional halt - - push new element to return_stack (current_code_idx, pc+3) - - update current_code_idx to idx and set pc to 0 - Inputs - ---- - Any: The inputs are not checked because we cannot know how many inputs the callee - function/section requires - Outputs - ---- - Any: The outputs are variable because we cannot know how many outputs the callee - function/section produces - Fork - ---- - EOF Fork + JUMPDEST() ---- + + Description ---- Mark a valid destination for jumps + + Inputs ---- - None + + Outputs ---- - None + + Fork ---- Frontier + + Gas ---- 1 + + Source: [evm.codes/#5B](https://www.evm.codes/#5B) + - Gas - ---- - 5 - Source: - [ipsilon/eof/blob/main/spec/eof.md](https://github.com/ipsilon/eof/blob/main/spec/eof.md) """ - RETF = Opcode(0xE4, terminating=True) + NOOP = Opcode(0x5B) """ + + + + + + + NOOP() ---- + + Description ---- Synonym for JUMPDEST. Performs no operation. + + Inputs ---- - None + + Outputs ---- - None + + Fork ---- Frontier + + Gas ---- 1 + + Source: [evm.codes/#5B](https://www.evm.codes/#5B) + + + + """ + + TLOAD = Opcode(0x5C, popped_stack_items=1, pushed_stack_items=1, kwargs=["key"]) + """ + + + + + + + TLOAD(key) = value ---- + + Description ---- Load word from transient storage + + Inputs ---- - key: 32-byte key in transient storage + + Outputs ---- - value: 32-byte value corresponding to that key. 0 if that + key was never written + + Fork ---- Cancun + + Gas ---- 100 + + Source: + [eips.ethereum.org/EIPS/eip-1153](https://eips.ethereum.org/EIPS/eip-1153) + + + + """ + + TSTORE = Opcode(0x5D, popped_stack_items=2, kwargs=["key", "value"]) + """ + + + + + + + TSTORE(key, value) ---- + + Description ---- Save word to transient storage + + Inputs ---- - key: 32-byte key in transient storage - value: 32-byte value + to store + + Fork ---- Cancun + + Gas ---- 100 + + Source: + [eips.ethereum.org/EIPS/eip-1153](https://eips.ethereum.org/EIPS/eip-1153) + + + + """ + + MCOPY = Opcode(0x5E, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) + """ + + + + + + + MCOPY(dest_offset, offset, size) ---- + + Description ---- Copies areas in memory + + Inputs ---- - dest_offset: byte offset in the memory where the result will + be copied - offset: byte offset in the calldata to copy - size: byte size + to copy + + Outputs ---- - None + + Fork ---- Cancun + + Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 3 - + dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + + Source: + [eips.ethereum.org/EIPS/eip-5656](https://eips.ethereum.org/EIPS/eip-5656) + + + + """ + + PUSH0 = Opcode(0x5F, pushed_stack_items=1) + """ + + + + + + + PUSH0() = value ---- + + Description ---- Place value 0 on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, equal to 0 + + Fork ---- Shanghai + + Gas ---- 2 + + Source: [evm.codes/#5F](https://www.evm.codes/#5F) + + + + """ + + PUSH1 = Opcode(0x60, pushed_stack_items=1, data_portion_length=1) + """ + + + + + + + PUSH1() = value ---- + + Description ---- Place 1 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#60](https://www.evm.codes/#60) + + + + """ + + PUSH2 = Opcode(0x61, pushed_stack_items=1, data_portion_length=2) + """ + + + + + + + PUSH2() = value ---- + + Description ---- Place 2 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#61](https://www.evm.codes/#61) + + + + """ + + PUSH3 = Opcode(0x62, pushed_stack_items=1, data_portion_length=3) + """ + + + + + + + PUSH3() = value ---- + + Description ---- Place 3 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#62](https://www.evm.codes/#62) + + + + """ + + PUSH4 = Opcode(0x63, pushed_stack_items=1, data_portion_length=4) + """ + + + + + + + PUSH4() = value ---- + + Description ---- Place 4 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#63](https://www.evm.codes/#63) + + + + """ + + PUSH5 = Opcode(0x64, pushed_stack_items=1, data_portion_length=5) + """ + + + + + + + PUSH5() = value ---- + + Description ---- Place 5 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#64](https://www.evm.codes/#64) + + + + """ + + PUSH6 = Opcode(0x65, pushed_stack_items=1, data_portion_length=6) + """ + + + + + + + PUSH6() = value ---- + + Description ---- Place 6 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#65](https://www.evm.codes/#65) + + + + """ + + PUSH7 = Opcode(0x66, pushed_stack_items=1, data_portion_length=7) + """ + + + + + + + PUSH7() = value ---- + + Description ---- Place 7 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#66](https://www.evm.codes/#66) + + + + """ + + PUSH8 = Opcode(0x67, pushed_stack_items=1, data_portion_length=8) + """ + + + + + + + PUSH8() = value ---- + + Description ---- Place 8 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#67](https://www.evm.codes/#67) + + + + """ + + PUSH9 = Opcode(0x68, pushed_stack_items=1, data_portion_length=9) + """ + + + + + + + PUSH9() = value ---- + + Description ---- Place 9 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#68](https://www.evm.codes/#68) + + + + """ + + PUSH10 = Opcode(0x69, pushed_stack_items=1, data_portion_length=10) + """ + + + + + + + PUSH10() = value ---- + + Description ---- Place 10 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#69](https://www.evm.codes/#69) + + + + """ + + PUSH11 = Opcode(0x6A, pushed_stack_items=1, data_portion_length=11) + """ + + + + + + + PUSH11() = value ---- + + Description ---- Place 11 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#6A](https://www.evm.codes/#6A) + + + + """ + + PUSH12 = Opcode(0x6B, pushed_stack_items=1, data_portion_length=12) + """ + + + + + + + PUSH12() = value ---- + + Description ---- Place 12 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#6B](https://www.evm.codes/#6B) + + + + """ + + PUSH13 = Opcode(0x6C, pushed_stack_items=1, data_portion_length=13) + """ + + + + + + + PUSH13() = value ---- + + Description ---- Place 13 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#6C](https://www.evm.codes/#6C) + + + + """ + + PUSH14 = Opcode(0x6D, pushed_stack_items=1, data_portion_length=14) + """ + + + + + + + PUSH14() = value ---- + + Description ---- Place 14 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + + + + + Gas ---- 3 + + Source: [evm.codes/#6D](https://www.evm.codes/#6D) + + + + """ + + PUSH15 = Opcode(0x6E, pushed_stack_items=1, data_portion_length=15) + """ + + + + + + + PUSH15() = value ---- + + Description ---- Place 15 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#6E](https://www.evm.codes/#6E) + + + + """ + + PUSH16 = Opcode(0x6F, pushed_stack_items=1, data_portion_length=16) + """ + + + + + + + PUSH16() = value ---- + + Description ---- Place 16 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#6F](https://www.evm.codes/#6F) + + + + """ + + PUSH17 = Opcode(0x70, pushed_stack_items=1, data_portion_length=17) + """ + + + + + + + PUSH17() = value ---- + + Description ---- Place 17 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#70](https://www.evm.codes/#70) + + + + """ + + PUSH18 = Opcode(0x71, pushed_stack_items=1, data_portion_length=18) + """ + + + + + + + PUSH18() = value ---- + + Description ---- Place 18 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#71](https://www.evm.codes/#71) + + + + """ + + PUSH19 = Opcode(0x72, pushed_stack_items=1, data_portion_length=19) + """ + + + + + + + PUSH19() = value ---- + + Description ---- Place 19 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#72](https://www.evm.codes/#72) + + + + """ + + PUSH20 = Opcode(0x73, pushed_stack_items=1, data_portion_length=20) + """ + + + + + + + PUSH20() = value ---- + + Description ---- Place 20 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#73](https://www.evm.codes/#73) + + + + """ + + PUSH21 = Opcode(0x74, pushed_stack_items=1, data_portion_length=21) + """ + + + + + + + PUSH21() = value ---- + + Description ---- Place 21 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#74](https://www.evm.codes/#74) + + + + """ + + PUSH22 = Opcode(0x75, pushed_stack_items=1, data_portion_length=22) + """ + + + + + + + PUSH22() = value ---- + + Description ---- Place 22 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#75](https://www.evm.codes/#75) + + + + """ + + PUSH23 = Opcode(0x76, pushed_stack_items=1, data_portion_length=23) + """ + + + + + + + PUSH23() = value ---- + + Description ---- Place 23 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#76](https://www.evm.codes/#76) + + + + """ + + PUSH24 = Opcode(0x77, pushed_stack_items=1, data_portion_length=24) + """ + + + + + + + PUSH24() = value ---- + + Description ---- Place 24 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#77](https://www.evm.codes/#77) + + + + """ + + PUSH25 = Opcode(0x78, pushed_stack_items=1, data_portion_length=25) + """ + + + + + + + PUSH25() = value ---- + + Description ---- Place 25 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#78](https://www.evm.codes/#78) + + + + """ + + PUSH26 = Opcode(0x79, pushed_stack_items=1, data_portion_length=26) + """ + + + + + + + PUSH26() = value ---- + + Description ---- Place 26 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#79](https://www.evm.codes/#79) + + + + """ + + PUSH27 = Opcode(0x7A, pushed_stack_items=1, data_portion_length=27) + """ + + + + + + + PUSH27() = value ---- + + Description ---- Place 27 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#7A](https://www.evm.codes/#7A) + + + + """ + + PUSH28 = Opcode(0x7B, pushed_stack_items=1, data_portion_length=28) + """ + + + + + + + PUSH28() = value ---- + + Description ---- Place 28 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#7B](https://www.evm.codes/#7B) + + + + """ + + PUSH29 = Opcode(0x7C, pushed_stack_items=1, data_portion_length=29) + """ + + + + + + + PUSH29() = value ---- + + Description ---- Place 29 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#7C](https://www.evm.codes/#7C) + + + + """ + + PUSH30 = Opcode(0x7D, pushed_stack_items=1, data_portion_length=30) + """ + + + + + + + PUSH30() = value ---- + + Description ---- Place 30 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#7D](https://www.evm.codes/#7D) + + + + """ + + PUSH31 = Opcode(0x7E, pushed_stack_items=1, data_portion_length=31) + """ + + + + + + + PUSH31() = value ---- + + Description ---- Place 31 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#7E](https://www.evm.codes/#7E) + + + + """ + + PUSH32 = Opcode(0x7F, pushed_stack_items=1, data_portion_length=32) + """ + + + + + + + PUSH32() = value ---- + + Description ---- Place 32 byte item on stack + + Inputs ---- - None + + Outputs ---- - value: pushed value, aligned to the right (put in the lowest + significant bytes) + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#7F](https://www.evm.codes/#7F) + + + + """ + + DUP1 = Opcode(0x80, pushed_stack_items=1, min_stack_height=1) + """ + + + + + + + DUP1(value) = value, value ---- + + Description ---- Duplicate 1st stack item + + Inputs ---- - value: value to duplicate + + Outputs ---- - value: duplicated value - value: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#80](https://www.evm.codes/#80) + + + + """ + + DUP2 = Opcode(0x81, pushed_stack_items=1, min_stack_height=2) + """ + + + + + + + DUP2(v1, v2) = v2, v1, v2 ---- + + Description ---- Duplicate 2nd stack item + + Inputs ---- - v1: ignored value - v2: value to duplicate + + Outputs ---- - v2: duplicated value - v1: ignored value - v2: original + value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#81](https://www.evm.codes/#81) + + + + """ + + DUP3 = Opcode(0x82, pushed_stack_items=1, min_stack_height=3) + """ + + + + + + + DUP3(v1, v2, v3) = v3, v1, v2, v3 ---- + + Description ---- Duplicate 3rd stack item + + Inputs ---- - v1: ignored value - v2: ignored value - v3: value to + duplicate + + Outputs ---- - v3: duplicated value - v1: ignored value - v2: ignored value + - v3: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#82](https://www.evm.codes/#82) + + + + """ + + DUP4 = Opcode(0x83, pushed_stack_items=1, min_stack_height=4) + """ + + + + + + + DUP4(v1, v2, v3, v4) = v4, v1, v2, v3, v4 ---- + + Description ---- Duplicate 4th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - v3: ignored value - + v4: value to duplicate + + Outputs ---- - v4: duplicated value - v1: ignored value - v2: ignored value + - v3: ignored value - v4: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#83](https://www.evm.codes/#83) + + + + """ + + DUP5 = Opcode(0x84, pushed_stack_items=1, min_stack_height=5) + """ + + + + + + + DUP5(v1, v2, v3, v4, v5) = v5, v1, v2, v3, v4, v5 ---- + + Description ---- Duplicate 5th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - v3: ignored value - + v4: ignored value - v5: value to duplicate + + Outputs ---- - v5: duplicated value - v1: ignored value - v2: ignored value + - v3: ignored value - v4: ignored value - v5: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#84](https://www.evm.codes/#84) + + + + """ + + DUP6 = Opcode(0x85, pushed_stack_items=1, min_stack_height=6) + """ + + + + + + + DUP6(v1, v2, ..., v5, v6) = v6, v1, v2, ..., v5, v6 ---- + + Description ---- Duplicate 6th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - ... - v5: ignored + value - v6: value to duplicate + + Outputs ---- - v6: duplicated value - v1: ignored value - v2: ignored value + - ... - v5: ignored value - v6: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#85](https://www.evm.codes/#85) + + + + """ + + DUP7 = Opcode(0x86, pushed_stack_items=1, min_stack_height=7) + """ + + + + + + + DUP7(v1, v2, ..., v6, v7) = v7, v1, v2, ..., v6, v7 ---- + + Description ---- Duplicate 7th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - ... - v6: ignored + value - v7: value to duplicate + + Outputs ---- - v7: duplicated value - v1: ignored value - v2: ignored value + - ... - v6: ignored value - v7: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#86](https://www.evm.codes/#86) + + + + """ + + DUP8 = Opcode(0x87, pushed_stack_items=1, min_stack_height=8) + """ + + + + + + + DUP8(v1, v2, ..., v7, v8) = v8, v1, v2, ..., v7, v8 ---- + + Description ---- Duplicate 8th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - ... - v7: ignored + value - v8: value to duplicate + + Outputs ---- - v8: duplicated value - v1: ignored value - v2: ignored value + - ... - v7: ignored value - v8: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#87](https://www.evm.codes/#87) + + + + """ + + DUP9 = Opcode(0x88, pushed_stack_items=1, min_stack_height=9) + """ + + + + + + + DUP9(v1, v2, ..., v8, v9) = v9, v1, v2, ..., v8, v9 ---- + + Description ---- Duplicate 9th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - ... - v8: ignored + value - v9: value to duplicate + + Outputs ---- - v9: duplicated value - v1: ignored value - v2: ignored value + - ... - v8: ignored value - v9: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#88](https://www.evm.codes/#88) + + + + """ + DUP10 = Opcode(0x89, pushed_stack_items=1, min_stack_height=10) + """ + + + + + + + DUP10(v1, v2, ..., v9, v10) = v10, v1, v2, ..., v9, v10 ---- + + Description ---- Duplicate 10th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - ... - v9: ignored + value - v10: value to duplicate + + Outputs ---- - v10: duplicated value - v1: ignored value - v2: ignored + value - ... - v9: ignored value - v10: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#89](https://www.evm.codes/#89) + + + + """ + + DUP11 = Opcode(0x8A, pushed_stack_items=1, min_stack_height=11) + """ + + + + + + + DUP11(v1, v2, ..., v10, v11) = v11, v1, v2, ..., v10, v11 ---- + + Description ---- Duplicate 11th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - ... - v10: ignored + value - v11: value to duplicate + + Outputs ---- - v11: duplicated value - v1: ignored value - v2: ignored + value - ... - v10: ignored value - v11: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#8A](https://www.evm.codes/#8A) + + + + """ + + DUP12 = Opcode(0x8B, pushed_stack_items=1, min_stack_height=12) + """ + + + + + + + DUP12(v1, v2, ..., v11, v12) = v12, v1, v2, ..., v11, v12 ---- + + Description ---- Duplicate 12th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - ... - v11: ignored + value - v12: value to duplicate + + Outputs ---- - v12: duplicated value - v1: ignored value - v2: ignored + value - ... - v11: ignored value - v12: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#8B](https://www.evm.codes/#8B) + + + + """ + + DUP13 = Opcode(0x8C, pushed_stack_items=1, min_stack_height=13) + """ + + + + + + + DUP13(v1, v2, ..., v12, v13) = v13, v1, v2, ..., v12, v13 ---- + + Description ---- Duplicate 13th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - ... - v12: ignored + value - v13: value to duplicate + + Outputs ---- - v13: duplicated value - v1: ignored value - v2: ignored + value - ... - v12: ignored value - v13: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#8C](https://www.evm.codes/#8C) + + + + """ + + DUP14 = Opcode(0x8D, pushed_stack_items=1, min_stack_height=14) + """ + + + + + + + DUP14(v1, v2, ..., v13, v14) = v14, v1, v2, ..., v13, v14 ---- + + Description ---- Duplicate 14th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - ... - v13: ignored + value - v14: value to duplicate + + Outputs ---- - v14: duplicated value - v1: ignored value - v2: ignored + value - ... - v13: ignored value - v14: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#8D](https://www.evm.codes/#8D) + + + + """ + + DUP15 = Opcode(0x8E, pushed_stack_items=1, min_stack_height=15) + """ + + + + + + + DUP15(v1, v2, ..., v14, v15) = v15, v1, v2, ..., v14, v15 ---- + + Description ---- Duplicate 15th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - ... - v14: ignored + value - v15: value to duplicate + + Outputs ---- - v15: duplicated value - v1: ignored value - v2: ignored + value - ... - v14: ignored value - v15: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#8E](https://www.evm.codes/#8E) + + + + """ + + DUP16 = Opcode(0x8F, pushed_stack_items=1, min_stack_height=16) + """ + + + + + + + DUP16(v1, v2, ..., v15, v16) = v16, v1, v2, ..., v15, v16 ---- + + Description ---- Duplicate 16th stack item + + Inputs ---- - v1: ignored value - v2: ignored value - ... - v15: ignored + value - v16: value to duplicate + + Outputs ---- - v16: duplicated value - v1: ignored value - v2: ignored + value - ... - v15: ignored value - v16: original value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#8F](https://www.evm.codes/#8F) + + + + """ + + SWAP1 = Opcode(0x90, min_stack_height=2) + """ + + + + + + + SWAP1(v1, v2) = v2, v1 ---- + + Description ---- Exchange the top stack item with the second stack item. + + Inputs ---- - v1: value to swap - v2: value to swap + + Outputs ---- - v1: swapped value - v2: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#90](https://www.evm.codes/#90) + + + + """ + + SWAP2 = Opcode(0x91, min_stack_height=3) + """ + + + + + + + SWAP2(v1, v2, v3) = v3, v2, v1 ---- + + Description ---- Exchange 1st and 3rd stack items + + Inputs ---- - v1: value to swap - v2: ignored value - v3: value to swap + + Outputs ---- - v3: swapped value - v2: ignored value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#91](https://www.evm.codes/#91) + + + + """ + + SWAP3 = Opcode(0x92, min_stack_height=4) + """ + + + + + + + SWAP3(v1, v2, v3, v4) = v4, v2, v3, v1 ---- + + Description ---- Exchange 1st and 4th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - v3: ignored value - + v4: value to swap + + Outputs ---- - v4: swapped value - v2: ignored value - v3: ignored value - + v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#92](https://www.evm.codes/#92) + + + + """ + + SWAP4 = Opcode(0x93, min_stack_height=5) + """ + + + + + + + SWAP4(v1, v2, ..., v4, v5) = v5, v2, ..., v4, v1 ---- + + Description ---- Exchange 1st and 5th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v4: ignored + value - v5: value to swap + + Outputs ---- - v5: swapped value - v2: ignored value - ... - v4: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#93](https://www.evm.codes/#93) + + + + """ + + SWAP5 = Opcode(0x94, min_stack_height=6) + """ + + + + + + + SWAP5(v1, v2, ..., v5, v6) = v6, v2, ..., v5, v1 ---- + + Description ---- Exchange 1st and 6th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v5: ignored + value - v6: value to swap + + Outputs ---- - v6: swapped value - v2: ignored value - ... - v5: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#94](https://www.evm.codes/#94) + + + + """ + + SWAP6 = Opcode(0x95, min_stack_height=7) + """ + + + + + + + SWAP6(v1, v2, ..., v6, v7) = v7, v2, ..., v6, v1 ---- + + Description ---- Exchange 1st and 7th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v6: ignored + value - v7: value to swap + + Outputs ---- - v7: swapped value - v2: ignored value - ... - v6: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#95](https://www.evm.codes/#95) + + + + """ + + SWAP7 = Opcode(0x96, min_stack_height=8) + """ + + + + + + + SWAP7(v1, v2, ..., v7, v8) = v8, v2, ..., v7, v1 ---- + + Description ---- Exchange 1st and 8th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v7: ignored + value - v8: value to swap + + Outputs ---- - v8: swapped value - v2: ignored value - ... - v7: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#96](https://www.evm.codes/#96) + + + + """ + + SWAP8 = Opcode(0x97, min_stack_height=9) + """ + + + + + + + SWAP8(v1, v2, ..., v8, v9) = v9, v2, ..., v8, v1 ---- + + Description ---- Exchange 1st and 9th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v8: ignored + value - v9: value to swap + + Outputs ---- - v9: swapped value - v2: ignored value - ... - v8: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#97](https://www.evm.codes/#97) + + + + """ + + SWAP9 = Opcode(0x98, min_stack_height=10) + """ + + + + + + + SWAP9(v1, v2, ..., v9, v10) = v10, v2, ..., v9, v1 ---- + + Description ---- Exchange 1st and 10th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v9: ignored + value - v10: value to swap + + Outputs ---- - v10: swapped value - v2: ignored value - ... - v9: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#98](https://www.evm.codes/#98) + + + + """ + + SWAP10 = Opcode(0x99, min_stack_height=11) + """ + + + + + + + SWAP10(v1, v2, ..., v10, v11) = v11, v2, ..., v10, v1 ---- + + Description ---- Exchange 1st and 11th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v10: ignored + value - v11: value to swap + + Outputs ---- - v11: swapped value - v2: ignored value - ... - v10: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#99](https://www.evm.codes/#99) + + + + """ + + SWAP11 = Opcode(0x9A, min_stack_height=12) + """ + + + + + + + SWAP11(v1, v2, ..., v11, v12) = v12, v2, ..., v11, v1 ---- + + Description ---- Exchange 1st and 12th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v11: ignored + value - v12: value to swap + + Outputs ---- - v12: swapped value - v2: ignored value - ... - v11: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#9A](https://www.evm.codes/#9A) + + + + """ + + SWAP12 = Opcode(0x9B, min_stack_height=13) + """ + + + + + + + SWAP12(v1, v2, ..., v12, v13) = v13, v2, ..., v12, v1 ---- + + Description ---- Exchange 1st and 13th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v12: ignored + value - v13: value to swap + + Outputs ---- - v13: swapped value - v2: ignored value - ... - v12: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#9B](https://www.evm.codes/#9B) + + + + """ + + SWAP13 = Opcode(0x9C, min_stack_height=14) + """ + + + + + + + SWAP13(v1, v2, ..., v13, v14) = v14, v2, ..., v13, v1 ---- + + Description ---- Exchange 1st and 14th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v13: ignored + value - v14: value to swap + + Outputs ---- - v14: swapped value - v2: ignored value - ... - v13: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#9C](https://www.evm.codes/#9C) + + + + """ + + SWAP14 = Opcode(0x9D, min_stack_height=15) + """ + + + + + + + SWAP14(v1, v2, ..., v14, v15) = v15, v2, ..., v14, v1 ---- + + Description ---- Exchange 1st and 15th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v14: ignored + value - v15: value to swap + + Outputs ---- - v15: swapped value - v2: ignored value - ... - v14: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#9D](https://www.evm.codes/#9D) + + + + """ + + SWAP15 = Opcode(0x9E, min_stack_height=16) + """ + + + + + + + SWAP15(v1, v2, ..., v15, v16) = v16, v2, ..., v15, v1 ---- + + Description ---- Exchange 1st and 16th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v15: ignored + value - v16: value to swap + + Outputs ---- - v16: swapped value - v2: ignored value - ... - v15: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#9E](https://www.evm.codes/#9E) + + + + """ + + SWAP16 = Opcode(0x9F, min_stack_height=17) + """ + + + + + + + SWAP16(v1, v2, ..., v16, v17) = v17, v2, ..., v16, v1 ---- + + Description ---- Exchange 1st and 17th stack items + + Inputs ---- - v1: value to swap - v2: ignored value - ... - v16: ignored + value - v17: value to swap + + Outputs ---- - v17: swapped value - v2: ignored value - ... - v16: ignored + value - v1: swapped value + + Fork ---- Frontier + + Gas ---- 3 + + Source: [evm.codes/#9F](https://www.evm.codes/#9F) + + + + """ + + LOG0 = Opcode(0xA0, popped_stack_items=2, kwargs=["offset", "size"]) + """ + + + + + + + LOG0(offset, size) ---- + + Description ---- Append log record with no topics + + Inputs ---- - offset: byte offset in the memory in bytes - size: byte size + to copy + + Outputs ---- - None + + Fork ---- Frontier + + Gas ---- - static_gas = 375 - dynamic_gas = 375 * topic_count + 8 * size + + memory_expansion_cost + + Source: [evm.codes/#A0](https://www.evm.codes/#A0) + + + + """ + + LOG1 = Opcode(0xA1, popped_stack_items=3, kwargs=["offset", "size", "topic_1"]) + """ + + + + + + + LOG1(offset, size, topic_1) ---- + + Description ---- Append log record with one topic + + Inputs ---- - offset: byte offset in the memory in bytes - size: byte size + to copy - topic_1: 32-byte value + + Outputs ---- - None + + Fork ---- Frontier + + Gas ---- - static_gas = 375 - dynamic_gas = 375 * topic_count + 8 * size + + memory_expansion_cost + + Source: [evm.codes/#A1](https://www.evm.codes/#A1) + + + + """ + + LOG2 = Opcode(0xA2, popped_stack_items=4, kwargs=["offset", "size", "topic_1", "topic_2"]) + """ + + + + + + + LOG2(offset, size, topic_1, topic_2) ---- + + Description ---- Append log record with two topics + + Inputs ---- - offset: byte offset in the memory in bytes - size: byte size + to copy - topic_1: 32-byte value - topic_2: 32-byte value + + Outputs ---- - None + + Fork ---- Frontier + + Gas ---- - static_gas = 375 - dynamic_gas = 375 * topic_count + 8 * size + + memory_expansion_cost + + Source: [evm.codes/#A2](https://www.evm.codes/#A2) + + + + """ + + LOG3 = Opcode( + 0xA3, popped_stack_items=5, kwargs=["offset", "size", "topic_1", "topic_2", "topic_3"] + ) + """ + + + + + + + LOG3(offset, size, topic_1, topic_2, topic_3) ---- + + Description ---- Append log record with three topics + + Inputs ---- - offset: byte offset in the memory in bytes - size: byte size + to copy - topic_1: 32-byte value - topic_2: 32-byte value - topic_3: + 32-byte value + + Outputs ---- - None + + Fork ---- Frontier + + Gas ---- - static_gas = 375 - dynamic_gas = 375 * topic_count + 8 * size + + memory_expansion_cost + + Source: [evm.codes/#A3](https://www.evm.codes/#A3) + + + + """ + + LOG4 = Opcode( + 0xA4, + popped_stack_items=6, + kwargs=["offset", "size", "topic_1", "topic_2", "topic_3", "topic_4"], + ) + """ + + + + + + + LOG4(offset, size, topic_1, topic_2, topic_3, topic_4) ---- + + Description ---- Append log record with four topics + + Inputs ---- - offset: byte offset in the memory in bytes - size: byte size + to copy - topic_1: 32-byte value - topic_2: 32-byte value - topic_3: + 32-byte value - topic_4: 32-byte value + + Outputs ---- - None + + Fork ---- Frontier + + Gas ---- - static_gas = 375 - dynamic_gas = 375 * topic_count + 8 * size + + memory_expansion_cost + + Source: [evm.codes/#A4](https://www.evm.codes/#A4) + + + + """ + + RJUMP = Opcode(0xE0, data_portion_length=2) + """ + + + + + + + !!! Note: This opcode is under development + + RJUMP() ---- + + Description ---- + + Inputs ---- + + Outputs ---- + + Fork ---- EOF Fork + + Gas ---- + + Source: + [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/eip-4200) + + + + """ + + DATALOAD = Opcode(0xD0, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) + """ + + + + + + + !!! Note: This opcode is under development + + DATALOAD(offset) ---- + + Description ---- Reads 32 bytes of data at offset onto the stack + + Inputs ---- - offset: offset within the data section to start copying + + Outputs ---- none + + Fork ---- EOF Fork + + Gas ---- 4 + + Source: + [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) + + + + """ + + DATALOADN = Opcode(0xD1, pushed_stack_items=1, data_portion_length=2) + """ + + + + + + + !!! Note: This opcode is under development + + DATALOADN() ---- + + Description ---- Reads 32 bytes of data at offset onto the stack + + Immediates ---- 2 bytes forming a UInt16, which is the offset into the data + section. + + Inputs ---- none + + Outputs ---- none + + Fork ---- EOF Fork + + Gas ---- 3 + + Source: + [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) + + + + """ + + DATASIZE = Opcode(0xD2, pushed_stack_items=1) + """ + + + + + + + !!! Note: This opcode is under development + + DATASIZE() ---- + + Description ---- Returns the size of the data section + + Inputs ---- + + Outputs ---- The size of the data section. If there is no data section, + returns 0. + + Fork ---- EOF Fork + + Gas ---- 2 + + Source: + [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) + + + + """ + + DATACOPY = Opcode(0xD3, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) + """ + + + + + + + !!! Note: This opcode is under development + + DATACOPY(dest_offset, offset, size) ---- + + Description ---- Copies data from the data section into call frame memory + + Inputs ---- - dest_offset: The offset within the memory section to start + copying to - offset: The offset within the data section to start copying + from - size: The number of bytes to copy + + Outputs ---- none + + Fork ---- EOF Fork + + Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 3 - + dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + + Source: + [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) + + + + """ + + RJUMPI = Opcode(0xE1, popped_stack_items=1, data_portion_length=2) + """ + + + + + + + !!! Note: This opcode is under development + + RJUMPI() ---- + + Description ---- + + Inputs ---- + + Outputs ---- + + Fork ---- EOF Fork + + Gas ---- + + Source: + [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/eip-4200) + + + + """ + + RJUMPV = Opcode( + 0xE2, + popped_stack_items=1, + data_portion_formatter=_rjumpv_encoder, + ) + """ + + + + + + + !!! Note: This opcode is under development + + RJUMPV() ---- + + Description ---- Relative jump with variable offset. + + When calling this opcode to generate bytecode, the first argument is used + to format the data portion of the opcode, and it can be either of two + types: - A bytes type, and in this instance the bytes are used verbatim as + the data portion. - An integer iterable, list or tuple or any other + iterable, where each element is a jump offset. + + Inputs ---- + + Outputs ---- + + Fork ---- EOF Fork + + Gas ---- + + Source: + [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/eip-4200) + + + + """ + + CALLF = Opcode(0xE3, data_portion_length=2, unchecked_stack=True) + """ + + + + + + + !!! Note: This opcode is under development + + CALLF() ---- + + Description ---- + + - deduct 5 gas - read uint16 operand idx - if 1024 < len(stack) + + types[idx].max_stack_height - types[idx].inputs, execution results in an + exceptional halt - if 1024 <= len(return_stack), execution results in an + exceptional halt - push new element to return_stack (current_code_idx, + pc+3) - update current_code_idx to idx and set pc to 0 + + Inputs ---- Any: The inputs are not checked because we cannot know how many + inputs the callee function/section requires + + Outputs ---- Any: The outputs are variable because we cannot know how many + outputs the callee function/section produces + + Fork ---- EOF Fork + + Gas ---- 5 + + Source: + [ipsilon/eof/blob/main/spec/eof.md](https://github.com/ipsilon/eof/blob/main/sp + ec/eof.md) + + + + """ + + RETF = Opcode(0xE4, terminating=True) + """ + + + + + + + !!! Note: This opcode is under development + + RETF() ---- + + Description ---- + + Inputs ---- + + Outputs ---- + + Fork ---- EOF Fork + + Gas ---- 3 + + + + """ + + JUMPF = Opcode(0xE5, data_portion_length=2, terminating=True, unchecked_stack=True) + """ + + + + + + + !!! Note: This opcode is under development + + JUMPF() ---- + + Description ---- + + - deduct 5 gas - read uint16 operand idx - if 1024 < len(stack) + + types[idx].max_stack_height - types[idx].inputs, execution results in an + exceptional halt - set current_code_idx to idx - set pc = 0 + + + + + + Inputs ---- + + Outputs ---- + + Fork ---- EOF Fork + + Gas ---- 5 + + + + + + + + """ + + DUPN = Opcode( + 0xE6, + pushed_stack_items=1, + data_portion_length=1, + stack_properties_modifier=_dupn_stack_properties_modifier, + ) + """ + + + + + + !!! Note: This opcode is under development - RETF() - ---- + DUPN() ---- - Description - ---- + Description ---- - Inputs - ---- + - deduct 3 gas - read uint8 operand imm - n = imm + 1 - n‘th (1-based) + stack item is duplicated at the top of the stack - Stack validation: + stack_height >= n - Outputs - ---- - Fork - ---- - EOF Fork - Gas - ---- - 3 - """ - JUMPF = Opcode(0xE5, data_portion_length=2, terminating=True, unchecked_stack=True) - """ - !!! Note: This opcode is under development - JUMPF() - ---- + Inputs ---- - Description - ---- + Outputs ---- + + Fork ---- EOF Fork + + Gas ---- - - deduct 5 gas - - read uint16 operand idx - - if 1024 < len(stack) + types[idx].max_stack_height - types[idx].inputs, execution results in - an exceptional halt - - set current_code_idx to idx - - set pc = 0 - Inputs - ---- - Outputs - ---- - Fork - ---- - EOF Fork - Gas - ---- - 5 """ - DUPN = Opcode( - 0xE6, - pushed_stack_items=1, - data_portion_length=1, - stack_properties_modifier=_dupn_stack_properties_modifier, + SWAPN = Opcode( + 0xE7, data_portion_length=1, stack_properties_modifier=_swapn_stack_properties_modifier ) """ - !!! Note: This opcode is under development - DUPN() - ---- - Description - ---- - - deduct 3 gas - - read uint8 operand imm - - n = imm + 1 - - n‘th (1-based) stack item is duplicated at the top of the stack - - Stack validation: stack_height >= n - Inputs - ---- - Outputs - ---- + !!! Note: This opcode is under development + + SWAPN() ---- + + Description ---- + + - deduct 3 gas - read uint8 operand imm - n = imm + 1 - n + 1th stack item + is swapped with the top stack item (1-based). - Stack validation: + stack_height >= n + 1 - Fork - ---- - EOF Fork - Gas - ---- - """ - SWAPN = Opcode( - 0xE7, data_portion_length=1, stack_properties_modifier=_swapn_stack_properties_modifier - ) - """ - !!! Note: This opcode is under development - SWAPN() - ---- + Inputs ---- - Description - ---- + Outputs ---- + + Fork ---- EOF Fork + + Gas ---- - - deduct 3 gas - - read uint8 operand imm - - n = imm + 1 - - n + 1th stack item is swapped with the top stack item (1-based). - - Stack validation: stack_height >= n + 1 - Inputs - ---- - Outputs - ---- - Fork - ---- - EOF Fork - Gas - ---- """ @@ -5095,36 +4683,39 @@ class Opcodes(Opcode, Enum): stack_properties_modifier=_exchange_stack_properties_modifier, ) """ + + + + + + !!! Note: This opcode is under development - EXCHANGE[x, y] - ---- + EXCHANGE[x, y] ---- + + Description ---- Exchanges two stack positions. Two nybbles, n is high 4 + bits + 1, then m is 4 low bits + 1. Exchanges the n+1'th item with the n + + m + 1 item. + + Inputs x and y when the opcode is used as `EXCHANGE[x, y]`, are equal to: - + x = n + 1 - y = n + m + 1 Which each equals to 1-based stack positions + swapped. + + Inputs ---- n + m + 1, or ((imm >> 4) + (imm &0x0F) + 3) from the raw + immediate, + + Outputs ---- n + m + 1, or ((imm >> 4) + (imm &0x0F) + 3) from the raw + immediate, + + Fork ---- EOF_FORK + + Gas ---- 3 - Description - ---- - Exchanges two stack positions. Two nybbles, n is high 4 bits + 1, then m is 4 low bits + 1. - Exchanges the n+1'th item with the n + m + 1 item. - Inputs x and y when the opcode is used as `EXCHANGE[x, y]`, are equal to: - - x = n + 1 - - y = n + m + 1 - Which each equals to 1-based stack positions swapped. - Inputs - ---- - n + m + 1, or ((imm >> 4) + (imm &0x0F) + 3) from the raw immediate, - Outputs - ---- - n + m + 1, or ((imm >> 4) + (imm &0x0F) + 3) from the raw immediate, - Fork - ---- - EOF_FORK - Gas - ---- - 3 """ @@ -5136,25 +4727,31 @@ class Opcodes(Opcode, Enum): kwargs=["salt", "input_offset", "input_size", "value"], ) """ + + + + + + !!! Note: This opcode is under development - EOFCREATE[initcontainer_index] (salt, input_offset, input_size, value) - ---- + EOFCREATE[initcontainer_index] (salt, input_offset, input_size, value) ---- + + Description ---- + + Inputs ---- + + Outputs ---- + + Fork ---- + + Gas ---- + - Description - ---- - Inputs - ---- - Outputs - ---- - Fork - ---- - Gas - ---- """ @@ -5165,25 +4762,31 @@ class Opcodes(Opcode, Enum): kwargs=["tx_initcode_hash", "salt", "input_offset", "input_size", "value"], ) """ + + + + + + !!! Note: This opcode is under development - TXCREATE (tx_initcode_hash, salt, input_offset, input_size, value) - ---- + TXCREATE (tx_initcode_hash, salt, input_offset, input_size, value) ---- + + Description ---- + + Inputs ---- + + Outputs ---- + + Fork ---- + + Gas ---- + - Description - ---- - Inputs - ---- - Outputs - ---- - Fork - ---- - Gas - ---- """ @@ -5195,25 +4798,31 @@ class Opcodes(Opcode, Enum): kwargs=["auxdata_offset", "auxdata_size"], ) """ + + + + + + !!! Note: This opcode is under development - RETURNCODE() - ---- + RETURNCODE() ---- + + Description ---- + + Inputs ---- + + Outputs ---- + + Fork ---- + + Gas ---- + - Description - ---- - Inputs - ---- - Outputs - ---- - Fork - ---- - Gas - ---- """ @@ -5221,40 +4830,35 @@ class Opcodes(Opcode, Enum): 0xF0, popped_stack_items=3, pushed_stack_items=1, kwargs=["value", "offset", "size"] ) """ - CREATE(value, offset, size) = address - ---- - Description - ---- - Create a new contract with the given code - Inputs - ---- - - value: value in wei to send to the new account - - offset: byte offset in the memory in bytes, the initialization code for the new account + + + + + CREATE(value, offset, size) = address ---- + + Description ---- Create a new contract with the given code + + Inputs ---- - value: value in wei to send to the new account - offset: byte + offset in the memory in bytes, the initialization code for the new account - size: byte size to copy (size of the initialization code) - Outputs - ---- - - address: the address of the deployed contract, 0 if the deployment failed + Outputs ---- - address: the address of the deployed contract, 0 if the + deployment failed - Fork - ---- - Frontier + Fork ---- Frontier - Gas - ---- - ``` - minimum_word_size = (size + 31) / 32 - init_code_cost = 2 * minimum_word_size - code_deposit_cost = 200 * deployed_code_size + Gas ---- ``` minimum_word_size = (size + 31) / 32 init_code_cost = 2 * + minimum_word_size code_deposit_cost = 200 * deployed_code_size - static_gas = 32000 - dynamic_gas = init_code_cost + memory_expansion_cost + deployment_code_execution_cost - + code_deposit_cost - ``` + static_gas = 32000 dynamic_gas = init_code_cost + memory_expansion_cost + + deployment_code_execution_cost + code_deposit_cost ``` Source: [evm.codes/#F0](https://www.evm.codes/#F0) + + + """ CALL = Opcode( @@ -5265,42 +4869,38 @@ class Opcodes(Opcode, Enum): kwargs_defaults={"gas": GAS}, ) """ - CALL(gas, address, value, args_offset, args_size, ret_offset, ret_size) = success - ---- - - Description - ---- - Message-call into an account - - Inputs - ---- - - gas: amount of gas to send to the sub context to execute. The gas that is not used by the sub - context is returned to this one - - address: the account which context to execute - - value: value in wei to send to the account - - args_offset: byte offset in the memory in bytes, the calldata of the sub context - - args_size: byte size to copy (size of the calldata) - - ret_offset: byte offset in the memory in bytes, where to store the return data of the sub - context - - ret_size: byte size to copy (size of the return data) - - Outputs - ---- - - success: return 0 if the sub context reverted, 1 otherwise - - Fork - ---- - Frontier - - Gas - ---- - ``` - static_gas = 0 - dynamic_gas = memory_expansion_cost + code_execution_cost + address_access_cost - + positive_value_cost + value_to_empty_account_cost - ``` + + + + + + + CALL(gas, address, value, args_offset, args_size, ret_offset, ret_size) = + success ---- + + Description ---- Message-call into an account + + Inputs ---- - gas: amount of gas to send to the sub context to execute. The + gas that is not used by the sub context is returned to this one - address: + the account which context to execute - value: value in wei to send to the + account - args_offset: byte offset in the memory in bytes, the calldata of + the sub context - args_size: byte size to copy (size of the calldata) - + ret_offset: byte offset in the memory in bytes, where to store the return + data of the sub context - ret_size: byte size to copy (size of the return + data) + + Outputs ---- - success: return 0 if the sub context reverted, 1 otherwise + + Fork ---- Frontier + + Gas ---- ``` static_gas = 0 dynamic_gas = memory_expansion_cost + + code_execution_cost + address_access_cost + positive_value_cost + + value_to_empty_account_cost ``` Source: [evm.codes/#F1](https://www.evm.codes/#F1) + + + """ CALLCODE = Opcode( @@ -5311,74 +4911,67 @@ class Opcodes(Opcode, Enum): kwargs_defaults={"gas": GAS}, ) """ - CALLCODE(gas, address, value, args_offset, args_size, ret_offset, ret_size) = success - ---- - - Description - ---- - Message-call into this account with an alternative account's code. Executes code starting at - the address to which the call is made. - - Inputs - ---- - - gas: amount of gas to send to the sub context to execute. The gas that is not used by the sub - context is returned to this one - - address: the account which code to execute - - value: value in wei to send to the account - - args_offset: byte offset in the memory in bytes, the calldata of the sub context - - args_size: byte size to copy (size of the calldata) - - ret_offset: byte offset in the memory in bytes, where to store the return data of the sub - context - - ret_size: byte size to copy (size of the return data) - - Outputs - ---- - - success: return 0 if the sub context reverted, 1 otherwise - - Fork - ---- - Frontier - - Gas - ---- - ``` - static_gas = 0 - dynamic_gas = memory_expansion_cost + code_execution_cost + address_access_cost - + positive_value_cost - ``` + + + + + + + CALLCODE(gas, address, value, args_offset, args_size, ret_offset, ret_size) + = success ---- + + Description ---- Message-call into this account with an alternative + account's code. Executes code starting at the address to which the call is + made. + + Inputs ---- - gas: amount of gas to send to the sub context to execute. The + gas that is not used by the sub context is returned to this one - address: + the account which code to execute - value: value in wei to send to the + account - args_offset: byte offset in the memory in bytes, the calldata of + the sub context - args_size: byte size to copy (size of the calldata) - + ret_offset: byte offset in the memory in bytes, where to store the return + data of the sub context - ret_size: byte size to copy (size of the return + data) + + Outputs ---- - success: return 0 if the sub context reverted, 1 otherwise + + Fork ---- Frontier + + Gas ---- ``` static_gas = 0 dynamic_gas = memory_expansion_cost + + code_execution_cost + address_access_cost + positive_value_cost ``` Source: [evm.codes/#F2](https://www.evm.codes/#F2) + + + """ RETURN = Opcode(0xF3, popped_stack_items=2, kwargs=["offset", "size"], terminating=True) """ - RETURN(offset, size) - ---- - Description - ---- - Halt execution returning output data - Inputs - ---- - - offset: byte offset in the memory in bytes, to copy what will be the return data of this - context - - size: byte size to copy (size of the return data) - Outputs - ---- - - None - Fork - ---- - Frontier - Gas - ---- - - static_gas = 0 - - dynamic_gas = memory_expansion_cost + + RETURN(offset, size) ---- + + Description ---- Halt execution returning output data + + Inputs ---- - offset: byte offset in the memory in bytes, to copy what will + be the return data of this context - size: byte size to copy (size of the + return data) + + Outputs ---- - None + + Fork ---- Frontier + + Gas ---- - static_gas = 0 - dynamic_gas = memory_expansion_cost Source: [evm.codes/#F3](https://www.evm.codes/#F3) + + + """ DELEGATECALL = Opcode( @@ -5389,39 +4982,37 @@ class Opcodes(Opcode, Enum): kwargs_defaults={"gas": GAS}, ) """ - DELEGATECALL(gas, address, args_offset, args_size, ret_offset, ret_size) = success - ---- - - Description - ---- - Message-call into this account with an alternative account's code, but persisting the current - values for sender and value - - Inputs - ---- - - gas: amount of gas to send to the sub context to execute. The gas that is not used by the sub - context is returned to this one - - address: the account which code to execute - - args_offset: byte offset in the memory in bytes, the calldata of the sub context - - args_size: byte size to copy (size of the calldata) - - ret_offset: byte offset in the memory in bytes, where to store the return data of the sub - context - - ret_size: byte size to copy (size of the return data) - - Outputs - ---- - - success: return 0 if the sub context reverted, 1 otherwise - - Fork - ---- - Byzantium - - Gas - ---- - - static_gas = 0 - - dynamic_gas = memory_expansion_cost + code_execution_cost + address_access_cost + + + + + + + DELEGATECALL(gas, address, args_offset, args_size, ret_offset, ret_size) = + success ---- + + Description ---- Message-call into this account with an alternative + account's code, but persisting the current values for sender and value + + Inputs ---- - gas: amount of gas to send to the sub context to execute. The + gas that is not used by the sub context is returned to this one - address: + the account which code to execute - args_offset: byte offset in the memory + in bytes, the calldata of the sub context - args_size: byte size to copy + (size of the calldata) - ret_offset: byte offset in the memory in bytes, + where to store the return data of the sub context - ret_size: byte size to + copy (size of the return data) + + Outputs ---- - success: return 0 if the sub context reverted, 1 otherwise + + Fork ---- Byzantium + + Gas ---- - static_gas = 0 - dynamic_gas = memory_expansion_cost + + code_execution_cost + address_access_cost Source: [evm.codes/#F4](https://www.evm.codes/#F4) + + + """ CREATE2 = Opcode( @@ -5431,42 +5022,38 @@ class Opcodes(Opcode, Enum): kwargs=["value", "offset", "size", "salt"], ) """ - CREATE2(value, offset, size, salt) = address - ---- - Description - ---- - Creates a new contract - Inputs - ---- - - value: value in wei to send to the new account - - offset: byte offset in the memory in bytes, the initialization code of the new account - - size: byte size to copy (size of the initialization code) - - salt: 32-byte value used to create the new account at a deterministic address - Outputs - ---- - - address: the address of the deployed contract, 0 if the deployment failed - Fork - ---- - Constantinople - Gas - ---- - ``` - minimum_word_size = (size + 31) / 32 - init_code_cost = 2 * minimum_word_size - hash_cost = 6 * minimum_word_size - code_deposit_cost = 200 * deployed_code_size - - static_gas = 32000 - dynamic_gas = init_code_cost + hash_cost + memory_expansion_cost - + deployment_code_execution_cost + code_deposit_cost + + CREATE2(value, offset, size, salt) = address ---- + + Description ---- Creates a new contract + + Inputs ---- - value: value in wei to send to the new account - offset: byte + offset in the memory in bytes, the initialization code of the new account - + size: byte size to copy (size of the initialization code) - salt: 32-byte + value used to create the new account at a deterministic address + + Outputs ---- - address: the address of the deployed contract, 0 if the + deployment failed + + Fork ---- Constantinople + + Gas ---- ``` minimum_word_size = (size + 31) / 32 init_code_cost = 2 * + minimum_word_size hash_cost = 6 * minimum_word_size code_deposit_cost = 200 + * deployed_code_size + + static_gas = 32000 dynamic_gas = init_code_cost + hash_cost + + memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost ``` Source: [evm.codes/#F5](https://www.evm.codes/#F5) + + + """ EXTCALL = Opcode( @@ -5476,40 +5063,35 @@ class Opcodes(Opcode, Enum): kwargs=["address", "args_offset", "args_size", "value"], ) """ - EXTCALL(address, args_offset, args_size, value) = address - ---- - - Description - ---- - Message-call into an account - - Inputs - ---- - - address: the account which context to execute - - args_offset: byte offset in the memory in bytes, the calldata of the sub context - - args_size: byte size to copy (size of the calldata) - - value: value in wei to send to the account - - Outputs - ---- - - success: - - `0` if the call was successful. - - `1` if the call has reverted (also can be pushed earlier in a light failure scenario). - - `2` if the call has failed. - - Fork - ---- - Prague - - Gas - ---- - ``` - static_gas = 0 - dynamic_gas = memory_expansion_cost + code_execution_cost + address_access_cost - + positive_value_cost + value_to_empty_account_cost - ``` + + + + + + + EXTCALL(address, args_offset, args_size, value) = address ---- + + Description ---- Message-call into an account + + Inputs ---- - address: the account which context to execute - args_offset: + byte offset in the memory in bytes, the calldata of the sub context - + args_size: byte size to copy (size of the calldata) - value: value in wei + to send to the account + + Outputs ---- - success: - `0` if the call was successful. - `1` if the call + has reverted (also can be pushed earlier in a light failure scenario). - + `2` if the call has failed. + + Fork ---- Prague + + Gas ---- ``` static_gas = 0 dynamic_gas = memory_expansion_cost + + code_execution_cost + address_access_cost + positive_value_cost + + value_to_empty_account_cost ``` Source: [EIP-7069](https://eips.ethereum.org/EIPS/eip-7069) + + + """ EXTDELEGATECALL = Opcode( @@ -5519,37 +5101,34 @@ class Opcodes(Opcode, Enum): kwargs=["address", "args_offset", "args_size"], ) """ - EXTDELEGATECALL(address, args_offset, args_size) = address - ---- - Description - ---- - Message-call into this account with an alternative account's code, but persisting the current - values for sender and value - Inputs - ---- - - address: the account which context to execute - - args_offset: byte offset in the memory in bytes, the calldata of the sub context - - args_size: byte size to copy (size of the calldata) - Outputs - ---- - - success: - - `0` if the call was successful. - - `1` if the call has reverted (also can be pushed earlier in a light failure scenario). - - `2` if the call has failed. - Fork - ---- - Prague - Gas - ---- - - static_gas = 0 - - dynamic_gas = memory_expansion_cost + code_execution_cost + address_access_cost + + EXTDELEGATECALL(address, args_offset, args_size) = address ---- + + Description ---- Message-call into this account with an alternative + account's code, but persisting the current values for sender and value + + Inputs ---- - address: the account which context to execute - args_offset: + byte offset in the memory in bytes, the calldata of the sub context - + args_size: byte size to copy (size of the calldata) + + Outputs ---- - success: - `0` if the call was successful. - `1` if the call + has reverted (also can be pushed earlier in a light failure scenario). - + `2` if the call has failed. + + Fork ---- Prague + + Gas ---- - static_gas = 0 - dynamic_gas = memory_expansion_cost + + code_execution_cost + address_access_cost Source: [EIP-7069](https://eips.ethereum.org/EIPS/eip-7069) + + + """ STATICCALL = Opcode( @@ -5560,38 +5139,36 @@ class Opcodes(Opcode, Enum): kwargs_defaults={"gas": GAS}, ) """ - STATICCALL(gas, address, args_offset, args_size, ret_offset, ret_size) = success - ---- - - Description - ---- - Static message-call into an account - - Inputs - ---- - - gas: amount of gas to send to the sub context to execute. The gas that is not used by the sub - context is returned to this one - - address: the account which context to execute - - args_offset: byte offset in the memory in bytes, the calldata of the sub context - - args_size: byte size to copy (size of the calldata) - - ret_offset: byte offset in the memory in bytes, where to store the return data of the sub - context - - ret_size: byte size to copy (size of the return data) - - Outputs - ---- - - success: return 0 if the sub context reverted, 1 otherwise - - Fork - ---- - Byzantium - - Gas - ---- - - static_gas = 0 - - dynamic_gas = memory_expansion_cost + code_execution_cost + address_access_cost + + + + + + + STATICCALL(gas, address, args_offset, args_size, ret_offset, ret_size) = + success ---- + + Description ---- Static message-call into an account + + Inputs ---- - gas: amount of gas to send to the sub context to execute. The + gas that is not used by the sub context is returned to this one - address: + the account which context to execute - args_offset: byte offset in the + memory in bytes, the calldata of the sub context - args_size: byte size to + copy (size of the calldata) - ret_offset: byte offset in the memory in + bytes, where to store the return data of the sub context - ret_size: byte + size to copy (size of the return data) + + Outputs ---- - success: return 0 if the sub context reverted, 1 otherwise + + Fork ---- Byzantium + + Gas ---- - static_gas = 0 - dynamic_gas = memory_expansion_cost + + code_execution_cost + address_access_cost Source: [evm.codes/#FA](https://www.evm.codes/#FA) + + + """ EXTSTATICCALL = Opcode( @@ -5601,136 +5178,132 @@ class Opcodes(Opcode, Enum): kwargs=["address", "args_offset", "args_size"], ) """ - EXTSTATICCALL(address, args_offset, args_size) = address - ---- - Description - ---- - Static message-call into an account - Inputs - ---- - - address: the account which context to execute - - args_offset: byte offset in the memory in bytes, the calldata of the sub context - - args_size: byte size to copy (size of the calldata) - Outputs - ---- - - success: - - `0` if the call was successful. - - `1` if the call has reverted (also can be pushed earlier in a light failure scenario). - - `2` if the call has failed. - Fork - ---- - Prague - Gas - ---- - - static_gas = 0 - - dynamic_gas = memory_expansion_cost + code_execution_cost + address_access_cost + + EXTSTATICCALL(address, args_offset, args_size) = address ---- + + Description ---- Static message-call into an account + + Inputs ---- - address: the account which context to execute - args_offset: + byte offset in the memory in bytes, the calldata of the sub context - + args_size: byte size to copy (size of the calldata) + + Outputs ---- - success: - `0` if the call was successful. - `1` if the call + has reverted (also can be pushed earlier in a light failure scenario). - + `2` if the call has failed. + + Fork ---- Prague + + Gas ---- - static_gas = 0 - dynamic_gas = memory_expansion_cost + + code_execution_cost + address_access_cost Source: [EIP-7069](https://eips.ethereum.org/EIPS/eip-7069) + + + """ RETURNDATALOAD = Opcode(0xF7, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) """ - RETURNDATALOAD(offset) - ---- - Description - ---- - Copy 32 bytes from returndata at offset onto the stack - Inputs - ---- - - offset: byte offset in the return data from the last executed sub context to copy - Fork - ---- - EOF - Gas - ---- - 3 + + + RETURNDATALOAD(offset) ---- + + Description ---- Copy 32 bytes from returndata at offset onto the stack + + Inputs ---- - offset: byte offset in the return data from the last executed + sub context to copy + + Fork ---- EOF + + Gas ---- 3 + + + """ REVERT = Opcode(0xFD, popped_stack_items=2, kwargs=["offset", "size"], terminating=True) """ - REVERT(offset, size) - ---- - Description - ---- - Halt execution reverting state changes but returning data and remaining gas - Inputs - ---- - - offset: byte offset in the memory in bytes. The return data of the calling context - - size: byte size to copy (size of the return data) - Fork - ---- - Byzantium - Gas - ---- - static_gas = 0 - dynamic_gas = memory_expansion_cost + + + REVERT(offset, size) ---- + + Description ---- Halt execution reverting state changes but returning data + and remaining gas + + Inputs ---- - offset: byte offset in the memory in bytes. The return data + of the calling context - size: byte size to copy (size of the return data) + + Fork ---- Byzantium + + Gas ---- static_gas = 0 dynamic_gas = memory_expansion_cost Source: [evm.codes/#FD](https://www.evm.codes/#FD) + + + """ INVALID = Opcode(0xFE, terminating=True) """ - INVALID() - ---- - Description - ---- - Designated invalid instruction - Inputs - ---- - None - Outputs - ---- - None - Fork - ---- - Frontier - Gas - ---- - All the remaining gas in this context is consumed + + INVALID() ---- + + Description ---- Designated invalid instruction + + Inputs ---- None + + Outputs ---- None + + Fork ---- Frontier + + Gas ---- All the remaining gas in this context is consumed Source: [evm.codes/#FE](https://www.evm.codes/#FE) + + + """ SELFDESTRUCT = Opcode(0xFF, popped_stack_items=1, kwargs=["address"]) """ - SELFDESTRUCT(address) - ---- - Description - ---- - Halt execution and register the account for later deletion - Inputs - ---- - - address: account to send the current balance to - Fork - ---- - Frontier - Gas - ---- - 5000 + + + SELFDESTRUCT(address) ---- + + Description ---- Halt execution and register the account for later deletion + + Inputs ---- - address: account to send the current balance to + + Fork ---- Frontier + + Gas ---- 5000 Source: [evm.codes/#FF](https://www.evm.codes/#FF) + + + """ @@ -5771,7 +5344,9 @@ class Opcodes(Opcode, Enum): def _mstore_operation(data: OpcodeCallArg = b"", offset: OpcodeCallArg = 0) -> Bytecode: - """Generate the bytecode that stores an arbitrary amount of data in memory.""" + """ + Generate the bytecode that stores an arbitrary amount of data in memory. + """ assert isinstance(offset, int) if isinstance(data, int): data = data.to_bytes(32, "big") @@ -5782,10 +5357,11 @@ def _mstore_operation(data: OpcodeCallArg = b"", offset: OpcodeCallArg = 0) -> B if len(chunk) == 32: bytecode += Opcodes.MSTORE(offset, chunk) else: - # We need to MLOAD the existing data at the offset and then do a bitwise OR with the - # new data to store it in memory. + # We need to MLOAD the existing data at the offset and then do a + # bitwise OR with the new data to store it in memory. bytecode += Opcodes.MLOAD(offset) - # Create a mask to zero out the leftmost bytes of the existing data. + # Create a mask to zero out the leftmost bytes of the existing + # data. mask_size = 32 - len(chunk) bytecode += _push_opcodes_byte_list[mask_size - 1][-1] bytecode += Opcodes.AND @@ -5802,53 +5378,54 @@ class Macros(Macro, Enum): OOG = Macro(Opcodes.SHA3(0, 100000000000)) """ - OOG() - ---- + + + + + + + OOG() ---- Halt execution by consuming all available gas. - Inputs - ---- - - None. Any input arguments are ignored. + Inputs ---- - None. Any input arguments are ignored. - Outputs - ---- - - None + Outputs ---- - None - Fork - ---- - Frontier + Fork ---- Frontier + + Gas ---- `SHA3(0, 100000000000)` results in 19073514453125027 gas used and + an OOG exception. + + Note: If a value > `100000000000` is used as second argument, the resulting + geth trace reports gas `30` and an OOG exception. `SHA3(0, SUB(0, 1))` + causes a gas > u64 exception and an OOG exception. + + Bytecode ---- SHA3(0, 100000000000) - Gas - ---- - `SHA3(0, 100000000000)` results in 19073514453125027 gas used and an OOG - exception. - Note: - If a value > `100000000000` is used as second argument, the resulting geth - trace reports gas `30` and an OOG exception. - `SHA3(0, SUB(0, 1))` causes a gas > u64 exception and an OOG exception. - Bytecode - ---- - SHA3(0, 100000000000) """ MSTORE = Macro(lambda_operation=_mstore_operation) """ - MSTORE(data, offset) - ---- + + + + + + + MSTORE(data, offset) ---- Place data of arbitrary length into memory at a given offset. - Inputs - ---- - - data: The data to store in memory. Can be an integer or bytes. - - offset: The offset in memory to store the data. + Inputs ---- - data: The data to store in memory. Can be an integer or + bytes. - offset: The offset in memory to store the data. + + Outputs ---- - None + + - Outputs - ---- - - None """ diff --git a/src/pytest_plugins/concurrency.py b/src/pytest_plugins/concurrency.py index 10dadcca9c6..0601824c338 100644 --- a/src/pytest_plugins/concurrency.py +++ b/src/pytest_plugins/concurrency.py @@ -1,6 +1,6 @@ """ -Pytest plugin to create a temporary folder for the session where -multi-process tests can store data that is shared between processes. +Pytest plugin to create a temporary folder for the session where multi-process +tests can store data that is shared between processes. The provided `session_temp_folder` fixture is used, for example, by `consume` when running hive simulators to ensure that only one `test_suite` is created @@ -24,8 +24,8 @@ def session_temp_folder_name(testrun_uid: str) -> str: Define the name of the temporary folder that will be shared among all the xdist workers to coordinate the tests. - "testrun_uid" is a fixture provided by the xdist plugin, and is unique for each test run, - so it is used to create the unique folder name. + "testrun_uid" is a fixture provided by the xdist plugin, and is unique for + each test run, so it is used to create the unique folder name. """ return f"pytest-{testrun_uid}" @@ -35,11 +35,11 @@ def session_temp_folder( session_temp_folder_name: str, ) -> Generator[Path, None, None]: """ - Create a global temporary folder that will be shared among all the - xdist workers to coordinate the tests. + Create a global temporary folder that will be shared among all the xdist + workers to coordinate the tests. - We also create a file to keep track of how many workers are still using the folder, so we can - delete it when the last worker is done. + We also create a file to keep track of how many workers are still using the + folder, so we can delete it when the last worker is done. """ session_temp_folder = Path(get_temp_dir()) / session_temp_folder_name session_temp_folder.mkdir(exist_ok=True) diff --git a/src/pytest_plugins/consume/consume.py b/src/pytest_plugins/consume/consume.py index 676c7548081..fb04421aa4e 100644 --- a/src/pytest_plugins/consume/consume.py +++ b/src/pytest_plugins/consume/consume.py @@ -1,4 +1,6 @@ -"""A pytest plugin providing common functionality for consuming test fixtures.""" +""" +A pytest plugin providing common functionality for consuming test fixtures. +""" import re import sys @@ -53,7 +55,10 @@ def __init__(self, url: str, destination_folder: Path): # noqa: D107 self.archive_name = self.strip_archive_extension(Path(self.parsed_url.path).name) def download_and_extract(self) -> Tuple[bool, Path]: - """Download the URL and extract it locally if it hasn't already been downloaded.""" + """ + Download the URL and extract it locally if it hasn't already been + downloaded. + """ if self.destination_folder.exists(): return True, self.detect_extracted_directory() @@ -94,8 +99,8 @@ def fetch_and_extract(self) -> Path: def detect_extracted_directory(self) -> Path: """ - Detect a single top-level dir within the extracted archive, otherwise return - destination_folder. + Detect a single top-level dir within the extracted archive, otherwise + return destination_folder. """ # noqa: D200 extracted_dirs = [ d for d in self.destination_folder.iterdir() if d.is_dir() and d.name != ".meta" @@ -196,7 +201,9 @@ def from_url( def from_release_spec( cls, spec: str, cache_folder: Optional[Path] = None, extract_to: Optional[Path] = None ) -> "FixturesSource": - """Create a fixture source from a release spec (e.g., develop@latest).""" + """ + Create a fixture source from a release spec (e.g., develop@latest). + """ if cache_folder is None: cache_folder = CACHED_DOWNLOADS_DIRECTORY url = get_release_url(spec) @@ -224,7 +231,9 @@ def from_release_spec( @staticmethod def validate_local_path(path: Path) -> "FixturesSource": - """Validate that a local fixture path exists and contains JSON files.""" + """ + Validate that a local fixture path exists and contains JSON files. + """ if not path.exists(): pytest.exit(f"Specified fixture directory '{path}' does not exist.") if not any(path.glob("**/*.json")): @@ -242,24 +251,26 @@ def __init__(self, pattern: str, collectonly: bool = False): # noqa: D107 @staticmethod def _escape_id(pattern: str) -> str: """ - Escape regex char in the pattern; prepend and append '.*' (for `fill` IDs). + Escape regex char in the pattern; prepend and append '.*' (for `fill` + IDs). - The `pattern` is prefixed and suffixed with a wildcard match to allow `fill` - test case IDs to be specified, otherwise the full `consume` test ID must be - specified. + The `pattern` is prefixed and suffixed with a wildcard match to allow + `fill` test case IDs to be specified, otherwise the full `consume` test + ID must be specified. """ return f".*{re.escape(pattern)}.*" @classmethod def from_string(cls, pattern: str) -> "SimLimitBehavior": """ - Parse the `--sim.limit` argument and return a `SimLimitBehavior` instance. - - If `pattern`: - - Is "collectonly", enable collection mode without filtering. - - Starts with "collectonly:", enable collection mode and use the rest as a regex pattern. - - Starts with "id:", treat the rest as a literal test ID and escape special regex chars. - - Starts with "collectonly:id:", enable collection mode with a literal test ID. + Parse the `--sim.limit` argument and return a `SimLimitBehavior` + instance. + + If `pattern`: - Is "collectonly", enable collection mode without + filtering. - Starts with "collectonly:", enable collection mode and use + the rest as a regex pattern. - Starts with "id:", treat the rest as a + literal test ID and escape special regex chars. - Starts with + "collectonly:id:", enable collection mode with a literal test ID. """ if pattern == "collectonly": return cls(pattern=".*", collectonly=True) @@ -357,22 +368,23 @@ def pytest_configure(config): # noqa: D103 test collection begins. `@pytest.hookimpl(tryfirst=True)` is applied to ensure that this hook is - called before the pytest-html plugin's pytest_configure to ensure that - it uses the modified `htmlpath` option. + called before the pytest-html plugin's pytest_configure to ensure that it + uses the modified `htmlpath` option. """ # Validate --extract-to usage if config.option.extract_to_folder is not None and "cache" not in sys.argv: pytest.exit("The --extract-to flag is only valid with the 'cache' command.") if config.option.fixtures_source is None: - # NOTE: Setting the default value here is necessary for correct stdin/piping behavior. + # NOTE: Setting the default value here is necessary for correct + # stdin/piping behavior. config.fixtures_source = FixturesSource( input_option=default_input(), path=Path(default_input()) ) else: - # NOTE: Setting `type=FixturesSource.from_input` in pytest_addoption() causes the option to - # be evaluated twice which breaks the result of `was_cached`; the work-around is to call it - # manually here. + # NOTE: Setting `type=FixturesSource.from_input` in pytest_addoption() + # causes the option to be evaluated twice which breaks the result of + # `was_cached`; the work-around is to call it manually here. config.fixtures_source = FixturesSource.from_input( config.option.fixtures_source, Path(config.option.fixture_cache_folder), @@ -428,7 +440,8 @@ def pytest_configure(config): # noqa: D103 all_forks = { # type: ignore fork for fork in set(get_forks()) | get_transition_forks() if not fork.ignore() } - # Append all forks within the index file (compatibility with `ethereum/tests`) + # Append all forks within the index file (compatibility with + # `ethereum/tests`) all_forks.update(getattr(index, "forks", [])) for fork in all_forks: config.addinivalue_line("markers", f"{fork}: Tests for the {fork} fork") @@ -483,7 +496,8 @@ def fixtures_source(request) -> FixturesSource: # noqa: D103 def pytest_generate_tests(metafunc): """ Generate test cases for every test fixture in all the JSON fixture files - within the specified fixtures directory, or read from stdin if the directory is 'stdin'. + within the specified fixtures directory, or read from stdin if the + directory is 'stdin'. """ if "cache" in sys.argv: return diff --git a/src/pytest_plugins/consume/direct/conftest.py b/src/pytest_plugins/consume/direct/conftest.py index e584e013471..db9208a910a 100644 --- a/src/pytest_plugins/consume/direct/conftest.py +++ b/src/pytest_plugins/consume/direct/conftest.py @@ -1,6 +1,6 @@ """ -A pytest plugin that configures the consume command to act as a test runner -for "direct" client fixture consumer interfaces. +A pytest plugin that configures the consume command to act as a test runner for +"direct" client fixture consumer interfaces. For example, via go-ethereum's `evm blocktest` or `evm statetest` commands. """ @@ -120,7 +120,8 @@ def fixture_path(test_case: TestCaseIndexFile | TestCaseStream, fixtures_source: """ Path to the current JSON fixture file. - If the fixture source is stdin, the fixture is written to a temporary json file. + If the fixture source is stdin, the fixture is written to a temporary json + file. """ if fixtures_source.is_stdin: assert isinstance(test_case, TestCaseStream) diff --git a/src/pytest_plugins/consume/direct/test_via_direct.py b/src/pytest_plugins/consume/direct/test_via_direct.py index f1f95081444..e1f014d0198 100644 --- a/src/pytest_plugins/consume/direct/test_via_direct.py +++ b/src/pytest_plugins/consume/direct/test_via_direct.py @@ -1,6 +1,6 @@ """ -Executes a JSON test fixture directly against a client using a dedicated -client interface similar to geth's EVM 'blocktest' command. +Executes a JSON test fixture directly against a client using a dedicated client +interface similar to geth's EVM 'blocktest' command. """ from pathlib import Path @@ -16,8 +16,8 @@ def test_fixture( test_dump_dir: Path | None, ): """ - Generic test function used to call the fixture consumer with a given fixture file path and - a fixture name (for a single test run). + Generic test function used to call the fixture consumer with a given + fixture file path and a fixture name (for a single test run). """ fixture_consumer.consume_fixture( test_case.format, diff --git a/src/pytest_plugins/consume/releases.py b/src/pytest_plugins/consume/releases.py index 2e694a7eec5..082b1ca98dc 100644 --- a/src/pytest_plugins/consume/releases.py +++ b/src/pytest_plugins/consume/releases.py @@ -48,7 +48,8 @@ def from_string(cls, release_string: str) -> "ReleaseTag": """ Create a release descriptor from a string. - The release source can be in the format `tag_name@version` or just `tag_name`. + The release source can be in the format `tag_name@version` or just + `tag_name`. """ version: str | None if "@" in release_string: @@ -69,7 +70,8 @@ def __eq__(self, value) -> bool: """ Check if the release descriptor matches the string value. - Returns True if the value is the same as the tag name or the tag name and version. + Returns True if the value is the same as the tag name or the tag name + and version. """ assert isinstance(value, str), f"Expected a string, but got: {value}" if self.version is not None: @@ -141,7 +143,9 @@ class Releases(RootModel[List[ReleaseInformation]]): def is_docker_or_ci() -> bool: - """Check if the code is running inside a Docker container or a CI environment.""" + """ + Check if the code is running inside a Docker container or a CI environment. + """ return "GITHUB_ACTIONS" in os.environ or Path("/.dockerenv").exists() @@ -220,15 +224,16 @@ def get_release_page_url(release_string: str) -> str: """ Return the GitHub Release page URL for a specific release descriptor. - This function can handle: - - A standard release string (e.g., "eip7692@latest") - from execution-spec-tests only. - - A direct asset download link (e.g., - "https://github.com/ethereum/execution-spec-tests/releases/download/v4.0.0/fixtures_eip7692.tar.gz"). + This function can handle: - A standard release string (e.g., + "eip7692@latest") - from execution-spec-tests only. - A direct asset + download link (e.g., + "https://github.com/ethereum/execution-spec-tests/releases/download/v4.0.0/fixt + ures_eip7692.tar.gz"). """ release_information = get_release_information() - # Case 1: If it's a direct GitHub Releases download link, - # find which release in `release_information` has an asset with this exact URL. + # Case 1: If it's a direct GitHub Releases download link, find which + # release in `release_information` has an asset with this exact URL. repo_pattern = "|".join(re.escape(repo) for repo in SUPPORTED_REPOS) regex_pattern = rf"https://github\.com/({repo_pattern})/releases/download/" if re.match(regex_pattern, release_string): @@ -238,7 +243,8 @@ def get_release_page_url(release_string: str) -> str: return release.url # The HTML page for this release raise NoSuchReleaseError(f"No release found for asset URL: {release_string}") - # Case 2: Otherwise, treat it as a release descriptor (e.g., "eip7692@latest") + # Case 2: Otherwise, treat it as a release descriptor (e.g., + # "eip7692@latest") release_descriptor = ReleaseTag.from_string(release_string) for release in release_information: if release_descriptor in release: @@ -252,9 +258,10 @@ def get_release_information() -> List[ReleaseInformation]: """ Get the release information. - First check if the cached release information file exists. If it does, but it is older than 4 - hours, delete the file, unless running inside a CI environment or a Docker container. - Then download the release information from the Github API and save it to the cache file. + First check if the cached release information file exists. If it does, but + it is older than 4 hours, delete the file, unless running inside a CI + environment or a Docker container. Then download the release information + from the Github API and save it to the cache file. """ if CACHED_RELEASE_INFORMATION_FILE.exists(): last_modified = CACHED_RELEASE_INFORMATION_FILE.stat().st_mtime diff --git a/src/pytest_plugins/consume/simulators/base.py b/src/pytest_plugins/consume/simulators/base.py index 0b62ebb5873..22736c97eba 100644 --- a/src/pytest_plugins/consume/simulators/base.py +++ b/src/pytest_plugins/consume/simulators/base.py @@ -45,7 +45,9 @@ def __init__(self) -> None: self._fixtures: Dict[Path, Fixtures] = {} def __getitem__(self, key: Path) -> Fixtures: - """Return the fixtures from the index file, if not found, load from disk.""" + """ + Return the fixtures from the index file, if not found, load from disk. + """ assert key.is_file(), f"Expected a file path, got '{key}'" if key not in self._fixtures: self._fixtures[key] = Fixtures.model_validate_json(key.read_text()) @@ -54,7 +56,10 @@ def __getitem__(self, key: Path) -> Fixtures: @pytest.fixture(scope="session") def fixture_file_loader() -> Dict[Path, Fixtures]: - """Return a singleton dictionary that caches loaded fixture files used in all tests.""" + """ + Return a singleton dictionary that caches loaded fixture files used in all + tests. + """ return FixturesDict() @@ -65,12 +70,12 @@ def fixture( test_case: TestCaseIndexFile | TestCaseStream, ) -> BaseFixture: """ - Load the fixture from a file or from stream in any of the supported - fixture formats. + Load the fixture from a file or from stream in any of the supported fixture + formats. - The fixture is either already available within the test case (if consume - is taking input on stdin) or loaded from the fixture json file if taking - input from disk (fixture directory with index file). + The fixture is either already available within the test case (if consume is + taking input on stdin) or loaded from the fixture json file if taking input + from disk (fixture directory with index file). """ fixture: BaseFixture if fixtures_source.is_stdin: diff --git a/src/pytest_plugins/consume/simulators/exceptions.py b/src/pytest_plugins/consume/simulators/exceptions.py index 0e8d4d63a78..8db60438e01 100644 --- a/src/pytest_plugins/consume/simulators/exceptions.py +++ b/src/pytest_plugins/consume/simulators/exceptions.py @@ -54,7 +54,10 @@ def client_exception_mapper( @pytest.fixture(scope="session") def disable_strict_exception_matching(request: pytest.FixtureRequest) -> List[str]: - """Return the list of clients or forks that should NOT use strict exception matching.""" + """ + Return the list of clients or forks that should NOT use strict exception + matching. + """ config_string = request.config.getoption("disable_strict_exception_matching") return config_string.split(",") if config_string else [] @@ -76,7 +79,8 @@ def fork_strict_exception_matching( disable_strict_exception_matching: List[str], ) -> bool: """Return True if the fork should use strict exception matching.""" - # NOTE: `in` makes it easier for transition forks ("Prague" in "CancunToPragueAtTime15k") + # NOTE: `in` makes it easier for transition forks ("Prague" in + # "CancunToPragueAtTime15k") return not any( s.lower() in str(fixture.fork).lower() for s in disable_strict_exception_matching ) diff --git a/src/pytest_plugins/consume/simulators/helpers/exceptions.py b/src/pytest_plugins/consume/simulators/helpers/exceptions.py index 6307fb095b6..f6a7e7e2bc4 100644 --- a/src/pytest_plugins/consume/simulators/helpers/exceptions.py +++ b/src/pytest_plugins/consume/simulators/helpers/exceptions.py @@ -16,10 +16,16 @@ class GenesisBlockMismatchExceptionError(Exception): - """Definers a mismatch exception between the client and fixture genesis blockhash.""" + """ + Definers a mismatch exception between the client and fixture genesis + blockhash. + """ def __init__(self, *, expected_header: FixtureHeader, got_genesis_block: Dict[str, str]): - """Initialize the exception with the expected and received genesis block headers.""" + """ + Initialize the exception with the expected and received genesis block + headers. + """ message = ( "Genesis block hash mismatch.\n\n" f"Expected: {expected_header.block_hash}\n" @@ -47,7 +53,9 @@ def __init__(self, *, expected_header: FixtureHeader, got_genesis_block: Dict[st @staticmethod def compare_models(expected: FixtureHeader, got: FixtureHeader) -> Tuple[Dict, List]: - """Compare two FixtureHeader model instances and return their differences.""" + """ + Compare two FixtureHeader model instances and return their differences. + """ differences = {} unexpected_fields = [] for (exp_name, exp_value), (got_name, got_value) in zip(expected, got, strict=False): diff --git a/src/pytest_plugins/consume/simulators/helpers/ruleset.py b/src/pytest_plugins/consume/simulators/helpers/ruleset.py index c1b7195b290..751f6c02846 100644 --- a/src/pytest_plugins/consume/simulators/helpers/ruleset.py +++ b/src/pytest_plugins/consume/simulators/helpers/ruleset.py @@ -43,10 +43,10 @@ def get_blob_schedule_entries(fork: Fork) -> Dict[str, int]: """ Generate blob schedule entries for each fork (and respective parent forks). - Adds the following entries to the ruleset for the given fork (and parent forks): - HIVE_{FORK}_BLOB_TARGET: target_blobs_per_block() - HIVE_{FORK}_BLOB_MAX: max_blobs_per_block() - HIVE_{FORK}_BLOB_BASE_FEE_UPDATE_FRACTION: blob_base_fee_update_fraction() + Adds the following entries to the ruleset for the given fork (and parent + forks): HIVE_{FORK}_BLOB_TARGET: target_blobs_per_block() + HIVE_{FORK}_BLOB_MAX: max_blobs_per_block() + HIVE_{FORK}_BLOB_BASE_FEE_UPDATE_FRACTION: blob_base_fee_update_fraction() """ entries: Dict = {} forks_with_blobs: List[Fork] = [] diff --git a/src/pytest_plugins/consume/simulators/helpers/timing.py b/src/pytest_plugins/consume/simulators/helpers/timing.py index eddfe3f7804..e5cadee9578 100644 --- a/src/pytest_plugins/consume/simulators/helpers/timing.py +++ b/src/pytest_plugins/consume/simulators/helpers/timing.py @@ -5,7 +5,9 @@ class TimingData: - """The times taken to perform the various steps of a test case (seconds).""" + """ + The times taken to perform the various steps of a test case (seconds). + """ name: str start_time: float | None diff --git a/src/pytest_plugins/consume/simulators/rlp/conftest.py b/src/pytest_plugins/consume/simulators/rlp/conftest.py index f2d8f93a343..92a2c97fb52 100644 --- a/src/pytest_plugins/consume/simulators/rlp/conftest.py +++ b/src/pytest_plugins/consume/simulators/rlp/conftest.py @@ -46,7 +46,10 @@ def blocks_rlp(fixture: BlockchainFixture) -> List[Bytes]: @pytest.fixture(scope="function") def buffered_blocks_rlp(blocks_rlp: List[bytes]) -> List[io.BufferedReader]: - """Convert the RLP-encoded blocks of the current test fixture to buffered readers.""" + """ + Convert the RLP-encoded blocks of the current test fixture to buffered + readers. + """ block_rlp_files = [] for _, block_rlp in enumerate(blocks_rlp): block_rlp_stream = io.BytesIO(block_rlp) @@ -62,9 +65,9 @@ def client_files( """ Define the files that hive will start the client with. - The files are specified as a dictionary whose: - - Keys are the target file paths in the client's docker container, and, - - Values are in-memory buffered file objects. + The files are specified as a dictionary whose: - Keys are the target file + paths in the client's docker container, and, - Values are in-memory + buffered file objects. """ files = {f"/blocks/{i + 1:04d}.rlp": rlp for i, rlp in enumerate(buffered_blocks_rlp)} files["/genesis.json"] = buffered_genesis diff --git a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_engine.py b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_engine.py index 1d54d0586c8..8be888d79e3 100644 --- a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_engine.py +++ b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_engine.py @@ -1,8 +1,10 @@ """ -A hive based simulator that executes blocks against clients using the `engine_newPayloadVX` method -from the Engine API. The simulator uses the `BlockchainEngineFixtures` to test against clients. +A hive based simulator that executes blocks against clients using the +`engine_newPayloadVX` method from the Engine API. The simulator uses the +`BlockchainEngineFixtures` to test against clients. -Each `engine_newPayloadVX` is verified against the appropriate VALID/INVALID responses. +Each `engine_newPayloadVX` is verified against the appropriate VALID/INVALID +responses. """ import time @@ -39,10 +41,11 @@ def test_blockchain_via_engine( strict_exception_matching: bool, ): """ - 1. Check the client genesis block hash matches `fixture.genesis.block_hash`. - 2. Execute the test case fixture blocks against the client under test using the - `engine_newPayloadVX` method from the Engine API. - 3. For valid payloads a forkchoice update is performed to finalize the chain. + 1. Check the client genesis block hash matches + `fixture.genesis.block_hash`. 2. Execute the test case fixture blocks + against the client under test using the `engine_newPayloadVX` method from + the Engine API. 3. For valid payloads a forkchoice update is performed to + finalize the chain. """ # Send a initial forkchoice update with timing_data.time("Initial forkchoice update"): diff --git a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_rlp.py b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_rlp.py index 4c63eba5b78..b2936cfe3dc 100644 --- a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_rlp.py +++ b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_rlp.py @@ -1,8 +1,9 @@ """ -A hive based simulator that executes RLP-encoded blocks against clients. The simulator uses the -`BlockchainFixtures` to test this against clients. +A hive based simulator that executes RLP-encoded blocks against clients. The +simulator uses the `BlockchainFixtures` to test this against clients. -Clients consume the genesis and RLP-encoded blocks from input files upon start-up. +Clients consume the genesis and RLP-encoded blocks from input files upon +start-up. """ import logging @@ -23,8 +24,9 @@ def test_via_rlp( fixture: BlockchainFixture, ): """ - 1. Check the client genesis block hash matches `fixture.genesis.block_hash`. - 2. Check the client last block hash matches `fixture.last_block_hash`. + 1. Check the client genesis block hash matches + `fixture.genesis.block_hash`. 2. Check the client last block hash matches + `fixture.last_block_hash`. """ with timing_data.time("Get genesis block"): logger.info("Calling getBlockByNumber to get genesis block...") diff --git a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py index 5ef252776af..8765b34ee67 100644 --- a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py +++ b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py @@ -1,13 +1,13 @@ """ -A hive based simulator that executes blocks against clients using the `engine_newPayloadV*` method -from the Engine API with sync testing. The simulator uses the `BlockchainEngineSyncFixtures` to -test against clients with client synchronization. - -This simulator: -1. Spins up two clients: one as the client under test and another as the sync client -2. Executes payloads on the client under test -3. Has the sync client synchronize from the client under test -4. Verifies that the sync was successful +A hive based simulator that executes blocks against clients using the +`engine_newPayloadV*` method from the Engine API with sync testing. The +simulator uses the `BlockchainEngineSyncFixtures` to test against clients with +client synchronization. + +This simulator: 1. Spins up two clients: one as the client under test and +another as the sync client 2. Executes payloads on the client under test 3. Has +the sync client synchronize from the client under test 4. Verifies that the +sync was successful """ import time @@ -115,12 +115,11 @@ def test_blockchain_via_sync( """ Test blockchain synchronization between two clients. - 1. Initialize the client under test with the genesis block - 2. Execute all payloads on the client under test - 3. Initialize the sync client with the genesis block - 4. Send sync payload and forkchoice_updated to the sync client to trigger - synchronization - 5. Verify that the sync client successfully syncs to the same state + 1. Initialize the client under test with the genesis block 2. Execute all + payloads on the client under test 3. Initialize the sync client with the + genesis block 4. Send sync payload and forkchoice_updated to the sync + client to trigger synchronization 5. Verify that the sync client + successfully syncs to the same state """ # Initialize client under test with timing_data.time("Initialize client under test"): @@ -328,8 +327,8 @@ def test_blockchain_via_sync( f"{forkchoice_response}" ) - # Add peer using admin_addPeer - # This seems to be required... TODO: we can maybe improve flow here if not required + # Add peer using admin_addPeer This seems to be required... TODO: we can + # maybe improve flow here if not required logger.info(f"Adding peer: {client_enode_url}") assert sync_admin_rpc is not None, "sync_admin_rpc is required" try: @@ -338,7 +337,8 @@ def test_blockchain_via_sync( except Exception as e: raise LoggedError(f"admin_addPeer failed: {e}") from e - time.sleep(1) # quick sleep to allow for connection - TODO: is this necessary? + time.sleep(1) # quick sleep to allow for connection - TODO: is this + # necessary? try: sync_peer_count = sync_net_rpc.peer_count() @@ -352,7 +352,8 @@ def test_blockchain_via_sync( except Exception as e: logger.warning(f"Could not verify peer connection: {e}") - # Trigger sync by sending the target block via newPayload followed by forkchoice update + # Trigger sync by sending the target block via newPayload followed by + # forkchoice update logger.info(f"Triggering sync to block {last_valid_block_hash}") # Find the last valid payload to send to sync client @@ -374,7 +375,9 @@ def test_blockchain_via_sync( ) try: - version = last_valid_payload.new_payload_version # log version used for debugging + version = last_valid_payload.new_payload_version # log version + # used for + # debugging logger.info(f"Sending target payload via engine_newPayloadV{version}") # send the payload to sync client @@ -403,9 +406,9 @@ def test_blockchain_via_sync( # Give a moment for P2P connections to establish after sync starts time.sleep(1) - # Check peer count after triggering sync - # Note: Reth does not actually raise the peer count but doesn't seem - # to need this to sync. + # Check peer count after triggering sync Note: Reth does not + # actually raise the peer count but doesn't seem to need this to + # sync. try: assert sync_net_rpc is not None, "sync_net_rpc is required" client_peer_count = net_rpc.peer_count() @@ -444,7 +447,8 @@ def test_blockchain_via_sync( # Send periodic forkchoice updates to keep sync alive if time.time() - last_forkchoice_time >= forkchoice_interval: try: - # Send forkchoice update to sync client to trigger/maintain sync + # Send forkchoice update to sync client to trigger/maintain + # sync assert sync_engine_rpc is not None, "sync_engine_rpc is required" sync_fc_response = sync_engine_rpc.forkchoice_updated( forkchoice_state=last_valid_block_forkchoice_state, diff --git a/src/pytest_plugins/consume/simulators/single_test_client.py b/src/pytest_plugins/consume/simulators/single_test_client.py index b6db7674c95..0ea5da90acb 100644 --- a/src/pytest_plugins/consume/simulators/single_test_client.py +++ b/src/pytest_plugins/consume/simulators/single_test_client.py @@ -1,4 +1,6 @@ -"""Common pytest fixtures for simulators with single-test client architecture.""" +""" +Common pytest fixtures for simulators with single-test client architecture. +""" import io import json @@ -23,7 +25,10 @@ @pytest.fixture(scope="function") def client_genesis(fixture: BlockchainFixtureCommon) -> dict: - """Convert the fixture genesis block header and pre-state to a client genesis state.""" + """ + Convert the fixture genesis block header and pre-state to a client genesis + state. + """ genesis = to_json(fixture.genesis) alloc = to_json(fixture.pre) # NOTE: nethermind requires account keys without '0x' prefix @@ -51,7 +56,10 @@ def environment( @pytest.fixture(scope="function") def buffered_genesis(client_genesis: dict) -> io.BufferedReader: - """Create a buffered reader for the genesis block header of the current test fixture.""" + """ + Create a buffered reader for the genesis block header of the current test + fixture. + """ genesis_json = json.dumps(client_genesis) genesis_bytes = genesis_json.encode("utf-8") return io.BufferedReader(cast(io.RawIOBase, io.BytesIO(genesis_bytes))) @@ -71,7 +79,9 @@ def client( client_type: ClientType, total_timing_data: TimingData, ) -> Generator[Client, None, None]: - """Initialize the client with the appropriate files and environment variables.""" + """ + Initialize the client with the appropriate files and environment variables. + """ logger.info(f"Starting client ({client_type.name})...") logger.debug(f"Main client Network ID: {environment.get('HIVE_NETWORK_ID', 'NOT SET!')}") logger.debug(f"Main client Chain ID: {environment.get('HIVE_CHAIN_ID', 'NOT SET!')}") diff --git a/src/pytest_plugins/consume/simulators/sync/conftest.py b/src/pytest_plugins/consume/simulators/sync/conftest.py index bf9a1323792..2bc30a68f37 100644 --- a/src/pytest_plugins/consume/simulators/sync/conftest.py +++ b/src/pytest_plugins/consume/simulators/sync/conftest.py @@ -60,9 +60,10 @@ def pytest_collection_modifyitems(session, config, items): # Format: ``-{client}_sync_{sync_client}`` new_suffix = f"-{client_name}::sync_{sync_client_name}" - # client_param-tests/path/to/test.py::test_name[test_params]-sync_client_param - # 1. Remove the client prefix from the beginning - # 2. Replace the -client_param part at the end with our new format + # client_param- + # tests/path/to/test.py::test_name[test_params]-sync_client_param + # 1. Remove the client prefix from the beginning 2. Replace the + # -client_param part at the end with our new format nodeid = item.nodeid prefix_index = item.nodeid.find("-tests/") if prefix_index != -1: @@ -119,7 +120,10 @@ def admin_rpc(client: Client) -> AdminRPC: @pytest.fixture(scope="function") def sync_genesis(fixture: BlockchainEngineSyncFixture) -> dict: - """Convert the fixture genesis block header and pre-state to a sync client genesis state.""" + """ + Convert the fixture genesis block header and pre-state to a sync client + genesis state. + """ genesis = to_json(fixture.genesis) alloc = to_json(fixture.pre) # NOTE: nethermind requires account keys without '0x' prefix @@ -129,7 +133,9 @@ def sync_genesis(fixture: BlockchainEngineSyncFixture) -> dict: @pytest.fixture(scope="function") def sync_buffered_genesis(sync_genesis: dict) -> io.BufferedReader: - """Create a buffered reader for the genesis block header of the sync client.""" + """ + Create a buffered reader for the genesis block header of the sync client. + """ genesis_json = json.dumps(sync_genesis) genesis_bytes = genesis_json.encode("utf-8") return io.BufferedReader(cast(io.RawIOBase, io.BytesIO(genesis_bytes))) diff --git a/src/pytest_plugins/consume/simulators/test_case_description.py b/src/pytest_plugins/consume/simulators/test_case_description.py index 3a97c63f198..8989bd05c2f 100644 --- a/src/pytest_plugins/consume/simulators/test_case_description.py +++ b/src/pytest_plugins/consume/simulators/test_case_description.py @@ -1,4 +1,7 @@ -"""Pytest fixtures that help create the test case "Description" displayed in the Hive UI.""" +""" +Pytest fixtures that help create the test case "Description" displayed in the +Hive UI. +""" import logging import textwrap @@ -30,7 +33,10 @@ def hive_clients_yaml_generator_command( hive_clients_yaml_target_filename: str, hive_info: HiveInfo, ) -> str: - """Generate a shell command that creates a clients YAML file for the current client.""" + """ + Generate a shell command that creates a clients YAML file for the current + client. + """ try: if not client_file: raise ValueError("No client information available - try updating hive") @@ -65,10 +71,13 @@ def filtered_hive_options(hive_info: HiveInfo) -> List[str]: logger.info("Hive info: %s", hive_info.command) unwanted_options = [ - "--client", # gets overwritten: we specify a single client; the one from the test case + "--client", # gets overwritten: we specify a single client; the one + # from the test case "--client-file", # gets overwritten: we'll write our own client file - "--results-root", # use default value instead (or you have to pass it to ./hiveview) - "--sim.limit", # gets overwritten: we only run the current test case id + "--results-root", # use default value instead (or you have to pass it + # to ./hiveview) + "--sim.limit", # gets overwritten: we only run the current test case + # id "--sim.parallelism", # skip; we'll only be running a single test ] @@ -118,7 +127,10 @@ def hive_dev_command( client_type: ClientType, hive_client_config_file_parameter: str, ) -> str: - """Return the command used to instantiate hive alongside the `consume` command.""" + """ + Return the command used to instantiate hive alongside the `consume` + command. + """ return f"./hive --dev {hive_client_config_file_parameter} --client {client_type.name}" @@ -151,7 +163,8 @@ def test_case_description( if "description" not in fixture.info or fixture.info["description"] is None: test_docstring = "No documentation available." else: - # this prefix was included in the fixture description field for fixtures <= v4.3.0 + # this prefix was included in the fixture description field for + # fixtures <= v4.3.0 test_docstring = fixture.info["description"].replace("Test function documentation:\n", "") # type: ignore description = textwrap.dedent(f""" @@ -162,15 +175,18 @@ def test_case_description( {test_docstring} Run This Test Locally: - To run this test in hive: + To run this test in + hive + : {hive_clients_yaml_generator_command} {hive_consume_command} - Advanced: Run the test against a hive developer backend using EEST's consume command + Advanced: Run the test against a hive developer backend using + EEST's consume command Create the client YAML file, as above, then: 1. Start hive in dev mode: {hive_dev_command} 2. In the EEST repository root: {eest_consume_command} - """) # noqa: E501 + """) description = description.strip() description = description.replace("\n", "
") diff --git a/src/pytest_plugins/consume/tests/test_consume_args.py b/src/pytest_plugins/consume/tests/test_consume_args.py index 110566fd808..455c82aee34 100644 --- a/src/pytest_plugins/consume/tests/test_consume_args.py +++ b/src/pytest_plugins/consume/tests/test_consume_args.py @@ -22,7 +22,10 @@ def test_function(state_test, pre): @pytest.fixture def minimal_test_path(pytester: pytest.Pytester) -> Path: - """Minimal test file that's written to a file using pytester and ready to fill.""" + """ + Minimal test file that's written to a file using pytester and ready to + fill. + """ tests_dir = pytester.mkdir("tests") test_file = tests_dir / MINIMAL_TEST_FILE_NAME test_file.write_text(MINIMAL_TEST_CONTENTS) @@ -72,11 +75,12 @@ def fill_tests( """ Run fill to generate test fixtures for use with testing consume. - We only need to do this once so ideally the scope of this fixture should be "module", - however the `pytester` fixture's scope is function and cannot be accessed from a higher - scope fixture. + We only need to do this once so ideally the scope of this fixture should be + "module", however the `pytester` fixture's scope is function and cannot be + accessed from a higher scope fixture. - Instead we use a file lock and only write the fixtures once to the directory. + Instead we use a file lock and only write the fixtures once to the + directory. """ with FileLock(fixtures_dir.with_suffix(".lock")): meta_folder = fixtures_dir / ".meta" @@ -100,9 +104,11 @@ def fill_tests( @pytest.fixture(autouse=True, scope="function") def test_fixtures(pytester: Pytester, fixtures_dir: Path, fill_tests: None) -> List[Path]: """ - Copy test fixtures from the regular temp path to the pytester temporary dir. + Copy test fixtures from the regular temp path to the pytester temporary + dir. - We intentionally copy the `.meta/index.json` file to test its compatibility with consume. + We intentionally copy the `.meta/index.json` file to test its compatibility + with consume. """ del fill_tests @@ -131,7 +137,9 @@ def copy_consume_test_paths(pytester: Pytester): shutil.move("conftest.py", target_dir / "conftest.py") -single_test_id = f"src/pytest_plugins/consume/direct/test_via_direct.py::test_fixture[CollectOnlyFixtureConsumer-tests/{MINIMAL_TEST_FILE_NAME}::test_function[fork_Shanghai-state_test]]" # noqa: E501 +single_test_id = "src/pytest_plugins/consume/direct/" +"test_via_direct.py::test_fixture[CollectOnlyFixtureConsumer-tests/" +f"{MINIMAL_TEST_FILE_NAME}::test_function[fork_Shanghai-state_test]]" @pytest.mark.parametrize( diff --git a/src/pytest_plugins/consume/tests/test_fixtures_source_input_types.py b/src/pytest_plugins/consume/tests/test_fixtures_source_input_types.py index 9eb205c73f0..e18cc2b7312 100644 --- a/src/pytest_plugins/consume/tests/test_fixtures_source_input_types.py +++ b/src/pytest_plugins/consume/tests/test_fixtures_source_input_types.py @@ -10,7 +10,9 @@ class TestSimplifiedConsumeBehavior: """Test suite for the simplified consume behavior.""" def test_fixtures_source_from_release_url_no_api_calls(self): - """Test that direct release URLs do not make API calls for release page.""" + """ + Test that direct release URLs do not make API calls for release page. + """ test_url = "https://github.com/ethereum/execution-spec-tests/releases/download/v3.0.0/fixtures_develop.tar.gz" with patch("pytest_plugins.consume.consume.FixtureDownloader") as mock_downloader: @@ -26,7 +28,9 @@ def test_fixtures_source_from_release_url_no_api_calls(self): assert source.input_option == test_url def test_fixtures_source_from_release_spec_makes_api_calls(self): - """Test that release specs still make API calls and get release page.""" + """ + Test that release specs still make API calls and get release page. + """ test_spec = "stable@latest" with patch("pytest_plugins.consume.consume.get_release_url") as mock_get_url: @@ -68,7 +72,9 @@ def test_fixtures_source_from_regular_url_no_release_page(self): assert source.url == test_url def test_output_formatting_without_release_page_for_direct_urls(self): - """Test output formatting when release page is empty for direct URLs.""" + """ + Test output formatting when release page is empty for direct URLs. + """ from unittest.mock import MagicMock from pytest import Config @@ -97,7 +103,9 @@ def test_output_formatting_without_release_page_for_direct_urls(self): assert "Input:" in reason def test_output_formatting_with_release_page_for_specs(self): - """Test output formatting when release page is present for release specs.""" + """ + Test output formatting when release page is present for release specs. + """ from unittest.mock import MagicMock from pytest import Config diff --git a/src/pytest_plugins/custom_logging/__init__.py b/src/pytest_plugins/custom_logging/__init__.py index a03e1b28ad7..9e71d615bae 100644 --- a/src/pytest_plugins/custom_logging/__init__.py +++ b/src/pytest_plugins/custom_logging/__init__.py @@ -1,4 +1,7 @@ -"""Import the logging module content to make it available from pytest_plugins.logging.""" +""" +Import the logging module content to make it available from +pytest_plugins.logging. +""" from .plugin_logging import ( FAIL_LEVEL, diff --git a/src/pytest_plugins/custom_logging/plugin_logging.py b/src/pytest_plugins/custom_logging/plugin_logging.py index dfe2cf7d1ae..2580f9f7af5 100644 --- a/src/pytest_plugins/custom_logging/plugin_logging.py +++ b/src/pytest_plugins/custom_logging/plugin_logging.py @@ -1,16 +1,17 @@ """ A Pytest plugin to configure logging for pytest sessions. -Note: While pytest's builtin logging is generally amazing, it does not write timestamps -when log output is written to pytest's caplog (the captured output for a test). And having -timestamps in this output is the main use case for adding logging to our plugins. -This output gets shown in the `FAILURES` summary section, which is shown as the -"simulator log" in hive simulations. For this use case, timestamps are essential to verify -timing issues against the clients log. - -This module provides both: -1. A standalone logging configuration system that can be used in any Python project -2. A pytest plugin that automatically configures logging for pytest sessions +Note: While pytest's builtin logging is generally amazing, it does not write +timestamps when log output is written to pytest's caplog (the captured output +for a test). And having timestamps in this output is the main use case for +adding logging to our plugins. This output gets shown in the `FAILURES` summary +section, which is shown as the "simulator log" in hive simulations. For this +use case, timestamps are essential to verify timing issues against the clients +log. + +This module provides both: 1. A standalone logging configuration system that +can be used in any Python project 2. A pytest plugin that automatically +configures logging for pytest sessions """ import functools @@ -71,8 +72,8 @@ def fail( """ Log a message with FAIL level severity (35). - This level is between WARNING (30) and ERROR (40), intended for test failures - and similar issues. + This level is between WARNING (30) and ERROR (40), intended for test + failures and similar issues. """ if stacklevel is None: stacklevel = 1 @@ -94,15 +95,22 @@ def get_logger(name: str) -> EESTLogger: class UTCFormatter(logging.Formatter): - """Log formatter that formats UTC timestamps with milliseconds and +00:00 suffix.""" + """ + Log formatter that formats UTC timestamps with milliseconds and +00:00 + suffix. + """ - def formatTime(self, record, datefmt=None): # noqa: D102,N802 # camelcase required + def formatTime(self, record, datefmt=None): # noqa: D102,N802 # camelcase + # required dt = datetime.fromtimestamp(record.created, tz=timezone.utc) return dt.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3] + "+00:00" class ColorFormatter(UTCFormatter): - """Formatter that adds ANSI color codes to log level names for terminal output.""" + """ + Formatter that adds ANSI color codes to log level names for terminal + output. + """ running_in_docker: ClassVar[bool] = Path("/.dockerenv").exists() @@ -150,9 +158,9 @@ def from_cli(cls, value: str) -> int: raise ValueError(f"Invalid log level '{value}'. Expected one of: {valid} or a number.") -# ============================================================================== +# ========================================================================= # Standalone logging configuration (usable without pytest) -# ============================================================================== +# ========================================================================= def configure_logging( @@ -168,16 +176,12 @@ def configure_logging( This function can be used in any Python project to set up logging with the same settings as the pytest plugin. - Args: - log_level: The logging level to use (name or numeric value) - log_file: Path to the log file (if None, no file logging is set up) - log_to_stdout: Whether to log to stdout - log_format: The log format string - use_color: Whether to use colors in stdout output (auto-detected if None) - - Returns: - The file handler if log_file is provided, otherwise None + Args: log_level: The logging level to use (name or numeric value) log_file: + Path to the log file (if None, no file logging is set up) log_to_stdout: + Whether to log to stdout log_format: The log format string use_color: + Whether to use colors in stdout output (auto-detected if None) + Returns: The file handler if log_file is provided, otherwise None """ # Initialize root logger root_logger = logging.getLogger() @@ -222,9 +226,9 @@ def configure_logging( return file_handler_instance -# ============================================================================== +# ========================================================================== # Pytest plugin integration -# ============================================================================== +# ========================================================================== def pytest_addoption(parser): # noqa: D103 @@ -232,7 +236,8 @@ def pytest_addoption(parser): # noqa: D103 "logging", "Arguments related to logging from test fixtures and tests." ) logging_group.addoption( - "--eest-log-level", # --log-level is defined by pytest's built-in logging + "--eest-log-level", # --log-level is defined by pytest's built-in + # logging "--eestloglevel", action="store", default="INFO", @@ -274,9 +279,9 @@ def pytest_configure(config: pytest.Config) -> None: """ Initialize logging for pytest sessions. - This goes to a lot of effort to ensure that a log file is created per worker - if xdist is used and that the timestamp used in the filename is the same across - main and all workers. + This goes to a lot of effort to ensure that a log file is created per + worker if xdist is used and that the timestamp used in the filename is the + same across main and all workers. """ global file_handler @@ -313,9 +318,10 @@ def pytest_report_header(config: pytest.Config) -> list[str]: def pytest_terminal_summary(terminalreporter: TerminalReporter, exitstatus: int) -> None: - """Display the log file path in the terminal summary like the HTML report does.""" - del exitstatus - + """ + Display the log file path in the terminal summary like the HTML report + does. + """ if terminalreporter.config.option.collectonly: return if eest_log_file_path := terminalreporter.config.option.eest_log_file_path: diff --git a/src/pytest_plugins/execute/__init__.py b/src/pytest_plugins/execute/__init__.py index 08e96f51787..71d37fb87ee 100644 --- a/src/pytest_plugins/execute/__init__.py +++ b/src/pytest_plugins/execute/__init__.py @@ -1 +1,4 @@ -"""A pytest plugin that provides fixtures that execute tests in live devnets/testnets.""" +""" +A pytest plugin that provides fixtures that execute tests in live +devnets/testnets. +""" diff --git a/src/pytest_plugins/execute/eth_config/eth_config.py b/src/pytest_plugins/execute/eth_config/eth_config.py index cb8d30a029e..2f6a08c6f5e 100644 --- a/src/pytest_plugins/execute/eth_config/eth_config.py +++ b/src/pytest_plugins/execute/eth_config/eth_config.py @@ -95,8 +95,8 @@ def pytest_addoption(parser): def pytest_configure(config: pytest.Config) -> None: """ - Load the network configuration file and load the specific network to be used for - the test. + Load the network configuration file and load the specific network to be + used for the test. """ genesis_config_file = config.getoption("genesis_config_file") genesis_config_url = config.getoption("genesis_config_url") @@ -183,14 +183,20 @@ def pytest_configure(config: pytest.Config) -> None: @pytest.fixture(autouse=True, scope="session") def rpc_endpoint(request) -> str: - """Return remote RPC endpoint to be used to make requests to the execution client.""" + """ + Return remote RPC endpoint to be used to make requests to the execution + client. + """ return request.config.getoption("rpc_endpoint") def all_rpc_endpoints(config) -> Dict[str, List[EthRPC]]: - """Derive a mapping of exec clients to the RPC URLs they are reachable at.""" + """ + Derive a mapping of exec clients to the RPC URLs they are reachable at. + """ rpc_endpoint = config.getoption("rpc_endpoint") - el_clients: List[str] = config.getoption("majority_clients") # besu, erigon, .. + el_clients: List[str] = config.getoption("majority_clients") # besu, + # erigon, .. if len(el_clients) == 0: endpoint_name = rpc_endpoint try: @@ -215,23 +221,23 @@ def all_rpc_endpoints(config) -> Dict[str, List[EthRPC]]: for exec_client in el_clients } # url_dict looks like this: - # { - # 'besu': [, , ..], # noqa: E501 - # 'erigon': ... - # ... - # } + # { 'besu': [, + # , ..], + # 'erigon': ... ... } return url_dict def pytest_generate_tests(metafunc: pytest.Metafunc): """Generate tests for all clients under test.""" # all_rpc_endpoints is a dictionary with the name of the exec client as key - # and the possible URLs to contact it (different cl combinations) as value list + # and the possible URLs to contact it (different cl combinations) as value + # list all_rpc_endpoints_dict = all_rpc_endpoints(metafunc.config) if metafunc.definition.name == "test_eth_config_majority": if len(all_rpc_endpoints_dict) < 2: - # The test function is not run because we only have a single client, so no majority comparison # noqa: E501 + # The test function is not run because we only have a single + # client, so no majority comparison logger.info( "Skipping eth_config majority because less than 2 exec clients were passed" ) diff --git a/src/pytest_plugins/execute/eth_config/execute_eth_config.py b/src/pytest_plugins/execute/eth_config/execute_eth_config.py index af43ec0b1e2..7316551db8b 100644 --- a/src/pytest_plugins/execute/eth_config/execute_eth_config.py +++ b/src/pytest_plugins/execute/eth_config/execute_eth_config.py @@ -1,4 +1,6 @@ -"""Pytest test to verify a client's configuration using `eth_config` RPC endpoint.""" +""" +Pytest test to verify a client's configuration using `eth_config` RPC endpoint. +""" import json import time @@ -17,7 +19,9 @@ @pytest.fixture(scope="function") def eth_config_response(eth_rpc: List[EthRPC]) -> EthConfigResponse | None: - """Get the `eth_config` response from the client to be verified by all tests.""" + """ + Get the `eth_config` response from the client to be verified by all tests. + """ for rpc in eth_rpc: try: response = rpc.config() @@ -37,13 +41,17 @@ def network(request) -> NetworkConfig: @pytest.fixture(scope="function") def current_time() -> int: - """Get the `eth_config` response from the client to be verified by all tests.""" + """ + Get the `eth_config` response from the client to be verified by all tests. + """ return int(time.time()) @pytest.fixture(scope="function") def expected_eth_config(network: NetworkConfig, current_time: int) -> EthConfigResponse: - """Calculate the current fork value to verify against the client's response.""" + """ + Calculate the current fork value to verify against the client's response. + """ return network.get_eth_config(current_time) @@ -190,12 +198,15 @@ def test_eth_config_last_fork_id( def test_eth_config_majority( all_rpc_endpoints: Dict[str, List[EthRPC]], ) -> None: - """Queries devnet exec clients for their eth_config and fails if not all have the same response.""" # noqa: E501 + """ + Queries devnet exec clients for their eth_config and fails if not all have + the same response. + """ responses = dict() # Dict[exec_client_name : response] # noqa: C408 client_to_url_used_dict = dict() # noqa: C408 for exec_client in all_rpc_endpoints.keys(): - # try only as many consensus+exec client combinations until you receive a response - # if all combinations for a given exec client fail we panic + # try only as many consensus+exec client combinations until you receive + # a response if all combinations for a given exec client fail we panic for eth_rpc_target in all_rpc_endpoints[exec_client]: try: response = eth_rpc_target.config(timeout=5) @@ -212,7 +223,7 @@ def test_eth_config_majority( responses[exec_client] = response_str client_to_url_used_dict[exec_client] = ( eth_rpc_target.url - ) # remember which cl+el combination was used # noqa: E501 + ) # remember which cl+el combination was used logger.info(f"Response of {exec_client}: {response_str}\n\n") break # no need to gather more responses for this client @@ -226,14 +237,15 @@ def test_eth_config_majority( "this execution client" ) # determine hashes of client responses - client_to_hash_dict = dict() # Dict[exec_client : response hash] # noqa: C408 + client_to_hash_dict = {} # Dict[exec_client : response hash] # noqa: C408 for client in responses.keys(): response_bytes = responses[client].encode("utf-8") response_hash = sha256(response_bytes).digest().hex() logger.info(f"Response hash of client {client}: {response_hash}") client_to_hash_dict[client] = response_hash - # if not all responses have the same hash there is a critical consensus issue + # if not all responses have the same hash there is a critical consensus + # issue expected_hash = "" for h in client_to_hash_dict.keys(): if expected_hash == "": @@ -247,9 +259,10 @@ def test_eth_config_majority( + "\n\n" # noqa: E501 "Here is an overview of which URLs were contacted:\n\t" + "\n\t".join(f"{k}: @{v.split('@')[1]}" for k, v in client_to_url_used_dict.items()) - + "\n\n" # log which cl+el combinations were used without leaking full url # noqa: E501 + + "\n\n" + # log which cl+el combinations were used without leaking full url "Here is a dump of all client responses:\n" - + "\n\n".join(f"{k}: {v}" for k, v in responses.items()) # noqa: E501 + + "\n\n".join(f"{k}: {v}" for k, v in responses.items()) ) assert expected_hash != "" diff --git a/src/pytest_plugins/execute/eth_config/execute_types.py b/src/pytest_plugins/execute/eth_config/execute_types.py index efe32bb430a..aea17d14fb6 100644 --- a/src/pytest_plugins/execute/eth_config/execute_types.py +++ b/src/pytest_plugins/execute/eth_config/execute_types.py @@ -33,8 +33,8 @@ class AddressOverrideDict(EthereumTestRootModel): """ Dictionary with overrides to the default addresses specified for each fork. - Required for testnets or devnets which have a different location of precompiles or system - contracts. + Required for testnets or devnets which have a different location of + precompiles or system contracts. """ root: Dict[Address, Address] @@ -73,8 +73,8 @@ def system_contracts(self) -> Dict[str, Address]: def get_config(self, fork_id: ForkHash) -> ForkConfig: """ - Get the current and next fork configurations given the current time and the network - configuration. + Get the current and next fork configurations given the current time and + the network configuration. """ return ForkConfig( activation_time=self.activation_time, @@ -87,7 +87,10 @@ def get_config(self, fork_id: ForkHash) -> ForkConfig: def calculate_fork_id(genesis_hash: Hash, activation_times: Set[int]) -> ForkHash: - """Calculate the fork Id given the genesis hash and each fork activation times.""" + """ + Calculate the fork Id given the genesis hash and each fork activation + times. + """ buffer = bytes(genesis_hash) for activation_time in sorted(activation_times): if activation_time == 0: @@ -275,20 +278,17 @@ def fork(self) -> Fork: @classmethod def preprocess_fork_times_blocks(cls, data: Any): """ - Pre-process the dictionary to put fork block numbers and times in the correct format. - - Fork times and block numbers have the following format in the root of the object: + Pre-process the dictionary to put fork block numbers and times in the + correct format. - ``` - "berlinBlock": 0, - "londonBlock": 0, - ... - "pragueTime": 0, - "osakaTime": 1753379304, - ``` + Fork times and block numbers have the following format in the root of + the object: - This function strips the "*Block" and "*Time" part and moves the values. + ``` "berlinBlock": 0, "londonBlock": 0, ... "pragueTime": 0, + "osakaTime": 1753379304, ``` + This function strips the "*Block" and "*Time" part and moves the + values. """ if isinstance(data, dict): fork_activation_times: Dict[str, int] = {} diff --git a/src/pytest_plugins/execute/eth_config/tests/test_execute_eth_config.py b/src/pytest_plugins/execute/eth_config/tests/test_execute_eth_config.py index bb147b82411..ec9c7bff0c4 100644 --- a/src/pytest_plugins/execute/eth_config/tests/test_execute_eth_config.py +++ b/src/pytest_plugins/execute/eth_config/tests/test_execute_eth_config.py @@ -435,7 +435,9 @@ def network(request: pytest.FixtureRequest, network_configs: NetworkConfigFile) @pytest.fixture def eth_config(network: NetworkConfig, current_time: int) -> EthConfigResponse: - """Get the `eth_config` response from the client to be verified by all tests.""" + """ + Get the `eth_config` response from the client to be verified by all tests. + """ return network.get_eth_config(current_time) diff --git a/src/pytest_plugins/execute/execute.py b/src/pytest_plugins/execute/execute.py index e6ed68af657..6037cdf57aa 100644 --- a/src/pytest_plugins/execute/execute.py +++ b/src/pytest_plugins/execute/execute.py @@ -1,4 +1,6 @@ -"""Test execution plugin for pytest, to run Ethereum tests using in live networks.""" +""" +Test execution plugin for pytest, to run Ethereum tests using in live networks. +""" import os from dataclasses import dataclass, field @@ -119,15 +121,16 @@ def pytest_configure(config): Pytest hook called after command line options have been parsed and before test collection begins. - Couple of notes: - 1. Register the plugin's custom markers and process command-line options. + Couple of notes: 1. Register the plugin's custom markers and process + command-line options. - Custom marker registration: - https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers + Custom marker registration: + https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom + -markers 2. `@pytest.hookimpl(tryfirst=True)` is applied to ensure that this hook is - called before the pytest-html plugin's pytest_configure to ensure that - it uses the modified `htmlpath` option. + called before the pytest-html plugin's pytest_configure to ensure that it + uses the modified `htmlpath` option. """ # Modify the block gas limit if specified. if config.getoption("transaction_gas_limit"): @@ -256,7 +259,9 @@ def default_max_priority_fee_per_gas(request) -> int: def modify_transaction_defaults( default_gas_price: int, default_max_fee_per_gas: int, default_max_priority_fee_per_gas: int ): - """Modify transaction defaults to values better suited for live networks.""" + """ + Modify transaction defaults to values better suited for live networks. + """ TransactionDefaults.gas_price = default_gas_price TransactionDefaults.max_fee_per_gas = default_max_fee_per_gas TransactionDefaults.max_priority_fee_per_gas = default_max_priority_fee_per_gas @@ -264,7 +269,10 @@ def modify_transaction_defaults( @dataclass(kw_only=True) class Collector: - """A class that collects transactions and post-allocations for every test case.""" + """ + A class that collects transactions and post-allocations for every test + case. + """ eth_rpc: EthRPC collected_tests: Dict[str, BaseExecute] = field(default_factory=dict) @@ -280,8 +288,8 @@ def collector( eth_rpc: EthRPC, ) -> Generator[Collector, None, None]: """ - Return configured fixture collector instance used for all tests - in one test module. + Return configured fixture collector instance used for all tests in one test + module. """ del request @@ -293,8 +301,8 @@ def base_test_parametrizer(cls: Type[BaseTest]): """ Generate pytest.fixture for a given BaseTest subclass. - Implementation detail: All spec fixtures must be scoped on test function level to avoid - leakage between tests. + Implementation detail: All spec fixtures must be scoped on test function + level to avoid leakage between tests. """ cls_fixture_parameters = [p for p in ALL_FIXTURE_PARAMETERS if p in cls.model_fields] @@ -311,14 +319,15 @@ def base_test_parametrizer_func( collector: Collector, ): """ - Fixture used to instantiate an auto-fillable BaseTest object from within - a test function. + Fixture used to instantiate an auto-fillable BaseTest object from + within a test function. - Every test that defines a test filler must explicitly specify its parameter name - (see `pytest_parameter_name` in each implementation of BaseTest) in its function - arguments. + Every test that defines a test filler must explicitly specify its + parameter name (see `pytest_parameter_name` in each implementation of + BaseTest) in its function arguments. - When parametrize, indirect must be used along with the fixture format as value. + When parametrize, indirect must be used along with the fixture format + as value. """ execute_format = request.param assert execute_format in BaseExecute.formats.values() @@ -377,8 +386,8 @@ def __init__(self, *args, **kwargs): def pytest_generate_tests(metafunc: pytest.Metafunc): """ - Pytest hook used to dynamically generate test cases for each fixture format a given - test spec supports. + Pytest hook used to dynamically generate test cases for each fixture format + a given test spec supports. """ engine_rpc_supported = metafunc.config.engine_rpc_supported # type: ignore for test_type in BaseTest.spec_types.values(): @@ -398,9 +407,10 @@ def pytest_generate_tests(metafunc: pytest.Metafunc): def pytest_collection_modifyitems(config: pytest.Config, items: List[pytest.Item]): - """Remove transition tests and add the appropriate execute markers to the test.""" - del config - + """ + Remove transition tests and add the appropriate execute markers to the + test. + """ items_for_removal = [] for i, item in enumerate(items): if isinstance(item, EIPSpecTestItem): diff --git a/src/pytest_plugins/execute/pre_alloc.py b/src/pytest_plugins/execute/pre_alloc.py index 273a6ab3a44..9fcb524fb87 100644 --- a/src/pytest_plugins/execute/pre_alloc.py +++ b/src/pytest_plugins/execute/pre_alloc.py @@ -48,8 +48,9 @@ class AddressStubs(EthereumTestRootModel[Dict[str, Address]]): """ Address stubs class. - The key represents the label that is used in the test to tag the contract, and the value - is the address where the contract is already located at in the current network. + The key represents the label that is used in the test to tag the contract, + and the value is the address where the contract is already located at in + the current network. """ root: Dict[str, Address] @@ -65,8 +66,8 @@ def __getitem__(self, item: str) -> Address: @classmethod def model_validate_json_or_file(cls, json_data_or_path: str) -> Self: """ - Try to load from file if the value resembles a path that ends with .json/.yml and the - file exists. + Try to load from file if the value resembles a path that ends with + .json/.yml and the file exists. """ lower_json_data_or_path = json_data_or_path.lower() if ( @@ -342,7 +343,10 @@ def fund_eoa( delegation: Address | Literal["Self"] | None = None, nonce: NumberConvertible | None = None, ) -> EOA: - """Add a previously unused EOA to the pre-alloc with the balance specified by `amount`.""" + """ + Add a previously unused EOA to the pre-alloc with the balance specified + by `amount`. + """ assert nonce is None, "nonce parameter is not supported for execute" eoa = next(self._eoa_iterator) eoa.label = label @@ -385,7 +389,8 @@ def fund_eoa( if delegation is not None: if not isinstance(delegation, Address) and delegation == "Self": delegation = eoa - # TODO: This tx has side-effects on the EOA state because of the delegation + # TODO: This tx has side-effects on the EOA state because of + # the delegation fund_tx = Transaction( sender=self._sender, to=eoa, @@ -409,7 +414,8 @@ def fund_eoa( authorization_list=[ AuthorizationTuple( chain_id=self._chain_id, - address=0, # Reset delegation to an address without code + address=0, # Reset delegation to an address + # without code nonce=eoa.nonce, signer=eoa, ), @@ -478,20 +484,17 @@ def fund_address(self, address: Address, amount: NumberConvertible): def empty_account(self) -> Address: """ - Add a previously unused account guaranteed to be empty to the pre-alloc. - - This ensures the account has: - - Zero balance - - Zero nonce - - No code - - No storage + Add a previously unused account guaranteed to be empty to the + pre-alloc. - This is different from precompiles or system contracts. The function does not - send any transactions, ensuring that the account remains "empty." + This ensures the account has: - Zero balance - Zero nonce - No code - + No storage - Returns: - Address: The address of the created empty account. + This is different from precompiles or system contracts. The function + does not send any transactions, ensuring that the account remains + "empty." + Returns: Address: The address of the created empty account. """ eoa = next(self._eoa_iterator) diff --git a/src/pytest_plugins/execute/rpc/chain_builder_eth_rpc.py b/src/pytest_plugins/execute/rpc/chain_builder_eth_rpc.py index 017eb40fbcb..30820df5065 100644 --- a/src/pytest_plugins/execute/rpc/chain_builder_eth_rpc.py +++ b/src/pytest_plugins/execute/rpc/chain_builder_eth_rpc.py @@ -1,4 +1,7 @@ -"""Chain builder Ethereum RPC that can drive the chain when new transactions are submitted.""" +""" +Chain builder Ethereum RPC that can drive the chain when new transactions are +submitted. +""" import time from pathlib import Path @@ -87,10 +90,11 @@ def __iter__(self): class PendingTxHashes: """ - A class to manage the pending transaction hashes in a multi-process environment. + A class to manage the pending transaction hashes in a multi-process + environment. - It uses a lock file to ensure that only one process can access the pending hashes file at a - time. + It uses a lock file to ensure that only one process can access the pending + hashes file at a time. """ pending_hashes_file: Path @@ -166,9 +170,9 @@ def __iter__(self): class ChainBuilderEthRPC(BaseEthRPC, namespace="eth"): """ - Special type of Ethereum RPC client that also has access to the Engine API and automatically - coordinates block generation based on the number of pending transactions or a block generation - interval. + Special type of Ethereum RPC client that also has access to the Engine API + and automatically coordinates block generation based on the number of + pending transactions or a block generation interval. """ fork: Fork @@ -323,12 +327,9 @@ def wait_for_transaction(self, transaction: Transaction) -> TransactionByHashRes Waits for a specific transaction to be included in a block by polling `eth_getTransactionByHash` until it is confirmed or a timeout occurs. - Args: - transaction: The transaction to track. - - Returns: - The transaction details after it is included in a block. + Args: transaction: The transaction to track. + Returns: The transaction details after it is included in a block. """ return self.wait_for_transactions([transaction])[0] @@ -336,22 +337,20 @@ def wait_for_transactions( self, transactions: List[Transaction] ) -> List[TransactionByHashResponse]: """ - Wait for all transactions in the provided list to be included in a block. - - Waits for all transactions in the provided list to be included in a block - by polling `eth_getTransactionByHash` until they are confirmed or a - timeout occurs. + Wait for all transactions in the provided list to be included in a + block. - Args: - transactions: A list of transactions to track. + Waits for all transactions in the provided list to be included in a + block by polling `eth_getTransactionByHash` until they are confirmed or + a timeout occurs. - Returns: - A list of transaction details after they are included in a block. + Args: transactions: A list of transactions to track. - Raises: - Exception: If one or more transactions are not included in a block - within the timeout period. + Returns: A list of transaction details after they are included in a + block. + Raises: Exception: If one or more transactions are not included in a + block within the timeout period. """ tx_hashes = [tx.hash for tx in transactions] responses: List[TransactionByHashResponse] = [] @@ -398,13 +397,11 @@ def wait_for_transactions( class PendingTransactionHandler: """ - Manages block generation based on the number of pending transactions or a block generation - interval. - - Attributes: - block_generation_interval: The number of iterations after which a block - is generated if no new transactions are added (default: 10). + Manages block generation based on the number of pending transactions or a + block generation interval. + Attributes: block_generation_interval: The number of iterations after which + a block is generated if no new transactions are added (default: 10). """ chain_builder_eth_rpc: ChainBuilderEthRPC @@ -423,11 +420,12 @@ def handle(self): """ Handle pending transactions and generate blocks if necessary. - If the number of pending transactions reaches the limit, a block is generated. + If the number of pending transactions reaches the limit, a block is + generated. - If no new transactions have been added to the pending list and the block - generation interval has been reached, a block is generated to avoid potential - deadlock. + If no new transactions have been added to the pending list and the + block generation interval has been reached, a block is generated to + avoid potential deadlock. """ with self.chain_builder_eth_rpc.pending_tx_hashes: if ( @@ -442,8 +440,8 @@ def handle(self): == self.last_pending_tx_hashes_count and self.i % self.block_generation_interval == 0 ): - # If no new transactions have been added to the pending list, - # generate a block to avoid potential deadlock. + # If no new transactions have been added to the pending + # list, generate a block to avoid potential deadlock. self.chain_builder_eth_rpc.generate_block() self.last_pending_tx_hashes_count = len(self.chain_builder_eth_rpc.pending_tx_hashes) self.i += 1 diff --git a/src/pytest_plugins/execute/rpc/hive.py b/src/pytest_plugins/execute/rpc/hive.py index 0ae0f02e09b..c36349c5faf 100644 --- a/src/pytest_plugins/execute/rpc/hive.py +++ b/src/pytest_plugins/execute/rpc/hive.py @@ -147,7 +147,10 @@ def base_pre_genesis( @pytest.fixture(scope="session") def client_genesis(base_pre_genesis: Tuple[Alloc, FixtureHeader]) -> dict: - """Convert the fixture's genesis block header and pre-state to a client genesis state.""" + """ + Convert the fixture's genesis block header and pre-state to a client + genesis state. + """ genesis = to_json(base_pre_genesis[1]) # NOTE: to_json() excludes None values alloc = to_json(base_pre_genesis[0]) # NOTE: nethermind requires account keys without '0x' prefix @@ -211,7 +214,9 @@ def test_suite_description() -> str: def base_hive_test( request: pytest.FixtureRequest, test_suite: HiveTestSuite, session_temp_folder: Path ) -> Generator[HiveTest, None, None]: - """Test (base) used to deploy the main client to be used throughout all tests.""" + """ + Test (base) used to deploy the main client to be used throughout all tests. + """ base_name = "base_hive_test" base_file = session_temp_folder / base_name base_lock_file = session_temp_folder / f"{base_name}.lock" @@ -276,7 +281,9 @@ def client( client_type: ClientType, session_temp_folder: Path, ) -> Generator[Client, None, None]: - """Initialize the client with the appropriate files and environment variables.""" + """ + Initialize the client with the appropriate files and environment variables. + """ base_name = "hive_client" base_file = session_temp_folder / base_name base_error_file = session_temp_folder / f"{base_name}.err" diff --git a/src/pytest_plugins/execute/rpc/remote.py b/src/pytest_plugins/execute/rpc/remote.py index d5168af951a..4f87766235b 100644 --- a/src/pytest_plugins/execute/rpc/remote.py +++ b/src/pytest_plugins/execute/rpc/remote.py @@ -87,7 +87,8 @@ def pytest_configure(config: pytest.Config): """Check if a chain ID configuration is provided.""" if config.getoption("rpc_chain_id") is None and config.getoption("chain_id") is None: pytest.exit("No chain ID configuration found. Please use --chain-id.") - # Verify the chain ID configuration is consistent with the remote RPC endpoint + # Verify the chain ID configuration is consistent with the remote RPC + # endpoint rpc_endpoint = config.getoption("rpc_endpoint") eth_rpc = EthRPC(rpc_endpoint) remote_chain_id = eth_rpc.chain_id() @@ -127,8 +128,9 @@ def pytest_configure(config: pytest.Config): f"JWT secret must be a bytes object, got {type(jwt_secret)}" ) engine_rpc = EngineRPC(engine_endpoint, jwt_secret=jwt_secret) - # TODO: Perform a request to the engine endpoint to verify that the JWT secret is valid. - # Potentially could be `engine_getClientVersionV1` but need to implement this in rpc.py. + # TODO: Perform a request to the engine endpoint to verify that the JWT + # secret is valid. Potentially could be `engine_getClientVersionV1` but + # need to implement this in rpc.py. config.engine_rpc = engine_rpc # type: ignore @@ -140,7 +142,10 @@ def engine_rpc(request) -> EngineRPC | None: @pytest.fixture(autouse=True, scope="session") def rpc_endpoint(request) -> str: - """Return remote RPC endpoint to be used to make requests to the execution client.""" + """ + Return remote RPC endpoint to be used to make requests to the execution + client. + """ return request.config.getoption("rpc_endpoint") diff --git a/src/pytest_plugins/execute/sender.py b/src/pytest_plugins/execute/sender.py index 016fd4862f8..a93a4081d21 100644 --- a/src/pytest_plugins/execute/sender.py +++ b/src/pytest_plugins/execute/sender.py @@ -85,15 +85,17 @@ def sender_key_initial_balance( """ Calculate the initial balance of each sender key. - The way to do this is to fetch the seed sender balance and divide it by the number of - workers. This way we can ensure that each sender key has the same initial balance. + The way to do this is to fetch the seed sender balance and divide it by the + number of workers. This way we can ensure that each sender key has the same + initial balance. - We also only do this once per session, because if we try to fetch the balance again, it - could be that another worker has already sent a transaction and the balance is different. + We also only do this once per session, because if we try to fetch the + balance again, it could be that another worker has already sent a + transaction and the balance is different. - It's not really possible to calculate the transaction costs of each test that each worker - is going to run, so we can't really calculate the initial balance of each sender key - based on that. + It's not really possible to calculate the transaction costs of each test + that each worker is going to run, so we can't really calculate the initial + balance of each sender key based on that. """ base_name = "sender_key_initial_balance" base_file = session_temp_folder / base_name @@ -108,7 +110,8 @@ def sender_key_initial_balance( seed_account_sweep_amount = eth_rpc.get_balance(seed_sender) seed_sender_balance_per_worker = seed_account_sweep_amount // worker_count assert seed_sender_balance_per_worker > 100, "Seed sender balance too low" - # Subtract the cost of the transaction that is going to be sent to the seed sender + # Subtract the cost of the transaction that is going to be sent to + # the seed sender sender_key_initial_balance = seed_sender_balance_per_worker - ( sender_fund_refund_gas_limit * sender_funding_transactions_gas_price ) @@ -132,11 +135,12 @@ def sender_key( """ Get the sender keys for all tests. - The seed sender is going to be shared among different processes, so we need to lock it - before we produce each funding transaction. + The seed sender is going to be shared among different processes, so we need + to lock it before we produce each funding transaction. """ - # For the seed sender we do need to keep track of the nonce because it is shared among - # different processes, and there might not be a new block produced between the transactions. + # For the seed sender we do need to keep track of the nonce because it is + # shared among different processes, and there might not be a new block + # produced between the transactions. seed_sender_nonce_file_name = "seed_sender_nonce" seed_sender_lock_file_name = f"{seed_sender_nonce_file_name}.lock" seed_sender_nonce_file = session_temp_folder / seed_sender_nonce_file_name @@ -172,15 +176,16 @@ def sender_key( ) refund_gas_limit = sender_fund_refund_gas_limit - # double the gas price to ensure the transaction is included and overwrites any other - # transaction that might have been sent by the sender. + # double the gas price to ensure the transaction is included and overwrites + # any other transaction that might have been sent by the sender. refund_gas_price = sender_funding_transactions_gas_price * 2 tx_cost = refund_gas_limit * refund_gas_price if (remaining_balance - 1) < tx_cost: return - # Update the nonce of the sender in case one of the pre-alloc transactions failed + # Update the nonce of the sender in case one of the pre-alloc transactions + # failed sender.nonce = Number(eth_rpc.get_transaction_count(sender)) refund_tx = Transaction( diff --git a/src/pytest_plugins/filler/eip_checklist.py b/src/pytest_plugins/filler/eip_checklist.py index 2387aa178c0..855c903bb57 100644 --- a/src/pytest_plugins/filler/eip_checklist.py +++ b/src/pytest_plugins/filler/eip_checklist.py @@ -1,8 +1,8 @@ """ Pytest plugin for generating EIP test completion checklists. -This plugin collects checklist markers from tests and generates a filled checklist -for each EIP based on the template at +This plugin collects checklist markers from tests and generates a filled +checklist for each EIP based on the template at docs/writing_tests/checklist_templates/eip_testing_checklist_template.md """ @@ -195,7 +195,9 @@ class ConflictingChecklistItemsWarning(ChecklistWarning): @classmethod def from_items(cls, all_items: Dict[str, EIPItem]) -> ChecklistWarning | None: - """Generate a conflicting checklist items warning from a list of items.""" + """ + Generate a conflicting checklist items warning from a list of items. + """ conflicting_items = [ item for item in all_items.values() if item.not_applicable and item.covered ] @@ -335,8 +337,8 @@ def generate_filled_checklist_lines(self) -> List[str]: # Replace the title line with the EIP number lines[lines.index(TITLE_LINE)] = f"# EIP-{self.number} Test Checklist" - # Last, add the warnings if there are any, this must be the last thing we do - # to avoid shifting the lines below the percentage line + # Last, add the warnings if there are any, this must be the last thing + # we do to avoid shifting the lines below the percentage line if self.warnings: warnings_line_idx = lines.index(WARNINGS_LINE) warnings_lines = ["", "## ⚠️ Checklist Warnings ⚠️", ""] diff --git a/src/pytest_plugins/filler/filler.py b/src/pytest_plugins/filler/filler.py index 30b605d7534..765c272ac36 100644 --- a/src/pytest_plugins/filler/filler.py +++ b/src/pytest_plugins/filler/filler.py @@ -1,9 +1,8 @@ """ -Top-level pytest configuration file providing: -- Command-line options, -- Test-fixtures that can be used by all test cases, -and that modifies pytest hooks in order to fill test specs for all tests and -writes the generated fixtures to file. +Top-level pytest configuration file providing: - Command-line options, - +Test-fixtures that can be used by all test cases, and that modifies pytest +hooks in order to fill test specs for all tests and writes the generated +fixtures to file. """ import configparser @@ -60,12 +59,13 @@ class PhaseManager: """ Manages the execution phase for fixture generation. - The filler plugin supports two-phase execution for pre-allocation group generation: - - Phase 1: Generate pre-allocation groups (pytest run with --generate-pre-alloc-groups). - - Phase 2: Fill fixtures using pre-allocation groups (pytest run with --use-pre-alloc-groups). + The filler plugin supports two-phase execution for pre-allocation group + generation: - Phase 1: Generate pre-allocation groups (pytest run with + --generate-pre-alloc-groups). - Phase 2: Fill fixtures using pre-allocation + groups (pytest run with --use-pre-alloc-groups). - Note: These are separate pytest runs orchestrated by the CLI wrapper. - Each run gets a fresh PhaseManager instance (no persistence between phases). + Note: These are separate pytest runs orchestrated by the CLI wrapper. Each + run gets a fresh PhaseManager instance (no persistence between phases). """ current_phase: FixtureFillingPhase @@ -76,14 +76,14 @@ def from_config(cls, config: pytest.Config) -> "Self": """ Create a PhaseManager from pytest configuration. - Flag logic: - - use_pre_alloc_groups: We're in phase 2 (FILL) after phase 1 (PRE_ALLOC_GENERATION). - - generate_pre_alloc_groups or generate_all_formats: We're in phase 1 - (PRE_ALLOC_GENERATION). - - Otherwise: Normal single-phase filling (FILL). + Flag logic: - use_pre_alloc_groups: We're in phase 2 (FILL) after phase + 1 (PRE_ALLOC_GENERATION). - generate_pre_alloc_groups or + generate_all_formats: We're in phase 1 (PRE_ALLOC_GENERATION). - + Otherwise: Normal single-phase filling (FILL). - Note: generate_all_formats triggers PRE_ALLOC_GENERATION because the CLI - passes it to phase 1 to ensure all formats are considered for grouping. + Note: generate_all_formats triggers PRE_ALLOC_GENERATION because the + CLI passes it to phase 1 to ensure all formats are considered for + grouping. """ generate_pre_alloc = config.getoption("generate_pre_alloc_groups", False) use_pre_alloc = config.getoption("use_pre_alloc_groups", False) @@ -127,10 +127,11 @@ def is_single_phase_fill(self) -> bool: @dataclass(kw_only=True) class FormatSelector: """ - Handles fixture format selection based on the current phase and format capabilities. + Handles fixture format selection based on the current phase and format + capabilities. - This class encapsulates the complex logic for determining which fixture formats - should be generated in each phase of the two-phase execution model. + This class encapsulates the complex logic for determining which fixture + formats should be generated in each phase of the two-phase execution model. """ phase_manager: PhaseManager @@ -140,12 +141,10 @@ def should_generate(self, fixture_format: Type[BaseFixture] | LabeledFixtureForm """ Determine if a fixture format should be generated in the current phase. - Args: - fixture_format: The fixture format to check (may be wrapped in LabeledFixtureFormat) - - Returns: - True if the format should be generated in the current phase + Args: fixture_format: The fixture format to check (may be wrapped in + LabeledFixtureFormat) + Returns: True if the format should be generated in the current phase """ format_phases = fixture_format.format_phases @@ -155,7 +154,10 @@ def should_generate(self, fixture_format: Type[BaseFixture] | LabeledFixtureForm return self._should_generate_fill(format_phases) def _should_generate_pre_alloc(self, format_phases: Set[FixtureFillingPhase]) -> bool: - """Determine if format should be generated during pre-alloc generation phase.""" + """ + Determine if format should be generated during pre-alloc generation + phase. + """ # Only generate formats that need pre-allocation groups return FixtureFillingPhase.PRE_ALLOC_GENERATION in format_phases @@ -164,7 +166,8 @@ def _should_generate_fill(self, format_phases: Set[FixtureFillingPhase]) -> bool if FixtureFillingPhase.PRE_ALLOC_GENERATION in self.phase_manager.previous_phases: # Phase 2: After pre-alloc generation if self.generate_all_formats: - # Generate all formats, including those that don't need pre-alloc + # Generate all formats, including those that don't need pre- + # alloc return True else: # Only generate formats that needed pre-alloc groups @@ -179,12 +182,13 @@ class FillingSession: """ Manages all state for a single pytest fill session. - This class serves as the single source of truth for all filler state management, - including phase management, format selection, and pre-allocation groups. + This class serves as the single source of truth for all filler state + management, including phase management, format selection, and + pre-allocation groups. - Important: Each pytest run gets a fresh FillingSession instance. There is no - persistence between phase 1 (generate pre-alloc) and phase 2 (use pre-alloc) - except through file I/O. + Important: Each pytest run gets a fresh FillingSession instance. There is + no persistence between phase 1 (generate pre-alloc) and phase 2 (use + pre-alloc) except through file I/O. """ fixture_output: FixtureOutput @@ -197,9 +201,7 @@ def from_config(cls, config: pytest.Config) -> "Self": """ Initialize a filling session from pytest configuration. - Args: - config: The pytest configuration object. - + Args: config: The pytest configuration object. """ phase_manager = PhaseManager.from_config(config) instance = cls( @@ -240,14 +242,12 @@ def should_generate_format( self, fixture_format: Type[BaseFixture] | LabeledFixtureFormat ) -> bool: """ - Determine if a fixture format should be generated in the current session. - - Args: - fixture_format: The fixture format to check. + Determine if a fixture format should be generated in the current + session. - Returns: - True if the format should be generated. + Args: fixture_format: The fixture format to check. + Returns: True if the format should be generated. """ return self.format_selector.should_generate(fixture_format) @@ -255,15 +255,12 @@ def get_pre_alloc_group(self, hash_key: str) -> PreAllocGroup: """ Get a pre-allocation group by hash. - Args: - hash_key: The hash of the pre-alloc group. + Args: hash_key: The hash of the pre-alloc group. - Returns: - The pre-allocation group. - - Raises: - ValueError: If pre-alloc groups not initialized or hash not found. + Returns: The pre-allocation group. + Raises: ValueError: If pre-alloc groups not initialized or hash not + found. """ if self.pre_alloc_groups is None: raise ValueError("Pre-allocation groups not initialized") @@ -282,13 +279,10 @@ def update_pre_alloc_group(self, hash_key: str, group: PreAllocGroup) -> None: """ Update or add a pre-allocation group. - Args: - hash_key: The hash of the pre-alloc group. - group: The pre-allocation group. - - Raises: - ValueError: If not in pre-alloc generation phase. + Args: hash_key: The hash of the pre-alloc group. group: The + pre-allocation group. + Raises: ValueError: If not in pre-alloc generation phase. """ if not self.phase_manager.is_pre_alloc_generation: raise ValueError("Can only update pre-alloc groups in generation phase") @@ -311,9 +305,7 @@ def aggregate_pre_alloc_groups(self, worker_groups: PreAllocGroups) -> None: """ Aggregate pre-alloc groups from a worker process (xdist support). - Args: - worker_groups: Pre-alloc groups from a worker process. - + Args: worker_groups: Pre-alloc groups from a worker process. """ if self.pre_alloc_groups is None: self.pre_alloc_groups = PreAllocGroups(root={}) @@ -335,22 +327,19 @@ def calculate_post_state_diff(post_state: Alloc, genesis_state: Alloc) -> Alloc: """ Calculate the state difference between post_state and genesis_state. - This function enables significant space savings in Engine X fixtures by storing - only the accounts that changed during test execution, rather than the full - post-state which may contain thousands of unchanged accounts. - - Returns an Alloc containing only the accounts that: - - Changed between genesis and post state (balance, nonce, storage, code) - - Were created during test execution (new accounts) - - Were deleted during test execution (represented as None) + This function enables significant space savings in Engine X fixtures by + storing only the accounts that changed during test execution, rather than + the full post-state which may contain thousands of unchanged accounts. - Args: - post_state: Final state after test execution - genesis_state: Genesis pre-allocation state + Returns an Alloc containing only the accounts that: - Changed between + genesis and post state (balance, nonce, storage, code) - Were created + during test execution (new accounts) - Were deleted during test execution + (represented as None) - Returns: - Alloc containing only the state differences for efficient storage + Args: post_state: Final state after test execution genesis_state: Genesis + pre-allocation state + Returns: Alloc containing only the state differences for efficient storage """ diff: Dict[Address, Account | None] = {} @@ -621,15 +610,16 @@ def pytest_configure(config): Pytest hook called after command line options have been parsed and before test collection begins. - Couple of notes: - 1. Register the plugin's custom markers and process command-line options. + Couple of notes: 1. Register the plugin's custom markers and process + command-line options. - Custom marker registration: - https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers + Custom marker registration: + https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html# registering- + # custom -markers 2. `@pytest.hookimpl(tryfirst=True)` is applied to ensure that this hook is - called before the pytest-html plugin's pytest_configure to ensure that - it uses the modified `htmlpath` option. + called before the pytest-html plugin's pytest_configure to ensure that it + uses the modified `htmlpath` option. """ # Register custom markers # Modify the block gas limit if specified. @@ -646,7 +636,8 @@ def pytest_configure(config): return try: - # Check whether the directory exists and is not empty; if --clean is set, it will delete it + # Check whether the directory exists and is not empty; if --clean is + # set, it will delete it config.fixture_output.create_directories(is_master=not hasattr(config, "workerinput")) except ValueError as e: pytest.exit(str(e), returncode=pytest.ExitCode.USAGE_ERROR) @@ -670,8 +661,9 @@ def pytest_configure(config): "optimize_gas", False ) - # Instantiate the transition tool here to check that the binary path/trace option is valid. - # This ensures we only raise an error once, if appropriate, instead of for every test. + # Instantiate the transition tool here to check that the binary path/trace + # option is valid. This ensures we only raise an error once, if + # appropriate, instead of for every test. evm_bin = config.getoption("evm_bin") trace = config.getoption("evm_collect_traces") t8n_server_url = config.getoption("t8n_server_url") @@ -730,11 +722,8 @@ def pytest_report_teststatus(report, config: pytest.Config): We use this: 1. To disable test session progress report if we're writing the JSON - fixtures to stdout to be read by a consume command on stdin. I.e., - don't write this type of output to the console: - ```text - ...x... - ``` + fixtures to stdout to be read by a consume command on stdin. I.e., don't + write this type of output to the console: ```text ...x... ``` """ if config.fixture_output.is_stdout: # type: ignore[attr-defined] return report.outcome, "", report.outcome.upper() @@ -872,7 +861,10 @@ def pytest_runtest_makereport(item, call): ]: report.user_properties.append(("evm_dump_dir", item.config.evm_dump_dir)) else: - report.user_properties.append(("evm_dump_dir", "N/A")) # not yet for EOF + report.user_properties.append(("evm_dump_dir", "N/A")) # not + # yet + # for + # EOF def pytest_html_report_title(report): @@ -889,8 +881,7 @@ def evm_bin(request: pytest.FixtureRequest) -> Path | None: @pytest.fixture(autouse=True, scope="session") def verify_fixtures_bin(request: pytest.FixtureRequest) -> Path | None: """ - Return configured evm tool binary path used to run statetest or - blocktest. + Return configured evm tool binary path used to run statetest or blocktest. """ return request.config.getoption("verify_fixtures_bin") @@ -935,8 +926,8 @@ def evm_fixture_verification( verify_fixtures_bin: Path | None, ) -> Generator[FixtureConsumer | None, None, None]: """ - Return configured evm binary for executing statetest and blocktest - commands used to verify generated JSON fixtures. + Return configured evm binary for executing statetest and blocktest commands + used to verify generated JSON fixtures. """ if not do_fixture_verification: yield None @@ -1049,8 +1040,9 @@ def dump_dir_parameter_level( Directory to dump evm transition tool debug output on a test parameter level. - Example with --evm-dump-dir=/tmp/evm: - -> /tmp/evm/shanghai__eip3855_push0__test_push0__test_push0_key_sstore/fork_shanghai/ + Example with --evm-dump-dir=/tmp/evm: -> + /tmp/evm/shanghai__eip3855_push0__test_push0__test_push0_key_sstore/fork_shangh + ai/ """ evm_dump_dir = node_to_test_info(request.node).get_dump_dir_path( base_dump_dir, @@ -1102,8 +1094,8 @@ def fixture_collector( fixture_output: FixtureOutput, ) -> Generator[FixtureCollector, None, None]: """ - Return configured fixture collector instance used for all tests - in one test module. + Return configured fixture collector instance used for all tests in one test + module. """ # Dynamically load the 'static_filler' and 'solc' plugins if needed if request.config.getoption("fill_static_tests_enabled"): @@ -1163,8 +1155,9 @@ def fixture_source_url( ) test_module_relative_path = os.path.relpath(request.module.__file__) if module_relative_path != test_module_relative_path: - # This can be the case when the test function's body only contains pass and the entire - # test logic is implemented as a test generator from the framework. + # This can be the case when the test function's body only contains pass + # and the entire test logic is implemented as a test generator from the + # framework. test_module_github_url = generate_github_url( test_module_relative_path, branch_or_commit_or_tag=commit_hash_or_tag, @@ -1177,8 +1170,8 @@ def base_test_parametrizer(cls: Type[BaseTest]): """ Generate pytest.fixture for a given BaseTest subclass. - Implementation detail: All spec fixtures must be scoped on test function level to avoid - leakage between tests. + Implementation detail: All spec fixtures must be scoped on test function + level to avoid leakage between tests. """ cls_fixture_parameters = [p for p in ALL_FIXTURE_PARAMETERS if p in cls.model_fields] @@ -1201,14 +1194,15 @@ def base_test_parametrizer_func( witness_generator, ): """ - Fixture used to instantiate an auto-fillable BaseTest object from within - a test function. + Fixture used to instantiate an auto-fillable BaseTest object from + within a test function. - Every test that defines a test filler must explicitly specify its parameter name - (see `pytest_parameter_name` in each implementation of BaseTest) in its function - arguments. + Every test that defines a test filler must explicitly specify its + parameter name (see `pytest_parameter_name` in each implementation of + BaseTest) in its function arguments. - When parametrize, indirect must be used along with the fixture format as value. + When parametrize, indirect must be used along with the fixture format + as value. """ if hasattr(request.node, "fixture_format"): fixture_format = request.node.fixture_format @@ -1248,13 +1242,15 @@ def __init__(self, *args, **kwargs): # Phase 1: Generate pre-allocation groups if session.phase_manager.is_pre_alloc_generation: - # Use the original update_pre_alloc_groups method which returns the groups + # Use the original update_pre_alloc_groups method which + # returns the groups self.update_pre_alloc_groups( session.pre_alloc_groups, fork, request.node.nodeid ) return # Skip fixture generation in phase 1 - # Phase 2: Use pre-allocation groups (only for BlockchainEngineXFixture) + # Phase 2: Use pre-allocation groups (only for + # BlockchainEngineXFixture) pre_alloc_hash = None if FixtureFillingPhase.PRE_ALLOC_GENERATION in fixture_format.format_phases: pre_alloc_hash = self.compute_pre_alloc_group_hash(fork=fork) @@ -1273,11 +1269,13 @@ def __init__(self, *args, **kwargs): ): gas_optimized_tests = request.config.gas_optimized_tests assert gas_optimized_tests is not None - # Force adding something to the list, even if it's None, - # to keep track of failed tests in the output file. + # Force adding something to the list, even if it's + # None, to keep track of failed tests in the output + # file. gas_optimized_tests[request.node.nodeid] = self._gas_optimization - # Post-process for Engine X format (add pre_hash and state diff) + # Post-process for Engine X format (add pre_hash and state + # diff) if ( FixtureFillingPhase.PRE_ALLOC_GENERATION in fixture_format.format_phases and pre_alloc_hash is not None @@ -1299,7 +1297,8 @@ def __init__(self, *args, **kwargs): _info_metadata=t8n._info_metadata, ) - # Generate witness data if witness functionality is enabled via the witness plugin + # Generate witness data if witness functionality is enabled via + # the witness plugin if witness_generator is not None: witness_generator(fixture) @@ -1328,11 +1327,11 @@ def __init__(self, *args, **kwargs): def pytest_generate_tests(metafunc: pytest.Metafunc): """ - Pytest hook used to dynamically generate test cases for each fixture format a given - test spec supports. + Pytest hook used to dynamically generate test cases for each fixture format + a given test spec supports. - NOTE: The static test filler does NOT use this hook. See FillerFile.collect() in - ./static_filler.py for more details. + NOTE: The static test filler does NOT use this hook. See + FillerFile.collect() in ./static_filler.py for more details. """ session: FillingSession = metafunc.config.filling_session # type: ignore[attr-defined] for test_type in BaseTest.spec_types.values(): @@ -1360,7 +1359,8 @@ def pytest_collection_modifyitems( Remove pre-Paris tests parametrized to generate hive type fixtures; these can't be used in the Hive Pyspec Simulator. - Replaces the test ID for state tests that use a transition fork with the base fork. + Replaces the test ID for state tests that use a transition fork with the + base fork. These can't be handled in this plugins pytest_generate_tests() as the fork parametrization occurs in the forks plugin. @@ -1390,7 +1390,8 @@ def pytest_collection_modifyitems( markers = list(item.iter_markers()) - # Automatically apply pre_alloc_group marker to slow tests that are not benchmark tests + # Automatically apply pre_alloc_group marker to slow tests that are not + # benchmark tests has_slow_marker = any(marker.name == "slow" for marker in markers) has_benchmark_marker = any(marker.name == "benchmark" for marker in markers) has_pre_alloc_group_marker = any(marker.name == "pre_alloc_group" for marker in markers) @@ -1408,8 +1409,8 @@ def pytest_collection_modifyitems( # Re-collect markers after adding the new one markers = list(item.iter_markers()) - # Both the fixture format itself and the spec filling it have a chance to veto the - # filling of a specific format. + # Both the fixture format itself and the spec filling it have a chance + # to veto the filling of a specific format. if fixture_format.discard_fixture_format_by_marks(fork, markers): items_for_removal.append(i) continue @@ -1444,10 +1445,9 @@ def pytest_sessionfinish(session: pytest.Session, exitstatus: int): """ Perform session finish tasks. - - Save pre-allocation groups (phase 1) - - Remove any lock files that may have been created. - - Generate index file for all produced fixtures. - - Create tarball of the output directory if the output is a tarball. + - Save pre-allocation groups (phase 1) - Remove any lock files that may + have been created. - Generate index file for all produced fixtures. - + Create tarball of the output directory if the output is a tarball. """ del exitstatus diff --git a/src/pytest_plugins/filler/fixture_output.py b/src/pytest_plugins/filler/fixture_output.py index 3238c7d6ec2..c9f421f6ed9 100644 --- a/src/pytest_plugins/filler/fixture_output.py +++ b/src/pytest_plugins/filler/fixture_output.py @@ -69,7 +69,9 @@ def pre_alloc_groups_folder_path(self) -> Path: @property def should_auto_enable_all_formats(self) -> bool: - """Check if all formats should be auto-enabled due to tarball output.""" + """ + Check if all formats should be auto-enabled due to tarball output. + """ return self.is_tarball @staticmethod @@ -95,7 +97,8 @@ def is_directory_usable_for_phase(self) -> bool: # Phase 1: Directory must be completely empty return self.is_directory_empty() elif self.use_pre_alloc_groups: - # Phase 2: Only pre-allocation groups must exist, no other files allowed + # Phase 2: Only pre-allocation groups must exist, no other files + # allowed if not self.pre_alloc_groups_folder_path.exists(): return False # Check that only the pre-allocation group files exist @@ -149,13 +152,14 @@ def create_directories(self, is_master: bool) -> None: """ Create output and metadata directories if needed. - If clean flag is set, remove and recreate the directory. - Otherwise, verify the directory is empty before proceeding. + If clean flag is set, remove and recreate the directory. Otherwise, + verify the directory is empty before proceeding. """ if self.is_stdout: return - # Only the master process should delete/create directories if using pytest-xdist + # Only the master process should delete/create directories if using + # pytest-xdist if not is_master: return diff --git a/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py b/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py index 044b2a2e9a1..66583ced925 100644 --- a/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py +++ b/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py @@ -1,42 +1,32 @@ """ A pytest plugin that generates test case documentation for use in mkdocs. -It generates the top-level "Test Case Reference" section in EEST's mkdocs -site. +It generates the top-level "Test Case Reference" section in EEST's mkdocs site. -Note: ----- -- No output directory is specified for the generated output; file IO occurs - via the `mkdocs-gen-files` plugin. `mkdocs serve` writes intermediate files - to our local `docs/` directory and then copies it to the site directory. - We modify `docs/navigation.md` and write all other output underneath - `docs/tests`. If mkdocs is interrupted, these intermediate artifacts are - left in `docs/`. +Note: ---- - No output directory is specified for the generated output; file IO +occurs via the `mkdocs-gen-files` plugin. `mkdocs serve` writes intermediate +files to our local `docs/` directory and then copies it to the site directory. +We modify `docs/navigation.md` and write all other output underneath +`docs/tests`. If mkdocs is interrupted, these intermediate artifacts are left +in `docs/`. -Usage: ------- +Usage: ------ !!! note "Ensuring a clean build" - In case mkdocs has polluted the `docs/` directory with intermediate files, run: +In case mkdocs has polluted the `docs/` directory with intermediate files, run: - ```console - git restore docs/navigation.md # Careful if you have local modifications! - rm -rf docs/tests docs/docs site - ``` +```console git restore docs/navigation.md # Careful if you have local +modifications! rm -rf docs/tests docs/docs site ``` To test doc generation, run the plugin without mkdocs: -```console -uv run fill -p pytest_plugins.filler.gen_test_doc.gen_test_doc --gen-docs --fork= tests -``` +```console uv run fill -p pytest_plugins.filler.gen_test_doc.gen_test_doc +--gen-docs --fork= tests ``` Or to build and view the site: -```console -uv run mkdocs serve -``` - +```console uv run mkdocs serve ``` """ import glob @@ -128,8 +118,8 @@ def get_test_function_import_path(item: pytest.Item) -> str: """ Retrieve the fully qualified import path for an item's test function. - This is used in jinja2 templates to get the test function, respectively - the test function's class, documentation with mkdocstrings. + This is used in jinja2 templates to get the test function, respectively the + test function's class, documentation with mkdocstrings. """ item = cast(pytest.Function, item) # help mypy infer type module_name = item.module.__name__ @@ -149,11 +139,10 @@ def get_import_path(path: Path) -> str: """ Get the import path for a given path. - - For modules, strip the file extension. - - For directories (i.e., packages such as `tests.berlin`), `with_suffix()` is ignored. + - For modules, strip the file extension. - For directories (i.e., packages + such as `tests.berlin`), `with_suffix()` is ignored. - To do: - ------ + To do: ------ - This should be combined with `get_test_function_import_path`. """ @@ -273,7 +262,8 @@ def pytest_collection_modifyitems(self, config: pytest.Config, items: List[pytes self.create_module_page_props() # add the pages to the page_props dict self.page_props = {**self.page_props, **self.function_page_props, **self.module_page_props} - # this adds pages for the intermediate directory structure (tests, tests/berlin) + # this adds pages for the intermediate directory structure (tests, + # tests/berlin) self.add_directory_page_props() # add other interesting pages self.add_spec_page_props() @@ -297,7 +287,8 @@ def _setup_logger(self): Configure the mkdocs logger and adds a StreamHandler if outside mkdocs. We use the mkdocs logger to report warnings if conditions are invalid - - this will inform the user and fail the build with `mkdocs build --strict`. + this will inform the user and fail the build with `mkdocs build + --strict`. """ if not logger.hasHandlers() or logger.level == logging.NOTSET: stream_handler = logging.StreamHandler(sys.stdout) @@ -309,15 +300,14 @@ def get_doc_site_base_url(self) -> str: """ Return site's base in its URL for inclusion of local files. - This is required in order to include docs/javascripts/site.js, for + This is required in order to include docs/javascripts/site.js, for example, in the standalone html pages. - Github pages deploys to a sub-directory "execution-spec-tests" and - mike deploys a version of the site underneath a sub-directory named - after the version, e.g.: + Github pages deploys to a sub-directory "execution-spec-tests" and mike + deploys a version of the site underneath a sub-directory named after + the version, e.g.: - - https://eest.ethereum.org/main/ - - https://eest.ethereum.org/v4.1.0/ + - https://eest.ethereum.org/main/ - https://eest.ethereum.org/v4.1.0/ We need to be able to include the javascript available at: @@ -352,7 +342,8 @@ def add_global_page_props_to_env(self): def create_function_page_props(self, test_functions: Dict["str", List[Item]]) -> None: """ - Traverse all test items and create a lookup of doc pages & required props. + Traverse all test items and create a lookup of doc pages & required + props. To do: Needs refactor. """ @@ -361,17 +352,20 @@ def create_function_page_props(self, test_functions: Dict["str", List[Item]]) -> ] for function_id, function_items in test_functions.items(): assert all(isinstance(item, pytest.Function) for item in function_items) - items = cast(List[pytest.Function], function_items) # help mypy infer type + items = cast(List[pytest.Function], function_items) # help mypy + # infer type # extract parametrized test cases for each test function test_cases = [] if getattr(items[0], "callspec", None): for item in items: param_set = item.callspec.params - # Don't show skipped parameters as columns in the test case table + # Don't show skipped parameters as columns in the test case + # table keys = [key for key in param_set.keys() if key not in skip_params] values = [param_set[key] for key in keys] - # TODO: This formatting of bytes objects should be moved elsewhere + # TODO: This formatting of bytes objects should be moved + # elsewhere values = [ ( " ".join( @@ -406,8 +400,8 @@ def create_function_page_props(self, test_functions: Dict["str", List[Item]]) -> if not valid_from_marker: valid_from_fork = "Frontier" else: - # NOTE: The EOF tests cases contain two fork names in their valid_from marker, - # separated by a comma. Take the last. + # NOTE: The EOF tests cases contain two fork names in their + # valid_from marker, separated by a comma. Take the last. valid_from_fork = valid_from_marker.args[0].split(",")[-1] target_or_valid_fork = ( @@ -481,7 +475,8 @@ def add_directory_page_props(self) -> None: """ Discover the intermediate directory pages and extract their properties. - These directories may not have any test modules within them, e.g., tests/berlin/. + These directories may not have any test modules within them, e.g., + tests/berlin/. """ sub_paths: Set[Path] = set() for module_page in self.module_page_props.values(): @@ -511,10 +506,12 @@ def add_directory_page_props(self) -> None: path=directory, pytest_node_id=str(directory), source_code_url=generate_github_url(directory, branch_or_commit_or_tag=self.ref), - # TODO: This won't work in all cases; should be from the development fork - # Currently breaks for `tests/unscheduled/eip7692_eof_v1/index.md` # noqa: SC100 + # TODO: This won't work in all cases; should be from the + # development fork Currently breaks for + # `tests/unscheduled/eip7692_eof_v1/index.md` target_or_valid_fork=fork.capitalize() if fork else "Unknown", - package_name=get_import_path(directory), # init.py will be used for docstrings + package_name=get_import_path(directory), # init.py will be + # used for docstrings is_benchmark=is_benchmark, ) @@ -538,7 +535,10 @@ def find_files_within_collection_scope(self, file_pattern: str) -> List[Path]: return [Path(file) for file in set(files)] def add_spec_page_props(self) -> None: - """Add page path properties for spec files discovered in the collection scope.""" + """ + Add page path properties for spec files discovered in the collection + scope. + """ for spec_path in self.find_files_within_collection_scope("spec.py"): self.page_props[str(spec_path)] = ModulePageProps( title="Spec", @@ -551,44 +551,56 @@ def add_spec_page_props(self) -> None: ) def add_markdown_page_props(self) -> None: - """Add page path properties for markdown files discovered in the collection scope.""" + """ + Add page path properties for markdown files discovered in the + collection scope. + """ for md_path in self.find_files_within_collection_scope("*.md"): self.page_props[str(md_path)] = MarkdownPageProps( title=md_path.stem, path=md_path, source_code_url=generate_github_url(md_path, branch_or_commit_or_tag=self.ref), - pytest_node_id=str(md_path), # abuse: not a test, but used in source code link + pytest_node_id=str(md_path), # abuse: not a test, but used in + # source code link target_or_valid_fork="", package_name="", ) def update_mkdocs_nav(self) -> None: - """Add the generated 'Test Case Reference' entries to the mkdocs navigation menu.""" + """ + Add the generated 'Test Case Reference' entries to the mkdocs + navigation menu. + """ fork_order = {fork.name().lower(): i for i, fork in enumerate(reversed(get_forks()))} def sort_by_fork_deployment_and_path(x: PageProps) -> Tuple[Any, ...]: """ - Key function used to sort navigation menu entries for test case ref docs. + Key function used to sort navigation menu entries for test case ref + docs. Nav entries / output files contain special cases such as: - - ("Test Case Reference",) -> tests/index.md - - ("Test Case Reference", "Berlin") -> tests/berlin/index.md - - ("Test Case Reference", "EIP-7692 EOF V1", tracker.md") - tests/unscheduled/eip7692_eof_v1/tracker.md - - ("Test Case Reference", "Shanghai", "EIP-3855 PUSH0", "Spec") -> - tests/shanghai/eip3855_push0/spec.py + - ("Test Case Reference",) -> tests/index.md - ("Test Case + Reference", "Berlin") -> tests/berlin/index.md - ("Test Case + Reference", "EIP-7692 EOF V1", tracker.md") + tests/unscheduled/eip7692_eof_v1/tracker.md - ("Test Case + Reference", "Shanghai", "EIP-3855 PUSH0", "Spec") -> + tests/shanghai/eip3855_push0/spec.py - This function provides and ordering to sort nav men entries as follows: + This function provides and ordering to sort nav men entries as + follows: - 1. Forks are listed in the chronological order that they were deployed. - 2. Special files listed first (before test pages): "*.md" and `Spec.py`, - 3. The page's corresponding file path under `./tests/`. + 1. Forks are listed in the chronological order that they were + deployed. 2. Special files listed first (before test pages): "*.md" + and `Spec.py`, 3. The page's corresponding file path under + `./tests/`. """ length = len(x.path.parts) if length > 1: - fork = str(x.path.parts[1]).lower() # the fork folder from the relative path - if fork not in fork_order: # unscheduled features added to the end + fork = str(x.path.parts[1]).lower() # the fork folder from the + # relative path + if fork not in fork_order: # unscheduled features added to the + # end return (999, str(x.path)) if length == 1: return (0,) diff --git a/src/pytest_plugins/filler/gen_test_doc/page_props.py b/src/pytest_plugins/filler/gen_test_doc/page_props.py index 2c3194ee8cb..471cd1f2d56 100644 --- a/src/pytest_plugins/filler/gen_test_doc/page_props.py +++ b/src/pytest_plugins/filler/gen_test_doc/page_props.py @@ -1,10 +1,10 @@ """ Classes and helpers used for templates, navigation menus and file output. -The dataclass fields are used to define the page properties fields which -are used in the jinja2 templates when generating site content (located in -docs/templates). The classes also define each page's navigation menu entry -and target output file. +The dataclass fields are used to define the page properties fields which are +used in the jinja2 templates when generating site content (located in +docs/templates). The classes also define each page's navigation menu entry and +target output file. A few helpers are defined with EEST logic in order to sanitize strings from file paths for use in navigation menu. @@ -23,7 +23,8 @@ def apply_name_filters(input_string: str): """ - Apply a list of capitalizations/regexes to names used in titles & nav menus. + Apply a list of capitalizations/regexes to names used in titles & nav + menus. Note: As of 2024-10-08, with 634 doc pages, this function constitutes ~2.0s of the total runtime (~5.5s). This seems to be insignificant with the time @@ -62,7 +63,9 @@ def apply_name_filters(input_string: str): def snake_to_capitalize(string: str) -> str: # noqa: D103 - """Convert valid identifiers to a capitalized string, otherwise leave as-is.""" + """ + Convert valid identifiers to a capitalized string, otherwise leave as-is. + """ if string.isidentifier(): return " ".join(word.capitalize() for word in string.split("_")) return string @@ -74,14 +77,17 @@ def sanitize_string_title(string: str) -> str: def nav_path_to_sanitized_str_tuple(nav_path: Path) -> tuple: - """Convert a nav path to a tuple of sanitized strings for use in mkdocs navigation.""" + """ + Convert a nav path to a tuple of sanitized strings for use in mkdocs + navigation. + """ return tuple(sanitize_string_title(part) for part in nav_path.parts) class FileOpener(Protocol): """ - Protocol to replace `mkdocs_gen_files` so it doesn't have to be imported/installed for - unit tests. + Protocol to replace `mkdocs_gen_files` so it doesn't have to be + imported/installed for unit tests. """ def open(self, path: Path, mode: str) -> ContextManager[IO[Any]]: @@ -94,8 +100,8 @@ class PagePropsBase: """ Common test reference doc page properties and definitions. - The dataclass attributes are made directly available in the jinja2 - found in `docs/templates/*.j2`. + The dataclass attributes are made directly available in the jinja2 found in + `docs/templates/*.j2`. """ title: str @@ -159,7 +165,10 @@ def write_page(self, file_opener: FileOpener, jinja2_env: Environment): @dataclass class TestCase: - """Properties used to define a single test case in test function parameter tables.""" + """ + Properties used to define a single test case in test function parameter + tables. + """ full_id: str abbreviated_id: str @@ -200,10 +209,11 @@ def nav_entry(self, top_level_nav_entry) -> tuple: def write_page(self, file_opener: FileOpener, jinja2_env: Environment): """ - Test functions also get a static HTML page with parametrized test cases. + Test functions also get a static HTML page with parametrized test + cases. - This is intended for easier viewing (without mkdocs styling) of the data-table - that documents the parametrized test cases. + This is intended for easier viewing (without mkdocs styling) of the + data-table that documents the parametrized test cases. """ super().write_page(file_opener, jinja2_env) if not self.cases: @@ -218,7 +228,10 @@ def write_page(self, file_opener: FileOpener, jinja2_env: Environment): @dataclass class TestFunction: - """Properties used to build the test function overview table in test module pages.""" + """ + Properties used to build the test function overview table in test module + pages. + """ name: str test_type: str @@ -228,7 +241,10 @@ class TestFunction: @dataclass class ModulePageProps(PagePropsBase): - """Definitions used for test modules, e.g., `tests/berlin/eip2930_access_list/test_acl.py`.""" + """ + Definitions used for test modules, e.g., + `tests/berlin/eip2930_access_list/test_acl.py`. + """ test_functions: List[TestFunction] = field(default_factory=list) @@ -247,7 +263,10 @@ def target_output_file(self) -> Path: @dataclass class DirectoryPageProps(PagePropsBase): - """Definitions used for parent directories in test paths, e.g., `tests/berlin`.""" + """ + Definitions used for parent directories in test paths, e.g., + `tests/berlin`. + """ @property def template(self) -> str: @@ -262,7 +281,9 @@ def target_output_file(self) -> Path: @dataclass class MarkdownPageProps(PagePropsBase): - """Definitions used to verbatim include markdown files included in test paths.""" + """ + Definitions used to verbatim include markdown files included in test paths. + """ @property def template(self) -> str: diff --git a/src/pytest_plugins/filler/ported_tests.py b/src/pytest_plugins/filler/ported_tests.py index 228647baf5c..3d0207d9951 100644 --- a/src/pytest_plugins/filler/ported_tests.py +++ b/src/pytest_plugins/filler/ported_tests.py @@ -1,34 +1,25 @@ """ A pytest plugin that shows `ported_from` marker information. -This plugin extracts and displays information from @pytest.mark.ported_from markers, -showing either the static filler file paths or associated PR URLs. - -Usage: ------- -# Show static filler file paths -uv run fill --show-ported-from tests/ - -# Show PR URLs instead -uv run fill --show-ported-from=prs tests/ - -The plugin will: -1. Collect all test items with @pytest.mark.ported_from markers -2. Extract either the file paths (first positional argument) or PR URLs (pr keyword argument) -3. Output a deduplicated, sorted list, one per line -4. Skip test execution (collection only) -5. Exclude tests with coverage_missed_reason from output - -Marker Format: --------------- -@pytest.mark.ported_from( - ["path/to/static_filler1.json", "path/to/static_filler2.json"], - pr=[ - "https://github.com/ethereum/execution-spec-tests/pull/1234", - "https://github.com/ethereum/execution-spec-tests/pull/5678", - ], - coverage_missed_reason="Optional reason for accepted coverage miss", -) +This plugin extracts and displays information from @pytest.mark.ported_from +markers, showing either the static filler file paths or associated PR URLs. + +Usage: ------ # Show static filler file paths uv run fill --show-ported-from +tests/ + +# Show PR URLs instead uv run fill --show-ported-from=prs tests/ + +The plugin will: 1. Collect all test items with @pytest.mark.ported_from +markers 2. Extract either the file paths (first positional argument) or PR URLs +(pr keyword argument) 3. Output a deduplicated, sorted list, one per line 4. +Skip test execution (collection only) 5. Exclude tests with +coverage_missed_reason from output + +Marker Format: -------------- @pytest.mark.ported_from( +["path/to/static_filler1.json", "path/to/static_filler2.json"], pr=[ +"https://github.com/ethereum/execution-spec-tests/pull/1234", +"https://github.com/ethereum/execution-spec-tests/pull/5678", ], +coverage_missed_reason="Optional reason for accepted coverage miss", ) """ import re diff --git a/src/pytest_plugins/filler/pre_alloc.py b/src/pytest_plugins/filler/pre_alloc.py index 49a9a4594bc..8330a3f0761 100644 --- a/src/pytest_plugins/filler/pre_alloc.py +++ b/src/pytest_plugins/filler/pre_alloc.py @@ -147,8 +147,9 @@ def deploy_contract( """ Deploy a contract to the allocation. - Warning: `address` parameter is a temporary solution to allow tests to hard-code the - contract address. Do NOT use in new tests as it will be removed in the future! + Warning: `address` parameter is a temporary solution to allow tests to + hard-code the contract address. Do NOT use in new tests as it will be + removed in the future! """ if storage is None: storage = {} @@ -195,10 +196,11 @@ def fund_eoa( nonce: NumberConvertible | None = None, ) -> EOA: """ - Add a previously unused EOA to the pre-alloc with the balance specified by `amount`. + Add a previously unused EOA to the pre-alloc with the balance specified + by `amount`. - If amount is 0, nothing will be added to the pre-alloc but a new and unique EOA will be - returned. + If amount is 0, nothing will be added to the pre-alloc but a new and + unique EOA will be returned. """ eoa = next(self._eoa_iterator) if amount is None: @@ -218,13 +220,14 @@ def fund_eoa( if nonce > 0: eoa.nonce = nonce else: - # Type-4 transaction is sent to the EOA to set the storage, so the nonce must be 1 + # Type-4 transaction is sent to the EOA to set the storage, so + # the nonce must be 1 if not isinstance(delegation, Address) and delegation == "Self": delegation = eoa - # If delegation is None but storage is not, realistically the nonce should be 2 - # because the account must have delegated to set the storage and then again to - # reset the delegation (but can be overridden by the test for a non-realistic - # scenario) + # If delegation is None but storage is not, realistically the + # nonce should be 2 because the account must have delegated to + # set the storage and then again to reset the delegation (but + # can be overridden by the test for a non-realistic scenario) real_nonce = 2 if delegation is None else 1 nonce = Number(real_nonce if nonce is None else nonce) account = Account( @@ -257,20 +260,17 @@ def fund_address(self, address: Address, amount: NumberConvertible): def empty_account(self) -> Address: """ - Add a previously unused account guaranteed to be empty to the pre-alloc. + Add a previously unused account guaranteed to be empty to the + pre-alloc. - This ensures the account has: - - Zero balance - - Zero nonce - - No code - - No storage + This ensures the account has: - Zero balance - Zero nonce - No code - + No storage - This is different from precompiles or system contracts. The function does not - send any transactions, ensuring that the account remains "empty." - - Returns: - Address: The address of the created empty account. + This is different from precompiles or system contracts. The function + does not send any transactions, ensuring that the account remains + "empty." + Returns: Address: The address of the created empty account. """ eoa = next(self._eoa_iterator) @@ -314,8 +314,8 @@ def sha256_from_string(s: str) -> int: if name not in ALL_FIXTURE_FORMAT_NAMES: ALL_FIXTURE_FORMAT_NAMES.append(name) -# Sort by length, from longest to shortest, since some fixture format names contain others -# so we are always sure to catch the longest one first. +# Sort by length, from longest to shortest, since some fixture format names +# contain others so we are always sure to catch the longest one first. ALL_FIXTURE_FORMAT_NAMES.sort(key=len, reverse=True) @@ -324,17 +324,18 @@ def node_id_for_entropy(request: pytest.FixtureRequest, fork: Fork | None) -> st """ Return the node id with the fixture format name and fork name stripped. - Used in cases where we are filling for pre-alloc groups, and we take the name of the - test as source of entropy to get a deterministic address when generating the pre-alloc - grouping. + Used in cases where we are filling for pre-alloc groups, and we take the + name of the test as source of entropy to get a deterministic address when + generating the pre-alloc grouping. - Removing the fixture format and the fork name from the node id before hashing results in the - contracts and senders addresses being the same across fixture types and forks for the same - test. + Removing the fixture format and the fork name from the node id before + hashing results in the contracts and senders addresses being the same + across fixture types and forks for the same test. """ node_id: str = request.node.nodeid if fork is None: - # FIXME: Static tests don't have a fork, so we need to get it from the node. + # FIXME: Static tests don't have a fork, so we need to get it from the + # node. assert hasattr(request.node, "fork") fork = request.node.fork for fixture_format_name in ALL_FIXTURE_FORMAT_NAMES: @@ -358,7 +359,8 @@ def contract_address_iterator( ) -> Iterator[Address]: """Return iterator over contract addresses with dynamic scoping.""" if request.config.getoption( - # TODO: Ideally, we should check the fixture format instead of checking parameters. + # TODO: Ideally, we should check the fixture format instead of checking + # parameters. "generate_pre_alloc_groups", default=False, ) or request.config.getoption("use_pre_alloc_groups", default=False): @@ -383,7 +385,8 @@ def eoa_iterator( ) -> Iterator[EOA]: """Return iterator over EOAs copies with dynamic scoping.""" if request.config.getoption( - # TODO: Ideally, we should check the fixture format instead of checking parameters. + # TODO: Ideally, we should check the fixture format instead of checking + # parameters. "generate_pre_alloc_groups", default=False, ) or request.config.getoption("use_pre_alloc_groups", default=False): diff --git a/src/pytest_plugins/filler/static_filler.py b/src/pytest_plugins/filler/static_filler.py index 4fbe412f096..70feff2023d 100644 --- a/src/pytest_plugins/filler/static_filler.py +++ b/src/pytest_plugins/filler/static_filler.py @@ -1,6 +1,6 @@ """ -Static filler pytest plugin that reads test cases from static files and fills them into test -fixtures. +Static filler pytest plugin that reads test cases from static files and fills +them into test fixtures. """ import inspect @@ -111,7 +111,10 @@ def get_all_combinations_from_parametrize_marks( def pytest_collect_file(file_path: Path, parent) -> pytest.Collector | None: - """Pytest hook that collects test cases from static files and fills them into test fixtures.""" + """ + Pytest hook that collects test cases from static files and fills them into + test fixtures. + """ fill_static_tests_enabled = parent.config.getoption("fill_static_tests_enabled") if not fill_static_tests_enabled: return None @@ -147,8 +150,8 @@ class NoIntResolver(yaml.SafeLoader): class FillerFile(pytest.File): """ - Filler file that reads test cases from static files and fills them into test - fixtures. + Filler file that reads test cases from static files and fills them into + test fixtures. """ def collect(self: "FillerFile") -> Generator["FillerTestItem", None, None]: @@ -241,7 +244,8 @@ def collect(self: "FillerFile") -> Generator["FillerTestItem", None, None]: get_all_combinations_from_parametrize_marks(parametrize_marks) ) for parameter_set in parameter_set_list: - # Copy and extend the params with the parameter set + # Copy and extend the params with the + # parameter set case_marks = ( marks[:] + [ @@ -349,10 +353,10 @@ def yul(fork: Fork, request: pytest.FixtureRequest): """ Fixture that allows contract code to be defined with Yul code. - This fixture defines a class that wraps the ::ethereum_test_tools.Yul - class so that upon instantiation within the test case, it provides the - test case's current fork parameter. The forks is then available for use - in solc's arguments for the Yul code compilation. + This fixture defines a class that wraps the ::ethereum_test_tools.Yul class + so that upon instantiation within the test case, it provides the test + case's current fork parameter. The forks is then available for use in + solc's arguments for the Yul code compilation. Test cases can override the default value by specifying a fixed version with the @pytest.mark.compile_yul_with(FORK) marker. diff --git a/src/pytest_plugins/filler/tests/conftest.py b/src/pytest_plugins/filler/tests/conftest.py index 903d6e8019c..570f9e3d0d2 100644 --- a/src/pytest_plugins/filler/tests/conftest.py +++ b/src/pytest_plugins/filler/tests/conftest.py @@ -9,10 +9,11 @@ @pytest.fixture(autouse=True) def monkeypatch_path_for_entry_points(monkeypatch): """ - Monkeypatch the PATH to add the "bin" directory where entrypoints are installed. + Monkeypatch the PATH to add the "bin" directory where entrypoints are + installed. - This would typically be in the venv in which pytest is running these tests and fill, - which, with uv, is `./.venv/bin`. + This would typically be in the venv in which pytest is running these tests + and fill, which, with uv, is `./.venv/bin`. This is required in order for fill to locate the ethereum-spec-evm-resolver "binary" (entrypoint) when being executed using pytester. diff --git a/src/pytest_plugins/filler/tests/test_benchmarking.py b/src/pytest_plugins/filler/tests/test_benchmarking.py index acceecda6be..fe7fd976c6c 100644 --- a/src/pytest_plugins/filler/tests/test_benchmarking.py +++ b/src/pytest_plugins/filler/tests/test_benchmarking.py @@ -36,14 +36,10 @@ def setup_test_directory_structure( """ Set up the common test directory structure used across multiple tests. - Args: - pytester: The pytest Pytester fixture - test_content: The content to write to the test file - test_filename: The name of the test file to create - - Returns: - The path to the created test module file + Args: pytester: The pytest Pytester fixture test_content: The content to + write to the test file test_filename: The name of the test file to create + Returns: The path to the created test module file """ tests_dir = pytester.mkdir("tests") istanbul_tests_dir = tests_dir / "istanbul" @@ -71,7 +67,10 @@ def test_gas_benchmark_option_added(pytester: pytest.Pytester): def test_benchmarking_mode_configured_with_option(pytester: pytest.Pytester): - """Test that fill_mode is set to BENCHMARKING when --gas-benchmark-values is used.""" + """ + Test that fill_mode is set to BENCHMARKING when --gas-benchmark-values is + used. + """ setup_test_directory_structure(pytester, test_module_dummy, "test_dummy_benchmark.py") # Test with gas benchmark values @@ -96,7 +95,10 @@ def test_benchmarking_mode_configured_with_option(pytester: pytest.Pytester): def test_benchmarking_mode_not_configured_without_option(pytester: pytest.Pytester): - """Test that fill_mode is not set to BENCHMARKING when --gas-benchmark-values is not used.""" + """ + Test that fill_mode is not set to BENCHMARKING when --gas-benchmark-values + is not used. + """ setup_test_directory_structure(pytester, test_module_dummy, "test_dummy_benchmark.py") # Test without gas benchmark values diff --git a/src/pytest_plugins/filler/tests/test_collect_only.py b/src/pytest_plugins/filler/tests/test_collect_only.py index 8fee4e198f0..b9b09974cbc 100644 --- a/src/pytest_plugins/filler/tests/test_collect_only.py +++ b/src/pytest_plugins/filler/tests/test_collect_only.py @@ -51,6 +51,6 @@ def test_collect_only_output(pytester: pytest.Pytester): in line for line in result.outlines ), f"Expected test output: {result.outlines}" - # fill generates 3 test variants: state_test, blockchain_test_from_state_test, - # blockchain_test_engine_from_state_test + # fill generates 3 test variants: state_test, + # blockchain_test_from_state_test, blockchain_test_engine_from_state_test assert any("3 tests collected" in line for line in result.outlines) diff --git a/src/pytest_plugins/filler/tests/test_format_selector.py b/src/pytest_plugins/filler/tests/test_format_selector.py index 16c34c5939b..0346bc1ce5a 100644 --- a/src/pytest_plugins/filler/tests/test_format_selector.py +++ b/src/pytest_plugins/filler/tests/test_format_selector.py @@ -77,11 +77,14 @@ def test_should_generate_single_phase_pre_alloc_format(self): }, ) - # Should not generate because it needs pre-alloc but we're in single phase + # Should not generate because it needs pre-alloc but we're in single + # phase assert not format_selector.should_generate(format_with_pre_alloc) def test_should_generate_phase2_with_pre_alloc_format(self): - """Test phase 2 (after pre-alloc) with format that supports pre-alloc.""" + """ + Test phase 2 (after pre-alloc) with format that supports pre-alloc. + """ phase_manager = PhaseManager( current_phase=FixtureFillingPhase.FILL, previous_phases={FixtureFillingPhase.PRE_ALLOC_GENERATION}, @@ -166,8 +169,12 @@ def test_should_generate_labeled_format(self): assert format_selector.should_generate(labeled_format) def test_comprehensive_scenarios(self): - """Test comprehensive scenarios covering all phase and format combinations.""" - # Test matrix: (current_phase, previous_phases, format_phases, generate_all) -> expected + """ + Test comprehensive scenarios covering all phase and format + combinations. + """ + # Test matrix: (current_phase, previous_phases, format_phases, + # generate_all) -> expected test_cases: List[ # type: ignore[annotation-unchecked] Tuple[ FixtureFillingPhase, Set[FixtureFillingPhase], Set[FixtureFillingPhase], bool, bool diff --git a/src/pytest_plugins/filler/tests/test_generate_all_formats.py b/src/pytest_plugins/filler/tests/test_generate_all_formats.py index 8c39d017084..3f7a3543339 100644 --- a/src/pytest_plugins/filler/tests/test_generate_all_formats.py +++ b/src/pytest_plugins/filler/tests/test_generate_all_formats.py @@ -4,7 +4,10 @@ def test_fixture_output_with_generate_all_formats(): - """Test that FixtureOutput properly handles the should_generate_all_formats parameter.""" + """ + Test that FixtureOutput properly handles the should_generate_all_formats + parameter. + """ # Test with should_generate_all_formats=True fixture_output = FixtureOutput( output_path="/tmp/test", @@ -20,7 +23,10 @@ def test_fixture_output_with_generate_all_formats(): def test_fixture_output_from_config_includes_generate_all_formats(): - """Test that FixtureOutput.from_config includes the should_generate_all_formats option.""" + """ + Test that FixtureOutput.from_config includes the + should_generate_all_formats option. + """ # Mock pytest config object class MockConfig: @@ -43,7 +49,10 @@ def getoption(self, option): def test_tarball_output_auto_enables_generate_all_formats(): - """Test that tarball output (.tar.gz) automatically enables should_generate_all_formats.""" + """ + Test that tarball output (.tar.gz) automatically enables + should_generate_all_formats. + """ # Mock pytest config object with tarball output class MockConfig: @@ -67,7 +76,10 @@ def getoption(self, option): def test_regular_output_does_not_auto_enable_generate_all_formats(): - """Test that regular directory output doesn't auto-enable should_generate_all_formats.""" + """ + Test that regular directory output doesn't auto-enable + should_generate_all_formats. + """ # Mock pytest config object with regular output class MockConfig: @@ -91,7 +103,10 @@ def getoption(self, option): def test_explicit_generate_all_formats_overrides_tarball_auto_enable(): - """Test that explicitly setting should_generate_all_formats=True works with tarball output.""" + """ + Test that explicitly setting should_generate_all_formats=True works with + tarball output. + """ # Mock pytest config object with tarball output and explicit flag class MockConfig: diff --git a/src/pytest_plugins/filler/tests/test_output_directory.py b/src/pytest_plugins/filler/tests/test_output_directory.py index 4eba64d88f2..eca2cb1015e 100644 --- a/src/pytest_plugins/filler/tests/test_output_directory.py +++ b/src/pytest_plugins/filler/tests/test_output_directory.py @@ -21,7 +21,10 @@ def test_function(state_test, pre): @pytest.fixture def minimal_test_path(pytester: pytest.Pytester) -> Path: - """Minimal test file that's written to a file using pytester and ready to fill.""" + """ + Minimal test file that's written to a file using pytester and ready to + fill. + """ tests_dir = pytester.mkdir("tests") test_file = tests_dir / MINIMAL_TEST_FILE_NAME test_file.write_text(MINIMAL_TEST_CONTENTS) @@ -48,7 +51,10 @@ def run_fill( fill_fork_until: str, default_t8n: TransitionTool, ): - """Create a function to run the fill command with various output directory scenarios.""" + """ + Create a function to run the fill command with various output directory + scenarios. + """ def _run_fill( output_dir: Path, @@ -56,7 +62,10 @@ def _run_fill( expect_failure: bool = False, disable_capture_output: bool = False, ) -> pytest.RunResult: - """Run the fill command with the specified output directory and clean flag.""" + """ + Run the fill command with the specified output directory and clean + flag. + """ pytester.copy_example(name="src/cli/pytest_commands/pytest_ini_files/pytest-fill.ini") args = [ "-c", @@ -141,7 +150,9 @@ def test_fill_to_nonempty_directory_with_clean(tmp_path_factory: TempPathFactory def test_fill_to_directory_with_meta_fails(tmp_path_factory: TempPathFactory, run_fill): - """Test filling to a directory with .meta subdirectory fails without --clean.""" + """ + Test filling to a directory with .meta subdirectory fails without --clean. + """ # Create a directory with .meta output_dir = tmp_path_factory.mktemp("directory_with_meta") meta_dir = output_dir / ".meta" @@ -204,7 +215,9 @@ def test_fill_to_tarball_directory(tmp_path_factory: TempPathFactory, run_fill): # New tests for the is_master functionality def test_create_directories_skips_when_not_master(): - """Test that create_directories skips operations when not the master process.""" + """ + Test that create_directories skips operations when not the master process. + """ fixture_output = FixtureOutput( output_path=Path("/fake/path"), clean=True, @@ -227,7 +240,10 @@ def test_create_directories_skips_when_not_master(): def test_create_directories_operates_when_master(): - """Test that create_directories performs operations when is the master process.""" + """ + Test that create_directories performs operations when is the master + process. + """ fixture_output = FixtureOutput( output_path=Path("/fake/path"), clean=True, @@ -264,7 +280,8 @@ def test_create_directories_checks_empty_when_master(): patch.object(Path, "exists", return_value=True), patch.object(Path, "mkdir"), ): - # Call with is_master=True and expect an error about non-empty directory + # Call with is_master=True and expect an error about non-empty + # directory with pytest.raises(ValueError, match="not empty"): fixture_output.create_directories(is_master=True) @@ -274,7 +291,10 @@ def test_create_directories_checks_empty_when_master(): def test_stdout_skips_directory_operations_regardless_of_master(): - """Test that stdout output skips directory operations regardless of is_master value.""" + """ + Test that stdout output skips directory operations regardless of is_master + value. + """ fixture_output = FixtureOutput( output_path=Path("stdout"), clean=True, diff --git a/src/pytest_plugins/filler/tests/test_phase_manager.py b/src/pytest_plugins/filler/tests/test_phase_manager.py index e727b641543..4463788c743 100644 --- a/src/pytest_plugins/filler/tests/test_phase_manager.py +++ b/src/pytest_plugins/filler/tests/test_phase_manager.py @@ -74,7 +74,7 @@ def test_from_config_use_pre_alloc(self): assert not phase_manager.is_single_phase_fill def test_from_config_generate_all_formats(self): - """Test that generate_all_formats triggers PRE_ALLOC_GENERATION phase.""" + """Generate_all_formats should trigger PRE_ALLOC_GENERATION phase.""" config = MockConfig(generate_all_formats=True) phase_manager = PhaseManager.from_config(config) @@ -94,7 +94,7 @@ def test_from_config_generate_all_and_pre_alloc(self): assert phase_manager.is_pre_alloc_generation def test_from_config_use_pre_alloc_with_generate_all(self): - """Test phase 2 with generate_all_formats (passed by CLI to phase 2).""" + """Test phase 2 with generate_all_formats (passed by CLI).""" config = MockConfig(use_pre_alloc_groups=True, generate_all_formats=True) phase_manager = PhaseManager.from_config(config) @@ -104,19 +104,31 @@ def test_from_config_use_pre_alloc_with_generate_all(self): assert phase_manager.is_fill_after_pre_alloc def test_all_flag_combinations(self): - """Test all 8 possible flag combinations to ensure correct phase determination.""" + """ + Test all 8 possible flag combinations to ensure correct phase + determination. + """ test_cases = [ - # (generate_pre_alloc, use_pre_alloc, generate_all) -> (current_phase, has_previous) - (False, False, False, FixtureFillingPhase.FILL, False), # Normal fill + # (generate_pre_alloc, use_pre_alloc, generate_all) -> + # (current_phase, has_previous) + (False, False, False, FixtureFillingPhase.FILL, False), # Normal + # fill # Generate all triggers phase 1 (False, False, True, FixtureFillingPhase.PRE_ALLOC_GENERATION, False), (False, True, False, FixtureFillingPhase.FILL, True), # Phase 2 - (False, True, True, FixtureFillingPhase.FILL, True), # Phase 2 with generate all + (False, True, True, FixtureFillingPhase.FILL, True), # Phase 2 + # with + # generate + # all (True, False, False, FixtureFillingPhase.PRE_ALLOC_GENERATION, False), # Phase 1 # Phase 1 with generate all (True, False, True, FixtureFillingPhase.PRE_ALLOC_GENERATION, False), - (True, True, False, FixtureFillingPhase.FILL, True), # Invalid but use_pre_alloc wins - (True, True, True, FixtureFillingPhase.FILL, True), # Invalid but use_pre_alloc wins + (True, True, False, FixtureFillingPhase.FILL, True), # Invalid but + # use_pre_alloc + # wins + (True, True, True, FixtureFillingPhase.FILL, True), # Invalid but + # use_pre_alloc + # wins ] for gen_pre, use_pre, gen_all, expected_phase, has_previous in test_cases: diff --git a/src/pytest_plugins/filler/tests/test_prealloc_group.py b/src/pytest_plugins/filler/tests/test_prealloc_group.py index 86ccc9c3b61..29e9da7c62b 100644 --- a/src/pytest_plugins/filler/tests/test_prealloc_group.py +++ b/src/pytest_plugins/filler/tests/test_prealloc_group.py @@ -412,7 +412,10 @@ def test_pre_alloc_grouping_by_test_type( test_definitions: List[FormattedTest], expected_different_pre_alloc_groups: int, ): - """Test pre-alloc grouping when filling state tests, and the effect of the `state_test.env`.""" + """ + Test pre-alloc grouping when filling state tests, and the effect of the + `state_test.env`. + """ tests_dir = Path(pytester.mkdir("tests")) for i, test in enumerate(test_definitions): test_module = tests_dir / f"test_{i}.py" diff --git a/src/pytest_plugins/filler/tests/test_prealloc_group_usage_example.py b/src/pytest_plugins/filler/tests/test_prealloc_group_usage_example.py index 508db25a68f..6ffd67994ae 100644 --- a/src/pytest_plugins/filler/tests/test_prealloc_group_usage_example.py +++ b/src/pytest_plugins/filler/tests/test_prealloc_group_usage_example.py @@ -1,8 +1,8 @@ """ Example usage of the pre_alloc_group marker. -This file demonstrates how tests would use the marker in practice. -Note: This is just documentation, not executable tests. +This file demonstrates how tests would use the marker in practice. Note: This +is just documentation, not executable tests. """ import pytest @@ -13,9 +13,12 @@ "separate", reason="Deploys beacon root contract using actual hardcoded deployer address" ) def test_beacon_root_contract_deployment(): - """Test beacon root contract deployment with the official deployer address.""" - # This test uses the actual beacon root deployer address (e.g., 0x4242...4242) - # which could conflict with dynamically allocated addresses in other tests + """ + Test beacon root contract deployment with the official deployer address. + """ + # This test uses the actual beacon root deployer address (e.g., + # 0x4242...4242) which could conflict with dynamically allocated addresses + # in other tests pass @@ -25,8 +28,9 @@ def test_beacon_root_contract_deployment(): ) def test_custom_consolidation_contract(): """Test that deploys a modified consolidation contract.""" - # This test deploys a consolidation contract with custom bytecode that differs - # from the standard implementation, requiring isolation from other consolidation tests + # This test deploys a consolidation contract with custom bytecode that + # differs from the standard implementation, requiring isolation from other + # consolidation tests pass @@ -36,8 +40,9 @@ def test_custom_consolidation_contract(): ) def test_custom_consolidation_edge_cases(): """Test edge cases with the custom consolidation contract.""" - # This test can share the pre-allocation with test_custom_consolidation_contract - # since they both use the same custom contract setup + # This test can share the pre-allocation with + # test_custom_consolidation_contract since they both use the same custom + # contract setup pass diff --git a/src/pytest_plugins/filler/tests/test_slow_marker_pre_alloc.py b/src/pytest_plugins/filler/tests/test_slow_marker_pre_alloc.py index c5f3d012c15..1258211ce98 100644 --- a/src/pytest_plugins/filler/tests/test_slow_marker_pre_alloc.py +++ b/src/pytest_plugins/filler/tests/test_slow_marker_pre_alloc.py @@ -6,7 +6,10 @@ def test_slow_marker_gets_pre_alloc_group(pytester, default_t8n: TransitionTool): - """Test that slow tests without benchmark marker get pre_alloc_group automatically.""" + """ + Test that slow tests without benchmark marker get pre_alloc_group + automatically. + """ test_module = textwrap.dedent( """\ import pytest @@ -49,7 +52,9 @@ def test_slow_without_benchmark(state_test: StateTestFiller, pre: Alloc): def test_slow_with_benchmark_no_pre_alloc(pytester, default_t8n: TransitionTool): - """Test that slow tests WITH benchmark marker do NOT get pre_alloc_group.""" + """ + Test that slow tests WITH benchmark marker do NOT get pre_alloc_group. + """ test_module = textwrap.dedent( """\ import pytest @@ -92,7 +97,9 @@ def test_slow_with_benchmark(state_test: StateTestFiller, pre: Alloc): def test_slow_with_existing_pre_alloc_unchanged(pytester, default_t8n: TransitionTool): - """Test that slow tests with existing pre_alloc_group marker are unchanged.""" + """ + Test that slow tests with existing pre_alloc_group marker are unchanged. + """ test_module = textwrap.dedent( """\ import pytest @@ -176,7 +183,9 @@ def test_normal_speed(state_test: StateTestFiller, pre: Alloc): def test_integration_with_fill(pytester, default_t8n: TransitionTool): - """Integration test using actual fill command to verify marker application.""" + """ + Integration test using actual fill command to verify marker application. + """ test_module = textwrap.dedent( """\ import pytest @@ -221,10 +230,12 @@ def test_slow_for_integration(state_test: StateTestFiller, pre: Alloc): "tests/cancun/slow_test_module/", ] - # The test generates 3 formats (state_test, blockchain_test, blockchain_test_engine) - # But it also runs on multiple forks (Cancun and Prague), so expect more tests - # This is fine - the important thing is that they all pass + # The test generates 3 formats (state_test, blockchain_test, + # blockchain_test_engine) But it also runs on multiple forks (Cancun and + # Prague), so expect more tests This is fine - the important thing is that + # they all pass result = pytester.runpytest(*args) - # Verify that tests passed (don't care about exact count due to fork variations) + # Verify that tests passed (don't care about exact count due to fork + # variations) assert result.ret == 0, "Fill command should succeed" diff --git a/src/pytest_plugins/filler/tests/test_verify_sync_marker.py b/src/pytest_plugins/filler/tests/test_verify_sync_marker.py index 2ecc167d621..381fe0f31b9 100644 --- a/src/pytest_plugins/filler/tests/test_verify_sync_marker.py +++ b/src/pytest_plugins/filler/tests/test_verify_sync_marker.py @@ -71,30 +71,26 @@ def test_verify_sync_marker( """ Test blockchain sync fixture generation with verify_sync marker. - The test module has 3 test functions (4 test cases with parametrization): - - test_verify_sync_default: generates all formats except sync (no verify_sync marker) - - test_verify_sync_with_marker: generates all formats including sync (has verify_sync marker) - - test_verify_sync_with_param_marks: tests parametrized marks with verify_sync (2 cases) - - Each test generates fixture formats: - - BlockchainFixture (always) - - BlockchainEngineFixture (always) - - BlockchainEngineSyncFixture (only when marked with verify_sync marker) - - Expected outcomes: - - 4 test cases total - - Each generates BlockchainFixture (4) and BlockchainEngineFixture (4) = 8 fixtures - - Sync fixtures: - - test_verify_sync_with_marker: 1 sync fixture ✓ - - test_verify_sync_with_param_marks[no_exception]: 1 sync fixture ✓ - - Total sync fixtures: 2 - - Not generated (due to exception_test marker): - - test_verify_sync_with_param_marks[with_exception]: sync fixture not generated - - Final counts: - - Passed: 8 (base fixtures) + 2 (sync fixtures) = 10 passed - - Skipped: 0 skipped - - Failed: 0 failed + The test module has 3 test functions (4 test cases with parametrization): - + test_verify_sync_default: generates all formats except sync (no verify_sync + marker) - test_verify_sync_with_marker: generates all formats including + sync (has verify_sync marker) - test_verify_sync_with_param_marks: tests + parametrized marks with verify_sync (2 cases) + + Each test generates fixture formats: - BlockchainFixture (always) - + BlockchainEngineFixture (always) - BlockchainEngineSyncFixture (only when + marked with verify_sync marker) + + Expected outcomes: - 4 test cases total - Each generates BlockchainFixture + (4) and BlockchainEngineFixture (4) = 8 fixtures - Sync fixtures: - + test_verify_sync_with_marker: 1 sync fixture ✓ - + test_verify_sync_with_param_marks[no_exception]: 1 sync fixture ✓ - Total + sync fixtures: 2 - Not generated (due to exception_test marker): - + test_verify_sync_with_param_marks[with_exception]: sync fixture not + generated + + Final counts: - Passed: 8 (base fixtures) + 2 (sync fixtures) = 10 passed - + Skipped: 0 skipped - Failed: 0 failed """ # Create proper directory structure for tests tests_dir = pytester.mkdir("tests") diff --git a/src/pytest_plugins/filler/witness.py b/src/pytest_plugins/filler/witness.py index fc21e3dceeb..fe88ab282c0 100644 --- a/src/pytest_plugins/filler/witness.py +++ b/src/pytest_plugins/filler/witness.py @@ -1,8 +1,9 @@ """ Pytest plugin for witness functionality. -Provides --witness command-line option that checks for the witness-filler tool in PATH -and generates execution witness data for blockchain test fixtures when enabled. +Provides --witness command-line option that checks for the witness-filler tool +in PATH and generates execution witness data for blockchain test fixtures when +enabled. """ import shutil @@ -17,7 +18,9 @@ class WitnessFillerResult(EthereumTestRootModel[List[WitnessChunk]]): - """Model that defines the expected result from the `witness-filler` command.""" + """ + Model that defines the expected result from the `witness-filler` command. + """ root: List[WitnessChunk] @@ -26,9 +29,9 @@ class Merge(Paris): """ Paris fork that serializes as 'Merge' for witness-filler compatibility. - IMPORTANT: This class MUST be named 'Merge' (not 'MergeForWitness' or similar) - because the class name is used directly in Pydantic serialization, and - witness-filler expects exactly 'Merge' for this fork. + IMPORTANT: This class MUST be named 'Merge' (not 'MergeForWitness' or + similar) because the class name is used directly in Pydantic serialization, + and witness-filler expects exactly 'Merge' for this fork. """ pass @@ -54,7 +57,8 @@ def pytest_configure(config): """ Pytest hook called after command line options have been parsed. - If --witness is enabled, checks that the witness-filler tool is available in PATH. + If --witness is enabled, checks that the witness-filler tool is available + in PATH. """ if config.getoption("witness"): # Check if witness-filler binary is available in PATH @@ -75,20 +79,22 @@ def witness_generator( """ Provide a witness generator function if --witness is enabled. - Returns: - None if witness functionality is disabled. - Callable that generates witness data for a BlockchainFixture if enabled. - + Returns: None if witness functionality is disabled. Callable that generates + witness data for a BlockchainFixture if enabled. """ if not request.config.getoption("witness"): return None def generate_witness(fixture: BlockchainFixture) -> None: - """Generate witness data for a blockchain fixture using the witness-filler tool.""" + """ + Generate witness data for a blockchain fixture using the witness-filler + tool. + """ if not isinstance(fixture, BlockchainFixture): return None - # Hotfix: witness-filler expects "Merge" but execution-spec-tests uses "Paris" + # Hotfix: witness-filler expects "Merge" but execution-spec-tests uses + # "Paris" original_fork = None if fixture.fork is Paris: original_fork = fixture.fork diff --git a/src/pytest_plugins/fix_package_test_path.py b/src/pytest_plugins/fix_package_test_path.py index a8503deeaa1..c54580ee2f2 100644 --- a/src/pytest_plugins/fix_package_test_path.py +++ b/src/pytest_plugins/fix_package_test_path.py @@ -1,6 +1,6 @@ """ -Pytest plugin to fix the test IDs for all pytest command that use a command-logic test -file. +Pytest plugin to fix the test IDs for all pytest command that use a +command-logic test file. """ from typing import List @@ -9,7 +9,10 @@ def pytest_collection_modifyitems(items: List[pytest.Item]): - """Modify collected item names to remove the test runner function from the name.""" + """ + Modify collected item names to remove the test runner function from the + name. + """ for item in items: original_name = item.originalname # type: ignore remove = f"{original_name}[" diff --git a/src/pytest_plugins/forks/forks.py b/src/pytest_plugins/forks/forks.py index 6147b981de3..7121c8dd411 100644 --- a/src/pytest_plugins/forks/forks.py +++ b/src/pytest_plugins/forks/forks.py @@ -86,12 +86,10 @@ def __init__( """ Initialize a new fork parametrizer object for a given fork. - Args: - fork: The fork for which the test cases will be parametrized. - marks: A list of pytest marks to apply to all the test cases parametrized by the fork. - fork_covariant_parameters: A list of fork covariant parameters for the test case, for - unit testing purposes only. - + Args: fork: The fork for which the test cases will be parametrized. + marks: A list of pytest marks to apply to all the test cases + parametrized by the fork. fork_covariant_parameters: A list of fork + covariant parameters for the test case, for unit testing purposes only. """ if marks is None: marks = [] @@ -122,7 +120,8 @@ def argnames(self) -> List[str]: def argvalues(self) -> List[ParameterSet]: """Return the parameter values for the test case.""" parameter_set_combinations = itertools.product( - # Add the values for each parameter, all of them are lists of at least one element. + # Add the values for each parameter, all of them are lists of at + # least one element. *[p.values for p in self.fork_covariant_parameters], ) @@ -148,8 +147,8 @@ def argvalues(self) -> List[ParameterSet]: class CovariantDescriptor: """ - A descriptor for a parameter that is covariant with the fork: - the parametrized values change depending on the fork. + A descriptor for a parameter that is covariant with the fork: the + parametrized values change depending on the fork. """ argnames: List[str] = [] @@ -174,13 +173,11 @@ def __init__( """ Initialize a new covariant descriptor. - Args: - argnames: The names of the parameters that are covariant with the fork. - fn: A function that takes the fork as the single parameter and returns the values for - the parameter for each fork. - selector: A function that filters the values for the parameter. - marks: A list of pytest marks to apply to the test cases parametrized by the parameter. - + Args: argnames: The names of the parameters that are covariant with the + fork. fn: A function that takes the fork as the single parameter and + returns the values for the parameter for each fork. selector: A + function that filters the values for the parameter. marks: A list of + pytest marks to apply to the test cases parametrized by the parameter. """ self.argnames = ( [argname.strip() for argname in argnames.split(",")] @@ -226,8 +223,8 @@ def process_values(self, values: Iterable[Any]) -> List[ParameterSet]: """ Filter the values for the covariant parameter. - I.e. if the marker has an argument, the argument is interpreted as a lambda function - that filters the values. + I.e. if the marker has an argument, the argument is interpreted as a + lambda function that filters the values. """ processed_values: List[ParameterSet] = [] for value in values: @@ -251,19 +248,17 @@ def add_values(self, fork_parametrizer: ForkParametrizer) -> None: class CovariantDecorator(CovariantDescriptor): """ - A marker used to parametrize a function by a covariant parameter with the values - returned by a fork method. - - The decorator must be subclassed with the appropriate class variables before initialization. + A marker used to parametrize a function by a covariant parameter with the + values returned by a fork method. - Attributes: - marker_name: Name of the marker. - description: Description of the marker. - fork_attribute_name: Name of the method to call on the fork to get the values. - marker_parameter_names: Names of the parameters to be parametrized in the test function. - indirect: Whether the parameters should be passed through fixtures (indirect - parametrization). + The decorator must be subclassed with the appropriate class variables + before initialization. + Attributes: marker_name: Name of the marker. description: Description of + the marker. fork_attribute_name: Name of the method to call on the fork to + get the values. marker_parameter_names: Names of the parameters to be + parametrized in the test function. indirect: Whether the parameters should + be passed through fixtures (indirect parametrization). """ marker_name: ClassVar[str] @@ -276,12 +271,11 @@ def __init__(self, metafunc: Metafunc): """ Initialize the covariant decorator. - The decorator must already be subclassed with the appropriate class variables before - initialization. - - Args: - metafunc: The metafunc object that pytest uses when generating tests. + The decorator must already be subclassed with the appropriate class + variables before initialization. + Args: metafunc: The metafunc object that pytest uses when generating + tests. """ self.metafunc = metafunc @@ -408,7 +402,9 @@ def pytest_configure(config: pytest.Config): Register the plugin's custom markers and process command-line options. Custom marker registration: - https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers + https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html# registering- + # custom + -markers """ config.addinivalue_line( "markers", @@ -565,7 +561,10 @@ def fork(request): @pytest.fixture(scope="session") def session_fork(request: pytest.FixtureRequest) -> Fork | None: - """Session-wide fork object used if the plugin is configured in single-fork mode.""" + """ + Session-wide fork object used if the plugin is configured in single-fork + mode. + """ if hasattr(request.config, "single_fork_mode") and request.config.single_fork_mode: return list(request.config.selected_fork_set)[0] # type: ignore raise AssertionError( @@ -584,13 +583,14 @@ class ValidityMarker(ABC): Subclassing this class allows for the creation of new validity markers. - Instantiation must be done per test function, and the `process` method must be called to - process the fork arguments. + Instantiation must be done per test function, and the `process` method must + be called to process the fork arguments. - When subclassing, the following optional parameters can be set: - - marker_name: Name of the marker, if not set, the class name is converted to underscore. - - mutually_exclusive: List of other marker types incompatible with this one. - - flag: Whether the marker is a flag and should always be included. + When subclassing, the following optional parameters can be set: - + marker_name: Name of the marker, if not set, the class name is converted to + underscore. - mutually_exclusive: List of other marker types incompatible + with this one. - flag: Whether the marker is a flag and should always be + included. """ marker_name: ClassVar[str] @@ -609,7 +609,8 @@ def __init_subclass__( """Register the validity marker subclass.""" super().__init_subclass__(**kwargs) if marker_name is None: - # Use the class name converted to underscore: https://stackoverflow.com/a/1176023 + # Use the class name converted to underscore: + # https://stackoverflow.com/a/1176023 marker_name = MARKER_NAME_REGEX.sub("_", cls.__name__).lower() cls.marker_name = marker_name cls.mutually_exclusive = mutually_exclusive if mutually_exclusive else [] @@ -661,14 +662,18 @@ def get_all_validity_markers(markers: Iterator[pytest.Mark]) -> List["ValidityMa @staticmethod def get_test_fork_set(validity_markers: List["ValidityMarker"]) -> Set[Fork]: - """Get the set of forks where a test is valid from the validity markers and filters.""" + """ + Get the set of forks where a test is valid from the validity markers + and filters. + """ if not len( [validity_marker for validity_marker in validity_markers if not validity_marker.flag] ): # Limit to non-transition forks if no validity markers were applied test_fork_set = set(ALL_FORKS) else: - # Start with all forks and transitions if any validity markers were applied + # Start with all forks and transitions if any validity markers were + # applied test_fork_set = set(ALL_FORKS_WITH_TRANSITIONS) for v in validity_markers: @@ -679,14 +684,20 @@ def get_test_fork_set(validity_markers: List["ValidityMarker"]) -> Set[Fork]: @staticmethod def get_test_fork_set_from_markers(markers: Iterator[pytest.Mark]) -> Set[Fork]: - """Get the set of forks where a test is valid using the markers applied to the test.""" + """ + Get the set of forks where a test is valid using the markers applied to + the test. + """ return ValidityMarker.get_test_fork_set(ValidityMarker.get_all_validity_markers(markers)) @staticmethod def get_test_fork_set_from_metafunc( metafunc: Metafunc, ) -> Set[Fork]: - """Get the set of forks where a test is valid using its pytest meta-function.""" + """ + Get the set of forks where a test is valid using its pytest + meta-function. + """ return ValidityMarker.get_test_fork_set_from_markers(metafunc.definition.iter_markers()) @staticmethod @@ -711,32 +722,28 @@ def _process_with_marker_args(self, *args, **kwargs) -> Set[Fork]: Method must be implemented by the subclass. - If the validity marker is of flag type, the returned forks will be subtracted from the - fork set, otherwise the returned forks will be intersected with the current set. + If the validity marker is of flag type, the returned forks will be + subtracted from the fork set, otherwise the returned forks will be + intersected with the current set. """ pass class ValidFrom(ValidityMarker): """ - Marker used to specify the fork from which the test is valid. The test will not be filled for - forks before the specified fork. + Marker used to specify the fork from which the test is valid. The test will + not be filled for forks before the specified fork. - ```python - import pytest + ```python import pytest from ethereum_test_tools import Alloc, StateTestFiller - @pytest.mark.valid_from("London") - def test_something_only_valid_after_london( - state_test: StateTestFiller, - pre: Alloc - ): - pass - ``` + @pytest.mark.valid_from("London") def + test_something_only_valid_after_london( state_test: StateTestFiller, pre: + Alloc ): pass ``` - In this example, the test will only be filled for the London fork and after, e.g. London, - Paris, Shanghai, Cancun, etc. + In this example, the test will only be filled for the London fork and + after, e.g. London, Paris, Shanghai, Cancun, etc. """ def _process_with_marker_args(self, *fork_args) -> Set[Fork]: @@ -750,24 +757,19 @@ def _process_with_marker_args(self, *fork_args) -> Set[Fork]: class ValidUntil(ValidityMarker): """ - Marker to specify the fork until which the test is valid. The test will not be filled for - forks after the specified fork. + Marker to specify the fork until which the test is valid. The test will not + be filled for forks after the specified fork. - ```python - import pytest + ```python import pytest from ethereum_test_tools import Alloc, StateTestFiller - @pytest.mark.valid_until("London") - def test_something_only_valid_until_london( - state_test: StateTestFiller, - pre: Alloc - ): - pass - ``` + @pytest.mark.valid_until("London") def + test_something_only_valid_until_london( state_test: StateTestFiller, pre: + Alloc ): pass ``` - In this example, the test will only be filled for the London fork and before, e.g. London, - Berlin, Istanbul, etc. + In this example, the test will only be filled for the London fork and + before, e.g. London, Berlin, Istanbul, etc. """ def _process_with_marker_args(self, *fork_args) -> Set[Fork]: @@ -783,20 +785,16 @@ class ValidAt(ValidityMarker): """ Marker to specify each fork individually for which the test is valid. - ```python - import pytest + ```python import pytest from ethereum_test_tools import Alloc, StateTestFiller - @pytest.mark.valid_at("London", "Cancun") - def test_something_only_valid_at_london_and_cancun( - state_test: StateTestFiller, - pre: Alloc - ): - pass - ``` + @pytest.mark.valid_at("London", "Cancun") def + test_something_only_valid_at_london_and_cancun( state_test: + StateTestFiller, pre: Alloc ): pass ``` - In this example, the test will only be filled for the London and Cancun forks. + In this example, the test will only be filled for the London and Cancun + forks. """ def _process_with_marker_args(self, *fork_args) -> Set[Fork]: @@ -806,55 +804,49 @@ def _process_with_marker_args(self, *fork_args) -> Set[Fork]: class ValidAtTransitionTo(ValidityMarker, mutually_exclusive=[ValidAt, ValidFrom, ValidUntil]): """ - Marker to specify that a test is only meant to be filled at the transition to the specified - fork. + Marker to specify that a test is only meant to be filled at the transition + to the specified fork. - The test usually starts at the fork prior to the specified fork at genesis and at block 5 (for - pre-merge forks) or at timestamp 15,000 (for post-merge forks) the fork transition occurs. + The test usually starts at the fork prior to the specified fork at genesis + and at block 5 (for pre-merge forks) or at timestamp 15,000 (for post-merge + forks) the fork transition occurs. - ```python - import pytest + ```python import pytest from ethereum_test_tools import Alloc, BlockchainTestFiller - @pytest.mark.valid_at_transition_to("London") - def test_something_that_happens_during_the_fork_transition_to_london( - blockchain_test: BlockchainTestFiller, - pre: Alloc - ): - pass - ``` + @pytest.mark.valid_at_transition_to("London") def + test_something_that_happens_during_the_fork_transition_to_london( + blockchain_test: BlockchainTestFiller, pre: Alloc ): pass ``` - In this example, the test will only be filled for the fork that transitions to London at block - number 5, `BerlinToLondonAt5`, and no other forks. + In this example, the test will only be filled for the fork that transitions + to London at block number 5, `BerlinToLondonAt5`, and no other forks. - To see or add a new transition fork, see the `ethereum_test_forks.forks.transition` module. + To see or add a new transition fork, see the + `ethereum_test_forks.forks.transition` module. - Note that the test uses a `BlockchainTestFiller` fixture instead of a `StateTestFiller`, - as the transition forks are used to test changes throughout the blockchain progression, and - not just the state change of a single transaction. + Note that the test uses a `BlockchainTestFiller` fixture instead of a + `StateTestFiller`, as the transition forks are used to test changes + throughout the blockchain progression, and not just the state change of a + single transaction. This marker also accepts the following keyword arguments: - - `subsequent_transitions`: Force the test to also fill for subsequent fork transitions. - - `until`: Implies `subsequent_transitions` and puts a limit on which transition fork will the - test filling will be limited to. + - `subsequent_transitions`: Force the test to also fill for subsequent fork + transitions. - `until`: Implies `subsequent_transitions` and puts a limit + on which transition fork will the test filling will be limited to. - For example: - ```python - @pytest.mark.valid_at_transition_to("Cancun", subsequent_transitions=True) - ``` + For example: ```python @pytest.mark.valid_at_transition_to("Cancun", + subsequent_transitions=True) ``` - produces tests on `ShanghaiToCancunAtTime15k` and `CancunToPragueAtTime15k`, and any transition - fork after that. + produces tests on `ShanghaiToCancunAtTime15k` and + `CancunToPragueAtTime15k`, and any transition fork after that. - And: - ```python - @pytest.mark.valid_at_transition_to("Cancun", subsequent_transitions=True, until="Prague") - ``` + And: ```python @pytest.mark.valid_at_transition_to("Cancun", + subsequent_transitions=True, until="Prague") ``` - produces tests on `ShanghaiToCancunAtTime15k` and `CancunToPragueAtTime15k`, but no forks after - Prague. + produces tests on `ShanghaiToCancunAtTime15k` and + `CancunToPragueAtTime15k`, but no forks after Prague. """ def _process_with_marker_args( @@ -889,18 +881,12 @@ class ValidForBPOForks(ValidityMarker, marker_name="valid_for_bpo_forks", flag=T """ Marker to specify that a test is valid for BPO forks. - ```python - import pytest + ```python import pytest from ethereum_test_tools import Alloc, BlockchainTestFiller - @pytest.mark.valid_for_bpo_forks() - def test_something_in_a_bpo_fork( - blockchain_test: BlockchainTestFiller, - pre: Alloc - ): - pass - ``` + @pytest.mark.valid_for_bpo_forks() def test_something_in_a_bpo_fork( + blockchain_test: BlockchainTestFiller, pre: Alloc ): pass ``` """ def _process_with_marker_args(self) -> Set[Fork]: @@ -984,7 +970,10 @@ def pytest_generate_tests(metafunc: pytest.Metafunc): def add_fork_covariant_parameters( metafunc: Metafunc, fork_parametrizers: List[ForkParametrizer] ) -> None: - """Iterate over the fork covariant descriptors and add their values to the test function.""" + """ + Iterate over the fork covariant descriptors and add their values to the + test function. + """ # Process all covariant decorators uniformly for covariant_descriptor in fork_covariant_decorators: if list(metafunc.definition.iter_markers(covariant_descriptor.marker_name)): diff --git a/src/pytest_plugins/forks/tests/test_bad_command_line_options.py b/src/pytest_plugins/forks/tests/test_bad_command_line_options.py index 3799dbb570a..448e7432164 100644 --- a/src/pytest_plugins/forks/tests/test_bad_command_line_options.py +++ b/src/pytest_plugins/forks/tests/test_bad_command_line_options.py @@ -1,6 +1,6 @@ """ -Test that the correct error is produced if bad/invalid command-line -arguments are used. +Test that the correct error is produced if bad/invalid command-line arguments +are used. """ import pytest @@ -58,12 +58,12 @@ ) def test_bad_options(pytester, options, error_string): """ - Test that a test with an invalid command-line options: - - Creates an outcome with exactly one error. - - Triggers the expected error string in pytest's console output. + Test that a test with an invalid command-line options: - Creates an outcome + with exactly one error. - Triggers the expected error string in pytest's + console output. - Each invalid marker/marker combination is tested with one test in its own test - session. + Each invalid marker/marker combination is tested with one test in its own + test session. """ pytester.makepyfile( """ diff --git a/src/pytest_plugins/forks/tests/test_bad_validity_markers.py b/src/pytest_plugins/forks/tests/test_bad_validity_markers.py index 7aea95220c2..ea8156408c2 100644 --- a/src/pytest_plugins/forks/tests/test_bad_validity_markers.py +++ b/src/pytest_plugins/forks/tests/test_bad_validity_markers.py @@ -1,4 +1,7 @@ -"""Test that the correct error is produced if bad/invalid validity markers are specified.""" +""" +Test that the correct error is produced if bad/invalid validity markers are +specified. +""" import pytest @@ -213,12 +216,12 @@ def test_case(state_test): ) def test_invalid_validity_markers(pytester, error_string, test_function): """ - Test that a test with an invalid marker cases: - - Creates an outcome with exactly one error. - - Triggers the expected error string in pytest's console output. + Test that a test with an invalid marker cases: - Creates an outcome with + exactly one error. - Triggers the expected error string in pytest's console + output. - Each invalid marker/marker combination is tested with one test in its own test - session. + Each invalid marker/marker combination is tested with one test in its own + test session. """ pytester.makepyfile(test_function) pytester.copy_example(name="src/cli/pytest_commands/pytest_ini_files/pytest-fill.ini") diff --git a/src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py b/src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py index e655b46605a..49adf3eda51 100644 --- a/src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py +++ b/src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py @@ -188,7 +188,10 @@ def test_fork_parametrizer( expected_names: List[str], expected_parameter_sets: List[ParameterSet], ): - """Test that the fork parametrizer correctly parametrizes tests based on the fork name.""" + """ + Test that the fork parametrizer correctly parametrizes tests based on the + fork name. + """ argnames, values = parameters_from_fork_parametrizer_list(fork_parametrizers) assert argnames == expected_names assert len(values) == len(expected_parameter_sets) diff --git a/src/pytest_plugins/help/__init__.py b/src/pytest_plugins/help/__init__.py index c1a6507e991..2e861b4d85e 100644 --- a/src/pytest_plugins/help/__init__.py +++ b/src/pytest_plugins/help/__init__.py @@ -1 +1,3 @@ -"""Pytest plugin that prints help defined in other execution-spec-tests plugins.""" +""" +Pytest plugin that prints help defined in other execution-spec-tests plugins. +""" diff --git a/src/pytest_plugins/help/help.py b/src/pytest_plugins/help/help.py index b70c0357a55..808584e3149 100644 --- a/src/pytest_plugins/help/help.py +++ b/src/pytest_plugins/help/help.py @@ -65,7 +65,9 @@ def pytest_addoption(parser): @pytest.hookimpl(tryfirst=True) def pytest_configure(config): - """Handle specific help flags by displaying the corresponding help message.""" + """ + Handle specific help flags by displaying the corresponding help message. + """ if config.getoption("show_check_eip_versions_help"): show_specific_help( config, @@ -143,7 +145,10 @@ def pytest_configure(config): def show_specific_help(config, expected_ini, substrings): - """Print help options filtered by specific substrings from the given configuration.""" + """ + Print help options filtered by specific substrings from the given + configuration. + """ pytest_ini = Path(config.inifile) if pytest_ini.name != expected_ini: raise ValueError( diff --git a/src/pytest_plugins/help/tests/test_help.py b/src/pytest_plugins/help/tests/test_help.py index 9b7b45ae6c8..3ed648720b2 100644 --- a/src/pytest_plugins/help/tests/test_help.py +++ b/src/pytest_plugins/help/tests/test_help.py @@ -18,8 +18,8 @@ @pytest.mark.parametrize("help_flag", ["--fill-help"]) def test_local_arguments_present_in_fill_help(pytester, help_flag): """ - Test that locally defined command-line flags appear in the help if - our custom help flag is used. + Test that locally defined command-line flags appear in the help if our + custom help flag is used. """ pytester.copy_example(name="src/cli/pytest_commands/pytest_ini_files/pytest-fill.ini") result = pytester.runpytest("-c", "pytest-fill.ini", help_flag) @@ -43,7 +43,10 @@ def test_local_arguments_present_in_fill_help(pytester, help_flag): ], ) def test_local_arguments_present_in_base_consume_help(pytester, help_flag, command): - """Test that locally defined command-line flags appear in the help for consume subcommands.""" + """ + Test that locally defined command-line flags appear in the help for consume + subcommands. + """ pytester.copy_example(name="src/cli/pytest_commands/pytest_ini_files/pytest-consume.ini") result = pytester.runpytest("-c", "pytest-consume.ini", command, help_flag) for test_arg in CONSUME_TEST_ARGS: diff --git a/src/pytest_plugins/pytest_hive/pytest_hive.py b/src/pytest_plugins/pytest_hive/pytest_hive.py index 34dfd788095..aff20fbc8e5 100644 --- a/src/pytest_plugins/pytest_hive/pytest_hive.py +++ b/src/pytest_plugins/pytest_hive/pytest_hive.py @@ -3,30 +3,30 @@ Simulators using this plugin must define two pytest fixtures: -1. `test_suite_name`: The name of the test suite. -2. `test_suite_description`: The description of the test suite. +1. `test_suite_name`: The name of the test suite. 2. `test_suite_description`: +The description of the test suite. These fixtures are used when creating the hive test suite. -Log Capture Architecture: -------------------------- -This module implements a log capture approach that ensures all logs, including those -generated during fixture teardown, are properly captured and included in the test results. - -The key insight is that we need to ensure that test finalization happens *before* the -test suite is finalized, but *after* all fixtures have been torn down so we can capture -their logs. This is accomplished through the fixture teardown mechanism in pytest: - -1. Since the `hive_test` fixture depends on the `test_suite` fixture, pytest guarantees - that the teardown of `hive_test` runs before the teardown of `test_suite` -2. All logs are processed and the test is finalized in the teardown phase of the - `hive_test` fixture using the pytest test report data -3. This sequencing ensures that all logs are captured and the test is properly finalized - before its parent test suite is finalized - -This approach relies on the pytest fixture dependency graph and teardown ordering to -ensure proper sequencing, which is more reliable than using hooks which might run in -an unpredictable order relative to fixture teardown. +Log Capture Architecture: ------------------------- This module implements a +log capture approach that ensures all logs, including those generated during +fixture teardown, are properly captured and included in the test results. + +The key insight is that we need to ensure that test finalization happens +*before* the test suite is finalized, but *after* all fixtures have been torn +down so we can capture their logs. This is accomplished through the fixture +teardown mechanism in pytest: + +1. Since the `hive_test` fixture depends on the `test_suite` fixture, pytest +guarantees that the teardown of `hive_test` runs before the teardown of +`test_suite` 2. All logs are processed and the test is finalized in the +teardown phase of the `hive_test` fixture using the pytest test report data 3. +This sequencing ensures that all logs are captured and the test is properly +finalized before its parent test suite is finalized + +This approach relies on the pytest fixture dependency graph and teardown +ordering to ensure proper sequencing, which is more reliable than using hooks +which might run in an unpredictable order relative to fixture teardown. """ import json @@ -59,8 +59,8 @@ def pytest_configure(config): # noqa: D103 "or in fish:\n" "set -x HIVE_SIMULATOR http://127.0.0.1:3000" ) - # TODO: Try and get these into fixtures; this is only here due to the "dynamic" parametrization - # of client_type with hive_execution_clients. + # TODO: Try and get these into fixtures; this is only here due to the + # "dynamic" parametrization of client_type with hive_execution_clients. config.hive_simulator_url = hive_simulator_url config.hive_simulator = Simulation(url=hive_simulator_url) try: @@ -133,15 +133,13 @@ def pytest_report_header(config, start_path): @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): """ - Make the setup, call, and teardown results available in the teardown phase of - a test fixture (i.e., after yield has been called). + Make the setup, call, and teardown results available in the teardown phase + of a test fixture (i.e., after yield has been called). This is used to get the test result and pass it to the hive test suite. - Available as: - - result_setup - setup result - - result_call - test result - - result_teardown - teardown result + Available as: - result_setup - setup result - result_call - test result - + result_teardown - teardown result """ del call @@ -238,10 +236,11 @@ def hive_test(request, test_suite: HiveTestSuite): """ Propagate the pytest test case and its result to the hive server. - This fixture handles both starting the test and ending it with all logs, including - those generated during teardown of other fixtures. The approach of processing teardown - logs directly in the teardown phase of this fixture ensures that the test gets properly - finalized before the test suite is torn down. + This fixture handles both starting the test and ending it with all logs, + including those generated during teardown of other fixtures. The approach + of processing teardown logs directly in the teardown phase of this fixture + ensures that the test gets properly finalized before the test suite is torn + down. """ try: test_case_description = request.getfixturevalue("test_case_description") diff --git a/src/pytest_plugins/shared/benchmarking.py b/src/pytest_plugins/shared/benchmarking.py index 6f198776655..c5688476b39 100644 --- a/src/pytest_plugins/shared/benchmarking.py +++ b/src/pytest_plugins/shared/benchmarking.py @@ -55,7 +55,10 @@ def gas_benchmark_value(request: pytest.FixtureRequest) -> int: @pytest.fixture def genesis_environment(request: pytest.FixtureRequest) -> Environment: # noqa: D103 - """Return an Environment instance with appropriate gas limit based on test type.""" + """ + Return an Environment instance with appropriate gas limit based on test + type. + """ if request.node.get_closest_marker("benchmark") is not None: return Environment(gas_limit=BENCHMARKING_MAX_GAS) return Environment() @@ -63,7 +66,10 @@ def genesis_environment(request: pytest.FixtureRequest) -> Environment: # noqa: @pytest.fixture def env(request: pytest.FixtureRequest) -> Environment: # noqa: D103 - """Return an Environment instance with appropriate gas limit based on test type.""" + """ + Return an Environment instance with appropriate gas limit based on test + type. + """ if request.node.get_closest_marker("benchmark") is not None: return Environment(gas_limit=BENCHMARKING_MAX_GAS) return Environment() diff --git a/src/pytest_plugins/shared/execute_fill.py b/src/pytest_plugins/shared/execute_fill.py index 21b9b7ea5ba..3708956dd0a 100644 --- a/src/pytest_plugins/shared/execute_fill.py +++ b/src/pytest_plugins/shared/execute_fill.py @@ -1,4 +1,6 @@ -"""Shared pytest fixtures and hooks for EEST generation modes (fill and execute).""" +""" +Shared pytest fixtures and hooks for EEST generation modes (fill and execute). +""" from typing import List @@ -18,11 +20,18 @@ "env", } """ -List of test parameters that have a default fixture value which can be retrieved and used -for the test instance if it was not explicitly specified when calling from the test -function. -All parameter names included in this list must define a fixture in one of the plugins. + + + + + +List of test parameters that have a default fixture value which can be +retrieved and used for the test instance if it was not explicitly specified +when calling from the test function. + +All parameter names included in this list must define a fixture in one of the +plugins. """ @@ -32,15 +41,16 @@ def pytest_configure(config: pytest.Config): Pytest hook called after command line options have been parsed and before test collection begins. - Couple of notes: - 1. Register the plugin's custom markers and process command-line options. + Couple of notes: 1. Register the plugin's custom markers and process + command-line options. - Custom marker registration: - https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers + Custom marker registration: + https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html# registering- + # custom -markers 2. `@pytest.hookimpl(tryfirst=True)` is applied to ensure that this hook is - called before the pytest-html plugin's pytest_configure to ensure that - it uses the modified `htmlpath` option. + called before the pytest-html plugin's pytest_configure to ensure that it + uses the modified `htmlpath` option. """ if config.pluginmanager.has_plugin("pytest_plugins.filler.filler"): for fixture_format in BaseFixture.formats.values(): @@ -154,7 +164,10 @@ def pytest_configure(config: pytest.Config): @pytest.fixture(scope="function") def test_case_description(request: pytest.FixtureRequest) -> str: - """Fixture to extract and combine docstrings from the test class and the test function.""" + """ + Fixture to extract and combine docstrings from the test class and the test + function. + """ description_unavailable = ( "No description available - add a docstring to the python test class or function." ) @@ -172,8 +185,8 @@ def test_case_description(request: pytest.FixtureRequest) -> str: def pytest_make_parametrize_id(config: pytest.Config, val: str, argname: str): """ - Pytest hook called when generating test ids. We use this to generate - more readable test ids for the generated tests. + Pytest hook called when generating test ids. We use this to generate more + readable test ids for the generated tests. """ del config return f"{argname}_{val}" diff --git a/src/pytest_plugins/shared/helpers.py b/src/pytest_plugins/shared/helpers.py index bbe720b652f..3c55d59376f 100644 --- a/src/pytest_plugins/shared/helpers.py +++ b/src/pytest_plugins/shared/helpers.py @@ -30,11 +30,11 @@ def labeled_format_parameter_set( | FixtureFormat, ) -> ParameterSet: """ - Return a parameter set from a fixture/execute format and parses a label if there's - any. + Return a parameter set from a fixture/execute format and parses a label if + there's any. - The label will be used in the test id and also will be added as a marker to the - generated test case when filling/executing the test. + The label will be used in the test id and also will be added as a marker to + the generated test case when filling/executing the test. """ if isinstance(format_with_or_without_label, LabeledExecuteFormat) or isinstance( format_with_or_without_label, LabeledFixtureFormat diff --git a/src/pytest_plugins/shared/transaction_fixtures.py b/src/pytest_plugins/shared/transaction_fixtures.py index be3b16a6d6d..cfe0cd6ef52 100644 --- a/src/pytest_plugins/shared/transaction_fixtures.py +++ b/src/pytest_plugins/shared/transaction_fixtures.py @@ -125,10 +125,12 @@ def type_4_default_transaction(sender, pre): @pytest.fixture def typed_transaction(request, fork): """ - Fixture that provides a Transaction object based on the parametrized tx type. + Fixture that provides a Transaction object based on the parametrized tx + type. - This fixture works with the @pytest.mark.with_all_typed_transactions marker, - which parametrizes the test with all transaction types supported by the fork. + This fixture works with the @pytest.mark.with_all_typed_transactions + marker, which parametrizes the test with all transaction types supported by + the fork. The actual transaction type value comes from the marker's parametrization. """ diff --git a/src/pytest_plugins/solc/solc.py b/src/pytest_plugins/solc/solc.py index e46d195478f..692c5237c9a 100644 --- a/src/pytest_plugins/solc/solc.py +++ b/src/pytest_plugins/solc/solc.py @@ -85,7 +85,8 @@ def pytest_configure(config: pytest.Config): # Extract version number try: - # --version format is typically something like "0.8.24+commit.e11b9ed9.Linux.g++" + # --version format is typically something like + # "0.8.24+commit.e11b9ed9.Linux.g++" version_str = version_line.split()[1].split("+")[0] solc_version_semver = Version.parse(version_str) except (IndexError, ValueError) as e: diff --git a/src/pytest_plugins/spec_version_checker/spec_version_checker.py b/src/pytest_plugins/spec_version_checker/spec_version_checker.py index 4091e88229e..5fd965139ae 100644 --- a/src/pytest_plugins/spec_version_checker/spec_version_checker.py +++ b/src/pytest_plugins/spec_version_checker/spec_version_checker.py @@ -45,7 +45,8 @@ def pytest_configure(config): Register the plugin's custom markers and process command-line options. Custom marker registration: - https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers + https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom + -markers """ config.addinivalue_line( "markers", @@ -69,20 +70,15 @@ def get_ref_spec_from_module( """ Return the reference spec object defined in a module. - Args: - module: The module to extract reference spec from - github_token: Optional GitHub token for API authentication + Args: module: The module to extract reference spec from github_token: + Optional GitHub token for API authentication - Raises: - Exception: If the module path contains "eip" and the module - does not define a reference spec. - - Returns: - spec_obj: Return None if the module path does not contain "eip", - i.e., the module is not required to define a reference spec, - otherwise, return the ReferenceSpec object as defined by the - module. + Raises: Exception: If the module path contains "eip" and the module does + not define a reference spec. + Returns: spec_obj: Return None if the module path does not contain "eip", + i.e., the module is not required to define a reference spec, otherwise, + return the ReferenceSpec object as defined by the module. """ if not is_test_for_an_eip(str(module.__file__)): return None @@ -115,14 +111,11 @@ def is_test_for_an_eip(input_string: str) -> bool: def test_eip_spec_version(module: ModuleType, github_token: Optional[str] = None): """ - Test that the ReferenceSpec object as defined in the test module - is not outdated when compared to the remote hash from - ethereum/EIPs. - - Args: - module: Module to test - github_token: Optional GitHub token for API authentication + Test that the ReferenceSpec object as defined in the test module is not + outdated when compared to the remote hash from ethereum/EIPs. + Args: module: Module to test github_token: Optional GitHub token for API + authentication """ ref_spec = get_ref_spec_from_module(module, github_token=github_token) assert ref_spec, "No reference spec object defined" @@ -156,11 +149,8 @@ def __init__(self, name: str, parent: Node, **kwargs: Any): """ Initialize the test item. - Args: - name: Name of the test - parent: Parent node - **kwargs: Additional keyword arguments - + Args: name: Name of the test parent: Parent node **kwargs: Additional + keyword arguments """ super().__init__(name, parent) self.module = None # type: ignore @@ -170,12 +160,11 @@ def __init__(self, name: str, parent: Node, **kwargs: Any): def from_parent(cls, parent: Node, **kw: Any) -> "EIPSpecTestItem": """ Public constructor to define new tests. - https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent. - - Args: - parent: The parent Node - kw: Additional keyword arguments (module, github_token) + https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.fr + om_parent. + Args: parent: The parent Node kw: Additional keyword arguments (module, + github_token) """ module = kw.pop("module", None) github_token = kw.pop("github_token", None) @@ -195,9 +184,7 @@ def reportinfo(self) -> tuple[str, int, str]: """ Get location information for this test item to use test reports. - Returns: - A tuple of (path, line_number, description) - + Returns: A tuple of (path, line_number, description) """ return "spec_version_checker", 0, f"{self.name}" @@ -205,9 +192,10 @@ def reportinfo(self) -> tuple[str, int, str]: def pytest_collection_modifyitems( session: pytest.Session, config: pytest.Config, items: List[Item] ): - """Insert a new test EIPSpecTestItem for every test module with 'eip' in its path.""" - del session - + """ + Insert a new test EIPSpecTestItem for every test module with 'eip' in its + path. + """ github_token = config.github_token if hasattr(config, "github_token") else None modules: Set[Module] = {item.parent for item in items if isinstance(item.parent, Module)} diff --git a/tests/amsterdam/__init__.py b/tests/amsterdam/__init__.py index b4d638e152d..89848292b52 100644 --- a/tests/amsterdam/__init__.py +++ b/tests/amsterdam/__init__.py @@ -1 +1,4 @@ -"""Test cases for EVM functionality introduced in Amsterdam, [EIP-7773: Hardfork Meta - Glamsterdam](https://eip.directory/eips/eip-7773).""" # noqa: E501 +""" +Test cases for EVM functionality introduced in Amsterdam, [EIP-7773: Hardfork +Meta - Glamsterdam](https://eip.directory/eips/eip-7773). +""" diff --git a/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py b/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py index 7041a3bbcfc..a08e0a3f35d 100644 --- a/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py +++ b/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py @@ -52,7 +52,10 @@ def test_bal_invalid_missing_nonce( blockchain_test: BlockchainTestFiller, pre: Alloc, ): - """Test that clients reject blocks where BAL is missing required nonce changes.""" + """ + Test that clients reject blocks where BAL is missing required nonce + changes. + """ sender = pre.fund_eoa(amount=10**18) receiver = pre.fund_eoa(amount=0) @@ -91,7 +94,9 @@ def test_bal_invalid_nonce_value( blockchain_test: BlockchainTestFiller, pre: Alloc, ): - """Test that clients reject blocks where BAL contains incorrect nonce value.""" + """ + Test that clients reject blocks where BAL contains incorrect nonce value. + """ sender = pre.fund_eoa(amount=10**18) receiver = pre.fund_eoa(amount=0) @@ -130,7 +135,10 @@ def test_bal_invalid_storage_value( blockchain_test: BlockchainTestFiller, pre: Alloc, ): - """Test that clients reject blocks where BAL contains incorrect storage values.""" + """ + Test that clients reject blocks where BAL contains incorrect storage + values. + """ sender = pre.fund_eoa(amount=10**18) # Simple storage contract with canary values @@ -190,7 +198,10 @@ def test_bal_invalid_tx_order( blockchain_test: BlockchainTestFiller, pre: Alloc, ): - """Test that clients reject blocks where BAL has incorrect transaction ordering.""" + """ + Test that clients reject blocks where BAL has incorrect transaction + ordering. + """ sender1 = pre.fund_eoa(amount=10**18) sender2 = pre.fund_eoa(amount=10**18) receiver = pre.fund_eoa(amount=0) @@ -247,7 +258,10 @@ def test_bal_invalid_account( blockchain_test: BlockchainTestFiller, pre: Alloc, ): - """Test that clients reject blocks where BAL contains accounts that don't exist.""" + """ + Test that clients reject blocks where BAL contains accounts that don't + exist. + """ sender = pre.fund_eoa(amount=10**18) receiver = pre.fund_eoa(amount=0) phantom = pre.fund_eoa(amount=0) @@ -295,7 +309,10 @@ def test_bal_invalid_duplicate_account( blockchain_test: BlockchainTestFiller, pre: Alloc, ): - """Test that clients reject blocks where BAL contains duplicate account entries.""" + """ + Test that clients reject blocks where BAL contains duplicate account + entries. + """ sender = pre.fund_eoa(amount=10**18) receiver = pre.fund_eoa(amount=0) @@ -337,7 +354,9 @@ def test_bal_invalid_account_order( blockchain_test: BlockchainTestFiller, pre: Alloc, ): - """Test that clients reject blocks where BAL has incorrect account ordering.""" + """ + Test that clients reject blocks where BAL has incorrect account ordering. + """ sender = pre.fund_eoa(amount=10**18) receiver = pre.fund_eoa(amount=0) @@ -454,7 +473,9 @@ def test_bal_invalid_missing_account( blockchain_test: BlockchainTestFiller, pre: Alloc, ): - """Test that clients reject blocks where BAL is missing an entire account.""" + """ + Test that clients reject blocks where BAL is missing an entire account. + """ sender = pre.fund_eoa(amount=10**18) receiver = pre.fund_eoa(amount=0) @@ -496,7 +517,9 @@ def test_bal_invalid_balance_value( blockchain_test: BlockchainTestFiller, pre: Alloc, ): - """Test that clients reject blocks where BAL contains incorrect balance value.""" + """ + Test that clients reject blocks where BAL contains incorrect balance value. + """ sender = pre.fund_eoa(amount=10**18) receiver = pre.fund_eoa(amount=0) diff --git a/tests/benchmark/conftest.py b/tests/benchmark/conftest.py index 1e2e7813817..d51b47dda83 100644 --- a/tests/benchmark/conftest.py +++ b/tests/benchmark/conftest.py @@ -10,7 +10,10 @@ def pytest_generate_tests(metafunc): - """Modify test generation to enforce default benchmark fork for benchmark tests.""" + """ + Modify test generation to enforce default benchmark fork for benchmark + tests. + """ benchmark_dir = Path(__file__).parent test_file_path = Path(metafunc.definition.fspath) diff --git a/tests/benchmark/helpers.py b/tests/benchmark/helpers.py index ca3e0705727..c0e7f80ac63 100644 --- a/tests/benchmark/helpers.py +++ b/tests/benchmark/helpers.py @@ -9,7 +9,8 @@ def code_loop_precompile_call(calldata: Bytecode, attack_block: Bytecode, fork: """Create a code loop that calls a precompile with the given calldata.""" max_code_size = fork.max_code_size() - # The attack contract is: CALLDATA_PREP + #JUMPDEST + [attack_block]* + JUMP(#) + # The attack contract is: CALLDATA_PREP + #JUMPDEST + [attack_block]* + + # JUMP(#) jumpdest = Op.JUMPDEST jump_back = Op.JUMP(len(calldata)) max_iters_loop = (max_code_size - len(calldata) - len(jumpdest) - len(jump_back)) // len( diff --git a/tests/benchmark/test_worst_blocks.py b/tests/benchmark/test_worst_blocks.py index b71f3035067..6d53ba43b5d 100644 --- a/tests/benchmark/test_worst_blocks.py +++ b/tests/benchmark/test_worst_blocks.py @@ -1,6 +1,6 @@ """ -abstract: Tests that benchmark EVMs in worst-case block scenarios. - Tests that benchmark EVMs in worst-case block scenarios. +abstract: Tests that benchmark EVMs in worst-case block scenarios. Tests that +benchmark EVMs in worst-case block scenarios. Tests running worst-case block scenarios for EVMs. """ @@ -26,7 +26,10 @@ @pytest.fixture def iteration_count(intrinsic_cost: int, gas_benchmark_value: int): - """Calculate the number of iterations based on the gas limit and intrinsic cost.""" + """ + Calculate the number of iterations based on the gas limit and intrinsic + cost. + """ return gas_benchmark_value // intrinsic_cost @@ -124,12 +127,10 @@ def test_block_full_of_ether_transfers( """ Single test for ether transfer scenarios. - Scenarios: - - a_to_a: one sender → one sender - - a_to_b: one sender → one receiver - - diff_acc_to_b: multiple senders → one receiver - - a_to_diff_acc: one sender → multiple receivers - - diff_acc_to_diff_acc: multiple senders → multiple receivers + Scenarios: - a_to_a: one sender → one sender - a_to_b: one sender → one + receiver - diff_acc_to_b: multiple senders → one receiver - a_to_diff_acc: + one sender → multiple receivers - diff_acc_to_diff_acc: multiple senders → + multiple receivers """ senders, receivers = ether_transfer_case @@ -186,29 +187,21 @@ def test_block_full_data( gas_benchmark_value: int, ): """Test a block with empty payload.""" - # Gas cost calculation based on EIP-7683: (https://eips.ethereum.org/EIPS/eip-7683) - # - # tx.gasUsed = 21000 + max( - # STANDARD_TOKEN_COST * tokens_in_calldata - # + execution_gas_used - # + isContractCreation * (32000 + INITCODE_WORD_COST * words(calldata)), - # TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata) - # - # Simplified in this test case: - # - No execution gas used (no opcodes are executed) - # - Not a contract creation (no initcode) - # - # Therefore: - # max_token_cost = max(STANDARD_TOKEN_COST, TOTAL_COST_FLOOR_PER_TOKEN) - # tx.gasUsed = 21000 + tokens_in_calldata * max_token_cost - # + # Gas cost calculation based on EIP-7683: + # (https://eips.ethereum.org/EIPS/eip-7683) + # tx.gasUsed = 21000 + max( STANDARD_TOKEN_COST * tokens_in_calldata + + # execution_gas_used + isContractCreation * (32000 + INITCODE_WORD_COST * + # words(calldata)), TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata) + # Simplified in this test case: - No execution gas used (no opcodes are + # executed) - Not a contract creation (no initcode) + # Therefore: max_token_cost = max(STANDARD_TOKEN_COST, + # TOTAL_COST_FLOOR_PER_TOKEN) tx.gasUsed = 21000 + tokens_in_calldata * + # max_token_cost # Since max(STANDARD_TOKEN_COST, TOTAL_COST_FLOOR_PER_TOKEN) = 10: - # tx.gasUsed = 21000 + tokens_in_calldata * 10 - # - # Token accounting: - # tokens_in_calldata = zero_bytes + 4 * non_zero_bytes - # - # So we calculate how many bytes we can fit into calldata based on available gas. + # tx.gasUsed = 21000 + tokens_in_calldata * 10 + # Token accounting: tokens_in_calldata = zero_bytes + 4 * non_zero_bytes + # So we calculate how many bytes we can fit into calldata based on + # available gas. gas_available = gas_benchmark_value - intrinsic_cost @@ -240,7 +233,10 @@ def test_block_full_access_list_and_data( fork: Fork, gas_benchmark_value: int, ): - """Test a block with access lists (60% gas) and calldata (40% gas) using random mixed bytes.""" + """ + Test a block with access lists (60% gas) and calldata (40% gas) using + random mixed bytes. + """ attack_gas_limit = gas_benchmark_value gas_available = attack_gas_limit - intrinsic_cost @@ -271,11 +267,10 @@ def test_block_full_access_list_and_data( ) ] - # Calculate calldata with 29% of gas for zero bytes and 71% for non-zero bytes - # Token accounting: tokens_in_calldata = zero_bytes + 4 * non_zero_bytes - # We want to split the gas budget: - # - 29% of gas_for_calldata for zero bytes - # - 71% of gas_for_calldata for non-zero bytes + # Calculate calldata with 29% of gas for zero bytes and 71% for non-zero + # bytes Token accounting: tokens_in_calldata = zero_bytes + 4 * + # non_zero_bytes We want to split the gas budget: - 29% of gas_for_calldata + # for zero bytes - 71% of gas_for_calldata for non-zero bytes max_tokens_in_calldata = gas_for_calldata // total_cost_standard_per_token @@ -287,7 +282,8 @@ def test_block_full_access_list_and_data( # Zero bytes: 1 token per byte # Non-zero bytes: 4 tokens per byte num_zero_bytes = tokens_for_zero_bytes # 1 token = 1 zero byte - num_non_zero_bytes = tokens_for_non_zero_bytes // 4 # 4 tokens = 1 non-zero byte + num_non_zero_bytes = tokens_for_non_zero_bytes // 4 # 4 tokens = 1 non- + # zero byte # Create calldata with mixed bytes calldata = bytearray() diff --git a/tests/benchmark/test_worst_bytecode.py b/tests/benchmark/test_worst_bytecode.py index 9c38e010bb2..5a4a211847d 100644 --- a/tests/benchmark/test_worst_bytecode.py +++ b/tests/benchmark/test_worst_bytecode.py @@ -1,6 +1,6 @@ """ -abstract: Tests that benchmark EVMs in worst-case opcode scenarios. - Tests that benchmark EVMs in worst-case opcode scenarios. +abstract: Tests that benchmark EVMs in worst-case opcode scenarios. Tests that +benchmark EVMs in worst-case opcode scenarios. Tests that benchmark EVMs in worst-case opcode scenarios. """ @@ -56,30 +56,30 @@ def test_worst_bytecode_single_opcode( gas_benchmark_value: int, ): """ - Test a block execution where a single opcode execution maxes out the gas limit, - and the opcodes access a huge amount of contract code. + Test a block execution where a single opcode execution maxes out the gas + limit, and the opcodes access a huge amount of contract code. - We first use a single block to deploy a factory contract that will be used to deploy - a large number of contracts. + We first use a single block to deploy a factory contract that will be used + to deploy a large number of contracts. This is done to avoid having a big pre-allocation size for the test. - The test is performed in the last block of the test, and the entire block gas limit is - consumed by repeated opcode executions. + The test is performed in the last block of the test, and the entire block + gas limit is consumed by repeated opcode executions. """ - # The attack gas limit is the gas limit which the target tx will use - # The test will scale the block gas limit to setup the contracts accordingly to be - # able to pay for the contract deposit. This has to take into account the 200 gas per byte, - # but also the quadratic memory expansion costs which have to be paid each time the - # memory is being setup + # The attack gas limit is the gas limit which the target tx will use The + # test will scale the block gas limit to setup the contracts accordingly to + # be able to pay for the contract deposit. This has to take into account + # the 200 gas per byte, but also the quadratic memory expansion costs which + # have to be paid each time the memory is being setup attack_gas_limit = gas_benchmark_value max_contract_size = fork.max_code_size() gas_costs = fork.gas_costs() - # Calculate the absolute minimum gas costs to deploy the contract - # This does not take into account setting up the actual memory (using KECCAK256 and XOR) - # so the actual costs of deploying the contract is higher + # Calculate the absolute minimum gas costs to deploy the contract This does + # not take into account setting up the actual memory (using KECCAK256 and + # XOR) so the actual costs of deploying the contract is higher memory_expansion_gas_calculator = fork.memory_expansion_gas_calculator() memory_gas_minimum = memory_expansion_gas_calculator(new_bytes=len(bytes(max_contract_size))) code_deposit_gas_minimum = ( @@ -90,7 +90,8 @@ def test_worst_bytecode_single_opcode( # Calculate the loop cost of the attacker to query one address loop_cost = ( gas_costs.G_KECCAK_256 # KECCAK static cost - + math.ceil(85 / 32) * gas_costs.G_KECCAK_256_WORD # KECCAK dynamic cost for CREATE2 + + math.ceil(85 / 32) * gas_costs.G_KECCAK_256_WORD # KECCAK dynamic + # cost for CREATE2 + gas_costs.G_VERY_LOW * 3 # ~MSTOREs+ADDs + gas_costs.G_COLD_ACCOUNT_ACCESS # Opcode cost + 30 # ~Gluing opcodes @@ -101,8 +102,9 @@ def test_worst_bytecode_single_opcode( attack_gas_limit - intrinsic_gas_cost_calc() - gas_costs.G_VERY_LOW * 4 ) // loop_cost - # Set the block gas limit to a relative high value to ensure the code deposit tx - # fits in the block (there is enough gas available in the block to execute this) + # Set the block gas limit to a relative high value to ensure the code + # deposit tx fits in the block (there is enough gas available in the block + # to execute this) minimum_gas_limit = code_deposit_gas_minimum * 2 * num_contracts if env.gas_limit < minimum_gas_limit: raise Exception( @@ -111,16 +113,17 @@ def test_worst_bytecode_single_opcode( "optimizing gas usage during the setup phase of this test." ) - # The initcode will take its address as a starting point to the input to the keccak - # hash function. - # It will reuse the output of the hash function in a loop to create a large amount of - # seemingly random code, until it reaches the maximum contract size. + # The initcode will take its address as a starting point to the input to + # the keccak hash function. It will reuse the output of the hash function + # in a loop to create a large amount of seemingly random code, until it + # reaches the maximum contract size. initcode = ( Op.MSTORE(0, Op.ADDRESS) + While( body=( Op.SHA3(Op.SUB(Op.MSIZE, 32), 32) - # Use a xor table to avoid having to call the "expensive" sha3 opcode as much + # Use a xor table to avoid having to call the "expensive" sha3 + # opcode as much + sum( (Op.PUSH32[xor_value] + Op.XOR + Op.DUP1 + Op.MSIZE + Op.MSTORE) for xor_value in XOR_TABLE @@ -129,16 +132,16 @@ def test_worst_bytecode_single_opcode( ), condition=Op.LT(Op.MSIZE, max_contract_size), ) - # Despite the whole contract has random bytecode, we make the first opcode be a STOP - # so CALL-like attacks return as soon as possible, while EXTCODE(HASH|SIZE) work as - # intended. + # Despite the whole contract has random bytecode, we make the first + # opcode be a STOP so CALL-like attacks return as soon as possible, + # while EXTCODE(HASH|SIZE) work as intended. + Op.MSTORE8(0, 0x00) + Op.RETURN(0, max_contract_size) ) initcode_address = pre.deploy_contract(code=initcode) - # The factory contract will simply use the initcode that is already deployed, - # and create a new contract and return its address if successful. + # The factory contract will simply use the initcode that is already + # deployed, and create a new contract and return its address if successful. factory_code = ( Op.EXTCODECOPY( address=initcode_address, @@ -160,8 +163,8 @@ def test_worst_bytecode_single_opcode( ) factory_address = pre.deploy_contract(code=factory_code) - # The factory caller will call the factory contract N times, creating N new contracts. - # Calldata should contain the N value. + # The factory caller will call the factory contract N times, creating N new + # contracts. Calldata should contain the N value. factory_caller_code = Op.CALLDATALOAD(0) + While( body=Op.POP(Op.CALL(address=factory_address)), condition=Op.PUSH1(1) + Op.SWAP1 + Op.SUB + Op.DUP1 + Op.ISZERO + Op.ISZERO, @@ -208,8 +211,8 @@ def test_worst_bytecode_single_opcode( ) if len(attack_code) > max_contract_size: - # TODO: A workaround could be to split the opcode code into multiple contracts - # and call them in sequence. + # TODO: A workaround could be to split the opcode code into multiple + # contracts and call them in sequence. raise ValueError( f"Code size {len(attack_code)} exceeds maximum code size {max_contract_size}" ) @@ -254,17 +257,18 @@ def test_worst_initcode_jumpdest_analysis( """ Test the jumpdest analysis performance of the initcode. - This benchmark places a very long initcode in the memory and then invoke CREATE instructions - with this initcode up to the block gas limit. The initcode itself has minimal execution time - but forces the EVM to perform the full jumpdest analysis on the parametrized byte pattern. - The initicode is modified by mixing-in the returned create address between CREATE invocations - to prevent caching. + This benchmark places a very long initcode in the memory and then invoke + CREATE instructions with this initcode up to the block gas limit. The + initcode itself has minimal execution time but forces the EVM to perform + the full jumpdest analysis on the parametrized byte pattern. The initicode + is modified by mixing-in the returned create address between CREATE + invocations to prevent caching. """ max_code_size = fork.max_code_size() initcode_size = fork.max_initcode_size() - # Expand the initcode pattern to the transaction data so it can be used in CALLDATACOPY - # in the main contract. TODO: tune the tx_data_len param. + # Expand the initcode pattern to the transaction data so it can be used in + # CALLDATACOPY in the main contract. TODO: tune the tx_data_len param. tx_data_len = 1024 tx_data = pattern * (tx_data_len // len(pattern)) tx_data += (tx_data_len - len(tx_data)) * bytes(Op.JUMPDEST) @@ -332,8 +336,9 @@ def test_worst_initcode_jumpdest_analysis( @pytest.mark.parametrize( "max_code_size_ratio, non_zero_data, value", [ - # To avoid a blowup of combinations, the value dimension is only explored for - # the non-zero data case, so isn't affected by code size influence. + # To avoid a blowup of combinations, the value dimension is only + # explored for the non-zero data case, so isn't affected by code size + # influence. pytest.param(0, False, 0, id="0 bytes without value"), pytest.param(0, False, 1, id="0 bytes with value"), pytest.param(0.25, True, 0, id="0.25x max code size with non-zero data"), @@ -356,7 +361,9 @@ def test_worst_create( value: int, gas_benchmark_value: int, ): - """Test the CREATE and CREATE2 performance with different configurations.""" + """ + Test the CREATE and CREATE2 performance with different configurations. + """ max_code_size = fork.max_code_size() code_size = int(max_code_size * max_code_size_ratio) @@ -378,16 +385,10 @@ def test_worst_create( initcode_template_contract = pre.deploy_contract(code=code) - # Create the benchmark contract which has the following design: - # ``` - # PUSH(value) - # [EXTCODECOPY(full initcode_template_contract) -- Conditional that non_zero_data is True]` - # JUMPDEST (#) - # (CREATE|CREATE2) - # (CREATE|CREATE2) - # ... - # JUMP(#) - # ``` + # Create the benchmark contract which has the following design: ``` + # PUSH(value) [EXTCODECOPY(full initcode_template_contract) -- Conditional + # that non_zero_data is True]` JUMPDEST (#) (CREATE|CREATE2) + # (CREATE|CREATE2) ... JUMP(#) ``` code_prefix = ( Op.PUSH3(code_size) + Op.PUSH1(value) @@ -407,10 +408,10 @@ def test_worst_create( # - DUP3 refers to PUSH1(value) above. Op.POP(Op.CREATE(value=Op.DUP3, offset=0, size=Op.DUP2)) if opcode == Op.CREATE - # For CREATE2: we manually push the arguments because we leverage the return value of - # previous CREATE2 calls as salt for the next CREATE2 call. - # - DUP4 is targeting the PUSH1(value) from the code_prefix. - # - DUP3 is targeting the EXTCODESIZE value pushed in code_prefix. + # For CREATE2: we manually push the arguments because we leverage the + # return value of previous CREATE2 calls as salt for the next CREATE2 + # call. - DUP4 is targeting the PUSH1(value) from the code_prefix. - + # DUP3 is targeting the EXTCODESIZE value pushed in code_prefix. else Op.DUP3 + Op.PUSH0 + Op.DUP4 + Op.CREATE2 ) code = code_loop_precompile_call(code_prefix, attack_block, fork) @@ -444,20 +445,20 @@ def test_worst_creates_collisions( gas_benchmark_value: int, ): """Test the CREATE and CREATE2 collisions performance.""" - # We deploy a "proxy contract" which is the contract that will be called in a loop - # using all the gas in the block. This "proxy contract" is the one executing CREATE2 - # failing with a collision. - # The reason why we need a "proxy contract" is that CREATE(2) failing with a collision will - # consume all the available gas. If we try to execute the CREATE(2) directly without being - # wrapped **and capped in gas** in a previous CALL, we would run out of gas very fast! - # - # The proxy contract calls CREATE(2) with empty initcode. The current call frame gas will - # be exhausted because of the collision. For this reason the caller will carefully give us - # the minimal gas necessary to execute the CREATE(2) and not waste any extra gas in the - # CREATE(2)-failure. - # - # Note that these CREATE(2) calls will fail because in (**) below we pre-alloc contracts - # with the same address as the ones that CREATE(2) will try to create. + # We deploy a "proxy contract" which is the contract that will be called in + # a loop using all the gas in the block. This "proxy contract" is the one + # executing CREATE2 failing with a collision. The reason why we need a + # "proxy contract" is that CREATE(2) failing with a collision will consume + # all the available gas. If we try to execute the CREATE(2) directly + # without being wrapped **and capped in gas** in a previous CALL, we would + # run out of gas very fast! + # The proxy contract calls CREATE(2) with empty initcode. The current call + # frame gas will be exhausted because of the collision. For this reason the + # caller will carefully give us the minimal gas necessary to execute the + # CREATE(2) and not waste any extra gas in the CREATE(2)-failure. + # Note that these CREATE(2) calls will fail because in (**) below we pre- + # alloc contracts with the same address as the ones that CREATE(2) will try + # to create. proxy_contract = pre.deploy_contract( code=Op.CREATE2(value=Op.PUSH0, salt=Op.PUSH0, offset=Op.PUSH0, size=Op.PUSH0) if opcode == Op.CREATE2 @@ -465,8 +466,8 @@ def test_worst_creates_collisions( ) gas_costs = fork.gas_costs() - # The CALL to the proxy contract needs at a minimum gas corresponding to the CREATE(2) - # plus extra required PUSH0s for arguments. + # The CALL to the proxy contract needs at a minimum gas corresponding to + # the CREATE(2) plus extra required PUSH0s for arguments. min_gas_required = gas_costs.G_CREATE + gas_costs.G_BASE * (3 if opcode == Op.CREATE else 4) code_prefix = Op.PUSH20(proxy_contract) + Op.PUSH3(min_gas_required) attack_block = Op.POP( @@ -477,7 +478,8 @@ def test_worst_creates_collisions( code = code_loop_precompile_call(code_prefix, attack_block, fork) tx_target = pre.deploy_contract(code=code) - # (**) We deploy the contract that CREATE(2) will attempt to create so any attempt will fail. + # (**) We deploy the contract that CREATE(2) will attempt to create so any + # attempt will fail. if opcode == Op.CREATE2: addr = compute_create2_address(address=proxy_contract, salt=0, initcode=[]) pre.deploy_contract(address=addr, code=Op.INVALID) diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index d7437a77e4c..052a791bd12 100644 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -1,8 +1,9 @@ """ -abstract: Tests that benchmark EVMs in worst-case compute scenarios. - Tests that benchmark EVMs in worst-case compute scenarios. +abstract: Tests that benchmark EVMs in worst-case compute scenarios. Tests that +benchmark EVMs in worst-case compute scenarios. -Tests that benchmark EVMs when running worst-case compute opcodes and precompile scenarios. +Tests that benchmark EVMs when running worst-case compute opcodes and +precompile scenarios. """ import math @@ -57,8 +58,8 @@ def neg(x: int) -> int: def make_dup(index: int) -> Opcode: """ - Create a DUP instruction which duplicates the index-th (counting from 0) element - from the top of the stack. E.g. make_dup(0) → DUP1. + Create a DUP instruction which duplicates the index-th (counting from 0) + element from the top of the stack. E.g. make_dup(0) → DUP1. """ assert 0 <= index < 16 return Opcode(0x80 + index, pushed_stack_items=1, min_stack_height=index + 1) @@ -158,9 +159,9 @@ def test_worst_callvalue( """ Test running a block with as many CALLVALUE opcodes as possible. - The `non_zero_value` parameter controls whether opcode must return non-zero value. - The `from_origin` parameter controls whether the call frame is the immediate from the - transaction or a previous CALL. + The `non_zero_value` parameter controls whether opcode must return non-zero + value. The `from_origin` parameter controls whether the call frame is the + immediate from the transaction or a previous CALL. """ max_code_size = fork.max_code_size() @@ -222,11 +223,12 @@ def test_worst_returndatasize_nonzero( gas_benchmark_value: int, ): """ - Test running a block which execute as many RETURNDATASIZE opcodes which return a non-zero - buffer as possible. + Test running a block which execute as many RETURNDATASIZE opcodes which + return a non-zero buffer as possible. - The `returned_size` parameter indicates the size of the returned data buffer. - The `return_data_style` indicates how returned data is produced for the opcode caller. + The `returned_size` parameter indicates the size of the returned data + buffer. The `return_data_style` indicates how returned data is produced for + the opcode caller. """ max_code_size = fork.max_code_size() @@ -271,7 +273,10 @@ def test_worst_returndatasize_zero( fork: Fork, gas_benchmark_value: int, ): - """Test running a block with as many RETURNDATASIZE opcodes as possible with a zero buffer.""" + """ + Test running a block with as many RETURNDATASIZE opcodes as possible with a + zero buffer. + """ max_code_size = fork.max_code_size() dummy_contract_call = Bytecode() @@ -351,40 +356,41 @@ def test_worst_keccak( max_code_size = fork.max_code_size() - # Discover the optimal input size to maximize keccak-permutations, not keccak calls. - # The complication of the discovery arises from the non-linear gas cost of memory expansion. + # Discover the optimal input size to maximize keccak-permutations, not + # keccak calls. The complication of the discovery arises from the non- + # linear gas cost of memory expansion. max_keccak_perm_per_block = 0 optimal_input_length = 0 for i in range(1, 1_000_000, 32): iteration_gas_cost = ( 2 * gsc.G_VERY_LOW # PUSHN + PUSH1 + gsc.G_KECCAK_256 # KECCAK256 static cost - + math.ceil(i / 32) * gsc.G_KECCAK_256_WORD # KECCAK256 dynamic cost + + math.ceil(i / 32) * gsc.G_KECCAK_256_WORD # KECCAK256 dynamic + # cost + gsc.G_BASE # POP ) - # From the available gas, we subtract the mem expansion costs considering we know the - # current input size length i. + # From the available gas, we subtract the mem expansion costs + # considering we know the current input size length i. available_gas_after_expansion = max(0, available_gas - mem_exp_gas_calculator(new_bytes=i)) # Calculate how many calls we can do. num_keccak_calls = available_gas_after_expansion // iteration_gas_cost # KECCAK does 1 permutation every 136 bytes. num_keccak_permutations = num_keccak_calls * math.ceil(i / KECCAK_RATE) - # If we found an input size that is better (reg permutations/gas), then save it. + # If we found an input size that is better (reg permutations/gas), then + # save it. if num_keccak_permutations > max_keccak_perm_per_block: max_keccak_perm_per_block = num_keccak_permutations optimal_input_length = i - # max_iters_loop contains how many keccak calls can be done per loop. - # The loop is as big as possible bounded by the maximum code size. - # + # max_iters_loop contains how many keccak calls can be done per loop. The + # loop is as big as possible bounded by the maximum code size. # The loop structure is: JUMPDEST + [attack iteration] + PUSH0 + JUMP - # - # Now calculate available gas for [attack iteration]: - # Numerator = max_code_size-3. The -3 is for the JUMPDEST, PUSH0 and JUMP. - # Denominator = (PUSHN + PUSH1 + KECCAK256 + POP) + PUSH1_DATA + PUSHN_DATA - # TODO: the testing framework uses PUSH1(0) instead of PUSH0 which is suboptimal for the - # attack, whenever this is fixed adjust accordingly. + # Now calculate available gas for [attack iteration]: Numerator = + # max_code_size-3. The -3 is for the JUMPDEST, PUSH0 and JUMP. Denominator + # = (PUSHN + PUSH1 + KECCAK256 + POP) + PUSH1_DATA + PUSHN_DATA TODO: the + # testing framework uses PUSH1(0) instead of PUSH0 which is suboptimal for + # the attack, whenever this is fixed adjust accordingly. start_code = Op.JUMPDEST + Op.PUSH20[optimal_input_length] loop_code = Op.POP(Op.SHA3(Op.PUSH0, Op.DUP1)) end_code = Op.POP + Op.JUMP(Op.PUSH0) @@ -427,7 +433,10 @@ def test_worst_precompile_only_data_input( bytes_per_unit_of_work: int, gas_benchmark_value: int, ): - """Test running a block with as many precompile calls which have a single `data` input.""" + """ + Test running a block with as many precompile calls which have a single + `data` input. + """ # Intrinsic gas cost is paid once. intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator() available_gas = gas_benchmark_value - intrinsic_gas_calculator() @@ -435,7 +444,8 @@ def test_worst_precompile_only_data_input( gsc = fork.gas_costs() mem_exp_gas_calculator = fork.memory_expansion_gas_calculator() - # Discover the optimal input size to maximize precompile work, not precompile calls. + # Discover the optimal input size to maximize precompile work, not + # precompile calls. max_work = 0 optimal_input_length = 0 for input_length in range(1, 1_000_000, 32): @@ -450,11 +460,13 @@ def test_worst_precompile_only_data_input( iteration_gas_cost = ( parameters_gas + +static_cost # Precompile static cost - + math.ceil(input_length / 32) * per_word_dynamic_cost # Precompile dynamic cost + + math.ceil(input_length / 32) * per_word_dynamic_cost # Precompile + # dynamic + # cost + gsc.G_BASE # POP ) - # From the available gas, we subtract the mem expansion costs considering we know the - # current input size length. + # From the available gas, we subtract the mem expansion costs + # considering we know the current input size length. available_gas_after_expansion = max( 0, available_gas - mem_exp_gas_calculator(new_bytes=input_length) ) @@ -462,7 +474,8 @@ def test_worst_precompile_only_data_input( num_calls = available_gas_after_expansion // iteration_gas_cost total_work = num_calls * math.ceil(input_length / bytes_per_unit_of_work) - # If we found an input size that is better (reg permutations/gas), then save it. + # If we found an input size that is better (reg permutations/gas), then + # save it. if total_work > max_work: max_work = total_work optimal_input_length = input_length @@ -641,7 +654,8 @@ def test_worst_precompile_only_data_input( ), id="mod_odd_32b_exp_cover_windows", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L38 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L38 pytest.param( ModExpInput( base=192 * "FF", @@ -650,7 +664,8 @@ def test_worst_precompile_only_data_input( ), id="mod_min_gas_base_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L40 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L40 pytest.param( ModExpInput( base=8 * "FF", @@ -659,7 +674,8 @@ def test_worst_precompile_only_data_input( ), id="mod_min_gas_exp_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L42 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L42 pytest.param( ModExpInput( base=40 * "FF", @@ -668,7 +684,8 @@ def test_worst_precompile_only_data_input( ), id="mod_min_gas_balanced", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L44 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L44 pytest.param( ModExpInput( base=32 * "FF", @@ -677,7 +694,8 @@ def test_worst_precompile_only_data_input( ), id="mod_exp_208_gas_balanced", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L46 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L46 pytest.param( ModExpInput( base=8 * "FF", @@ -686,7 +704,8 @@ def test_worst_precompile_only_data_input( ), id="mod_exp_215_gas_exp_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L48 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L48 pytest.param( ModExpInput( base=8 * "FF", @@ -695,7 +714,8 @@ def test_worst_precompile_only_data_input( ), id="mod_exp_298_gas_exp_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L50 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L50 pytest.param( ModExpInput( base=16 * "FF", @@ -704,7 +724,8 @@ def test_worst_precompile_only_data_input( ), id="mod_pawel_2", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L52 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L52 pytest.param( ModExpInput( base=24 * "FF", @@ -713,7 +734,8 @@ def test_worst_precompile_only_data_input( ), id="mod_pawel_3", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L54 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L54 pytest.param( ModExpInput( base=32 * "FF", @@ -722,7 +744,8 @@ def test_worst_precompile_only_data_input( ), id="mod_pawel_4", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L56 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L56 pytest.param( ModExpInput( base=280 * "FF", @@ -731,7 +754,8 @@ def test_worst_precompile_only_data_input( ), id="mod_408_gas_base_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L58 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L58 pytest.param( ModExpInput( base=16 * "FF", @@ -740,7 +764,8 @@ def test_worst_precompile_only_data_input( ), id="mod_400_gas_exp_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L60 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L60 pytest.param( ModExpInput( base=48 * "FF", @@ -749,7 +774,8 @@ def test_worst_precompile_only_data_input( ), id="mod_408_gas_balanced", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L62 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L62 pytest.param( ModExpInput( base=344 * "FF", @@ -758,7 +784,8 @@ def test_worst_precompile_only_data_input( ), id="mod_616_gas_base_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L64 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L64 pytest.param( ModExpInput( base=16 * "FF", @@ -767,7 +794,8 @@ def test_worst_precompile_only_data_input( ), id="mod_600_gas_exp_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L66 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L66 pytest.param( ModExpInput( base=48 * "FF", @@ -776,7 +804,8 @@ def test_worst_precompile_only_data_input( ), id="mod_600_gas_balanced", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L68 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L68 pytest.param( ModExpInput( base=392 * "FF", @@ -785,7 +814,8 @@ def test_worst_precompile_only_data_input( ), id="mod_800_gas_base_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L70 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L70 pytest.param( ModExpInput( base=16 * "FF", @@ -794,7 +824,8 @@ def test_worst_precompile_only_data_input( ), id="mod_800_gas_exp_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L72 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L72 pytest.param( ModExpInput( base=56 * "FF", @@ -803,7 +834,8 @@ def test_worst_precompile_only_data_input( ), id="mod_767_gas_balanced", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L74 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L74 pytest.param( ModExpInput( base=16 * "FF", @@ -812,7 +844,8 @@ def test_worst_precompile_only_data_input( ), id="mod_852_gas_exp_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L76 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L76 pytest.param( ModExpInput( base=408 * "FF", @@ -821,7 +854,8 @@ def test_worst_precompile_only_data_input( ), id="mod_867_gas_base_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L78 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L78 pytest.param( ModExpInput( base=56 * "FF", @@ -830,7 +864,8 @@ def test_worst_precompile_only_data_input( ), id="mod_996_gas_balanced", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L80 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L80 pytest.param( ModExpInput( base=448 * "FF", @@ -839,7 +874,8 @@ def test_worst_precompile_only_data_input( ), id="mod_1045_gas_base_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L82 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L82 pytest.param( ModExpInput( base=32 * "FF", @@ -848,7 +884,8 @@ def test_worst_precompile_only_data_input( ), id="mod_677_gas_base_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L84 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L84 pytest.param( ModExpInput( base=24 * "FF", @@ -857,7 +894,8 @@ def test_worst_precompile_only_data_input( ), id="mod_765_gas_exp_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L86 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L86 pytest.param( ModExpInput( base=32 * "FF", @@ -954,7 +992,8 @@ def test_worst_precompile_only_data_input( ), id="mod_1024_exp_2", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L122 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L122 pytest.param( ModExpInput( base="03", @@ -963,7 +1002,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_example_1", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L124 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L124 pytest.param( ModExpInput( base="", @@ -972,7 +1012,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_example_2", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L126 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L126 pytest.param( ModExpInput( base="e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", @@ -981,7 +1022,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_1_square", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L128 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L128 pytest.param( ModExpInput( base="e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", @@ -990,7 +1032,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_1_qube", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L130 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L130 pytest.param( ModExpInput( base="e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", @@ -999,7 +1042,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_1_pow_0x10001", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L132 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L132 pytest.param( ModExpInput( base="cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", @@ -1008,7 +1052,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_2_square", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L134 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L134 pytest.param( ModExpInput( base="cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", @@ -1017,7 +1062,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_2_qube", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L136 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L136 pytest.param( ModExpInput( base="cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", @@ -1026,7 +1072,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_2_pow_0x10001", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L138 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L138 pytest.param( ModExpInput( base="c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", @@ -1035,7 +1082,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_3_square", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L140 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L140 pytest.param( ModExpInput( base="c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", @@ -1044,7 +1092,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_3_qube", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L142 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L142 pytest.param( ModExpInput( base="c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", @@ -1053,7 +1102,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_3_pow_0x10001", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L144 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L144 pytest.param( ModExpInput( base="db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", @@ -1062,7 +1112,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_4_square", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L146 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L146 pytest.param( ModExpInput( base="db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", @@ -1071,7 +1122,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_4_qube", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L148 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L148 pytest.param( ModExpInput( base="db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", @@ -1080,7 +1132,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_4_pow_0x10001", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L150 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L150 pytest.param( ModExpInput( base="c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", @@ -1089,7 +1142,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_5_square", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L152 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L152 pytest.param( ModExpInput( base="c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", @@ -1098,7 +1152,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_5_qube", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L154 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L154 pytest.param( ModExpInput( base="c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", @@ -1107,7 +1162,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_nagydani_5_pow_0x10001", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L156 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L156 pytest.param( ModExpInput( base="ffffff", @@ -1116,7 +1172,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_marius_1_even", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L158 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L158 pytest.param( ModExpInput( base="ffffffffffffffff76ffffffffffffff", @@ -1125,7 +1182,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_guido_1_even", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L160 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L160 pytest.param( ModExpInput( base="e0060000a921212121212121ff000021", @@ -1134,7 +1192,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_guido_2_even", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L162 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L162 pytest.param( ModExpInput( base="0193585a48e18aad777e9c1b54221a0f58140392e4f091cd5f42b2e8644a9384fbd58ae1edec2477ebf7edbf7c0a3f8bd21d1890ee87646feab3c47be716f842cc3da9b940af312dc54450a960e3fc0b86e56abddd154068e10571a96fff6259431632bc15695c6c8679057e66c2c25c127e97e64ee5de6ea1fc0a4a0e431343fed1daafa072c238a45841da86a9806680bc9f298411173210790359209cd454b5af7b4d5688b4403924e5f863d97e2c5349e1a04b54fcf385b1e9d7714bab8fbf5835f6ff9ed575e77dff7af5cbb641db5d537933bae1fa6555d6c12d6fb31ca27b57771f4aebfbe0bf95e8990c0108ffe7cbdaf370be52cf3ade594543af75ad9329d2d11a402270b5b9a6bf4b83307506e118fca4862749d04e916fc7a039f0d13f2a02e0eedb800199ec95df15b4ccd8669b52586879624d51219e72102fad810b5909b1e372ddf33888fb9beb09b416e4164966edbabd89e4a286be36277fc576ed519a15643dac602e92b63d0b9121f0491da5b16ef793a967f096d80b6c81ecaaffad7e3f06a4a5ac2796f1ed9f68e6a0fd5cf191f0c5c2eec338952ff8d31abc68bf760febeb57e088995ba1d7726a2fdd6d8ca28a181378b8b4ab699bfd4b696739bbf17a9eb2df6251143046137fdbbfacac312ebf67a67da9741b59600000000000", @@ -1143,7 +1202,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_guido_3_even", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L166 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L166 pytest.param( ModExpInput( base="ffffffffffffffff", @@ -1152,7 +1212,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_pawel_1_exp_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L168 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L168 pytest.param( ModExpInput( base="ffffffffffffffffffffffffffffffff", @@ -1161,7 +1222,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_pawel_2_exp_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L170 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L170 pytest.param( ModExpInput( base="ffffffffffffffffffffffffffffffffffffffffffffffff", @@ -1176,7 +1238,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_pawel_3_exp_8", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L172 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L172 pytest.param( ModExpInput( base="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -1185,7 +1248,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_pawel_4_exp_heavy", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L174 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L174 pytest.param( ModExpInput( base="29356abadad68ad986c416de6f620bda0e1818b589e84f853a97391694d35496", @@ -1194,7 +1258,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_common_1360n1", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L176 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L176 pytest.param( ModExpInput( base="d41afaeaea32f7409827761b68c41b6e535da4ede1f0800bfb4a6aed18394f6b", @@ -1203,7 +1268,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_common_1360n2", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L178 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L178 pytest.param( ModExpInput( base="1a5be8fae3b3fda9ea329494ae8689c04fae4978ecccfa6a6bfb9f04b25846c0", @@ -1212,7 +1278,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_common_1349n1", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L182 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L182 pytest.param( ModExpInput( base="0000000000000000000000000000000000000000000000000000000000000003", @@ -1221,7 +1288,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_common_1152n1", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L184 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L184 pytest.param( ModExpInput( base="1fb473dd1171cf88116aa77ab3612c2c7d2cf466cc2386cc456130e2727c70b4", @@ -1230,7 +1298,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_common_200n1", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L186 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L186 pytest.param( ModExpInput( base="1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb", @@ -1239,7 +1308,8 @@ def test_worst_precompile_only_data_input( ), id="mod_vul_common_200n2", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L188 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L188 pytest.param( ModExpInput( base="288254ba43e713afbe36c9f03b54c00fae4c0a82df1cf165eb46a21c20a48ca2", @@ -1266,14 +1336,15 @@ def test_worst_modexp( gas_benchmark_value: int, ): """ - Test running a block with as many calls to the MODEXP (5) precompile as possible. - All the calls have the same parametrized input. + Test running a block with as many calls to the MODEXP (5) precompile as + possible. All the calls have the same parametrized input. """ # Skip the trailing zeros from the input to make EVM work even harder. calldata = bytes(mod_exp_input).rstrip(b"\x00") code = code_loop_precompile_call( - Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE), # Copy the input to the memory. + Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE), # Copy the input to the + # memory. Op.POP(Op.STATICCALL(Op.GAS, 0x5, Op.PUSH0, Op.CALLDATASIZE, Op.PUSH0, Op.PUSH0)), fork, ) @@ -1298,8 +1369,8 @@ def test_worst_modexp( pytest.param( 0x01, [ - # The inputs below are a valid signature, thus ECRECOVER call won't - # be short-circuited by validations and do actual work. + # The inputs below are a valid signature, thus ECRECOVER call + # won't be short-circuited by validations and do actual work. "38D18ACB67D25C8BB9942764B62F18E17054F66A817BD4295423ADF9ED98873E", "000000000000000000000000000000000000000000000000000000000000001B", "38D18ACB67D25C8BB9942764B62F18E17054F66A817BD4295423ADF9ED98873E", @@ -1317,7 +1388,8 @@ def test_worst_modexp( ], id="bn128_add", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L326 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L326 pytest.param( 0x06, [ @@ -1328,7 +1400,8 @@ def test_worst_modexp( ], id="bn128_add_infinities", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L329 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L329 pytest.param( 0x06, [ @@ -1348,7 +1421,8 @@ def test_worst_modexp( ], id="bn128_mul", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L335 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L335 pytest.param( 0x07, [ @@ -1358,7 +1432,8 @@ def test_worst_modexp( ], id="bn128_mul_infinities_2_scalar", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L338 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L338 pytest.param( 0x07, [ @@ -1368,7 +1443,8 @@ def test_worst_modexp( ], id="bn128_mul_infinities_32_byte_scalar", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L341 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L341 pytest.param( 0x07, [ @@ -1378,7 +1454,8 @@ def test_worst_modexp( ], id="bn128_mul_1_2_2_scalar", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L344 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L344 pytest.param( 0x07, [ @@ -1388,7 +1465,8 @@ def test_worst_modexp( ], id="bn128_mul_1_2_32_byte_scalar", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L347 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L347 pytest.param( 0x07, [ @@ -1398,7 +1476,8 @@ def test_worst_modexp( ], id="bn128_mul_32_byte_coord_and_2_scalar", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L350 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L350 pytest.param( 0x07, [ @@ -1441,7 +1520,8 @@ def test_worst_modexp( ], id="bn128_one_pairing", ), - # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L353 + # Ported from + # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCase.cs#L353 pytest.param(0x08, [], id="ec_pairing_zero_input"), pytest.param( 0x08, @@ -1640,9 +1720,10 @@ def test_worst_modexp( pytest.param( bls12381_spec.Spec.G2MSM, [ - # TODO: the //2 is required due to a limitation of the max contract size limit. - # In a further iteration we can insert the inputs as calldata or storage and avoid - # having to do PUSHes which has this limitation. This also applies to G1MSM. + # TODO: the //2 is required due to a limitation of the max + # contract size limit. In a further iteration we can insert the + # inputs as calldata or storage and avoid having to do PUSHes + # which has this limitation. This also applies to G1MSM. (bls12381_spec.Spec.P2 + bls12381_spec.Scalar(bls12381_spec.Spec.Q)) * (len(bls12381_spec.Spec.G2MSM_DISCOUNT_TABLE) // 2), ], @@ -1873,7 +1954,8 @@ def test_worst_jumpdests( DEFAULT_BINOP_ARGS, ), ( - # This has the cycle of 2, after two SUBs values are back to initials. + # This has the cycle of 2, after two SUBs values are back to + # initials. Op.SUB, DEFAULT_BINOP_ARGS, ), @@ -1886,8 +1968,8 @@ def test_worst_jumpdests( ( 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F, # We want the first divisor to be slightly bigger than 2**128: - # this is the worst case for the division algorithm with optimized paths - # for division by 1 and 2 words. + # this is the worst case for the division algorithm with + # optimized paths for division by 1 and 2 words. 0x100000000000000000000000000000033, ), ), @@ -1897,13 +1979,14 @@ def test_worst_jumpdests( ( 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F, # We want the first divisor to be slightly bigger than 2**64: - # this is the worst case for the division algorithm with an optimized path - # for division by 1 word. + # this is the worst case for the division algorithm with an + # optimized path for division by 1 word. 0x10000000000000033, ), ), ( - # Same as DIV-0, but the numerator made positive, and the divisor made negative. + # Same as DIV-0, but the numerator made positive, and the divisor + # made negative. Op.SDIV, ( 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F, @@ -1911,7 +1994,8 @@ def test_worst_jumpdests( ), ), ( - # Same as DIV-1, but the numerator made positive, and the divisor made negative. + # Same as DIV-1, but the numerator made positive, and the divisor + # made negative. Op.SDIV, ( 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F, @@ -1919,17 +2003,20 @@ def test_worst_jumpdests( ), ), ( - # This scenario is not suitable for MOD because the values quickly become 0. + # This scenario is not suitable for MOD because the values quickly + # become 0. Op.MOD, DEFAULT_BINOP_ARGS, ), ( - # This scenario is not suitable for SMOD because the values quickly become 0. + # This scenario is not suitable for SMOD because the values quickly + # become 0. Op.SMOD, DEFAULT_BINOP_ARGS, ), ( - # This keeps the values unchanged, pow(2**256-1, 2**256-1, 2**256) == 2**256-1. + # This keeps the values unchanged, pow(2**256-1, 2**256-1, 2**256) + # == 2**256-1. Op.EXP, ( 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, @@ -2006,9 +2093,9 @@ def test_worst_binop_simple( gas_benchmark_value: int, ): """ - Test running a block with as many binary instructions (takes two args, produces one value) - as possible. The execution starts with two initial values on the stack, and the stack is - balanced by the DUP2 instruction. + Test running a block with as many binary instructions (takes two args, + produces one value) as possible. The execution starts with two initial + values on the stack, and the stack is balanced by the DUP2 instruction. """ max_code_size = fork.max_code_size() @@ -2044,8 +2131,8 @@ def test_worst_unop( gas_benchmark_value: int, ): """ - Test running a block with as many unary instructions (takes one arg, produces one value) - as possible. + Test running a block with as many unary instructions (takes one arg, + produces one value) as possible. """ max_code_size = fork.max_code_size() @@ -2071,7 +2158,8 @@ def test_worst_unop( # `key_mut` indicates the key isn't fixed. @pytest.mark.parametrize("key_mut", [True, False]) -# `val_mut` indicates that at the end of each big-loop, the value of the target key changes. +# `val_mut` indicates that at the end of each big-loop, the value of the target +# key changes. @pytest.mark.parametrize("val_mut", [True, False]) def test_worst_tload( state_test: StateTestFiller, @@ -2098,7 +2186,8 @@ def test_worst_tload( if not key_mut and val_mut: code_prefix = Op.JUMPDEST loop_iter = Op.POP(Op.TLOAD(Op.CALLVALUE)) - code_val_mut = Op.TSTORE(Op.CALLVALUE, Op.GAS) # CALLVALUE configured in the tx + code_val_mut = Op.TSTORE(Op.CALLVALUE, Op.GAS) # CALLVALUE configured + # in the tx if not key_mut and not val_mut: code_prefix = Op.JUMPDEST loop_iter = Op.POP(Op.TLOAD(Op.CALLVALUE)) @@ -2140,12 +2229,13 @@ def test_worst_tstore( init_key = 42 code_prefix = Op.PUSH1(init_key) + Op.JUMPDEST - # If `key_mut` is True, we mutate the key on every iteration of the big loop. + # If `key_mut` is True, we mutate the key on every iteration of the big + # loop. code_key_mut = Op.POP + Op.GAS if key_mut else Bytecode() code_suffix = code_key_mut + Op.JUMP(len(code_prefix) - 1) - # If `dense_val_mut` is set, we use GAS as a cheap way of always storing a different value than - # the previous one. + # If `dense_val_mut` is set, we use GAS as a cheap way of always storing a + # different value than the previous one. loop_iter = Op.TSTORE(Op.DUP2, Op.GAS if dense_val_mut else Op.DUP1) code_body_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(loop_iter) @@ -2175,9 +2265,10 @@ def test_worst_shifts( gas_benchmark_value: int, ): """ - Test running a block with as many shift instructions with non-trivial arguments. - This test generates left-right pairs of shifts to avoid zeroing the argument. - The shift amounts are randomly pre-selected from the constant pool of 15 values on the stack. + Test running a block with as many shift instructions with non-trivial + arguments. This test generates left-right pairs of shifts to avoid zeroing + the argument. The shift amounts are randomly pre-selected from the constant + pool of 15 values on the stack. """ max_code_size = fork.max_code_size() @@ -2205,10 +2296,12 @@ def sar(x, s): raise ValueError(f"Unexpected shift op: {shift_right}") rng = random.Random(1) # Use random with a fixed seed. - initial_value = 2**256 - 1 # The initial value to be shifted; should be negative for SAR. + initial_value = 2**256 - 1 # The initial value to be shifted; should be + # negative for SAR. - # Create the list of shift amounts with 15 elements (max reachable by DUPs instructions). - # For the worst case keep the values small and omit values divisible by 8. + # Create the list of shift amounts with 15 elements (max reachable by DUPs + # instructions). For the worst case keep the values small and omit values + # divisible by 8. shift_amounts = [x + (x >= 8) + (x >= 15) for x in range(1, 16)] code_prefix = sum(Op.PUSH1[sh] for sh in shift_amounts) + Op.JUMPDEST + Op.CALLDATALOAD(0) @@ -2323,20 +2416,19 @@ def test_worst_mod( gas_benchmark_value: int, ): """ - Test running a block with as many MOD instructions with arguments of the parametrized range. - The test program consists of code segments evaluating the "MOD chain": - mod[0] = calldataload(0) - mod[1] = numerators[indexes[0]] % mod[0] - mod[2] = numerators[indexes[1]] % mod[1] ... - The "numerators" is a pool of 15 constants pushed to the EVM stack at the program start. - The order of accessing the numerators is selected in a way the mod value remains in the range - as long as possible. + Test running a block with as many MOD instructions with arguments of the + parametrized range. The test program consists of code segments evaluating + the "MOD chain": mod[0] = calldataload(0) mod[1] = numerators[indexes[0]] % + mod[0] mod[2] = numerators[indexes[1]] % mod[1] ... The "numerators" is a + pool of 15 constants pushed to the EVM stack at the program start. The + order of accessing the numerators is selected in a way the mod value + remains in the range as long as possible. """ max_code_size = fork.max_code_size() - # For SMOD we negate both numerator and modulus. The underlying computation is the same, - # just the SMOD implementation will have to additionally handle the sign bits. - # The result stays negative. + # For SMOD we negate both numerator and modulus. The underlying computation + # is the same, just the SMOD implementation will have to additionally + # handle the sign bits. The result stays negative. should_negate = op == Op.SMOD num_numerators = 15 @@ -2344,12 +2436,13 @@ def test_worst_mod( numerator_max = 2**numerator_bits - 1 numerator_min = 2 ** (numerator_bits - 1) - # Pick the modulus min value so that it is _unlikely_ to drop to the lower word count. + # Pick the modulus min value so that it is _unlikely_ to drop to the lower + # word count. assert mod_bits >= 63 mod_min = 2 ** (mod_bits - 63) - # Select the random seed giving the longest found MOD chain. - # You can look for a longer one by increasing the numerators_min_len. This will activate + # Select the random seed giving the longest found MOD chain. You can look + # for a longer one by increasing the numerators_min_len. This will activate # the while loop below. match op, mod_bits: case Op.MOD, 255: @@ -2392,18 +2485,23 @@ def test_worst_mod( mod = initial_mod indexes = [] while mod >= mod_min: - results = [n % mod for n in numerators] # Compute results for each numerator. - i = max(range(len(results)), key=results.__getitem__) # And pick the best one. + results = [n % mod for n in numerators] # Compute results for each + # numerator. + i = max(range(len(results)), key=results.__getitem__) # And pick + # the best + # one. mod = results[i] indexes.append(i) - assert len(indexes) > numerators_min_len # Disable if you want to find longer MOD chains. + assert len(indexes) > numerators_min_len # Disable if you want to find + # longer MOD chains. if len(indexes) > numerators_min_len: break seed += 1 print(f"{seed=}") - # TODO: Don't use fixed PUSH32. Let Bytecode helpers to select optimal push opcode. + # TODO: Don't use fixed PUSH32. Let Bytecode helpers to select optimal push + # opcode. code_constant_pool = sum((Op.PUSH32[n] for n in numerators), Bytecode()) code_prefix = code_constant_pool + Op.JUMPDEST code_suffix = Op.JUMP(len(code_constant_pool)) @@ -2448,7 +2546,9 @@ def test_worst_memory_access( big_memory_expansion: bool, gas_benchmark_value: int, ): - """Test running a block with as many memory access instructions as possible.""" + """ + Test running a block with as many memory access instructions as possible. + """ max_code_size = fork.max_code_size() mem_exp_code = Op.MSTORE8(10 * 1024, 1) if big_memory_expansion else Bytecode() @@ -2488,29 +2588,29 @@ def test_worst_modarith( gas_benchmark_value: int, ): """ - Test running a block with as many "op" instructions with arguments of the parametrized range. - The test program consists of code segments evaluating the "op chain": - mod[0] = calldataload(0) - mod[1] = (fixed_arg op args[indexes[0]]) % mod[0] - mod[2] = (fixed_arg op args[indexes[1]]) % mod[1] - The "args" is a pool of 15 constants pushed to the EVM stack at the program start. - The "fixed_arg" is the 0xFF...FF constant added to the EVM stack by PUSH32 - just before executing the "op". - The order of accessing the numerators is selected in a way the mod value remains in the range - as long as possible. + Test running a block with as many "op" instructions with arguments of the + parametrized range. The test program consists of code segments evaluating + the "op chain": mod[0] = calldataload(0) mod[1] = (fixed_arg op + args[indexes[0]]) % mod[0] mod[2] = (fixed_arg op args[indexes[1]]) % + mod[1] The "args" is a pool of 15 constants pushed to the EVM stack at the + program start. The "fixed_arg" is the 0xFF...FF constant added to the EVM + stack by PUSH32 just before executing the "op". The order of accessing the + numerators is selected in a way the mod value remains in the range as long + as possible. """ fixed_arg = 2**256 - 1 num_args = 15 max_code_size = fork.max_code_size() - # Pick the modulus min value so that it is _unlikely_ to drop to the lower word count. + # Pick the modulus min value so that it is _unlikely_ to drop to the lower + # word count. assert mod_bits >= 63 mod_min = 2 ** (mod_bits - 63) - # Select the random seed giving the longest found op chain. - # You can look for a longer one by increasing the op_chain_len. This will activate - # the while loop below. + # Select the random seed giving the longest found op chain. You can look + # for a longer one by increasing the op_chain_len. This will activate the + # while loop below. op_chain_len = 666 match op, mod_bits: case Op.ADDMOD, 255: @@ -2528,7 +2628,8 @@ def test_worst_modarith( case Op.MULMOD, 127: seed = 5 case Op.MULMOD, 63: - # For this setup we were not able to find an op-chain longer than 600. + # For this setup we were not able to find an op-chain longer than + # 600. seed = 4193 op_chain_len = 600 case _: @@ -2545,11 +2646,14 @@ def test_worst_modarith( indexes: list[int] = [] while mod >= mod_min and len(indexes) < op_chain_len: results = [op_fn(a, fixed_arg) % mod for a in args] - i = max(range(len(results)), key=results.__getitem__) # And pick the best one. + i = max(range(len(results)), key=results.__getitem__) # And pick + # the best + # one. mod = results[i] indexes.append(i) - assert len(indexes) == op_chain_len # Disable if you want to find longer op chains. + assert len(indexes) == op_chain_len # Disable if you want to find + # longer op chains. if len(indexes) == op_chain_len: break seed += 1 @@ -2561,8 +2665,8 @@ def test_worst_modarith( + sum(make_dup(len(args) - i) + Op.PUSH32[fixed_arg] + op for i in indexes) + Op.POP ) - # Construct the final code. Because of the usage of PUSH32 the code segment is very long, - # so don't try to include multiple of these. + # Construct the final code. Because of the usage of PUSH32 the code segment + # is very long, so don't try to include multiple of these. code = code_constant_pool + Op.JUMPDEST + code_segment + Op.JUMP(len(code_constant_pool)) assert (max_code_size - len(code_segment)) < len(code) <= max_code_size @@ -2608,8 +2712,9 @@ def test_amortized_bn128_pairings( intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator() mem_exp_gas_calculator = fork.memory_expansion_gas_calculator() - # This is a theoretical maximum number of pairings that can be done in a block. - # It is only used for an upper bound for calculating the optimal number of pairings below. + # This is a theoretical maximum number of pairings that can be done in a + # block. It is only used for an upper bound for calculating the optimal + # number of pairings below. maximum_number_of_pairings = (gas_benchmark_value - base_cost) // pairing_cost # Discover the optimal number of pairings balancing two dimensions: @@ -2620,19 +2725,21 @@ def test_amortized_bn128_pairings( for i in range(1, maximum_number_of_pairings + 1): # We'll pass all pairing arguments via calldata. available_gas_after_intrinsic = gas_benchmark_value - intrinsic_gas_calculator( - calldata=[0xFF] * size_per_pairing * i # 0xFF is to indicate non-zero bytes. + calldata=[0xFF] * size_per_pairing * i # 0xFF is to indicate non- + # zero bytes. ) available_gas_after_expansion = max( 0, available_gas_after_intrinsic - mem_exp_gas_calculator(new_bytes=i * size_per_pairing), ) - # This is ignoring "glue" opcodes, but helps to have a rough idea of the right - # cutting point. + # This is ignoring "glue" opcodes, but helps to have a rough idea of + # the right cutting point. approx_gas_cost_per_call = gsc.G_WARM_ACCOUNT_ACCESS + base_cost + i * pairing_cost num_precompile_calls = available_gas_after_expansion // approx_gas_cost_per_call - num_pairings_done = num_precompile_calls * i # Each precompile call does i pairings. + num_pairings_done = num_precompile_calls * i # Each precompile call + # does i pairings. if num_pairings_done > max_pairings: max_pairings = num_pairings_done @@ -2914,16 +3021,13 @@ def test_worst_return_revert( """Test running a block with as many RETURN or REVERT as possible.""" max_code_size = fork.max_code_size() - # Create the contract that will be called repeatedly. - # The bytecode of the contract is: - # ``` - # [CODECOPY(returned_size) -- Conditional if return_non_zero_data] - # opcode(returned_size) - # - # ``` - # Filling the contract up to the max size is a cheap way of leveraging CODECOPY to return - # non-zero bytes if requested. Note that since this is a pre-deploy this cost isn't - # relevant for the benchmark. + # Create the contract that will be called repeatedly. The bytecode of the + # contract is: ``` [CODECOPY(returned_size) -- Conditional if + # return_non_zero_data] opcode(returned_size) ``` Filling the contract up to the max size is + # a cheap way of leveraging CODECOPY to return non-zero bytes if requested. + # Note that since this is a pre-deploy this cost isn't relevant for the + # benchmark. mem_preparation = Op.CODECOPY(size=return_size) if return_non_zero_data else Bytecode() executable_code = mem_preparation + opcode(size=return_size) code = executable_code @@ -2999,7 +3103,9 @@ def test_worst_clz_diff_input( gas_benchmark_value: int, env: Environment, ): - """Test running a block with as many CLZ with different input as possible.""" + """ + Test running a block with as many CLZ with different input as possible. + """ tx_gas_limit = fork.transaction_gas_limit_cap() or env.gas_limit max_code_size = fork.max_code_size() diff --git a/tests/benchmark/test_worst_memory.py b/tests/benchmark/test_worst_memory.py index 8952c05a455..6e061cfc186 100644 --- a/tests/benchmark/test_worst_memory.py +++ b/tests/benchmark/test_worst_memory.py @@ -1,6 +1,6 @@ """ -abstract: Tests that benchmark EVMs in the worst-case memory opcodes. - Tests that benchmark EVMs in the worst-case memory opcodes. +abstract: Tests that benchmark EVMs in the worst-case memory opcodes. Tests +that benchmark EVMs in the worst-case memory opcodes. Tests that benchmark EVMs in the worst-case memory opcodes. """ @@ -74,8 +74,9 @@ def test_worst_calldatacopy( if size == 0 and non_zero_data: pytest.skip("Non-zero data with size 0 is not applicable.") - # If `non_zero_data` is True, we fill the calldata with deterministic random data. - # Note that if `size == 0` and `non_zero_data` is a skipped case. + # If `non_zero_data` is True, we fill the calldata with deterministic + # random data. Note that if `size == 0` and `non_zero_data` is a skipped + # case. data = Bytes([i % 256 for i in range(size)]) if non_zero_data else Bytes() intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator() @@ -83,10 +84,11 @@ def test_worst_calldatacopy( if min_gas > gas_benchmark_value: pytest.skip("Minimum gas required for calldata ({min_gas}) is greater than the gas limit") - # We create the contract that will be doing the CALLDATACOPY multiple times. - # - # If `non_zero_data` is True, we leverage CALLDATASIZE for the copy length. Otherwise, since we - # don't send zero data explicitly via calldata, PUSH the target size and use DUP1 to copy it. + # We create the contract that will be doing the CALLDATACOPY multiple + # times. + # If `non_zero_data` is True, we leverage CALLDATASIZE for the copy length. + # Otherwise, since we don't send zero data explicitly via calldata, PUSH + # the target size and use DUP1 to copy it. prefix = Bytecode() if non_zero_data or size == 0 else Op.PUSH3(size) src_dst = 0 if fixed_src_dst else Op.MOD(Op.GAS, 7) attack_block = Op.CALLDATACOPY( @@ -97,11 +99,11 @@ def test_worst_calldatacopy( tx_target = code_address - # If the origin is CALL, we need to create a contract that will call the target contract with - # the calldata. + # If the origin is CALL, we need to create a contract that will call the + # target contract with the calldata. if origin == CallDataOrigin.CALL: - # If `non_zero_data` is False we leverage just using zeroed memory. Otherwise, we - # copy the calldata received from the transaction. + # If `non_zero_data` is False we leverage just using zeroed memory. + # Otherwise, we copy the calldata received from the transaction. prefix = ( Op.CALLDATACOPY(Op.PUSH0, Op.PUSH0, Op.CALLDATASIZE) if non_zero_data else Bytecode() ) + Op.JUMPDEST @@ -161,9 +163,9 @@ def test_worst_codecopy( attack_block = Op.CODECOPY(src_dst, src_dst, Op.DUP1) # DUP1 copies size. code = code_loop_precompile_call(code_prefix, attack_block, fork) - # The code generated above is not guaranteed to be of max_code_size, so we pad it since - # a test parameter targets CODECOPYing a contract with max code size. Padded bytecode values - # are not relevant. + # The code generated above is not guaranteed to be of max_code_size, so we + # pad it since a test parameter targets CODECOPYing a contract with max + # code size. Padded bytecode values are not relevant. code = code + Op.INVALID * (max_code_size - len(code)) assert len(code) == max_code_size, ( f"Code size {len(code)} is not equal to max code size {max_code_size}." @@ -209,9 +211,10 @@ def test_worst_returndatacopy( """Test running a block filled with RETURNDATACOPY executions.""" max_code_size = fork.max_code_size() - # Create the contract that will RETURN the data that will be used for RETURNDATACOPY. - # Random-ish data is injected at different points in memory to avoid making the content - # predictable. If `size` is 0, this helper contract won't be used. + # Create the contract that will RETURN the data that will be used for + # RETURNDATACOPY. Random-ish data is injected at different points in memory + # to avoid making the content predictable. If `size` is 0, this helper + # contract won't be used. code = ( Op.MSTORE8(0, Op.GAS) + Op.MSTORE8(size // 2, Op.GAS) @@ -220,24 +223,18 @@ def test_worst_returndatacopy( ) helper_contract = pre.deploy_contract(code=code) - # We create the contract that will be doing the RETURNDATACOPY multiple times. + # We create the contract that will be doing the RETURNDATACOPY multiple + # times. returndata_gen = Op.STATICCALL(address=helper_contract) if size > 0 else Bytecode() dst = 0 if fixed_dst else Op.MOD(Op.GAS, 7) attack_iter = Op.RETURNDATACOPY(dst, Op.PUSH0, Op.RETURNDATASIZE) jumpdest = Op.JUMPDEST jump_back = Op.JUMP(len(returndata_gen)) - # The attack loop is constructed as: - # ``` - # JUMPDEST(#) - # RETURNDATACOPY(...) - # RETURNDATACOPY(...) - # ... - # STATICCALL(address=helper_contract) - # JUMP(#) - # ``` - # The goal is that once per (big) loop iteration, the helper contract is called to - # generate fresh returndata to continue calling RETURNDATACOPY. + # The attack loop is constructed as: ``` JUMPDEST(#) RETURNDATACOPY(...) + # RETURNDATACOPY(...) ... STATICCALL(address=helper_contract) JUMP(#) ``` + # The goal is that once per (big) loop iteration, the helper contract is + # called to generate fresh returndata to continue calling RETURNDATACOPY. max_iters_loop = ( max_code_size - 2 * len(returndata_gen) - len(jumpdest) - len(jump_back) ) // len(attack_iter) diff --git a/tests/benchmark/test_worst_stateful_opcodes.py b/tests/benchmark/test_worst_stateful_opcodes.py index f68783e61c3..75af5b2c0ec 100644 --- a/tests/benchmark/test_worst_stateful_opcodes.py +++ b/tests/benchmark/test_worst_stateful_opcodes.py @@ -1,6 +1,6 @@ """ -abstract: Tests that benchmark EVMs for worst-case stateful opcodes. - Tests that benchmark EVMs for worst-case stateful opcodes. +abstract: Tests that benchmark EVMs for worst-case stateful opcodes. Tests that +benchmark EVMs for worst-case stateful opcodes. Tests that benchmark EVMs for worst-case stateful opcodes. """ @@ -55,14 +55,17 @@ def test_worst_address_state_cold( env: Environment, gas_benchmark_value: int, ): - """Test running a block with as many stateful opcodes accessing cold accounts.""" + """ + Test running a block with as many stateful opcodes accessing cold accounts. + """ attack_gas_limit = gas_benchmark_value gas_costs = fork.gas_costs() intrinsic_gas_cost_calc = fork.transaction_intrinsic_cost_calculator() - # For calculation robustness, the calculation below ignores "glue" opcodes like PUSH and POP. - # It should be considered a worst-case number of accounts, and a few of them might not be - # targeted before the attacking transaction runs out of gas. + # For calculation robustness, the calculation below ignores "glue" opcodes + # like PUSH and POP. It should be considered a worst-case number of + # accounts, and a few of them might not be targeted before the attacking + # transaction runs out of gas. num_target_accounts = ( attack_gas_limit - intrinsic_gas_cost_calc() ) // gas_costs.G_COLD_ACCOUNT_ACCESS @@ -70,10 +73,10 @@ def test_worst_address_state_cold( blocks = [] post = {} - # Setup - # The target addresses are going to be constructed (in the case of absent=False) and called - # as addr_offset + i, where i is the index of the account. This is to avoid - # collisions with the addresses indirectly created by the testing framework. + # Setup The target addresses are going to be constructed (in the case of + # absent=False) and called as addr_offset + i, where i is the index of the + # account. This is to avoid collisions with the addresses indirectly + # created by the testing framework. addr_offset = int.from_bytes(pre.fund_eoa(amount=0)) if not absent_accounts: @@ -142,7 +145,10 @@ def test_worst_address_state_warm( absent_target: bool, gas_benchmark_value: int, ): - """Test running a block with as many stateful opcodes doing warm access for an account.""" + """ + Test running a block with as many stateful opcodes doing warm access for an + account. + """ max_code_size = fork.max_code_size() attack_gas_limit = gas_benchmark_value @@ -253,7 +259,9 @@ def test_worst_storage_access_cold( gas_benchmark_value: int, tx_result: TransactionResult, ): - """Test running a block with as many cold storage slot accesses as possible.""" + """ + Test running a block with as many cold storage slot accesses as possible. + """ gas_costs = fork.gas_costs() intrinsic_gas_cost_calc = fork.transaction_intrinsic_cost_calculator() attack_gas_limit = gas_benchmark_value @@ -280,7 +288,8 @@ def test_worst_storage_access_cold( execution_code_body = Op.SSTORE(Op.DUP1, Op.DUP1) loop_cost += gas_costs.G_VERY_LOW * 2 elif storage_action == StorageAction.WRITE_NEW_VALUE: - # The new value 2^256-1 is guaranteed to be different from the initial value. + # The new value 2^256-1 is guaranteed to be different from the initial + # value. execution_code_body = Op.SSTORE(Op.DUP2, Op.NOT(0)) loop_cost += gas_costs.G_VERY_LOW * 3 elif storage_action == StorageAction.READ: @@ -336,8 +345,9 @@ def test_worst_storage_access_cold( condition=Op.PUSH1(1) + Op.SWAP1 + Op.SUB + Op.DUP1 + Op.ISZERO + Op.ISZERO, ) - # To create the contract, we apply the slots_init code to initialize the storage slots - # (int the case of absent_slots=False) and then copy the execution code to the contract. + # To create the contract, we apply the slots_init code to initialize the + # storage slots (int the case of absent_slots=False) and then copy the + # execution code to the contract. creation_code = ( slots_init + Op.EXTCODECOPY( @@ -393,7 +403,9 @@ def test_worst_storage_access_warm( env: Environment, gas_benchmark_value: int, ): - """Test running a block with as many warm storage slot accesses as possible.""" + """ + Test running a block with as many warm storage slot accesses as possible. + """ attack_gas_limit = gas_benchmark_value blocks = [] @@ -455,7 +467,10 @@ def test_worst_blockhash( pre: Alloc, gas_benchmark_value: int, ): - """Test running a block with as many blockhash accessing oldest allowed block as possible.""" + """ + Test running a block with as many blockhash accessing oldest allowed block + as possible. + """ # Create 256 dummy blocks to fill the blockhash window. blocks = [Block()] * 256 @@ -560,7 +575,10 @@ def test_worst_selfdestruct_existing( env: Environment, gas_benchmark_value: int, ): - """Test running a block with as many SELFDESTRUCTs as possible for existing contracts.""" + """ + Test running a block with as many SELFDESTRUCTs as possible for existing + contracts. + """ attack_gas_limit = gas_benchmark_value fee_recipient = pre.fund_eoa(amount=1) @@ -574,12 +592,14 @@ def test_worst_selfdestruct_existing( ) + Op.RETURN(0, Op.EXTCODESIZE(selfdestructable_contract_addr)) initcode_address = pre.deploy_contract(code=initcode) - # Calculate the number of contracts that can be deployed with the available gas. + # Calculate the number of contracts that can be deployed with the available + # gas. gas_costs = fork.gas_costs() intrinsic_gas_cost_calc = fork.transaction_intrinsic_cost_calculator() loop_cost = ( gas_costs.G_KECCAK_256 # KECCAK static cost - + math.ceil(85 / 32) * gas_costs.G_KECCAK_256_WORD # KECCAK dynamic cost for CREATE2 + + math.ceil(85 / 32) * gas_costs.G_KECCAK_256_WORD # KECCAK dynamic + # cost for CREATE2 + gas_costs.G_VERY_LOW * 3 # ~MSTOREs+ADDs + gas_costs.G_COLD_ACCOUNT_ACCESS # CALL to self-destructing contract + gas_costs.G_SELF_DESTRUCT @@ -598,9 +618,9 @@ def test_worst_selfdestruct_existing( num_contracts = (attack_gas_limit - base_costs) // loop_cost expected_benchmark_gas_used = num_contracts * loop_cost + base_costs - # Create a factory that deployes a new SELFDESTRUCT contract instance pre-funded depending on - # the value_bearing parameter. We use CREATE2 so the caller contract can easily reproduce - # the addresses in a loop for CALLs. + # Create a factory that deployes a new SELFDESTRUCT contract instance pre- + # funded depending on the value_bearing parameter. We use CREATE2 so the + # caller contract can easily reproduce the addresses in a loop for CALLs. factory_code = ( Op.EXTCODECOPY( address=initcode_address, @@ -621,7 +641,8 @@ def test_worst_selfdestruct_existing( + Op.RETURN(0, 32) ) - required_balance = num_contracts if value_bearing else 0 # 1 wei per contract + required_balance = num_contracts if value_bearing else 0 # 1 wei per + # contract factory_address = pre.deploy_contract(code=factory_code, balance=required_balance) factory_caller_code = Op.CALLDATALOAD(0) + While( @@ -648,8 +669,8 @@ def test_worst_selfdestruct_existing( + While( body=Op.POP(Op.CALL(address=Op.SHA3(32 - 20 - 1, 85))) + Op.MSTORE(32, Op.ADD(Op.MLOAD(32), 1)), - # Only loop if we have enough gas to cover another iteration plus the - # final storage gas. + # Only loop if we have enough gas to cover another iteration plus + # the final storage gas. condition=Op.GT(Op.GAS, final_storage_gas + loop_cost), ) + Op.SSTORE(0, 42) # Done for successful tx execution assertion below. @@ -700,8 +721,8 @@ def test_worst_selfdestruct_created( gas_benchmark_value: int, ): """ - Test running a block with as many SELFDESTRUCTs as possible for deployed contracts in - the same transaction. + Test running a block with as many SELFDESTRUCTs as possible for deployed + contracts in the same transaction. """ fee_recipient = pre.fund_eoa(amount=1) env.fee_recipient = fee_recipient @@ -779,7 +800,8 @@ def test_worst_selfdestruct_created( sender=pre.fund_eoa(), ) - post = {code_addr: Account(storage={0: 42})} # Check for successful execution. + post = {code_addr: Account(storage={0: 42})} # Check for successful + # execution. state_test( env=env, pre=pre, @@ -798,7 +820,10 @@ def test_worst_selfdestruct_initcode( env: Environment, gas_benchmark_value: int, ): - """Test running a block with as many SELFDESTRUCTs as possible executed in initcode.""" + """ + Test running a block with as many SELFDESTRUCTs as possible executed in + initcode. + """ fee_recipient = pre.fund_eoa(amount=1) env.fee_recipient = fee_recipient @@ -861,7 +886,8 @@ def test_worst_selfdestruct_initcode( sender=pre.fund_eoa(), ) - post = {code_addr: Account(storage={0: 42})} # Check for successful execution. + post = {code_addr: Account(storage={0: 42})} # Check for successful + # execution. state_test( env=env, pre=pre, diff --git a/tests/berlin/eip2929_gas_cost_increases/__init__.py b/tests/berlin/eip2929_gas_cost_increases/__init__.py index 9646b2063ca..9a9455074e7 100644 --- a/tests/berlin/eip2929_gas_cost_increases/__init__.py +++ b/tests/berlin/eip2929_gas_cost_increases/__init__.py @@ -1,4 +1,4 @@ """ -abstract: Tests [EIP-2929: Gas cost increases for state access opcodes](https://eips.ethereum.org/EIPS/eip-2929) - Test cases for [EIP-2929: Gas cost increases for state access opcodes](https://eips.ethereum.org/EIPS/eip-2929). -""" # noqa: E501 +abstract: Tests [EIP-2929: Gas cost increases for +state access opcodes](https://eips.ethereum.org/EIPS/eip-2929). +""" diff --git a/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py b/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py index 696f68b2d57..620cdedd4fb 100644 --- a/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py +++ b/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py @@ -1,7 +1,9 @@ """ -abstract: Tests [EIP-2929: Gas cost increases for state access opcodes](https://eips.ethereum.org/EIPS/eip-2929) - Test cases for [EIP-2929: Gas cost increases for state access opcodes](https://eips.ethereum.org/EIPS/eip-2929). -""" # noqa: E501 +abstract: Tests [EIP-2929: Gas cost increases for state access +opcodes](https://eips.ethereum.org/EIPS/eip-2929) Test cases for [EIP-2929: Gas +cost increases for state access +opcodes](https://eips.ethereum.org/EIPS/eip-2929). +""" from typing import Iterator, Tuple @@ -31,15 +33,15 @@ def precompile_addresses_in_predecessor_successor( fork: Fork, ) -> Iterator[Tuple[Address, bool, bool]]: """ - Yield the addresses of precompiled contracts and whether they existed in the parent fork. - - Args: - fork (Fork): The transition fork instance containing precompiled contract information. + Yield the addresses of precompiled contracts and whether they existed in + the parent fork. - Yields: - Iterator[Tuple[str, bool]]: A tuple containing the address in hexadecimal format and a - boolean indicating whether the address has existed in the predecessor. + Args: fork (Fork): The transition fork instance containing precompiled + contract information. + Yields: Iterator[Tuple[str, bool]]: A tuple containing the address in + hexadecimal format and a boolean indicating whether the address has existed + in the predecessor. """ precompile_range = range(0x01, 0x100) predecessor_precompiles = set(get_transition_fork_predecessor(fork).precompiles()) @@ -84,14 +86,12 @@ def test_precompile_warming( """ Call BALANCE of a precompile addresses before and after a fork. - According to EIP-2929, when a transaction begins, accessed_addresses is initialized to include: - - tx.sender, tx.to - - and the set of all precompiles - - This test verifies that: - 1. Precompiles that exist in the predecessor fork are always "warm" (lower gas cost) - 2. New precompiles added in a fork are "cold" before the fork and become "warm" after + According to EIP-2929, when a transaction begins, accessed_addresses is + initialized to include: - tx.sender, tx.to - and the set of all precompiles + This test verifies that: 1. Precompiles that exist in the predecessor fork + are always "warm" (lower gas cost) 2. New precompiles added in a fork are + "cold" before the fork and become "warm" after """ sender = pre.fund_eoa() call_cost_slot = 0 diff --git a/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py b/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py index 77ec323172e..f3bd1023f6c 100644 --- a/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py +++ b/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py @@ -1,6 +1,8 @@ """ -abstract: Tests [EIP-2930: Access list transaction](https://eips.ethereum.org/EIPS/eip-2930). -Original test by Ori: https://github.com/ethereum/tests/blob/v15.0/src/GeneralStateTestsFiller/stEIP1559/intrinsicGen.js. +abstract: Tests [EIP-2930: Access list +transaction](https://eips.ethereum.org/EIPS/eip-2930). Original test by Ori: +https://github.com/ethereum/tests/blob/v15.0/src/GeneralStateTestsFiller/stEIP1 +559/intrinsicGen.js. """ from typing import List @@ -163,7 +165,8 @@ def test_tx_intrinsic_gas( if data_floor_gas_cost > intrinsic_gas_cost: exception = TransactionException.INTRINSIC_GAS_BELOW_FLOOR_GAS_COST elif data_floor_gas_cost == intrinsic_gas_cost: - # Depending on the implementation, client might raise either exception. + # Depending on the implementation, client might raise either + # exception. exception = [ TransactionException.INTRINSIC_GAS_TOO_LOW, TransactionException.INTRINSIC_GAS_BELOW_FLOOR_GAS_COST, diff --git a/tests/byzantium/eip198_modexp_precompile/helpers.py b/tests/byzantium/eip198_modexp_precompile/helpers.py index 9cc44fd25a1..0bc073c2183 100644 --- a/tests/byzantium/eip198_modexp_precompile/helpers.py +++ b/tests/byzantium/eip198_modexp_precompile/helpers.py @@ -9,16 +9,14 @@ class ModExpInput(TestParameterGroup): """ - Helper class that defines the MODEXP precompile inputs and creates the - call data from them. - - Attributes: - base (str): The base value for the MODEXP precompile. - exponent (str): The exponent value for the MODEXP precompile. - modulus (str): The modulus value for the MODEXP precompile. - extra_data (str): Defines extra padded data to be added at the end of the calldata - to the precompile. Defaults to an empty string. - + Helper class that defines the MODEXP precompile inputs and creates the call + data from them. + + Attributes: base (str): The base value for the MODEXP precompile. exponent + (str): The exponent value for the MODEXP precompile. modulus (str): The + modulus value for the MODEXP precompile. extra_data (str): Defines extra + padded data to be added at the end of the calldata to the precompile. + Defaults to an empty string. """ base: Bytes @@ -133,11 +131,9 @@ class ModExpOutput(TestParameterGroup): """ Expected test result. - Attributes: - call_success (bool): The return_code from CALL, 0 indicates unsuccessful call - (out-of-gas), 1 indicates call succeeded. - returned_data (str): The output returnData is the expected output of the call - + Attributes: call_success (bool): The return_code from CALL, 0 indicates + unsuccessful call (out-of-gas), 1 indicates call succeeded. returned_data + (str): The output returnData is the expected output of the call """ call_success: bool = True diff --git a/tests/byzantium/eip198_modexp_precompile/test_modexp.py b/tests/byzantium/eip198_modexp_precompile/test_modexp.py index 859a73b8e19..f676324487f 100644 --- a/tests/byzantium/eip198_modexp_precompile/test_modexp.py +++ b/tests/byzantium/eip198_modexp_precompile/test_modexp.py @@ -1,7 +1,8 @@ """ -abstract: Test [EIP-198: MODEXP Precompile](https://eips.ethereum.org/EIPS/eip-198) - Tests the MODEXP precompile, located at address 0x0000..0005. Test cases from the EIP are - labelled with `EIP-198-caseX` in the test id. +abstract: Test [EIP-198: MODEXP +Precompile](https://eips.ethereum.org/EIPS/eip-198) Tests the MODEXP +precompile, located at address 0x0000..0005. Test cases from the EIP are +labelled with `EIP-198-caseX` in the test id. """ import pytest @@ -94,7 +95,8 @@ ), id="EIP-198-case2", ), - pytest.param( # Note: This is the only test case which goes out-of-gas. + pytest.param( # Note: This is the only test case which goes out-of- + # gas. Bytes( "0000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000000020" @@ -135,7 +137,8 @@ id="EIP-198-case5-raw-input", ), ], - ids=lambda param: param.__repr__(), # only required to remove parameter names (input/output) + ids=lambda param: param.__repr__(), # only required to remove parameter + # names (input/output) ) def test_modexp( state_test: StateTestFiller, @@ -153,17 +156,18 @@ def test_modexp( # Store the returned CALL status (success = 1, fail = 0) into slot 0: + Op.SSTORE( 0, - # Setup stack to CALL into ModExp with the CALLDATA and CALL into it (+ pop value) + # Setup stack to CALL into ModExp with the CALLDATA and CALL into + # it (+ pop value) Op.CALL(Op.GAS(), 0x05, 0, 0, Op.CALLDATASIZE(), 0, 0), ) - # Store contract deployment code to deploy the returned data from ModExp as - # contract code (16 bytes) + # Store contract deployment code to deploy the returned data from + # ModExp as contract code (16 bytes) + Op.MSTORE( 0, ( - # Need to `ljust` this PUSH32 in order to ensure the code starts - # in memory at offset 0 (memory right-aligns stack items which are not - # 32 bytes) + # Need to `ljust` this PUSH32 in order to ensure the code + # starts in memory at offset 0 (memory right-aligns stack items + # which are not 32 bytes) Op.PUSH32( bytes( Op.CODECOPY(0, 16, Op.SUB(Op.CODESIZE(), 16)) @@ -172,9 +176,11 @@ def test_modexp( ) ), ) - # RETURNDATACOPY the returned data from ModExp into memory (offset 16 bytes) + # RETURNDATACOPY the returned data from ModExp into memory (offset 16 + # bytes) + Op.RETURNDATACOPY(16, 0, Op.RETURNDATASIZE()) - # CREATE contract with the deployment code + the returned data from ModExp + # CREATE contract with the deployment code + the returned data from + # ModExp + Op.CREATE(0, 0, Op.ADD(16, Op.RETURNDATASIZE())) # STOP (handy for tracing) + Op.STOP(), diff --git a/tests/cancun/eip1153_tstore/__init__.py b/tests/cancun/eip1153_tstore/__init__.py index 1ef8a2efb71..23d17ac5e19 100644 --- a/tests/cancun/eip1153_tstore/__init__.py +++ b/tests/cancun/eip1153_tstore/__init__.py @@ -13,35 +13,26 @@ class PytestParameterEnum(Enum): """ Helper class for defining Pytest parameters used in test cases. - This class helps define enum `value`s as `pytest.param` objects that then can - be used to create a parametrize decorator that can be applied to tests, + This class helps define enum `value`s as `pytest.param` objects that then + can be used to create a parametrize decorator that can be applied to tests, for example, - ```python - @TStorageCallContextTestCases.parametrize() - def test_function(test_value): - pass - ``` + ```python @TStorageCallContextTestCases.parametrize() def + test_function(test_value): pass ``` - Classes which derive from this class must define each test case as a different enum - field with a dictionary as value. + Classes which derive from this class must define each test case as a + different enum field with a dictionary as value. - The dictionary must contain: - i. A `description` key with a string value describing the test case. - ii. (Optional) A `pytest_marks` key with a single mark or list of pytest - marks to apply to the test case. For example, + The dictionary must contain: i. A `description` key with a string value + describing the test case. ii. (Optional) A `pytest_marks` key with a single + mark or list of pytest marks to apply to the test case. For example, - ``` - pytest_marks=pytest.mark.xfail - ``` - or + ``` pytest_marks=pytest.mark.xfail ``` or - ``` - pytest_marks=[pytest.mark.xfail, pytest.mark.skipif] - ``` - iii. (Optional) An `id` key with the name of the test. + ``` pytest_marks=[pytest.mark.xfail, pytest.mark.skipif] ``` iii. + (Optional) An `id` key with the name of the test. - The rest of the keys in the dictionary are the parameters of the test case. + The rest of the keys in the dictionary are the parameters of the test case. The test case ID is set as the enum name converted to lowercase. """ @@ -67,11 +58,15 @@ def param(self, names: List[str]): @classmethod def special_keywords(cls) -> List[str]: - """Return the special dictionary keywords that are not test parameters.""" + """ + Return the special dictionary keywords that are not test parameters. + """ return ["description", "pytest_marks", "pytest_id"] def names(self) -> List[str]: - """Return the names of all the parameters included in the enum value dict.""" + """ + Return the names of all the parameters included in the enum value dict. + """ return sorted([k for k in self._value_.keys() if k not in self.special_keywords()]) @property diff --git a/tests/cancun/eip1153_tstore/test_tload_calls.py b/tests/cancun/eip1153_tstore/test_tload_calls.py index 27837bc797c..8fa7880904d 100644 --- a/tests/cancun/eip1153_tstore/test_tload_calls.py +++ b/tests/cancun/eip1153_tstore/test_tload_calls.py @@ -1,7 +1,4 @@ -""" -Ethereum Transient Storage EIP Tests -https://eips.ethereum.org/EIPS/eip-1153. -""" +"""Ethereum Transient Storage EIP Tests https://eips.ethereum.org/EIPS/eip-1153.""" import pytest @@ -26,11 +23,11 @@ def test_tload_calls(state_test: StateTestFiller, pre: Alloc, call_type: Op): """ Ported .json vectors. - (04_tloadAfterCallFiller.yml) - Loading a slot after a call to another contract is 0. + (04_tloadAfterCallFiller.yml) Loading a slot after a call to another + contract is 0. - (12_tloadDelegateCallFiller.yml) - delegatecall reads transient storage in the context of the current address + (12_tloadDelegateCallFiller.yml) delegatecall reads transient storage in + the context of the current address """ # Storage variables slot_a_tload_after_subcall_result = 0 @@ -71,10 +68,12 @@ def make_call(call_type: Op, address: Address) -> Bytecode: post = { address_to: Account( storage={ - # other calls don't change context, there for tload updated in this account + # other calls don't change context, there for tload updated in + # this account slot_a_tload_after_subcall_result: 10 if call_type == Op.CALL else 20, slot_a_subcall_result: 1, - # since context unchanged the subcall works as if continued execution + # since context unchanged the subcall works as if continued + # execution slot_b_subcall_tload_result: 0 if call_type == Op.CALL else 10, slot_b_subcall_updated_tload_result: 0 if call_type == Op.CALL else 20, } diff --git a/tests/cancun/eip1153_tstore/test_tload_reentrancy.py b/tests/cancun/eip1153_tstore/test_tload_reentrancy.py index 4d66ea5115c..708a2a7ddef 100644 --- a/tests/cancun/eip1153_tstore/test_tload_reentrancy.py +++ b/tests/cancun/eip1153_tstore/test_tload_reentrancy.py @@ -1,7 +1,4 @@ -""" -Ethereum Transient Storage EIP Tests -https://eips.ethereum.org/EIPS/eip-1153. -""" +"""Ethereum Transient Storage EIP Tests https://eips.ethereum.org/EIPS/eip-1153.""" from enum import Enum @@ -53,8 +50,8 @@ def test_tload_reentrancy( """ Ported .json vectors. - (05_tloadReentrancyFiller.yml) - Reentrant calls access the same transient storage + (05_tloadReentrancyFiller.yml) Reentrant calls access the same transient + storage """ tload_value = 44 empty_value = 0 @@ -138,7 +135,8 @@ def make_call(call_type: Op) -> Bytecode: slot_tload_in_subcall_result: ( 0xFF # if call OOG, we fail to obtain the result if call_return == Om.OOG - # else delegate and callcode are working in the same context so tload works + # else delegate and callcode are working in the same + # context so tload works else ( tload_value if call_type == Op.DELEGATECALL or call_type == Op.CALLCODE diff --git a/tests/cancun/eip1153_tstore/test_tstorage.py b/tests/cancun/eip1153_tstore/test_tstorage.py index 990cd804e3f..5b25168eafe 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage.py +++ b/tests/cancun/eip1153_tstore/test_tstorage.py @@ -1,9 +1,13 @@ """ -abstract: Tests [EIP-1153: Transient Storage Opcodes](https://eips.ethereum.org/EIPS/eip-1153) - Test [EIP-1153: Transient Storage Opcodes](https://eips.ethereum.org/EIPS/eip-1153). Ports - and extends some tests from - [ethereum/tests/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage). -""" # noqa: E501 +abstract: Tests [EIP-1153: Transient Storage +Opcodes](https://eips.ethereum.org/EIPS/eip-1153). + +Ports and extends some tests from +[ethereum/tests/src/EIPTestsFiller/StateTests/ +stEIP1153-transientStorage/](https://github.com/ethereum/tests/blob/ +9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/ +StateTests/stEIP1153-transientStorage). +""" from enum import unique @@ -33,11 +37,15 @@ def test_transient_storage_unset_values(state_test: StateTestFiller, pre: Alloc): """ - Test that tload returns zero for unset values. Loading an arbitrary value is - 0 at beginning of transaction: TLOAD(x) is 0. - - Based on [ethereum/tests/.../01_tloadBeginningTxnFiller.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/01_tloadBeginningTxnFiller.yml)", - """ # noqa: E501 + Test that tload returns zero for unset values. Loading an arbitrary value + is 0 at beginning of transaction: TLOAD(x) is 0. + + Based on + [ethereum/tests/.../01_tloadBeginningTxnFiller.yml] + (https://github.com/ethereum/tests/blob/ + 9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/ + stEIP1153-transientStorage/01_tloadBeginningTxnFiller.yml)", + """ env = Environment() slots_under_test = [0, 1, 2, 2**128, 2**256 - 1] @@ -69,8 +77,12 @@ def test_tload_after_tstore(state_test: StateTestFiller, pre: Alloc): Loading after storing returns the stored value: TSTORE(x, y), TLOAD(x) returns y. - Based on [ethereum/tests/.../02_tloadAfterTstoreFiller.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/02_tloadAfterTstoreFiller.yml)", - """ # noqa: E501 + Based on + [ethereum/tests/.../02_tloadAfterTstoreFiller.yml] + (https://github.com/ethereum/tests/blob/ + 9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/ + stEIP1153-transientStorage/02_tloadAfterTstoreFiller.yml)", + """ env = Environment() slots_under_test = [0, 1, 2, 2**128, 2**256 - 1] @@ -103,8 +115,13 @@ def test_tload_after_sstore(state_test: StateTestFiller, pre: Alloc): Loading after storing returns the stored value: TSTORE(x, y), TLOAD(x) returns y. - Based on [ethereum/tests/.../18_tloadAfterStoreFiller.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/18_tloadAfterStoreFiller.yml)", - """ # noqa: E501 + Based on + [ethereum/tests/.../18_tloadAfterStoreFiller.yml] + (https://github.com/ethereum/tests/blob/ + 9b00b68593f5869eb51a6659e1cc983e875e616b/src/ + EIPTestsFiller/StateTests/stEIP1153-transientStorage/ + 18_tloadAfterStoreFiller.yml)", + """ env = Environment() slots_under_test = [1, 3, 2**128, 2**256 - 1] @@ -143,8 +160,12 @@ def test_tload_after_tstore_is_zero(state_test: StateTestFiller, pre: Alloc): """ Test that tload returns zero after tstore is called with zero. - Based on [ethereum/tests/.../03_tloadAfterStoreIs0Filler.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/03_tloadAfterStoreIs0Filler.yml)", - """ # noqa: E501 + Based on [ethereum/tests/.../03_tloadAfterStoreIs0Filler.yml] + (https://github.com/ethereum/tests/blob/ + 9b00b68593f5869eb51a6659e1cc983e875e616b/src/ + EIPTestsFiller/StateTests/ + stEIP1153-transientStorage/03_tloadAfterStoreIs0Filler.yml)", + """ env = Environment() slots_to_write = [1, 4, 2**128, 2**256 - 2] diff --git a/tests/cancun/eip1153_tstore/test_tstorage_clear_after_tx.py b/tests/cancun/eip1153_tstore/test_tstorage_clear_after_tx.py index 8cf988bd763..a1d71560696 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_clear_after_tx.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_clear_after_tx.py @@ -1,7 +1,4 @@ -""" -Ethereum Transient Storage EIP Tests -https://eips.ethereum.org/EIPS/eip-1153. -""" +"""Ethereum Transient Storage EIP Tests https://eips.ethereum.org/EIPS/eip-1153.""" from typing import Optional @@ -34,10 +31,10 @@ def test_tstore_clear_after_deployment_tx( evm_code_type: EVMCodeType, ): """ - First creates a contract, which TSTOREs a value 1 in slot 1. - After creating the contract, a new tx will call this contract, storing TLOAD(1) into slot 1. - The transient storage should be cleared after creating the contract (at tx-level), so - the storage should stay empty. + First creates a contract, which TSTOREs a value 1 in slot 1. After creating + the contract, a new tx will call this contract, storing TLOAD(1) into slot + 1. The transient storage should be cleared after creating the contract (at + tx-level), so the storage should stay empty. """ env = Environment() @@ -81,9 +78,9 @@ def test_tstore_clear_after_tx( pre: Alloc, ): """ - First SSTOREs the TLOAD value of key 1 in slot 1. Then, it TSTOREs 1 in slot 1. - The second tx will re-call the contract. The storage should stay empty, - because the transient storage is cleared after the transaction. + First SSTOREs the TLOAD value of key 1 in slot 1. Then, it TSTOREs 1 in + slot 1. The second tx will re-call the contract. The storage should stay + empty, because the transient storage is cleared after the transaction. """ env = Environment() diff --git a/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py index 5ce6c65c686..343bcee0166 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py @@ -1,7 +1,7 @@ """ -abstract: Tests for [EIP-1153: Transient Storage](https://eips.ethereum.org/EIPS/eip-1153) - Test cases for `TSTORE` and `TLOAD` opcode calls in contract initcode. -""" # noqa: E501 +abstract: Tests for [EIP-1153: Transient +Storage](https://eips.ethereum.org/EIPS/eip-1153). +""" from enum import unique @@ -32,8 +32,8 @@ @unique class InitcodeTestCases(PytestParameterEnum): """ - Defines test cases for transient storage opcode usage in contract constructor - and deployed code. + Defines test cases for transient storage opcode usage in contract + constructor and deployed code. """ ONLY_CONSTRUCTOR_CODE = { @@ -41,9 +41,11 @@ class InitcodeTestCases(PytestParameterEnum): "Test TLOAD and TSTORE behavior in contract constructor without deployed code" ), "constructor_code": ( - # test creator's transient storage inaccessible from constructor code + # test creator's transient storage inaccessible from constructor + # code Op.SSTORE(0, Op.TLOAD(0)) - # test constructor code can use its own transient storage & creator storage unaffected + # test constructor code can use its own transient storage & creator + # storage unaffected + Op.TSTORE(0, 1) + Op.SSTORE(1, Op.TLOAD(0)) ), @@ -53,13 +55,15 @@ class InitcodeTestCases(PytestParameterEnum): IN_CONSTRUCTOR_AND_DEPLOYED_CODE = { "description": "Test TLOAD and TSTORE behavior in contract constructor and deployed code", "constructor_code": ( - # test creator's transient storage inaccessible from constructor code + # test creator's transient storage inaccessible from constructor + # code Op.SSTORE(0, Op.TLOAD(0)) ), "deploy_code": ( # test creator's transient storage inaccessible from deployed code Op.SSTORE(1, Op.TLOAD(0)) - # test deploy code can use its own transient storage & creator storage unaffected + # test deploy code can use its own transient storage & creator + # storage unaffected + Op.TSTORE(1, 1) + Op.SSTORE(2, Op.TLOAD(1)) ), @@ -68,15 +72,18 @@ class InitcodeTestCases(PytestParameterEnum): ACROSS_CONSTRUCTOR_AND_DEPLOYED_CODE_V0 = { "description": ("Test TSTORE behavior across contract constructor and deploy code. "), "constructor_code": ( - # constructor code should be able to store its own transient storage + # constructor code should be able to store its own transient + # storage Op.TSTORE(1, 1) ), "deploy_code": ( # test creator's transient storage inaccessible from deployed code Op.SSTORE(0, Op.TLOAD(0)) - # test deploy code can use its own transient storage stored from constructor code + # test deploy code can use its own transient storage stored from + # constructor code + Op.SSTORE(1, Op.TLOAD(1)) - # test deploy code can use its own transient storage stored from deployed code + # test deploy code can use its own transient storage stored from + # deployed code + Op.TSTORE(2, 1) + Op.SSTORE(2, Op.TLOAD(2)) ), @@ -89,17 +96,19 @@ class InitcodeTestCases(PytestParameterEnum): "constructor_code": ( # test creator's transient storage inaccessible from constructor Op.SSTORE(0, Op.TLOAD(0)) - # constructor code should be able to use its own transient storage / creator storage - # unaffected + # constructor code should be able to use its own transient storage + # / creator storage unaffected + Op.TSTORE(1, 1) + Op.SSTORE(1, Op.TLOAD(1)) ), "deploy_code": ( # test creator's transient storage inaccessible from deployed code Op.SSTORE(2, Op.TLOAD(0)) - # test deploy code can use its own transient storage stored from constructor code + # test deploy code can use its own transient storage stored from + # constructor code + Op.SSTORE(3, Op.TLOAD(1)) - # test deploy code can use its own transient storage stored from deployed code + # test deploy code can use its own transient storage stored from + # deployed code + Op.TSTORE(2, 1) + Op.SSTORE(4, Op.TLOAD(2)) ), @@ -113,7 +122,8 @@ class InitcodeTestCases(PytestParameterEnum): "deploy_code": ( # test creator's transient storage inaccessible from deployed code Op.SSTORE(0, Op.TLOAD(0)) - # test deployed code can use its own transient storage & creator storage unaffected + # test deployed code can use its own transient storage & creator + # storage unaffected + Op.TSTORE(0, 1) + Op.SSTORE(1, Op.TLOAD(0)) ), @@ -125,11 +135,11 @@ class InitcodeTestCases(PytestParameterEnum): @InitcodeTestCases.parametrize() class TestTransientStorageInContractCreation: """ - Test transient storage in contract creation contexts. - - TSTORE/TLOAD in initcode should not be able to access the creator's transient storage. - - TSTORE/TLOAD in initcode should be able to access the created contract's transient - storage. - - TSTORE/TLOAD in creator contract should be able to use its own transient storage. + Test transient storage in contract creation contexts. - TSTORE/TLOAD in + initcode should not be able to access the creator's transient storage. - + TSTORE/TLOAD in initcode should be able to access the created contract's + transient storage. - TSTORE/TLOAD in creator contract should be able to use + its own transient storage. """ @pytest.fixture() @@ -165,8 +175,8 @@ def creator_contract_code( # noqa: D102 ) ), ) - # Save the state of transient storage following call to storage; the transient - # storage should not have been overwritten + # Save the state of transient storage following call to storage; + # the transient storage should not have been overwritten + Op.SSTORE(0, Op.TLOAD(0)) + Op.SSTORE(1, Op.TLOAD(1)) + Op.SSTORE(2, Op.TLOAD(2)) diff --git a/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py index 99c83f05566..4e5943d6cc7 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py @@ -1,7 +1,7 @@ """ -abstract: Tests for [EIP-1153: Transient Storage](https://eips.ethereum.org/EIPS/eip-1153) - Test cases for `TSTORE` and `TLOAD` opcode calls in different execution contexts. -""" # noqa: E501 +abstract: Tests for [EIP-1153: Transient +Storage](https://eips.ethereum.org/EIPS/eip-1153). +""" from enum import EnumMeta, unique from typing import Dict, Mapping @@ -33,9 +33,9 @@ class DynamicCallContextTestCases(EnumMeta): """ - Create dynamic transient storage test cases for contract sub-calls - using CALLCODE and DELEGATECALL (these opcodes share the same - signatures and test cases). + Create dynamic transient storage test cases for contract sub-calls using + CALLCODE and DELEGATECALL (these opcodes share the same signatures and test + cases). """ def __new__(cls, name, bases, classdict): # noqa: D102 @@ -258,14 +258,16 @@ class CallContextTestCases(PytestParameterEnum, metaclass=DynamicCallContextTest + Op.SSTORE(1, Op.TLOAD(0)) + Op.STOP ), - "callee_bytecode": Op.TSTORE(0, unchecked=True) # calling with stack underflow still fails + "callee_bytecode": Op.TSTORE(0, unchecked=True) # calling with stack + # underflow still + # fails + Op.STOP, "expected_caller_storage": {0: 0, 1: 420}, "expected_callee_storage": {}, } STATICCALL_CAN_CALL_TLOAD = { - # TODO: Not a very useful test; consider removing after implementing ethereum/tests - # staticcall tests + # TODO: Not a very useful test; consider removing after implementing + # ethereum/tests staticcall tests "pytest_id": "staticcalled_context_can_call_tload", "description": ("A STATICCALL callee can not use transient storage."), "caller_bytecode": ( @@ -274,7 +276,8 @@ class CallContextTestCases(PytestParameterEnum, metaclass=DynamicCallContextTest + Op.SSTORE(1, Op.TLOAD(0)) + Op.STOP ), - "callee_bytecode": Op.TLOAD(0) + Op.STOP, # calling tload does not cause the call to fail + "callee_bytecode": Op.TLOAD(0) + Op.STOP, # calling tload does not + # cause the call to fail "expected_caller_storage": {0: 1, 1: 420}, "expected_callee_storage": {}, } @@ -337,9 +340,6 @@ def test_subcall( """ Test transient storage with a subcall using the following opcodes. - - `CALL` - - `CALLCODE` - - `DELEGATECALL` - - `STATICCALL` + - `CALL` - `CALLCODE` - `DELEGATECALL` - `STATICCALL` """ state_test(env=env, pre=pre, post=post, tx=tx) diff --git a/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py index 18fed8cea93..c8fdfdcb4eb 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py @@ -1,7 +1,7 @@ """ -abstract: Tests for [EIP-1153: Transient Storage](https://eips.ethereum.org/EIPS/eip-1153) - Test cases for `TSTORE` and `TLOAD` opcode calls in reentrancy contexts. -""" # noqa: E501 +abstract: Tests for [EIP-1153: Transient +Storage](https://eips.ethereum.org/EIPS/eip-1153). +""" from enum import EnumMeta, unique from typing import Dict @@ -59,11 +59,15 @@ def __new__(cls, name, bases, classdict): # noqa: D102 classdict[f"TSTORE_BEFORE_{opcode._name_}_HAS_NO_EFFECT"] = { "description": ( - f"{opcode._name_} undoes the transient storage write from the failed call: " - f"TSTORE(x, y), CALL(self, ...), TSTORE(x, z), {opcode._name_}, TLOAD(x) " - "returns y." - "", - "Based on [ethereum/tests/.../08_revertUndoesTransientStoreFiller.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/08_revertUndoesTransientStoreFiller.yml)", # noqa: E501 + f"{opcode._name_} undoes the transient storage write " + "from the failed call: " + "TSTORE(x, y), CALL(self, ...), TSTORE(x, z), " + f"{opcode._name_}, TLOAD(x) returns y.", + "Based on [ethereum/tests/.../08_revertUndoes" + "TransientStoreFiller.yml](https://github.com/ethereum/" + "tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src" + "/EIPTestsFiller/StateTests/stEIP1153-transientStorage/" + "08_revertUndoesTransientStoreFiller.yml)", ), "bytecode": Conditional( condition=SETUP_CONDITION, @@ -84,8 +88,9 @@ def __new__(cls, name, bases, classdict): # noqa: D102 classdict[f"{opcode._name_}_UNDOES_ALL"] = { "description": ( - f"{opcode._name_} undoes all the transient storage writes to the same key ", - "from a failed call. TSTORE(x, y), CALL(self, ...), TSTORE(x, z), ", + f"{opcode._name_} undoes all the transient storage writes " + "to the same key from a failed call. ", + "TSTORE(x, y), CALL(self, ...), TSTORE(x, z), ", f"TSTORE(x, z + 1) {opcode._name_}, TLOAD(x) returns y.", "", "Based on [ethereum/tests/.../09_revertUndoesAllFiller.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/09_revertUndoesAllFiller.yml).", # noqa: E501 @@ -106,7 +111,8 @@ def __new__(cls, name, bases, classdict): # noqa: D102 ), # reenter if_false=( - # store twice and revert/invalid; none of the stores should take effect + # store twice and revert/invalid; none of the stores + # should take effect Op.TSTORE(0xFE, 0x201) + Op.TSTORE(0xFE, 0x202) + Op.TSTORE(0xFF, 0x201) @@ -128,11 +134,17 @@ def __new__(cls, name, bases, classdict): # noqa: D102 classdict[f"{opcode._name_}_UNDOES_TSTORAGE_AFTER_SUCCESSFUL_CALL"] = { "description": ( - f"{opcode._name_} undoes transient storage writes from inner calls that " - "successfully returned. TSTORE(x, y), CALL(self, ...), CALL(self, ...), " - f"TSTORE(x, y + 1), RETURN, {opcode._name_}, TLOAD(x) returns y." - "", - "Based on [ethereum/tests/.../10_revertUndoesStoreAfterReturnFiller.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/10_revertUndoesStoreAfterReturnFiller.yml).", # noqa: E501 + f"{opcode._name_} undoes transient storage writes from " + "inner calls that successfully returned. " + "TSTORE(x, y), CALL(self, ...), CALL(self, ...), " + f"TSTORE(x, y + 1), RETURN, {opcode._name_}, TLOAD(x) " + "returns y.", + "Based on [ethereum/tests/.../" + "10_revertUndoesStoreAfterReturnFiller.yml]" + "(https://github.com/ethereum/tests/blob/" + "9b00b68593f5869eb51a6659e1cc983e875e616b/src/" + "EIPTestsFiller/StateTests/stEIP1153-transientStorage/" + "10_revertUndoesStoreAfterReturnFiller.yml).", ), "bytecode": Switch( default_action=( # setup; make first reentrant sub-call @@ -149,11 +161,13 @@ def __new__(cls, name, bases, classdict): # noqa: D102 ret_size=32, ), ) - + Op.SSTORE(1, Op.MLOAD(32)) # should be 1 (successful call) + + Op.SSTORE(1, Op.MLOAD(32)) # should be 1 (successful + # call) + Op.SSTORE(3, Op.TLOAD(0xFF)) ), cases=[ - # the first, reentrant call, which reverts/receives invalid + # the first, reentrant call, which reverts/receives + # invalid CalldataCase( value=2, action=( @@ -162,7 +176,8 @@ def __new__(cls, name, bases, classdict): # noqa: D102 + opcode_call ), ), - # the second, reentrant call, which returns successfully + # the second, reentrant call, which returns + # successfully CalldataCase( value=3, action=Op.TSTORE(0xFF, 0x101), @@ -184,7 +199,10 @@ class ReentrancyTestCases(PytestParameterEnum, metaclass=DynamicReentrancyTestCa "Reentrant calls access the same transient storage: " "TSTORE(x, y), CALL(self, ...), TLOAD(x) returns y." "" - "Based on [ethereum/tests/.../05_tloadReentrancyFiller.yml](https://github.com/ethereum/tests/tree/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage).", # noqa: E501 + "Based on [ethereum/tests/.../05_tloadReentrancyFiller.yml]" + "(https://github.com/ethereum/tests/tree/" + "9b00b68593f5869eb51a6659e1cc983e875e616b/src/" + "EIPTestsFiller/StateTests/stEIP1153-transientStorage).", ), "bytecode": Conditional( condition=SETUP_CONDITION, @@ -197,10 +215,16 @@ class ReentrancyTestCases(PytestParameterEnum, metaclass=DynamicReentrancyTestCa } TLOAD_AFTER_REENTRANT_TSTORE = { "description": ( - "Successfully returned calls do not revert transient storage writes: " - "TSTORE(x, y), CALL(self, ...), TSTORE(x, z), RETURN, TLOAD(x) returns z." - "" - "Based on [ethereum/tests/.../07_tloadAfterReentrancyStoreFiller.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/07_tloadAfterReentrancyStoreFiller.yml).", # noqa: E501 + "Successfully returned calls do not revert transient " + "storage writes: " + "TSTORE(x, y), CALL(self, ...), TSTORE(x, z), RETURN, TLOAD(x) " + "returns z." + "Based on [ethereum/tests/.../" + "07_tloadAfterReentrancyStoreFiller.yml](https://github.com/" + "ethereum/tests/blob/" + "9b00b68593f5869eb51a6659e1cc983e875e616b/src/" + "EIPTestsFiller/StateTests/stEIP1153-transientStorage/" + "07_tloadAfterReentrancyStoreFiller.yml).", ), "bytecode": Conditional( condition=SETUP_CONDITION, @@ -209,7 +233,8 @@ class ReentrancyTestCases(PytestParameterEnum, metaclass=DynamicReentrancyTestCa Op.TSTORE(0xFF, 0x100) + Op.SSTORE(1, Op.TLOAD(0xFF)) + REENTRANT_CALL - + Op.SSTORE(2, Op.TLOAD(0xFF)) # test value updated during reentrant call + + Op.SSTORE(2, Op.TLOAD(0xFF)) # test value updated during + # reentrant call ), # reenter if_false=Op.TSTORE(0xFF, 0x101), @@ -221,7 +246,11 @@ class ReentrancyTestCases(PytestParameterEnum, metaclass=DynamicReentrancyTestCa "Reentrant calls can manipulate the same transient storage: " "TSTORE(x, y), CALL(self, ...), TSTORE(x, z), TLOAD(x) returns z." "" - "Based on [ethereum/tests/.../06_tstoreInReentrancyCallFiller.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/06_tstoreInReentrancyCallFiller.yml).", # noqa: E501 + "Based on [ethereum/tests/.../06_tstoreInReentrancyCallFiller.yml]" + "(https://github.com/ethereum/tests/blob/" + "9b00b68593f5869eb51a6659e1cc983e875e616b/src/" + "EIPTestsFiller/StateTests/stEIP1153-transientStorage/" + "06_tstoreInReentrancyCallFiller.yml).", ), "bytecode": Conditional( condition=SETUP_CONDITION, @@ -230,7 +259,8 @@ class ReentrancyTestCases(PytestParameterEnum, metaclass=DynamicReentrancyTestCa Op.TSTORE(0xFF, 0x100) + Op.SSTORE(1, Op.TLOAD(0xFF)) + REENTRANT_CALL - + Op.SSTORE(3, Op.TLOAD(0xFF)) # test value updated during reentrant call + + Op.SSTORE(3, Op.TLOAD(0xFF)) # test value updated during + # reentrant call ), # reenter if_false=Op.TSTORE(0xFF, 0x101) + Op.SSTORE(2, Op.TLOAD(0xFF)), @@ -239,9 +269,16 @@ class ReentrancyTestCases(PytestParameterEnum, metaclass=DynamicReentrancyTestCa } TSTORE_IN_CALL_THEN_TLOAD_RETURN_IN_STATICCALL = { "description": ( - "A reentrant call followed by a reentrant subcall can call tload correctly: " - "TSTORE(x, y), CALL(self, ...), STATICCALL(self, ...), TLOAD(x), RETURN returns y." - "Based on [ethereum/tests/.../10_revertUndoesStoreAfterReturnFiller.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/10_revertUndoesStoreAfterReturnFiller.yml).", # noqa: E501 + "A reentrant call followed by a reentrant subcall can " + "call tload correctly: " + "TSTORE(x, y), CALL(self, ...), STATICCALL(self, ...), " + "TLOAD(x), RETURN returns y." + "Based on [ethereum/tests/.../" + "10_revertUndoesStoreAfterReturnFiller.yml]" + "(https://github.com/ethereum/tests/blob/" + "9b00b68593f5869eb51a6659e1cc983e875e616b/src/" + "EIPTestsFiller/StateTests/stEIP1153-transientStorage/" + "10_revertUndoesStoreAfterReturnFiller.yml).", ), "bytecode": Switch( default_action=( # setup; make first reentrant sub-call @@ -252,7 +289,8 @@ class ReentrancyTestCases(PytestParameterEnum, metaclass=DynamicReentrancyTestCa + Op.SSTORE(4, Op.TLOAD(0xFE)) ), cases=[ - # the first, reentrant call which calls tstore and a further reentrant staticcall + # the first, reentrant call which calls tstore and a further + # reentrant staticcall CalldataCase( value=2, action=( @@ -264,7 +302,8 @@ class ReentrancyTestCases(PytestParameterEnum, metaclass=DynamicReentrancyTestCa + Op.SSTORE(3, Op.MLOAD(0)) ), ), - # the second, reentrant call, which calls tload and return returns successfully + # the second, reentrant call, which calls tload and return + # returns successfully CalldataCase( value=3, action=Op.MSTORE(0, Op.TLOAD(0xFE)) + Op.RETURN(0, 32), diff --git a/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py b/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py index fadd9fde032..16d2f23986a 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py @@ -1,8 +1,11 @@ """ -abstract: Tests for [EIP-1153: Transient Storage](https://eips.ethereum.org/EIPS/eip-1153) - Test cases for `TSTORE` and `TLOAD` opcode calls in reentrancy after self-destruct, taking into - account the changes in EIP-6780. -""" # noqa: E501 +abstract: Tests for [EIP-1153: Transient +Storage](https://eips.ethereum.org/EIPS/eip-1153). + +Test cases for `TSTORE` and +`TLOAD` opcode calls in reentrancy after self-destruct, taking into account +the changes in EIP-6780. +""" from enum import unique from typing import Dict @@ -36,7 +39,10 @@ def call_option(option_number: int) -> Bytecode: - """Return the bytecode for a call to the callee contract with the given option number.""" + """ + Return the bytecode for a call to the callee contract with the given option + number. + """ return Op.MSTORE(value=option_number) + Op.CALL( address=Op.SLOAD(0), args_offset=0, @@ -49,8 +55,8 @@ def call_option(option_number: int) -> Bytecode: @unique class SelfDestructCases(PytestParameterEnum): """ - Transient storage test cases for different reentrancy calls which involve the contract - self-destructing. + Transient storage test cases for different reentrancy calls which involve + the contract self-destructing. """ TLOAD_AFTER_SELFDESTRUCT_PRE_EXISTING_CONTRACT = { @@ -225,7 +231,10 @@ def test_reentrant_selfdestructing_call( callee_bytecode: Bytecode, expected_storage: Dict, ): - """Test transient storage in different reentrancy contexts after selfdestructing.""" + """ + Test transient storage in different reentrancy contexts after + selfdestructing. + """ env = Environment() caller_address = pre.deploy_contract(code=caller_bytecode) diff --git a/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py b/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py index 30d200b4fb6..516ea9ded7f 100644 --- a/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py +++ b/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py @@ -1,7 +1,4 @@ -""" -Ethereum Transient Storage EIP Tests -https://eips.ethereum.org/EIPS/eip-1153. -""" +"""Ethereum Transient Storage EIP Tests https://eips.ethereum.org/EIPS/eip-1153.""" from enum import Enum @@ -59,26 +56,26 @@ def test_tstore_reentrancy( """ Ported .json vectors. - (06_tstoreInReentrancyCallFiller.yml) - Reentrant calls access the same transient storage + (06_tstoreInReentrancyCallFiller.yml) Reentrant calls access the same + transient storage - (07_tloadAfterReentrancyStoreFiller.yml) - Successfully returned calls do not revert transient storage writes + (07_tloadAfterReentrancyStoreFiller.yml) Successfully returned calls do not + revert transient storage writes - (08_revertUndoesTransientStoreFiller.yml) - Revert undoes the transient storage writes from a call. + (08_revertUndoesTransientStoreFiller.yml) Revert undoes the transient + storage writes from a call. - (09_revertUndoesAllFiller.yml) - Revert undoes all the transient storage writes to the same key from the failed call. + (09_revertUndoesAllFiller.yml) Revert undoes all the transient storage + writes to the same key from the failed call. - (11_tstoreDelegateCallFiller.yml) - delegatecall manipulates transient storage in the context of the current address. + (11_tstoreDelegateCallFiller.yml) delegatecall manipulates transient + storage in the context of the current address. - (13_tloadStaticCallFiller.yml) - Transient storage cannot be manipulated in a static context, tstore reverts + (13_tloadStaticCallFiller.yml) Transient storage cannot be manipulated in a + static context, tstore reverts - (20_oogUndoesTransientStoreInCallFiller.yml) - Out of gas undoes the transient storage writes from a call. + (20_oogUndoesTransientStoreInCallFiller.yml) Out of gas undoes the + transient storage writes from a call. """ tload_value_set_before_call = 80 tload_value_set_in_call = 90 @@ -200,7 +197,8 @@ def make_call(call_type: Op) -> Bytecode: if call_type == Op.STATICCALL or call_return == Om.OOG else tload_value_set_in_call ), - # external tstore overrides value in upper level only in delegate and callcode + # external tstore overrides value in upper level only in + # delegate and callcode slot_tload_after_call: ( tload_value_set_in_call if on_successful_delegate_or_callcode @@ -208,7 +206,8 @@ def make_call(call_type: Op) -> Bytecode: ), slot_tload_1_after_call: 12 if on_successful_delegate_or_callcode else 0, slot_tstore_overwrite: 50, - # tstore in static call not allowed, reentrancy means external call here + # tstore in static call not allowed, reentrancy means + # external call here slot_subcall_worked: 0 if on_failing_calls else 1, } ) diff --git a/tests/cancun/eip4788_beacon_root/conftest.py b/tests/cancun/eip4788_beacon_root/conftest.py index 3a28b279ce5..12497eead19 100644 --- a/tests/cancun/eip4788_beacon_root/conftest.py +++ b/tests/cancun/eip4788_beacon_root/conftest.py @@ -34,7 +34,10 @@ def timestamp() -> int: # noqa: D103 @pytest.fixture def beacon_roots() -> Iterator[bytes]: - """By default, return an iterator that returns the keccak of an internal counter.""" + """ + By default, return an iterator that returns the keccak of an internal + counter. + """ class BeaconRoots: def __init__(self) -> None: @@ -97,7 +100,8 @@ def contract_call_code(call_type: Op, call_value: int, call_gas: int) -> Bytecod if call_type == Op.CALL or call_type == Op.CALLCODE: contract_call_code += Op.SSTORE( 0x00, # store the result of the contract call in storage[0] - call_type( # type: ignore # https://github.com/ethereum/execution-spec-tests/issues/348 # noqa: E501 + # https://github.com/ethereum/execution-spec-tests/issues/348 + call_type( # type: ignore call_gas, Spec.BEACON_ROOTS_ADDRESS, call_value, @@ -111,7 +115,8 @@ def contract_call_code(call_type: Op, call_value: int, call_gas: int) -> Bytecod # delegatecall and staticcall use one less argument contract_call_code += Op.SSTORE( 0x00, - call_type( # type: ignore # https://github.com/ethereum/execution-spec-tests/issues/348 # noqa: E501 + # https://github.com/ethereum/execution-spec-tests/issues/348 + call_type( # type: ignore call_gas, Spec.BEACON_ROOTS_ADDRESS, args_start, @@ -181,7 +186,9 @@ def auto_access_list() -> bool: @pytest.fixture def access_list(auto_access_list: bool, timestamp: int) -> List[AccessList]: - """Access list included in the transaction to call the beacon root contract.""" + """ + Access list included in the transaction to call the beacon root contract. + """ if auto_access_list: return [ AccessList( @@ -204,7 +211,8 @@ def tx_data(timestamp: int) -> bytes: @pytest.fixture def tx_type() -> int: """ - Transaction type to call the caller contract or the beacon root contract directly. + Transaction type to call the caller contract or the beacon root contract + directly. By default use a type 2 transaction. """ @@ -263,8 +271,8 @@ def post( call_beacon_root_contract: bool, ) -> Dict: """ - Prepare expected post state for a single contract call based upon the success or - failure of the call, and the validity of the timestamp input. + Prepare expected post state for a single contract call based upon the + success or failure of the call, and the validity of the timestamp input. """ storage = Storage() if not call_beacon_root_contract: diff --git a/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py b/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py index 69db3d19ab6..b26294bc6cd 100644 --- a/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py +++ b/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py @@ -1,21 +1,20 @@ """ -abstract: Tests beacon block root for [EIP-4788: Beacon block root in the EVM](https://eips.ethereum.org/EIPS/eip-4788) - Test the exposed beacon chain root in the EVM for [EIP-4788: Beacon block root in the EVM](https://eips.ethereum.org/EIPS/eip-4788). +abstract: Tests beacon block root for [EIP-4788: Beacon block root in the +EVM](https://eips.ethereum.org/EIPS/eip-4788). -note: Adding a new test - Add a function that is named `test_` and takes at least the following arguments: +Note: Adding a new test Add a function that is named `test_` and +takes at least the following arguments: - - state_test - - env - - pre - - tx - - post - - valid_call +- state_test +- env +- pre +- tx +- post +- valid_call - All other `pytest.fixtures` can be parametrized to generate new combinations and test - cases. - -""" # noqa: E501 +All other `pytest.fixtures` can be parametrized to generate new combinations +and test cases. +""" from itertools import count from typing import Callable, Dict, Iterator, List @@ -44,7 +43,10 @@ def count_factory(start: int, step: int = 1) -> Callable[[], Iterator[int]]: - """Create a factory that returns fresh count iterators to avoid state persistence.""" + """ + Create a factory that returns fresh count iterators to avoid state + persistence. + """ return lambda: count(start, step) @@ -80,20 +82,15 @@ def test_beacon_root_contract_calls( post: Dict, ): """ - Tests the beacon root contract call using various call contexts: - - `CALL` - - `DELEGATECALL` - - `CALLCODE` - - `STATICCALL` - for different call gas amounts: - - exact gas (valid call) - - extra gas (valid call) - - insufficient gas (invalid call). - - The expected result is that the contract call will be executed if the gas amount is met - and return the correct`parent_beacon_block_root`. Otherwise the call will be invalid, and not - be executed. This is highlighted within storage by storing the return value of each call - context. + Tests the beacon root contract call using various call contexts: - `CALL` - + `DELEGATECALL` - `CALLCODE` - `STATICCALL` for different call gas amounts: + - exact gas (valid call) - extra gas (valid call) - insufficient gas + (invalid call). + + The expected result is that the contract call will be executed if the gas + amount is met and return the correct`parent_beacon_block_root`. Otherwise + the call will be invalid, and not be executed. This is highlighted within + storage by storing the return value of each call context. """ blockchain_test( pre=pre, @@ -153,11 +150,12 @@ def test_beacon_root_contract_timestamps( post: Dict, ): """ - Tests the beacon root contract call across for various valid and invalid timestamps. + Tests the beacon root contract call across for various valid and invalid + timestamps. The expected result is that the contract call will return the correct - `parent_beacon_block_root` for a valid input timestamp and return the zero'd 32 bytes value - for an invalid input timestamp. + `parent_beacon_block_root` for a valid input timestamp and return the + zero'd 32 bytes value for an invalid input timestamp. """ blockchain_test( pre=pre, @@ -187,7 +185,9 @@ def test_calldata_lengths( tx: Transaction, post: Dict, ): - """Tests the beacon root contract call using multiple invalid input lengths.""" + """ + Tests the beacon root contract call using multiple invalid input lengths. + """ blockchain_test( pre=pre, blocks=[Block(txs=[tx], parent_beacon_block_root=beacon_root, timestamp=timestamp)], @@ -216,10 +216,11 @@ def test_beacon_root_equal_to_timestamp( post: Dict, ): """ - Tests the beacon root contract call where the beacon root is equal to the timestamp. + Tests the beacon root contract call where the beacon root is equal to the + timestamp. - The expected result is that the contract call will return the `parent_beacon_block_root`, - as all timestamps used are valid. + The expected result is that the contract call will return the + `parent_beacon_block_root`, as all timestamps used are valid. """ blockchain_test( pre=pre, @@ -240,7 +241,10 @@ def test_tx_to_beacon_root_contract( tx: Transaction, post: Dict, ): - """Tests the beacon root contract using a transaction with different types and data lengths.""" + """ + Tests the beacon root contract using a transaction with different types and + data lengths. + """ blockchain_test( pre=pre, blocks=[Block(txs=[tx], parent_beacon_block_root=beacon_root, timestamp=timestamp)], @@ -266,8 +270,8 @@ def test_invalid_beacon_root_calldata_value( post: Dict, ): """ - Tests the beacon root contract call using invalid input values: - - zero calldata. + Tests the beacon root contract call using invalid input values: - zero + calldata. Contract should revert. """ @@ -288,7 +292,10 @@ def test_beacon_root_selfdestruct( tx: Transaction, post: Dict, ): - """Tests that self destructing the beacon root address transfers actors balance correctly.""" + """ + Tests that self destructing the beacon root address transfers actors + balance correctly. + """ # self destruct actor self_destruct_actor_address = pre.deploy_contract( Op.SELFDESTRUCT(Spec.BEACON_ROOTS_ADDRESS), @@ -373,17 +380,20 @@ def test_multi_block_beacon_root_timestamp_calls( call_value: int, ): """ - Tests multiple blocks where each block writes a timestamp to storage and contains one - transaction that calls the beacon root contract multiple times. + Tests multiple blocks where each block writes a timestamp to storage and + contains one transaction that calls the beacon root contract multiple + times. - The blocks might overwrite the historical roots buffer, or not, depending on the `timestamps`, - and whether they increment in multiples of `Spec.HISTORY_BUFFER_LENGTH` or not. + The blocks might overwrite the historical roots buffer, or not, depending + on the `timestamps`, and whether they increment in multiples of + `Spec.HISTORY_BUFFER_LENGTH` or not. By default, the beacon roots are the keccak of the block number. - Each transaction checks the current timestamp and also all previous timestamps, and verifies - that the beacon root is correct for all of them if the timestamp is supposed to be in the - buffer, which might have been overwritten by a later block. + Each transaction checks the current timestamp and also all previous + timestamps, and verifies that the beacon root is correct for all of them if + the timestamp is supposed to be in the buffer, which might have been + overwritten by a later block. """ # Create fresh iterator to avoid state persistence between test phases timestamps = timestamps_factory() @@ -415,9 +425,9 @@ def test_multi_block_beacon_root_timestamp_calls( current_call_account_code = Bytecode() current_call_account_expected_storage = Storage() - # We are going to call the beacon roots contract once for every timestamp of the current - # and all previous blocks, and check that the returned beacon root is still correct only - # if it was not overwritten. + # We are going to call the beacon roots contract once for every + # timestamp of the current and all previous blocks, and check that the + # returned beacon root is still correct only if it was not overwritten. for t in all_timestamps: current_call_account_code += Op.MSTORE(0, t) call_valid = ( @@ -462,7 +472,8 @@ def test_multi_block_beacon_root_timestamp_calls( parent_beacon_block_root=beacon_root, timestamp=timestamp, withdrawals=[ - # Also withdraw to the beacon root contract and the system address + # Also withdraw to the beacon root contract and the system + # address Withdrawal( address=Spec.BEACON_ROOTS_ADDRESS, amount=1, @@ -503,8 +514,9 @@ def test_beacon_root_transition( fork: Fork, ): """ - Tests the fork transition to cancun and verifies that blocks with timestamp lower than the - transition timestamp do not contain beacon roots in the pre-deployed contract. + Tests the fork transition to cancun and verifies that blocks with timestamp + lower than the transition timestamp do not contain beacon roots in the + pre-deployed contract. """ # Create fresh iterator to avoid state persistence between test phases timestamps = timestamps_factory() @@ -527,7 +539,8 @@ def test_beacon_root_transition( transitioned = fork.header_beacon_root_required(i, timestamp) if transitioned: - # We've transitioned, the current timestamp must contain a value in the contract + # We've transitioned, the current timestamp must contain a value in + # the contract timestamps_in_beacon_root_contract.append(timestamp) timestamps_storage[timestamp_index] = timestamp roots_storage[timestamp_index] = beacon_root @@ -539,9 +552,10 @@ def test_beacon_root_transition( current_call_account_code = Bytecode() current_call_account_expected_storage = Storage() - # We are going to call the beacon roots contract once for every timestamp of the current - # and all previous blocks, and check that the returned beacon root is correct only - # if it was after the transition timestamp. + # We are going to call the beacon roots contract once for every + # timestamp of the current and all previous blocks, and check that the + # returned beacon root is correct only if it was after the transition + # timestamp. for t in all_timestamps: current_call_account_code += Op.MSTORE(0, t) call_valid = ( @@ -586,7 +600,8 @@ def test_beacon_root_transition( parent_beacon_block_root=beacon_root if transitioned else None, timestamp=timestamp, withdrawals=[ - # Also withdraw to the beacon root contract and the system address + # Also withdraw to the beacon root contract and the system + # address Withdrawal( address=Spec.BEACON_ROOTS_ADDRESS, amount=1, @@ -625,8 +640,8 @@ def test_no_beacon_root_contract_at_transition( fork: Fork, ): """ - Tests the fork transition to cancun in the case where the beacon root pre-deploy was not - deployed in time for the fork. + Tests the fork transition to cancun in the case where the beacon root + pre-deploy was not deployed in time for the fork. """ assert fork.header_beacon_root_required(1, timestamp) blocks: List[Block] = [ @@ -635,7 +650,8 @@ def test_no_beacon_root_contract_at_transition( parent_beacon_block_root=next(beacon_roots), timestamp=timestamp, withdrawals=[ - # Also withdraw to the beacon root contract and the system address + # Also withdraw to the beacon root contract and the system + # address Withdrawal( address=Spec.BEACON_ROOTS_ADDRESS, amount=1, @@ -652,7 +668,8 @@ def test_no_beacon_root_contract_at_transition( ) ] pre[Spec.BEACON_ROOTS_ADDRESS] = Account( - code=b"", # Remove the code that is automatically allocated on Cancun fork + code=b"", # Remove the code that is automatically allocated on Cancun + # fork nonce=0, balance=0, ) @@ -667,9 +684,8 @@ def test_no_beacon_root_contract_at_transition( balance=int(1e9), ), caller_address: Account( - storage={ - 0: 1 - }, # Successful call because the contract is not there, but nothing else is stored + storage={0: 1}, # Successful call because the contract is not there, but + # nothing else is stored ), } blockchain_test( @@ -704,8 +720,8 @@ def test_beacon_root_contract_deploy( fork: Fork, ): """ - Tests the fork transition to cancun deploying the contract during Shanghai and verifying the - code deployed and its functionality after Cancun. + Tests the fork transition to cancun deploying the contract during Shanghai + and verifying the code deployed and its functionality after Cancun. """ assert fork.header_beacon_root_required(1, timestamp) tx_gas_limit = 0x3D090 @@ -746,7 +762,8 @@ def test_beacon_root_contract_deploy( ), timestamp=timestamp // 2, withdrawals=[ - # Also withdraw to the beacon root contract and the system address + # Also withdraw to the beacon root contract and the + # system address Withdrawal( address=Spec.BEACON_ROOTS_ADDRESS, amount=1, @@ -773,7 +790,8 @@ def test_beacon_root_contract_deploy( parent_beacon_block_root=beacon_root, timestamp=timestamp, withdrawals=[ - # Also withdraw to the beacon root contract and the system address + # Also withdraw to the beacon root contract and the + # system address Withdrawal( address=Spec.BEACON_ROOTS_ADDRESS, amount=1, @@ -800,7 +818,8 @@ def test_beacon_root_contract_deploy( expected_code = fork.pre_allocation_blockchain()[Spec.BEACON_ROOTS_ADDRESS]["code"] pre[Spec.BEACON_ROOTS_ADDRESS] = Account( - code=b"", # Remove the code that is automatically allocated on Cancun fork + code=b"", # Remove the code that is automatically allocated on Cancun + # fork nonce=0, balance=0, ) diff --git a/tests/cancun/eip4844_blobs/conftest.py b/tests/cancun/eip4844_blobs/conftest.py index 2388a053c82..6da44f93c16 100644 --- a/tests/cancun/eip4844_blobs/conftest.py +++ b/tests/cancun/eip4844_blobs/conftest.py @@ -64,7 +64,9 @@ def parent_excess_blob_gas( parent_excess_blobs: int | None, blob_gas_per_blob: int, ) -> int | None: - """Calculate the excess blob gas of the parent block from the excess blobs.""" + """ + Calculate the excess blob gas of the parent block from the excess blobs. + """ if parent_excess_blobs is None: return None assert parent_excess_blobs >= 0 @@ -79,7 +81,8 @@ def excess_blob_gas( block_base_fee_per_gas: int, ) -> int | None: """ - Calculate the excess blob gas of the block under test from the parent block. + Calculate the excess blob gas of the block under test from the parent + block. Value can be overloaded by a test case to provide a custom excess blob gas. """ @@ -100,7 +103,8 @@ def correct_excess_blob_gas( block_base_fee_per_gas: int, ) -> int: """ - Calculate the correct excess blob gas of the block under test from the parent block. + Calculate the correct excess blob gas of the block under test from the + parent block. Should not be overloaded by a test case. """ @@ -160,7 +164,9 @@ def env( block_base_fee_per_gas: int, genesis_excess_blob_gas: int, ) -> Environment: - """Prepare the environment of the genesis block for all blockchain tests.""" + """ + Prepare the environment of the genesis block for all blockchain tests. + """ return Environment( excess_blob_gas=genesis_excess_blob_gas, blob_gas_used=0, @@ -213,7 +219,8 @@ def tx_max_priority_fee_per_gas() -> int: @pytest.fixture def tx_max_fee_per_blob_gas_multiplier() -> int: """ - Return default max fee per blob gas multiplier for transactions sent during test. + Return default max fee per blob gas multiplier for transactions sent during + test. Can be overloaded by a test case to provide a custom max fee per blob gas multiplier. @@ -224,7 +231,8 @@ def tx_max_fee_per_blob_gas_multiplier() -> int: @pytest.fixture def tx_max_fee_per_blob_gas_delta() -> int: """ - Return default max fee per blob gas delta for transactions sent during test. + Return default max fee per blob gas delta for transactions sent during + test. Can be overloaded by a test case to provide a custom max fee per blob gas delta. @@ -263,22 +271,21 @@ def non_zero_blob_gas_used_genesis_block( block_base_fee_per_gas: int, ) -> Block | None: """ - For test cases with a non-zero blobGasUsed field in the - original genesis block header we must instead utilize an - intermediate block to act on its behalf. - - Genesis blocks with a non-zero blobGasUsed field are invalid as - they do not have any blob txs. - - For the intermediate block to align with default genesis values, - we must add TARGET_BLOB_GAS_PER_BLOCK to the excessBlobGas of the - genesis value, expecting an appropriate drop to the intermediate block. - Similarly, we must add parent_blobs to the intermediate block within - a blob tx such that an equivalent blobGasUsed field is wrote. - - For forks >= Osaka where the MAX_BLOBS_PER_TX is introduced, we - split the blobs across multiple transactions to respect the - MAX_BLOBS_PER_TX limit. + For test cases with a non-zero blobGasUsed field in the original genesis + block header we must instead utilize an intermediate block to act on its + behalf. + + Genesis blocks with a non-zero blobGasUsed field are invalid as they do not + have any blob txs. + + For the intermediate block to align with default genesis values, we must + add TARGET_BLOB_GAS_PER_BLOCK to the excessBlobGas of the genesis value, + expecting an appropriate drop to the intermediate block. Similarly, we must + add parent_blobs to the intermediate block within a blob tx such that an + equivalent blobGasUsed field is wrote. + + For forks >= Osaka where the MAX_BLOBS_PER_TX is introduced, we split the + blobs across multiple transactions to respect the MAX_BLOBS_PER_TX limit. """ if parent_blobs == 0: return None @@ -300,9 +307,10 @@ def non_zero_blob_gas_used_genesis_block( empty_account_destination = pre.fund_eoa(0) blob_gas_price_calculator = fork.blob_gas_price_calculator(block_number=1) - # Split blobs into chunks when MAX_BLOBS_PER_TX < MAX_BLOBS_PER_BLOCK to respect per-tx limits. - # Allows us to keep single txs for forks where per-tx and per-block limits are equal, hitting - # coverage for block level blob gas validation when parent_blobs > MAX_BLOBS_PER_BLOCK. + # Split blobs into chunks when MAX_BLOBS_PER_TX < MAX_BLOBS_PER_BLOCK to + # respect per-tx limits. Allows us to keep single txs for forks where per- + # tx and per-block limits are equal, hitting coverage for block level blob + # gas validation when parent_blobs > MAX_BLOBS_PER_BLOCK. max_blobs_per_tx = ( fork.max_blobs_per_tx() if fork.max_blobs_per_tx() < fork.max_blobs_per_block() diff --git a/tests/cancun/eip4844_blobs/spec.py b/tests/cancun/eip4844_blobs/spec.py index 5eb5a29a7ee..309ac058e03 100644 --- a/tests/cancun/eip4844_blobs/spec.py +++ b/tests/cancun/eip4844_blobs/spec.py @@ -87,8 +87,8 @@ def get_min_excess_blob_gas_for_blob_gas_price( blob_gas_price: int, ) -> int: """ - Get the minimum required excess blob gas value to get a given blob gas cost in a - block. + Get the minimum required excess blob gas value to get a given blob gas + cost in a block. """ current_excess_blob_gas = 0 current_blob_gas_price = 1 @@ -106,7 +106,10 @@ def get_min_excess_blobs_for_blob_gas_price( fork: Fork, blob_gas_price: int, ) -> int: - """Get the minimum required excess blobs to get a given blob gas cost in a block.""" + """ + Get the minimum required excess blobs to get a given blob gas cost in a + block. + """ gas_per_blob = fork.blob_gas_per_blob() return ( cls.get_min_excess_blob_gas_for_blob_gas_price( @@ -122,23 +125,29 @@ def get_blob_combinations( blob_count: int, max_blobs_per_tx: int, ) -> List[Tuple[int, ...]]: - """Get all possible combinations of blobs that result in a given blob count.""" + """ + Get all possible combinations of blobs that result in a given blob + count. + """ combinations = [ seq for i in range( blob_count + 1, 0, -1 - ) # We can have from 1 to at most MAX_BLOBS_PER_BLOCK blobs per block + ) # We can have from 1 to at most MAX_BLOBS_PER_BLOCK blobs per + # block for seq in itertools.combinations_with_replacement( range(1, min(blob_count + 1, max_blobs_per_tx) + 1), i ) # We iterate through all possible combinations - if sum(seq) - == blob_count # And we only keep the ones that match the expected blob count - and all(tx_blobs <= max_blobs_per_tx for tx_blobs in seq) # Validate each tx + if sum(seq) == blob_count # And we only keep the ones that match the expected + # blob count + and all(tx_blobs <= max_blobs_per_tx for tx_blobs in seq) # Validate + # each + # tx ] - # We also add the reversed version of each combination, only if it's not - # already in the list. E.g. (4, 1) is added from (1, 4) but not - # (1, 1, 1, 1, 1) because its reversed version is identical. + # We also add the reversed version of each combination, only if it's + # not already in the list. E.g. (4, 1) is added from (1, 4) but not (1, + # 1, 1, 1, 1) because its reversed version is identical. combinations += [ tuple(reversed(x)) for x in combinations if tuple(reversed(x)) not in combinations ] @@ -147,8 +156,8 @@ def get_blob_combinations( @classmethod def all_valid_blob_combinations(cls, fork: Fork) -> List[Tuple[int, ...]]: """ - Return all valid blob tx combinations for a given block, - assuming the given MAX_BLOBS_PER_BLOCK, whilst respecting MAX_BLOBS_PER_TX. + Return all valid blob tx combinations for a given block, assuming the + given MAX_BLOBS_PER_BLOCK, whilst respecting MAX_BLOBS_PER_TX. """ max_blobs_per_block = fork.max_blobs_per_block() max_blobs_per_tx = fork.max_blobs_per_tx() diff --git a/tests/cancun/eip4844_blobs/test_blob_txs.py b/tests/cancun/eip4844_blobs/test_blob_txs.py index 166fb5ced43..0d4aa02575b 100644 --- a/tests/cancun/eip4844_blobs/test_blob_txs.py +++ b/tests/cancun/eip4844_blobs/test_blob_txs.py @@ -1,19 +1,18 @@ """ -abstract: Tests blob type transactions for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) - Test blob type transactions for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). +abstract: Tests blob type transactions for [EIP-4844: Shard Blob +Transactions](https://eips.ethereum.org/EIPS/eip-4844). +Note: Adding a new test Add a function that is named `test_` and +takes at least the following arguments: -note: Adding a new test - Add a function that is named `test_` and takes at least the following arguments: +- blockchain_test or state_test +- pre +- env +- block or txs - - blockchain_test or state_test - - pre - - env - - block or txs - - All other `pytest.fixture` fixtures can be parametrized to generate new combinations and test cases. - -""" # noqa: E501 +All other `pytest.fixture` fixtures can be parametrized to generate new +combinations and test cases. +""" from typing import List, Optional, Tuple @@ -126,8 +125,8 @@ def total_account_minimum_balance( # noqa: D103 blob_hashes_per_tx: List[List[bytes]], ) -> int: """ - Calculate minimum balance required for the account to be able to send - the transactions in the block of the test. + Calculate minimum balance required for the account to be able to send the + transactions in the block of the test. """ minimum_cost = 0 for tx_blob_count in [len(x) for x in blob_hashes_per_tx]: @@ -147,7 +146,9 @@ def total_account_transactions_fee( # noqa: D103 tx_max_priority_fee_per_gas: int, blob_hashes_per_tx: List[List[bytes]], ) -> int: - """Calculate actual fee for the blob transactions in the block of the test.""" + """ + Calculate actual fee for the blob transactions in the block of the test. + """ total_cost = 0 for tx_blob_count in [len(x) for x in blob_hashes_per_tx]: blob_cost = blob_gas_price * blob_gas_per_blob * tx_blob_count @@ -175,8 +176,8 @@ def tx_error() -> Optional[TransactionException]: """ Error produced by the block transactions (no error). - Can be overloaded on test cases where the transactions are expected - to fail. + Can be overloaded on test cases where the transactions are expected to + fail. """ return None @@ -230,8 +231,8 @@ def txs( # noqa: D103 @pytest.fixture def account_balance_modifier() -> int: """ - Account balance modifier for the source account of all tests. - See `pre` fixture. + Account balance modifier for the source account of all tests. See `pre` + fixture. """ return 0 @@ -243,9 +244,9 @@ def state_env( """ Prepare the environment for all state test cases. - Main difference is that the excess blob gas is not increased by the target, as - there is no genesis block -> block 1 transition, and therefore the excess blob gas - is not decreased by the target. + Main difference is that the excess blob gas is not increased by the target, + as there is no genesis block -> block 1 transition, and therefore the + excess blob gas is not decreased by the target. """ return Environment( excess_blob_gas=excess_blob_gas if excess_blob_gas else 0, @@ -255,8 +256,8 @@ def state_env( @pytest.fixture def engine_api_error_code() -> Optional[EngineAPIError]: """ - Engine API error code to be returned by the client on consumption - of the erroneous block in hive. + Engine API error code to be returned by the client on consumption of the + erroneous block in hive. """ return None @@ -268,8 +269,8 @@ def block_error( """ Error produced by the block transactions (no error). - Can be overloaded on test cases where the transactions are expected - to fail. + Can be overloaded on test cases where the transactions are expected to + fail. """ return tx_error @@ -385,15 +386,16 @@ def test_valid_blob_tx_combinations( block: Block, ): """ - Test all valid blob combinations in a single block, assuming a given value of - `MAX_BLOBS_PER_BLOCK`. + Test all valid blob combinations in a single block, assuming a given value + of `MAX_BLOBS_PER_BLOCK`. - This assumes a block can include from 1 and up to `MAX_BLOBS_PER_BLOCK` transactions where all - transactions contain at least 1 blob, and the sum of all blobs in a block is at - most `MAX_BLOBS_PER_BLOCK`. + This assumes a block can include from 1 and up to `MAX_BLOBS_PER_BLOCK` + transactions where all transactions contain at least 1 blob, and the sum of + all blobs in a block is at most `MAX_BLOBS_PER_BLOCK`. - This test is parametrized with all valid blob transaction combinations for a given block, and - therefore if value of `MAX_BLOBS_PER_BLOCK` changes, this test is automatically updated. + This test is parametrized with all valid blob transaction combinations for + a given block, and therefore if value of `MAX_BLOBS_PER_BLOCK` changes, + this test is automatically updated. """ blockchain_test( pre=pre, @@ -407,8 +409,8 @@ def generate_invalid_tx_max_fee_per_blob_gas_tests( fork: Fork, ) -> List: """ - Return a list of tests for invalid blob transactions due to insufficient max fee per blob gas - parametrized for each different fork. + Return a list of tests for invalid blob transactions due to insufficient + max fee per blob gas parametrized for each different fork. """ min_base_fee_per_blob_gas = fork.min_base_fee_per_blob_gas() minimum_excess_blobs_for_first_increment = SpecHelpers.get_min_excess_blobs_for_blob_gas_price( @@ -422,8 +424,10 @@ def generate_invalid_tx_max_fee_per_blob_gas_tests( tests = [] tests.append( pytest.param( - minimum_excess_blobs_for_first_increment - 1, # blob gas price is 1 - fork.target_blobs_per_block() + 1, # blob gas cost increases to above the minimum + minimum_excess_blobs_for_first_increment - 1, # blob gas price is + # 1 + fork.target_blobs_per_block() + 1, # blob gas cost increases to + # above the minimum min_base_fee_per_blob_gas, # tx max_blob_gas_cost is the minimum TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS, id="insufficient_max_fee_per_blob_gas", @@ -435,7 +439,8 @@ def generate_invalid_tx_max_fee_per_blob_gas_tests( pytest.param( minimum_excess_blobs_for_first_increment - 1, # blob gas price is one less than the minimum - fork.target_blobs_per_block() + 1, # blob gas cost increases to above the minimum + fork.target_blobs_per_block() + 1, # blob gas cost increases + # to above the minimum next_base_fee_per_blob_gas - 1, # tx max_blob_gas_cost is one less than the minimum TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS, @@ -448,7 +453,8 @@ def generate_invalid_tx_max_fee_per_blob_gas_tests( pytest.param( 0, # blob gas price is the minimum 0, # blob gas cost stays put at 1 - min_base_fee_per_blob_gas - 1, # tx max_blob_gas_cost is one less than the minimum + min_base_fee_per_blob_gas - 1, # tx max_blob_gas_cost is one + # less than the minimum TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS, id="insufficient_max_fee_per_blob_gas_one_less_than_min", marks=pytest.mark.exception_test, @@ -487,8 +493,8 @@ def test_invalid_tx_max_fee_per_blob_gas( """ Reject blocks with invalid blob txs. - - tx max_fee_per_blob_gas is barely not enough - - tx max_fee_per_blob_gas is zero + - tx max_fee_per_blob_gas is barely not enough - tx max_fee_per_blob_gas is + zero """ if non_zero_blob_gas_used_genesis_block is not None: blocks = [non_zero_blob_gas_used_genesis_block, block] @@ -517,8 +523,8 @@ def test_invalid_tx_max_fee_per_blob_gas_state( """ Reject an invalid blob transaction. - - tx max_fee_per_blob_gas is barely not enough - - tx max_fee_per_blob_gas is zero + - tx max_fee_per_blob_gas is barely not enough - tx max_fee_per_blob_gas is + zero """ assert len(txs) == 1 state_test( @@ -589,12 +595,12 @@ def test_invalid_block_blob_count( block: Block, ): """ - Test all invalid blob combinations in a single block, where the sum of all blobs in a block is - at `MAX_BLOBS_PER_BLOCK + 1`. + Test all invalid blob combinations in a single block, where the sum of all + blobs in a block is at `MAX_BLOBS_PER_BLOCK + 1`. This test is parametrized with all blob transaction combinations exceeding - `MAX_BLOBS_PER_BLOCK` by one for a given block, and - therefore if value of `MAX_BLOBS_PER_BLOCK` changes, this test is automatically updated. + `MAX_BLOBS_PER_BLOCK` by one for a given block, and therefore if value of + `MAX_BLOBS_PER_BLOCK` changes, this test is automatically updated. """ blockchain_test( pre=pre, @@ -632,11 +638,10 @@ def test_insufficient_balance_blob_tx( Reject blocks where user cannot afford the blob gas specified (but max_fee_per_gas would be enough for current block). - - Transactions with max fee equal or higher than current block base fee - - Transactions with and without priority fee - - Transactions with and without value - - Transactions with and without calldata - - Transactions with max fee per blob gas lower or higher than the priority fee + - Transactions with max fee equal or higher than current block base fee - + Transactions with and without priority fee - Transactions with and without + value - Transactions with and without calldata - Transactions with max fee + per blob gas lower or higher than the priority fee """ assert len(txs) == 1 state_test( @@ -677,14 +682,13 @@ def test_sufficient_balance_blob_tx( txs: List[Transaction], ): """ - Check that transaction is accepted when user can exactly afford the blob gas specified (and - max_fee_per_gas would be enough for current block). + Check that transaction is accepted when user can exactly afford the blob + gas specified (and max_fee_per_gas would be enough for current block). - - Transactions with max fee equal or higher than current block base fee - - Transactions with and without priority fee - - Transactions with and without value - - Transactions with and without calldata - - Transactions with max fee per blob gas lower or higher than the priority fee + - Transactions with max fee equal or higher than current block base fee - + Transactions with and without priority fee - Transactions with and without + value - Transactions with and without calldata - Transactions with max fee + per blob gas lower or higher than the priority fee """ assert len(txs) == 1 state_test( @@ -728,15 +732,14 @@ def test_sufficient_balance_blob_tx_pre_fund_tx( header_verify: Optional[Header], ): """ - Check that transaction is accepted when user can exactly afford the blob gas specified (and - max_fee_per_gas would be enough for current block) because a funding transaction is - prepended in the same block. - - - Transactions with max fee equal or higher than current block base fee - - Transactions with and without priority fee - - Transactions with and without value - - Transactions with and without calldata - - Transactions with max fee per blob gas lower or higher than the priority fee + Check that transaction is accepted when user can exactly afford the blob + gas specified (and max_fee_per_gas would be enough for current block) + because a funding transaction is prepended in the same block. + + - Transactions with max fee equal or higher than current block base fee - + Transactions with and without priority fee - Transactions with and without + value - Transactions with and without calldata - Transactions with max fee + per blob gas lower or higher than the priority fee """ pre_funding_sender = pre.fund_eoa(amount=(21_000 * 100) + total_account_minimum_balance) txs = [ @@ -808,14 +811,14 @@ def test_blob_gas_subtraction_tx( total_account_transactions_fee: int, ): """ - Check that the blob gas fee for a transaction is subtracted from the sender balance before the - transaction is executed. - - - Transactions with max fee equal or higher than current block base fee - - Transactions with and without value - - Transactions with and without calldata - - Transactions with max fee per blob gas lower or higher than the priority fee - - Transactions where an externally owned account sends funds to the sender mid execution + Check that the blob gas fee for a transaction is subtracted from the sender + balance before the transaction is executed. + + - Transactions with max fee equal or higher than current block base fee - + Transactions with and without value - Transactions with and without + calldata - Transactions with max fee per blob gas lower or higher than the + priority fee - Transactions where an externally owned account sends funds + to the sender mid execution """ assert len(txs) == 1 post = { @@ -851,10 +854,11 @@ def test_insufficient_balance_blob_tx_combinations( block: Block, ): """ - Reject all valid blob transaction combinations in a block, but block is invalid. + Reject all valid blob transaction combinations in a block, but block is + invalid. - - The amount of blobs is correct but the user cannot afford the - transaction total cost + - The amount of blobs is correct but the user cannot afford the transaction + total cost """ blockchain_test( pre=pre, @@ -867,7 +871,10 @@ def test_insufficient_balance_blob_tx_combinations( def generate_invalid_tx_blob_count_tests( fork: Fork, ) -> List: - """Return a list of tests for invalid blob transactions due to invalid blob counts.""" + """ + Return a list of tests for invalid blob transactions due to invalid blob + counts. + """ return [ pytest.param( [0], @@ -902,8 +909,8 @@ def test_invalid_tx_blob_count( """ Reject blocks that include blob transactions with invalid blob counts. - - `blob count == 0` in type 3 transaction - - `blob count > MAX_BLOBS_PER_BLOCK` in type 3 transaction + - `blob count == 0` in type 3 transaction - `blob count > + MAX_BLOBS_PER_BLOCK` in type 3 transaction """ assert len(txs) == 1 state_test( @@ -947,9 +954,9 @@ def test_invalid_blob_hash_versioning_single_tx( """ Reject blob transactions with invalid blob hash version. - - Transaction with single blob with invalid version - - Transaction with multiple blobs all with invalid version - - Transaction with multiple blobs either with invalid version + - Transaction with single blob with invalid version - Transaction with + multiple blobs all with invalid version - Transaction with multiple blobs + either with invalid version """ assert len(txs) == 1 state_test( @@ -1005,9 +1012,10 @@ def test_invalid_blob_hash_versioning_multiple_txs( Reject blocks that include blob transactions with invalid blob hash version. - - Multiple blob transactions with single blob all with invalid version - - Multiple blob transactions with multiple blobs all with invalid version - - Multiple blob transactions with multiple blobs only one with invalid version + - Multiple blob transactions with single blob all with invalid version - + Multiple blob transactions with multiple blobs all with invalid version - + Multiple blob transactions with multiple blobs only one with invalid + version """ blockchain_test( pre=pre, @@ -1029,10 +1037,14 @@ def test_invalid_blob_tx_contract_creation( txs: List[Transaction], header_verify: Optional[Header], ): - """Reject blocks that include blob transactions that have nil to value (contract creating).""" + """ + Reject blocks that include blob transactions that have nil to value + (contract creating). + """ assert len(txs) == 1 assert txs[0].blob_versioned_hashes is not None and len(txs[0].blob_versioned_hashes) == 1 - # Replace the transaction with a contract creating one, only in the RLP version + # Replace the transaction with a contract creating one, only in the RLP + # version contract_creating_tx = txs[0].copy(to=None).with_signature_and_sender() txs[0].rlp_override = contract_creating_tx.rlp() blockchain_test( @@ -1047,8 +1059,8 @@ def test_invalid_blob_tx_contract_creation( ], header_verify=header_verify, # Skipped due to the T8N not receiving the invalid transaction, - # instead we are passing a valid transaction to T8N and then the transaction - # is replaced directly in the block RLP. + # instead we are passing a valid transaction to T8N and then + # the transaction is replaced directly in the block RLP. skip_exception_verification=True, ) ], @@ -1071,7 +1083,10 @@ def opcode( tx_max_priority_fee_per_gas: int, tx_value: int, ) -> Tuple[Bytecode, Storage.StorageDictType]: - """Build bytecode and post to test each opcode that accesses transaction information.""" + """ + Build bytecode and post to test each opcode that accesses transaction + information. + """ if request.param == Op.ORIGIN: return ( Op.SSTORE(0, Op.ORIGIN), @@ -1137,10 +1152,10 @@ def test_blob_tx_attribute_opcodes( state_env: Environment, ): """ - Test opcodes that read transaction attributes work properly for blob type transactions. + Test opcodes that read transaction attributes work properly for blob type + transactions. - - ORIGIN - - CALLER + - ORIGIN - CALLER """ code, storage = opcode destination_account = pre.deploy_contract(code=code) @@ -1189,7 +1204,9 @@ def test_blob_tx_attribute_value_opcode( opcode: Tuple[Bytecode, Storage.StorageDictType], state_env: Environment, ): - """Test the VALUE opcode with different blob type transaction value amounts.""" + """ + Test the VALUE opcode with different blob type transaction value amounts. + """ code, storage = opcode destination_account = pre.deploy_contract(code=code) tx = Transaction( @@ -1255,11 +1272,10 @@ def test_blob_tx_attribute_calldata_opcodes( state_env: Environment, ): """ - Test calldata related opcodes to verify their behavior is not affected by blobs. + Test calldata related opcodes to verify their behavior is not affected by + blobs. - - CALLDATALOAD - - CALLDATASIZE - - CALLDATACOPY + - CALLDATALOAD - CALLDATASIZE - CALLDATACOPY """ code, storage = opcode destination_account = pre.deploy_contract(code=code) @@ -1289,9 +1305,14 @@ def test_blob_tx_attribute_calldata_opcodes( ) -@pytest.mark.parametrize("tx_max_priority_fee_per_gas", [0, 2]) # always below data fee -@pytest.mark.parametrize("tx_max_fee_per_blob_gas_delta", [0, 1]) # normal and above priority fee -@pytest.mark.parametrize("tx_max_fee_per_gas", [100]) # always above priority fee (FOR CANCUN) +@pytest.mark.parametrize("tx_max_priority_fee_per_gas", [0, 2]) # always below +# data fee +@pytest.mark.parametrize("tx_max_fee_per_blob_gas_delta", [0, 1]) # normal and +# above +# priority +# fee +@pytest.mark.parametrize("tx_max_fee_per_gas", [100]) # always above priority +# fee (FOR CANCUN) @pytest.mark.parametrize("opcode", [Op.GASPRICE], indirect=True) @pytest.mark.parametrize("tx_gas", [500_000]) @pytest.mark.valid_from("Cancun") @@ -1311,11 +1332,11 @@ def test_blob_tx_attribute_gasprice_opcode( state_env: Environment, ): """ - Test GASPRICE opcode to sanity check that the blob gas fee does not affect its calculation. + Test GASPRICE opcode to sanity check that the blob gas fee does not affect + its calculation. - - No priority fee - - Priority fee below data fee - - Priority fee above data fee + - No priority fee - Priority fee below data fee - Priority fee above data + fee """ code, storage = opcode destination_account = pre.deploy_contract(code=code) @@ -1382,8 +1403,9 @@ def test_blob_type_tx_pre_fork( """ Reject blocks with blob type transactions before Cancun fork. - Blocks sent by NewPayloadV2 (Shanghai) that contain blob type transactions, furthermore blobs - field within NewPayloadV2 method must be computed as INVALID, due to an invalid block hash. + Blocks sent by NewPayloadV2 (Shanghai) that contain blob type transactions, + furthermore blobs field within NewPayloadV2 method must be computed as + INVALID, due to an invalid block hash. """ assert len(txs) == 1 state_test( diff --git a/tests/cancun/eip4844_blobs/test_blob_txs_full.py b/tests/cancun/eip4844_blobs/test_blob_txs_full.py index ba6c091a707..01f1b3b417f 100644 --- a/tests/cancun/eip4844_blobs/test_blob_txs_full.py +++ b/tests/cancun/eip4844_blobs/test_blob_txs_full.py @@ -1,8 +1,7 @@ """ -abstract: Tests full blob type transactions for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) - Test full blob type transactions for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). - -""" # noqa: E501 +abstract: Tests full blob type transactions for [EIP-4844: Shard Blob +Transactions](https://eips.ethereum.org/EIPS/eip-4844). +""" from typing import List, Optional @@ -135,10 +134,10 @@ def tx_max_fee_per_blob_gas( # noqa: D103 @pytest.fixture def tx_error() -> Optional[TransactionException]: """ - Even though the final block we are producing in each of these tests is invalid, and some of the - transactions will be invalid due to the format in the final block, none of the transactions - should be rejected by the transition tool because they are being sent to it with the correct - format. + Even though the final block we are producing in each of these tests is + invalid, and some of the transactions will be invalid due to the format in + the final block, none of the transactions should be rejected by the + transition tool because they are being sent to it with the correct format. """ return None @@ -214,8 +213,8 @@ def blocks( header_blob_gas_used = 0 block_error = None if any(txs_wrapped_blobs): - # This is a block exception because the invalid block is only created in the RLP version, - # not in the transition tool. + # This is a block exception because the invalid block is only created + # in the RLP version, not in the transition tool. block_error = [ BlockException.RLP_STRUCTURES_ENCODING, TransactionException.TYPE_3_TX_WITH_FULL_BLOBS, @@ -289,8 +288,8 @@ def test_reject_valid_full_blob_in_block_rlp( blocks: List[Block], ): """ - Test valid blob combinations where one or more txs in the block - serialized version contain a full blob (network version) tx. + Test valid blob combinations where one or more txs in the block serialized + version contain a full blob (network version) tx. """ blockchain_test( pre=pre, diff --git a/tests/cancun/eip4844_blobs/test_blobhash_opcode.py b/tests/cancun/eip4844_blobs/test_blobhash_opcode.py index b22883be036..7a9e4bd3935 100644 --- a/tests/cancun/eip4844_blobs/test_blobhash_opcode.py +++ b/tests/cancun/eip4844_blobs/test_blobhash_opcode.py @@ -1,21 +1,20 @@ """ -abstract: Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) - Test cases for the `BLOBHASH` opcode in - [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). +abstract: Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob +Transactions](https://eips.ethereum.org/EIPS/eip-4844). -note: Adding a new test - Add a function that is named `test_` and takes at least the following arguments: +Note: Adding a new test Add a function that is named `test_` and +takes at least the following arguments: - - blockchain_test - - pre - - tx - - post +- blockchain_test +- pre +- tx +- post - Additional custom `pytest.fixture` fixtures can be added and parametrized for new test cases. +Additional custom `pytest.fixture` fixtures can be added and parametrized for +new test cases. - There is no specific structure to follow within this test module. - -""" # noqa: E501 +There is no specific structure to follow within this test module. +""" from typing import List @@ -81,15 +80,14 @@ class BlobhashScenario: @staticmethod def create_blob_hashes_list(length: int, max_blobs_per_tx: int) -> List[List[Hash]]: """ - Create list of MAX_BLOBS_PER_TX blob hashes - using `random_blob_hashes`. + Create list of MAX_BLOBS_PER_TX blob hashes using `random_blob_hashes`. - Cycle over random_blob_hashes to get a large list of - length: MAX_BLOBS_PER_TX * length - -> [0x01, 0x02, 0x03, 0x04, ..., 0x0A, 0x0B, 0x0C, 0x0D] + Cycle over random_blob_hashes to get a large list of length: + MAX_BLOBS_PER_TX * length -> [0x01, 0x02, 0x03, 0x04, ..., 0x0A, 0x0B, + 0x0C, 0x0D] - Then split list into smaller chunks of MAX_BLOBS_PER_TX - -> [[0x01, 0x02, 0x03, 0x04], ..., [0x0a, 0x0b, 0x0c, 0x0d]] + Then split list into smaller chunks of MAX_BLOBS_PER_TX -> [[0x01, + 0x02, 0x03, 0x04], ..., [0x0a, 0x0b, 0x0c, 0x0d]] """ b_hashes = [ random_blob_hashes[i % len(random_blob_hashes)] @@ -104,9 +102,8 @@ def blobhash_sstore(index: int, max_blobs_per_tx: int): """ Return BLOBHASH sstore to the given index. - If the index is out of the valid bounds, 0x01 is written - in storage, as we later check it is overwritten by - the BLOBHASH sstore. + If the index is out of the valid bounds, 0x01 is written in storage, as + we later check it is overwritten by the BLOBHASH sstore. """ invalidity_check = Op.SSTORE(index, 0x01) if index < 0 or index >= max_blobs_per_tx: @@ -158,9 +155,9 @@ def test_blobhash_gas_cost( """ Tests `BLOBHASH` opcode gas cost using a variety of indexes. - Asserts that the gas consumption of the `BLOBHASH` opcode is correct by ensuring - it matches `HASH_OPCODE_GAS = 3`. Includes both valid and invalid random - index sizes from the range `[0, 2**256-1]`, for tx types 2 and 3. + Asserts that the gas consumption of the `BLOBHASH` opcode is correct by + ensuring it matches `HASH_OPCODE_GAS = 3`. Includes both valid and invalid + random index sizes from the range `[0, 2**256-1]`, for tx types 2 and 3. """ gas_measure_code = CodeGasMeasure( code=Op.BLOBHASH(blobhash_index), @@ -279,12 +276,12 @@ def test_blobhash_invalid_blob_index( max_blobs_per_tx: int, ): """ - Tests that the `BLOBHASH` opcode returns a zeroed `bytes32` value for invalid - indexes. + Tests that the `BLOBHASH` opcode returns a zeroed `bytes32` value for + invalid indexes. - Includes cases where the index is negative (`index < 0`) or - exceeds the maximum number of `blob_versioned_hash` values stored: - (`index >= len(tx.message.blob_versioned_hashes)`). + Includes cases where the index is negative (`index < 0`) or exceeds the + maximum number of `blob_versioned_hash` values stored: (`index >= + len(tx.message.blob_versioned_hashes)`). It confirms that the returned value is a zeroed `bytes32` for each case. """ diff --git a/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py b/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py index b3ca64fd9c2..d1c365a11f5 100644 --- a/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py +++ b/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py @@ -1,9 +1,7 @@ """ -abstract: Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) - Test case for `BLOBHASH` opcode calls across different contexts - in [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). - -""" # noqa: E501 +abstract: Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob +Transactions](https://eips.ethereum.org/EIPS/eip-4844). +""" from enum import Enum from typing import Iterable, List @@ -34,8 +32,8 @@ class BlobhashContext(Enum): """ - A utility class for mapping common EVM opcodes in different contexts - to specific bytecode (with BLOBHASH), addresses and contracts. + A utility class for mapping common EVM opcodes in different contexts to + specific bytecode (with BLOBHASH), addresses and contracts. """ BLOBHASH_SSTORE = "blobhash_sstore" @@ -52,9 +50,7 @@ def code(self, *, indexes=Iterable[int]): """ Map opcode context to bytecode that utilizes the BLOBHASH opcode. - Args: - indexes: The indexes to request using the BLOBHASH opcode - + Args: indexes: The indexes to request using the BLOBHASH opcode """ match self: case BlobhashContext.BLOBHASH_SSTORE: @@ -81,10 +77,8 @@ def deploy_contract( """ Deploy a contract with the given context and indexes. - Args: - pre: The pre state to deploy the contract on - indexes: The indexes to request using the BLOBHASH opcode - + Args: pre: The pre state to deploy the contract on indexes: The indexes + to request using the BLOBHASH opcode """ match self: case BlobhashContext.BLOBHASH_SSTORE | BlobhashContext.BLOBHASH_RETURN: @@ -147,7 +141,9 @@ def deploy_contract( def simple_blob_hashes( max_blobs_per_tx: int, ) -> List[Hash]: - """Return a simple list of blob versioned hashes ranging from bytes32(1 to 4).""" + """ + Return a simple list of blob versioned hashes ranging from bytes32(1 to 4). + """ return add_kzg_version( [(1 << x) for x in range(max_blobs_per_tx)], Spec.BLOB_COMMITMENT_VERSION_KZG, @@ -177,14 +173,14 @@ def test_blobhash_opcode_contexts( state_test: StateTestFiller, ): """ - Tests that the `BLOBHASH` opcode functions correctly when called in different contexts. + Tests that the `BLOBHASH` opcode functions correctly when called in + different contexts. - - `BLOBHASH` opcode on the top level of the call stack. - - `BLOBHASH` opcode on the max value. - - `BLOBHASH` opcode on `CALL`, `DELEGATECALL`, `STATICCALL`, and `CALLCODE`. - - `BLOBHASH` opcode on Initcode. - - `BLOBHASH` opcode on `CREATE` and `CREATE2`. - - `BLOBHASH` opcode on transaction types 0, 1 and 2. + - `BLOBHASH` opcode on the top level of the call stack. - `BLOBHASH` opcode + on the max value. - `BLOBHASH` opcode on `CALL`, `DELEGATECALL`, + `STATICCALL`, and `CALLCODE`. - `BLOBHASH` opcode on Initcode. - `BLOBHASH` + opcode on `CREATE` and `CREATE2`. - `BLOBHASH` opcode on transaction types + 0, 1 and 2. """ tx_to: Address post: dict[Address, Account] @@ -292,14 +288,14 @@ def test_blobhash_opcode_contexts_tx_types( state_test: StateTestFiller, ): """ - Tests that the `BLOBHASH` opcode functions correctly when called in different contexts. + Tests that the `BLOBHASH` opcode functions correctly when called in + different contexts. - - `BLOBHASH` opcode on the top level of the call stack. - - `BLOBHASH` opcode on the max value. - - `BLOBHASH` opcode on `CALL`, `DELEGATECALL`, `STATICCALL`, and `CALLCODE`. - - `BLOBHASH` opcode on Initcode. - - `BLOBHASH` opcode on `CREATE` and `CREATE2`. - - `BLOBHASH` opcode on transaction types 0, 1 and 2. + - `BLOBHASH` opcode on the top level of the call stack. - `BLOBHASH` opcode + on the max value. - `BLOBHASH` opcode on `CALL`, `DELEGATECALL`, + `STATICCALL`, and `CALLCODE`. - `BLOBHASH` opcode on Initcode. - `BLOBHASH` + opcode on `CREATE` and `CREATE2`. - `BLOBHASH` opcode on transaction types + 0, 1 and 2. """ blobhash_sstore_address = BlobhashContext.BLOBHASH_SSTORE.deploy_contract(pre=pre, indexes=[0]) tx_kwargs = { diff --git a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py index b25ebc0dc0b..dbbee95c393 100644 --- a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py +++ b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py @@ -1,25 +1,26 @@ """ -abstract: Tests `excessBlobGas` and `blobGasUsed` block fields for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) - Test `excessBlobGas` and `blobGasUsed` block fields for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). +abstract: Tests `excessBlobGas` and `blobGasUsed` block fields for [EIP-4844: +Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). -note: Adding a new test - Add a function that is named `test_` and takes at least the following arguments: +Note: Adding a new test Add a function that is named `test_` and +takes at least the following arguments: - - blockchain_test - - env - - pre - - blocks - - post - - correct_excess_blob_gas +- blockchain_test +- env +- pre +- blocks +- post +- correct_excess_blob_gas - The following arguments can be parametrized to generate new combinations and test cases: +The following arguments can be parametrized to generate new combinations and +test cases: - - new_blobs: Number of blobs in the block (automatically split across transactions as needed) +- new_blobs: Number of blobs in the block (automatically split across +transactions as needed) - All other `pytest.fixture` fixtures can be parametrized to generate new combinations and test - cases. - -""" # noqa: E501 +All other `pytest.fixture` fixtures can be parametrized to generate new +combinations and test cases. +""" import itertools from typing import Callable, Dict, Iterator, List, Mapping, Optional, Tuple @@ -55,7 +56,9 @@ @pytest.fixture def parent_excess_blobs(fork: Fork) -> int: # noqa: D103 - """By default we start with an intermediate value between the target and max.""" + """ + By default we start with an intermediate value between the target and max. + """ return (fork.max_blobs_per_block() + fork.target_blobs_per_block()) // 2 + 1 @@ -304,12 +307,14 @@ def test_correct_excess_blob_gas_calculation( correct_excess_blob_gas: int, ): """ - Test calculation of the `excessBlobGas` increase/decrease across - multiple blocks with and without blobs. + Test calculation of the `excessBlobGas` increase/decrease across multiple + blocks with and without blobs. - With parent block containing `[0, MAX_BLOBS_PER_BLOCK]` blobs - - With parent block containing `[0, TARGET_BLOBS_PER_BLOCK]` equivalent value of excess blob gas - """ # noqa: E501 + + - With parent block containing `[0, TARGET_BLOBS_PER_BLOCK]` equivalent + value of excess blob gas + """ blockchain_test( pre=pre, post=post, @@ -321,8 +326,8 @@ def test_correct_excess_blob_gas_calculation( def generate_blob_gas_cost_increases_tests(delta: int) -> Callable[[Fork], List[int]]: """ - Generate a list of block excess blob gas values where the blob gas price increases - based on fork properties. + Generate a list of block excess blob gas values where the blob gas price + increases based on fork properties. """ def generator_function(fork: Fork) -> List[int]: @@ -365,15 +370,14 @@ def test_correct_increasing_blob_gas_costs( correct_excess_blob_gas: int, ): """ - Test calculation of the `excessBlobGas` and blob gas tx costs at - value points where the cost increases to interesting amounts. - - - At the first blob gas cost increase (1 to 2) - - At total transaction data cost increase to `> 2^32` - - At blob gas wei cost increase to `> 2^32` - - At total transaction data cost increase to `> 2^64` - - At blob gas wei cost increase to `> 2^64` - - At blob gas wei cost increase of around current total Ether supply + Test calculation of the `excessBlobGas` and blob gas tx costs at value + points where the cost increases to interesting amounts. + + - At the first blob gas cost increase (1 to 2) - At total transaction data + cost increase to `> 2^32` - At blob gas wei cost increase to `> 2^32` - At + total transaction data cost increase to `> 2^64` - At blob gas wei cost + increase to `> 2^64` - At blob gas wei cost increase of around current + total Ether supply """ blockchain_test( pre=pre, @@ -402,8 +406,8 @@ def test_correct_decreasing_blob_gas_costs( correct_excess_blob_gas: int, ): """ - Test calculation of the `excessBlobGas` and blob gas tx costs at - value points where the cost decreases to interesting amounts. + Test calculation of the `excessBlobGas` and blob gas tx costs at value + points where the cost decreases to interesting amounts. See test_correct_increasing_blob_gas_costs. """ @@ -433,8 +437,8 @@ def test_invalid_zero_excess_blob_gas_in_header( ): """ Test rejection of blocks where the `excessBlobGas` in the header drops to - zero in a block with or without data blobs, but the excess blobs in the parent are - greater than target. + zero in a block with or without data blobs, but the excess blobs in the + parent are greater than target. """ if header_excess_blob_gas is None: raise Exception("test case is badly formatted") @@ -484,8 +488,8 @@ def test_invalid_blob_gas_used_in_header( """ Test rejection of blocks where the `blobGasUsed` in the header is invalid. - - `blobGasUsed` is not equal to the number of data blobs in the block - - `blobGasUsed` is the max uint64 value + - `blobGasUsed` is not equal to the number of data blobs in the block - + `blobGasUsed` is the max uint64 value """ if header_blob_gas_used is None: raise Exception("test case is badly formatted") @@ -529,8 +533,9 @@ def test_invalid_excess_blob_gas_above_target_change( """ Test rejection of blocks where the `excessBlobGas`. - - decreases more than `TARGET_BLOB_GAS_PER_BLOCK` in a single block with zero blobs - - increases more than `TARGET_BLOB_GAS_PER_BLOCK` in a single block with max blobs + - decreases more than `TARGET_BLOB_GAS_PER_BLOCK` in a single block with + zero blobs - increases more than `TARGET_BLOB_GAS_PER_BLOCK` in a single + block with max blobs """ if header_excess_blob_gas is None: raise Exception("test case is badly formatted") @@ -572,8 +577,8 @@ def test_invalid_static_excess_blob_gas( parent_excess_blob_gas: int, ): """ - Test rejection of blocks where the `excessBlobGas` remains unchanged - but the parent blobs included are not `TARGET_BLOBS_PER_BLOCK`. + Test rejection of blocks where the `excessBlobGas` remains unchanged but + the parent blobs included are not `TARGET_BLOBS_PER_BLOCK`. Test is parametrized to `MAX_BLOBS_PER_BLOCK` and `TARGET_BLOBS_PER_BLOCK`. """ @@ -659,7 +664,8 @@ def test_invalid_static_excess_blob_gas_from_zero_on_blobs_above_target( Test rejection of blocks where the `excessBlobGas` does not increase from zero, even when the included blobs is above target. - Test is parametrized to `[TARGET_BLOBS_PER_BLOCK+1, MAX_BLOBS_PER_BLOCK]` new blobs. + Test is parametrized to `[TARGET_BLOBS_PER_BLOCK+1, MAX_BLOBS_PER_BLOCK]` + new blobs. """ if header_excess_blob_gas is None: raise Exception("test case is badly formatted") @@ -708,9 +714,9 @@ def test_invalid_excess_blob_gas_change( Test rejection of blocks where the `excessBlobGas` changes to an invalid value. - Given a parent block containing `[0, MAX_BLOBS_PER_BLOCK]` blobs, test an invalid - `excessBlobGas` value by changing it by `[-TARGET_BLOBS_PER_BLOCK, TARGET_BLOBS_PER_BLOCK]` - from the correct value. + Given a parent block containing `[0, MAX_BLOBS_PER_BLOCK]` blobs, test an + invalid `excessBlobGas` value by changing it by `[-TARGET_BLOBS_PER_BLOCK, + TARGET_BLOBS_PER_BLOCK]` from the correct value. """ if header_excess_blob_gas is None: raise Exception("test case is badly formatted") @@ -760,8 +766,8 @@ def test_invalid_negative_excess_blob_gas( Test rejection of blocks where the `excessBlobGas` changes to the two's complement equivalent of the negative value after subtracting target blobs. - Reasoning is that the `excessBlobGas` is a `uint64`, so it cannot be negative, and - we test for a potential underflow here. + Reasoning is that the `excessBlobGas` is a `uint64`, so it cannot be + negative, and we test for a potential underflow here. """ if header_excess_blob_gas is None: raise Exception("test case is badly formatted") @@ -810,8 +816,9 @@ def test_invalid_non_multiple_excess_blob_gas( Test rejection of blocks where the `excessBlobGas` changes to a value that is not a multiple of Spec.GAS_PER_BLOB`. - - Parent block contains `TARGET_BLOBS_PER_BLOCK + 1` blobs, but `excessBlobGas` is off by +/-1 - - Parent block contains `TARGET_BLOBS_PER_BLOCK - 1` blobs, but `excessBlobGas` is off by +/-1 + - Parent block contains `TARGET_BLOBS_PER_BLOCK + 1` blobs, but + `excessBlobGas` is off by +/-1 - Parent block contains + `TARGET_BLOBS_PER_BLOCK - 1` blobs, but `excessBlobGas` is off by +/-1 """ if header_excess_blob_gas is None: raise Exception("test case is badly formatted") diff --git a/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py b/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py index 1d11234da00..23056e9ff04 100644 --- a/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py +++ b/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py @@ -1,8 +1,8 @@ """ -abstract: Tests `excessBlobGas` and `blobGasUsed` block fields for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) at fork transition. - Test `excessBlobGas` and `blobGasUsed` block fields for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) at fork - transition. -""" # noqa: E501 +abstract: Tests `excessBlobGas` and `blobGasUsed` block fields for [EIP-4844: +Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) at fork +transition. +""" from typing import List, Mapping @@ -49,8 +49,8 @@ def block_gas_limit(fork: Fork) -> int: # noqa: D103 @pytest.fixture def genesis_environment(block_gas_limit: int, block_base_fee_per_gas: int) -> Environment: """ - Genesis environment that enables existing transition tests to be used of BPO forks. - Compatible with all fork transitions. + Genesis environment that enables existing transition tests to be used of + BPO forks. Compatible with all fork transitions. """ return Environment( base_fee_per_gas=(block_base_fee_per_gas * BASE_FEE_MAX_CHANGE_DENOMINATOR) // 7, @@ -158,8 +158,8 @@ def pre_fork_excess_blobs( pre_fork_blocks: List[Block], ) -> int: """ - Return the cumulative excess blobs up until the fork given the pre_fork_blobs_per_block - and the target blobs in the fork prior. + Return the cumulative excess blobs up until the fork given the + pre_fork_blobs_per_block and the target blobs in the fork prior. """ if not fork.supports_blobs(timestamp=0): return 0 @@ -331,11 +331,12 @@ def test_invalid_pre_fork_block_with_blob_fields( blob_gas_used_present: bool, ): """ - Test block rejection when `excessBlobGas` and/or `blobGasUsed` fields are present on a pre-fork - block. + Test block rejection when `excessBlobGas` and/or `blobGasUsed` fields are + present on a pre-fork block. - Blocks sent by NewPayloadV2 (Shanghai) that contain `excessBlobGas` and `blobGasUsed` fields - must be rejected with the appropriate `EngineAPIError.InvalidParams` error error. + Blocks sent by NewPayloadV2 (Shanghai) that contain `excessBlobGas` and + `blobGasUsed` fields must be rejected with the appropriate + `EngineAPIError.InvalidParams` error error. """ header_modifier = Header( excess_blob_gas=0 if excess_blob_gas_present else None, @@ -376,11 +377,12 @@ def test_invalid_post_fork_block_without_blob_fields( blob_gas_used_missing: bool, ): """ - Test block rejection when `excessBlobGas` and/or `blobGasUsed` fields are missing on a - post-fork block. + Test block rejection when `excessBlobGas` and/or `blobGasUsed` fields are + missing on a post-fork block. - Blocks sent by NewPayloadV3 (Cancun) without `excessBlobGas` and `blobGasUsed` fields must be - rejected with the appropriate `EngineAPIError.InvalidParams` error. + Blocks sent by NewPayloadV3 (Cancun) without `excessBlobGas` and + `blobGasUsed` fields must be rejected with the appropriate + `EngineAPIError.InvalidParams` error. """ header_modifier = Header() if excess_blob_gas_missing: @@ -432,8 +434,8 @@ def test_fork_transition_excess_blob_gas_at_blob_genesis( """ Test `excessBlobGas` calculation in the header when the fork is activated. - Also produce enough blocks to test the blob gas price increase when the block is full with - `SpecHelpers.max_blobs_per_block()` blobs. + Also produce enough blocks to test the blob gas price increase when the + block is full with `SpecHelpers.max_blobs_per_block()` blobs. """ blockchain_test( pre=pre, @@ -499,7 +501,9 @@ def test_fork_transition_excess_blob_gas_post_blob_genesis( post_fork_blocks: List[Block], post: Mapping[Address, Account], ): - """Test `excessBlobGas` calculation in the header when the fork is activated.""" + """ + Test `excessBlobGas` calculation in the header when the fork is activated. + """ blockchain_test( pre=pre, post=post, diff --git a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py index 44257dc67df..c039b7a85e6 100644 --- a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py +++ b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py @@ -1,31 +1,31 @@ """ -abstract: Tests point evaluation precompile for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) - Test point evaluation precompile for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). +abstract: Tests point evaluation precompile for [EIP-4844: Shard Blob +Transactions](https://eips.ethereum.org/EIPS/eip-4844). -note: Adding a new test - Add a function that is named `test_` and takes at least the following arguments: +Note: Adding a new test Add a function that is named `test_` and +takes at least the following arguments: - - blockchain_test | state_test - - pre - - tx - - post +- blockchain_test | state_test +- pre +- tx +- post - The following arguments *need* to be parametrized or the test will not be generated: +The following arguments *need* to be parametrized or the test will not be +generated: - - versioned_hash - - kzg_commitment - - z - - y - - kzg_proof - - result +- versioned_hash +- kzg_commitment +- z +- y +- kzg_proof +- result - These values correspond to a single call of the precompile, and `result` refers to - whether the call should succeed or fail. +These values correspond to a single call of the precompile, and `result` refers +to whether the call should succeed or fail. - All other `pytest.fixture` fixtures can be parametrized to generate new combinations and test - cases. - -""" # noqa: E501 +All other `pytest.fixture` fixtures can be parametrized to generate new +combinations and test cases. +""" import glob import json @@ -110,8 +110,8 @@ def call_gas() -> int: """ Amount of gas to pass to the precompile. - Defaults to Spec.POINT_EVALUATION_PRECOMPILE_GAS, but can be parametrized to - test different amounts. + Defaults to Spec.POINT_EVALUATION_PRECOMPILE_GAS, but can be parametrized + to test different amounts. """ return Spec.POINT_EVALUATION_PRECOMPILE_GAS @@ -144,7 +144,8 @@ def precompile_caller_code(call_opcode: Op, call_gas: int) -> Bytecode: precompile_caller_code = Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE) precompile_caller_code += Op.SSTORE( key_call_return_code, - call_opcode( # type: ignore # https://github.com/ethereum/execution-spec-tests/issues/348 # noqa: E501 + # https://github.com/ethereum/execution-spec-tests/issues/348 + call_opcode( # type: ignore gas=call_gas, address=Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS, args_offset=0x00, @@ -226,8 +227,8 @@ def post( precompile_input: bytes, ) -> Dict: """ - Prepare expected post for each test, depending on the success or - failure of the precompile call. + Prepare expected post for each test, depending on the success or failure of + the precompile call. """ expected_storage: Storage.StorageDictType = {} # CALL operation return code @@ -291,8 +292,9 @@ def test_valid_inputs( """ Test valid sanity precompile calls that are expected to succeed. - - `kzg_commitment` and `kzg_proof` are set to values such that `p(z)==0` for all values of `z`, - hence `y` is tested to be zero, and call to be successful. + - `kzg_commitment` and `kzg_proof` are set to values such that `p(z)==0` + for all values of `z`, hence `y` is tested to be zero, and call to be + successful. """ state_test( env=Environment(), @@ -344,11 +346,9 @@ def test_invalid_inputs( """ Test invalid precompile calls. - - Out of bounds inputs `z` and `y` - - Correct proof, commitment, z and y, but incorrect lengths - - Null inputs - - Zero inputs - - Correct proof, commitment, z and y, but incorrect version versioned hash + - Out of bounds inputs `z` and `y` - Correct proof, commitment, z and y, + but incorrect lengths - Null inputs - Zero inputs - Correct proof, + commitment, z and y, but incorrect version versioned hash """ state_test( env=Environment(), @@ -425,8 +425,8 @@ def get_point_evaluation_test_files_in_directory(path: str) -> list[str]: def all_external_vectors() -> List: """ - Test for the Point Evaluation Precompile from external sources, - contained in ./point_evaluation_vectors/. + Test for the Point Evaluation Precompile from external sources, contained + in ./point_evaluation_vectors/. """ test_cases = [] @@ -453,7 +453,8 @@ def test_external_vectors( post: Dict, ): """ - Test precompile calls using external test vectors compiled from different sources. + Test precompile calls using external test vectors compiled from different + sources. - `go_kzg_4844_verify_kzg_proof.json`: test vectors from the [go-kzg-4844](https://github.com/crate-crypto/go-kzg-4844) repository. @@ -492,9 +493,8 @@ def test_call_opcode_types( Test calling the Point Evaluation Precompile with different call types, gas and parameter configuration. - - Using CALL, DELEGATECALL, CALLCODE and STATICCALL. - - Using correct and incorrect proofs - - Using barely insufficient gas + - Using CALL, DELEGATECALL, CALLCODE and STATICCALL. - Using correct and + incorrect proofs - Using barely insufficient gas """ state_test( env=Environment(), @@ -531,16 +531,16 @@ def test_tx_entry_point( proof_correct: bool, ): """ - Test calling the Point Evaluation Precompile directly as - transaction entry point, and measure the gas consumption. + Test calling the Point Evaluation Precompile directly as transaction entry + point, and measure the gas consumption. - - Using `gas_limit` with exact necessary gas, insufficient gas and extra gas. - - Using correct and incorrect proofs + - Using `gas_limit` with exact necessary gas, insufficient gas and extra + gas. - Using correct and incorrect proofs """ sender = pre.fund_eoa() - # Starting from EIP-7623, we need to use an access list to raise the intrinsic gas cost to be - # above the floor data cost. + # Starting from EIP-7623, we need to use an access list to raise the + # intrinsic gas cost to be above the floor data cost. access_list = [AccessList(address=Address(i), storage_keys=[]) for i in range(1, 10)] # Gas is appended the intrinsic gas cost of the transaction @@ -614,7 +614,9 @@ def test_precompile_before_fork( tx: Transaction, precompile_caller_address: Address, ): - """Test calling the Point Evaluation Precompile before the appropriate fork.""" + """ + Test calling the Point Evaluation Precompile before the appropriate fork. + """ post = { precompile_caller_address: Account( storage={1: 1}, @@ -667,7 +669,9 @@ def test_precompile_during_fork( precompile_input: bytes, sender: EOA, ): - """Test calling the Point Evaluation Precompile during the appropriate fork.""" + """ + Test calling the Point Evaluation Precompile during the appropriate fork. + """ # Blocks before fork blocks = [ Block( diff --git a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py index 02a80eb3de9..e3d0cfec4a8 100644 --- a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py +++ b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py @@ -1,8 +1,7 @@ """ -abstract: Tests gas usage on point evaluation precompile for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) - Test gas usage on point evaluation precompile for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). - -""" # noqa: E501 +abstract: Tests gas usage on point evaluation precompile for [EIP-4844: Shard +Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). +""" from typing import Dict, Literal @@ -103,7 +102,8 @@ def precompile_caller_code( + copy_opcode_cost(fork, len(precompile_input)) ) if call_type == Op.CALL or call_type == Op.CALLCODE: - precompile_caller_code += call_type( # type: ignore # https://github.com/ethereum/execution-spec-tests/issues/348 # noqa: E501 + # https://github.com/ethereum/execution-spec-tests/issues/348 + precompile_caller_code += call_type( # type: ignore call_gas, Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS, 0x00, @@ -115,7 +115,8 @@ def precompile_caller_code( overhead_cost += (push_operations_cost * 6) + (calldatasize_cost * 1) elif call_type == Op.DELEGATECALL or call_type == Op.STATICCALL: # Delegatecall and staticcall use one less argument - precompile_caller_code += call_type( # type: ignore # https://github.com/ethereum/execution-spec-tests/issues/348 # noqa: E501 + # https://github.com/ethereum/execution-spec-tests/issues/348 + precompile_caller_code += call_type( # type: ignore call_gas, Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS, 0x00, @@ -163,8 +164,8 @@ def post( call_gas: int, ) -> Dict: """ - Prepare expected post for each test, depending on the success or - failure of the precompile call and the gas usage. + Prepare expected post for each test, depending on the success or failure of + the precompile call and the gas usage. """ if proof == "correct": expected_gas_usage = ( @@ -205,11 +206,12 @@ def test_point_evaluation_precompile_gas_usage( post: Dict, ): """ - Test point evaluation precompile gas usage under different call contexts and gas limits. + Test point evaluation precompile gas usage under different call contexts + and gas limits. - - Test using all call types (CALL, DELEGATECALL, CALLCODE, STATICCALL) - - Test using different gas limits (exact gas, insufficient gas, extra gas) - - Test using correct and incorrect proofs + - Test using all call types (CALL, DELEGATECALL, CALLCODE, STATICCALL) - + Test using different gas limits (exact gas, insufficient gas, extra gas) - + Test using correct and incorrect proofs """ state_test( env=Environment(), diff --git a/tests/cancun/eip5656_mcopy/common.py b/tests/cancun/eip5656_mcopy/common.py index 1c975f4f840..a4aef625cae 100644 --- a/tests/cancun/eip5656_mcopy/common.py +++ b/tests/cancun/eip5656_mcopy/common.py @@ -1,7 +1,7 @@ """ -Common procedures to test -[EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656). -""" # noqa: E501 +Common procedures to test [EIP-5656: MCOPY - Memory copying +instruction](https://eips.ethereum.org/EIPS/eip-5656). +""" from copy import copy @@ -16,7 +16,8 @@ def mcopy(*, src: int, dest: int, length: int, memory: bytes) -> bytes: res = bytearray(copy(memory)) - # If the destination or source are larger than the memory, we need to extend the memory + # If the destination or source are larger than the memory, we need to + # extend the memory max_byte_index = max(src, dest) + length if max_byte_index > len(memory): res.extend(b"\x00" * (max_byte_index - len(memory))) diff --git a/tests/cancun/eip5656_mcopy/test_mcopy.py b/tests/cancun/eip5656_mcopy/test_mcopy.py index cd1fdda802a..f2b2b3d3efc 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy.py @@ -1,8 +1,7 @@ """ -abstract: Tests [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656) - Test copy operations of [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656). - -""" # noqa: E501 +abstract: Tests [EIP-5656: MCOPY - Memory copying +instruction](https://eips.ethereum.org/EIPS/eip-5656). +""" from typing import Mapping @@ -54,8 +53,8 @@ def code_bytecode( code_storage: Storage, ) -> Bytecode: """ - Prepare bytecode and storage for the test, based on the starting memory and the final - memory that resulted from the copy. + Prepare bytecode and storage for the test, based on the starting memory and + the final memory that resulted from the copy. """ bytecode = Bytecode() @@ -90,8 +89,8 @@ def code_bytecode( Op.MLOAD(w * 0x20), ) - # If the memory was extended beyond the initial range, store the last word of the resulting - # memory into storage too + # If the memory was extended beyond the initial range, store the last word + # of the resulting memory into storage too if len(final_memory) > len(initial_memory): last_word = ceiling_division(len(final_memory), 0x20) - 1 bytecode += Op.SSTORE( @@ -187,12 +186,11 @@ def test_valid_mcopy_operations( tx: Transaction, ): """ - Perform MCOPY operations using different offsets and lengths: - - Zero inputs - - Memory rewrites (copy from and to the same location) - - Memory overwrites (copy from and to different locations) - - Memory extensions (copy to a location that is out of bounds) - - Memory clear (copy from a location that is out of bounds). + Perform MCOPY operations using different offsets and lengths: - Zero inputs + - Memory rewrites (copy from and to the same location) - Memory overwrites + (copy from and to different locations) - Memory extensions (copy to a + location that is out of bounds) - Memory clear (copy from a location that + is out of bounds). """ state_test( env=Environment(), @@ -214,7 +212,10 @@ def test_mcopy_on_empty_memory( post: Mapping[str, Account], tx: Transaction, ): - """Perform MCOPY operations on an empty memory, using different offsets and lengths.""" + """ + Perform MCOPY operations on an empty memory, using different offsets and + lengths. + """ state_test( env=Environment(), pre=pre, diff --git a/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py b/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py index 85049128097..ea03d058038 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py @@ -1,8 +1,11 @@ """ -abstract: Tests [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656) - Test memory copy under different call contexts [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656). +abstract: Tests [EIP-5656: MCOPY - Memory copying +instruction](https://eips.ethereum.org/EIPS/eip-5656). -""" # noqa: E501 +Test memory copy under +different call contexts [EIP-5656: MCOPY - Memory copying +instruction](https://eips.ethereum.org/EIPS/eip-5656). +""" from itertools import cycle, islice from typing import Mapping @@ -39,8 +42,8 @@ def callee_bytecode( call_opcode: Op, ) -> Bytecode: """ - Callee simply performs mcopy operations that should not have any effect on the - caller context. + Callee simply performs mcopy operations that should not have any effect on + the caller context. """ bytecode = Bytecode() @@ -76,7 +79,8 @@ def initial_memory( ret = bytes(list(islice(cycle(range(0x01, 0x100)), initial_memory_length))) if call_opcode in [Op.CREATE, Op.CREATE2]: - # We also need to put the callee_bytecode as initcode in memory for create operations + # We also need to put the callee_bytecode as initcode in memory for + # create operations ret = bytes(callee_bytecode) + ret[len(callee_bytecode) :] assert len(ret) == initial_memory_length @@ -97,8 +101,8 @@ def caller_bytecode( caller_storage: Storage, ) -> Bytecode: """ - Prepare bytecode and storage for the test, based on the starting memory and the final - memory that resulted from the copy. + Prepare bytecode and storage for the test, based on the starting memory and + the final memory that resulted from the copy. """ bytecode = Bytecode() @@ -116,8 +120,8 @@ def caller_bytecode( bytecode += Op.SSTORE(100_000, Op.MSIZE()) caller_storage[100_000] = ceiling_division(len(initial_memory), 0x20) * 0x20 - # Store all memory in the initial range to verify the MCOPY in the subcall did not affect - # this level's memory + # Store all memory in the initial range to verify the MCOPY in the subcall + # did not affect this level's memory for w in range(0, len(initial_memory) // 0x20): bytecode += Op.SSTORE(w, Op.MLOAD(w * 0x20)) caller_storage[w] = initial_memory[w * 0x20 : w * 0x20 + 0x20] @@ -171,8 +175,8 @@ def test_no_memory_corruption_on_upper_call_stack_levels( tx: Transaction, ): """ - Perform a subcall with any of the following opcodes, which uses MCOPY during its execution, - and verify that the caller's memory is unaffected. + Perform a subcall with any of the following opcodes, which uses MCOPY + during its execution, and verify that the caller's memory is unaffected. """ state_test( env=Environment(), @@ -197,10 +201,9 @@ def test_no_memory_corruption_on_upper_create_stack_levels( tx: Transaction, ): """ - Perform a subcall with any of the following opcodes, which uses MCOPY during its execution, - and verify that the caller's memory is unaffected: - - `CREATE` - - `CREATE2`. + Perform a subcall with any of the following opcodes, which uses MCOPY + during its execution, and verify that the caller's memory is unaffected: - + `CREATE` - `CREATE2`. TODO: [EOF] Add EOFCREATE opcode """ diff --git a/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py b/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py index 639d007542a..669a800e8b6 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py @@ -1,9 +1,12 @@ """ -abstract: Tests [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656) - Test copy operations of [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656) - that produce a memory expansion, and potentially an out-of-gas error. +abstract: Tests [EIP-5656: MCOPY - Memory copying +instruction](https://eips.ethereum.org/EIPS/eip-5656). -""" # noqa: E501 +Test copy operations of +[EIP-5656: MCOPY - Memory copying +instruction](https://eips.ethereum.org/EIPS/eip-5656) that produce a memory +expansion, and potentially an out-of-gas error. +""" import itertools from typing import List, Mapping @@ -74,11 +77,11 @@ def call_exact_cost( tx_access_list: List[AccessList], ) -> int: """ - Return the exact cost of the subcall, based on the initial memory and the length of the - copy. + Return the exact cost of the subcall, based on the initial memory and the + length of the copy. """ - # Starting from EIP-7623, we need to use an access list to raise the intrinsic gas cost to be - # above the floor data cost. + # Starting from EIP-7623, we need to use an access list to raise the + # intrinsic gas cost to be above the floor data cost. cost_memory_bytes = fork.memory_expansion_gas_calculator() gas_costs = fork.gas_costs() tx_intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator() @@ -218,7 +221,10 @@ def test_mcopy_memory_expansion( post: Mapping[str, Account], tx: Transaction, ): - """Perform MCOPY operations that expand the memory, and verify the gas it costs to do so.""" + """ + Perform MCOPY operations that expand the memory, and verify the gas it + costs to do so. + """ state_test( env=env, pre=pre, @@ -279,8 +285,8 @@ def test_mcopy_huge_memory_expansion( tx: Transaction, ): """ - Perform MCOPY operations that expand the memory by huge amounts, and verify that it correctly - runs out of gas. + Perform MCOPY operations that expand the memory by huge amounts, and verify + that it correctly runs out of gas. """ state_test( env=env, diff --git a/tests/cancun/eip6780_selfdestruct/test_dynamic_create2_selfdestruct_collision.py b/tests/cancun/eip6780_selfdestruct/test_dynamic_create2_selfdestruct_collision.py index ea59c47f2c0..90582de7807 100644 --- a/tests/cancun/eip6780_selfdestruct/test_dynamic_create2_selfdestruct_collision.py +++ b/tests/cancun/eip6780_selfdestruct/test_dynamic_create2_selfdestruct_collision.py @@ -51,20 +51,18 @@ def test_dynamic_create2_selfdestruct_collision( """ Dynamic Create2->Suicide->Create2 collision scenario. - Perform a CREATE2, make sure that the initcode sets at least a couple of storage keys, - then on a different call, in the same tx, perform a self-destruct. - Then: - a) on the same tx, attempt to recreate the contract <=== Covered in this test - 1) and create2 contract already in the state - 2) and create2 contract is not in the state - b) on a different tx, attempt to recreate the contract - Perform a CREATE2, make sure that the initcode sets at least a couple of storage keys, - then in a different tx, perform a self-destruct. - Then: - a) on the same tx, attempt to recreate the contract - b) on a different tx, attempt to recreate the contract - Verify that the test case described in - https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22156575/2024-01-06+Mainnet+Halting+Event + Perform a CREATE2, make sure that the initcode sets at least a couple of + storage keys, then on a different call, in the same tx, perform a + self-destruct. Then: a) on the same tx, attempt to recreate the contract + <=== Covered in this test 1) and create2 contract already in the state 2) + and create2 contract is not in the state b) on a different tx, attempt to + recreate the contract Perform a CREATE2, make sure that the initcode sets + at least a couple of storage keys, then in a different tx, perform a + self-destruct. Then: a) on the same tx, attempt to recreate the contract b) + on a different tx, attempt to recreate the contract Verify that the test + case described in + https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22156575/2024-01-06 + +Mainnet+Halting+Event """ assert call_create2_contract_in_between or call_create2_contract_at_the_end, "invalid test" @@ -79,7 +77,8 @@ def test_dynamic_create2_selfdestruct_collision( create2_salt = 1 # Create EOA for sendall destination (receives selfdestruct funds) - sendall_destination = pre.fund_eoa(0) # Will be funded by selfdestruct calls + sendall_destination = pre.fund_eoa(0) # Will be funded by selfdestruct + # calls # Create storage contract that will be called during initialization address_create2_storage = pre.deploy_contract( @@ -131,7 +130,8 @@ def test_dynamic_create2_selfdestruct_collision( + Op.CALL(100000, address_code, 0, 0, 0, 0, 0) # Call to the created account to trigger selfdestruct + Op.CALL(100000, call_address_in_between, first_call_value, 0, 0, 0, 0) - # Make a subcall that do CREATE2 collision and returns its address as the result + # Make a subcall that do CREATE2 collision and returns its address as + # the result + Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE()) + Op.CALL(100000, address_code, second_create2_value, 0, Op.CALLDATASIZE(), 0, 32) + Op.SSTORE( @@ -149,7 +149,8 @@ def test_dynamic_create2_selfdestruct_collision( sender = pre.fund_eoa(7000000000000000000) if create2_dest_already_in_state: - # Create2 address already in the state, e.g. deployed in a previous block + # Create2 address already in the state, e.g. deployed in a previous + # block pre[create2_address] = Account( balance=pre_existing_create2_balance, nonce=1, @@ -182,7 +183,8 @@ def test_dynamic_create2_selfdestruct_collision( } ) - # Calculate the destination account expected balance for the selfdestruct/sendall calls + # Calculate the destination account expected balance for the + # selfdestruct/sendall calls sendall_destination_balance = ( pre_existing_create2_balance if create2_dest_already_in_state else first_create2_value ) @@ -224,20 +226,18 @@ def test_dynamic_create2_selfdestruct_collision_two_different_transactions( """ Dynamic Create2->Suicide->Create2 collision scenario. - Perform a CREATE2, make sure that the initcode sets at least a couple of storage keys, - then on a different call, in the same tx, perform a self-destruct. - Then: - a) on the same tx, attempt to recreate the contract - 1) and create2 contract already in the state - 2) and create2 contract is not in the state - b) on a different tx, attempt to recreate the contract <=== Covered in this test - Perform a CREATE2, make sure that the initcode sets at least a couple of storage keys, - then in a different tx, perform a self-destruct. - Then: - a) on the same tx, attempt to recreate the contract - b) on a different tx, attempt to recreate the contract - Verify that the test case described in - https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22156575/2024-01-06+Mainnet+Halting+Event + Perform a CREATE2, make sure that the initcode sets at least a couple of + storage keys, then on a different call, in the same tx, perform a + self-destruct. Then: a) on the same tx, attempt to recreate the contract 1) + and create2 contract already in the state 2) and create2 contract is not in + the state b) on a different tx, attempt to recreate the contract <=== + Covered in this test Perform a CREATE2, make sure that the initcode sets at + least a couple of storage keys, then in a different tx, perform a + self-destruct. Then: a) on the same tx, attempt to recreate the contract b) + on a different tx, attempt to recreate the contract Verify that the test + case described in + https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22156575/2024-01-06 + +Mainnet+Halting+Event """ # assert call_create2_contract_at_the_end, "invalid test" @@ -252,7 +252,8 @@ def test_dynamic_create2_selfdestruct_collision_two_different_transactions( create2_salt = 1 # Create EOA for sendall destination (receives selfdestruct funds) - sendall_destination = pre.fund_eoa(0) # Will be funded by selfdestruct calls + sendall_destination = pre.fund_eoa(0) # Will be funded by selfdestruct + # calls # Create storage contract that will be called during initialization address_create2_storage = pre.deploy_contract( @@ -311,7 +312,8 @@ def test_dynamic_create2_selfdestruct_collision_two_different_transactions( # Create the second contract that performs the second transaction address_to_second = pre.deploy_contract( code=Op.JUMPDEST() - # Make a subcall that do CREATE2 collision and returns its address as the result + # Make a subcall that do CREATE2 collision and returns its address as + # the result + Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE()) + Op.CALL(100000, address_code, second_create2_value, 0, Op.CALLDATASIZE(), 0, 32) + Op.SSTORE( @@ -329,7 +331,8 @@ def test_dynamic_create2_selfdestruct_collision_two_different_transactions( sender = pre.fund_eoa(7000000000000000000) if create2_dest_already_in_state: - # Create2 address already in the state, e.g. deployed in a previous block + # Create2 address already in the state, e.g. deployed in a previous + # block pre[create2_address] = Account( balance=pre_existing_create2_balance, nonce=1, @@ -350,8 +353,9 @@ def test_dynamic_create2_selfdestruct_collision_two_different_transactions( ) ) - # after Cancun Create2 initcode is only executed if the contract did not already exist - # and before it will always be executed as the first tx deletes the account + # after Cancun Create2 initcode is only executed if the contract did not + # already exist and before it will always be executed as the first tx + # deletes the account post[address_create2_storage] = Account( storage={ create2_constructor_worked: int(fork < Cancun or not create2_dest_already_in_state) @@ -369,9 +373,10 @@ def test_dynamic_create2_selfdestruct_collision_two_different_transactions( post[address_to_second] = Account( storage={ code_worked: 0x01, - # Second create2 will not collide before Cancun as the first tx calls selfdestruct - # After cancun it will collide only if create2_dest_already_in_state otherwise the - # first tx creates and deletes it + # Second create2 will not collide before Cancun as the first tx + # calls selfdestruct After cancun it will collide only if + # create2_dest_already_in_state otherwise the first tx creates and + # deletes it second_create2_result: ( (0x00 if create2_dest_already_in_state else create2_address) if fork >= Cancun @@ -380,14 +385,16 @@ def test_dynamic_create2_selfdestruct_collision_two_different_transactions( } ) - # Calculate the destination account expected balance for the selfdestruct/sendall calls + # Calculate the destination account expected balance for the + # selfdestruct/sendall calls sendall_destination_balance = 0 if create2_dest_already_in_state: sendall_destination_balance += pre_existing_create2_balance if fork >= Cancun: - # first create2 fails, but first calls ok. the account is not removed on cancun - # therefore with the second create2 it is not successful + # first create2 fails, but first calls ok. the account is not + # removed on cancun therefore with the second create2 it is not + # successful sendall_destination_balance += first_call_value else: # first create2 fails, first calls totally removes the account @@ -396,8 +403,9 @@ def test_dynamic_create2_selfdestruct_collision_two_different_transactions( if call_create2_contract_at_the_end: sendall_destination_balance += second_create2_value else: - # if no account in the state, first create2 successful, first call successful and removes - # because it is removed in the next transaction second create2 successful + # if no account in the state, first create2 successful, first call + # successful and removes because it is removed in the next transaction + # second create2 successful sendall_destination_balance = first_create2_value + first_call_value if call_create2_contract_at_the_end: sendall_destination_balance += second_create2_value @@ -448,20 +456,20 @@ def test_dynamic_create2_selfdestruct_collision_multi_tx( blockchain_test: BlockchainTestFiller, ): """ - Dynamic Create2->Suicide->Create2 collision scenario over multiple transactions. - - Perform a CREATE2, make sure that the initcode sets at least a couple of storage keys, - then on a different call, in the same or different tx but same block, perform a self-destruct. - Then: - a) on the same tx, attempt to recreate the contract - b) on a different tx, attempt to recreate the contract - Perform a CREATE2, make sure that the initcode sets at least a couple of storage keys, - then in a different tx, perform a self-destruct. - Then: - a) on the same tx, attempt to recreate the contract <=== Covered in this test - b) on a different tx, attempt to recreate the contract <=== Covered in this test - Verify that the test case described in - https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22156575/2024-01-06+Mainnet+Halting+Event + Dynamic Create2->Suicide->Create2 collision scenario over multiple + transactions. + + Perform a CREATE2, make sure that the initcode sets at least a couple of + storage keys, then on a different call, in the same or different tx but + same block, perform a self-destruct. Then: a) on the same tx, attempt to + recreate the contract b) on a different tx, attempt to recreate the + contract Perform a CREATE2, make sure that the initcode sets at least a + couple of storage keys, then in a different tx, perform a self-destruct. + Then: a) on the same tx, attempt to recreate the contract <=== + Covered in this test b) on a different tx, attempt to recreate the contract + <=== Covered in this test Verify that the test case described in + https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22156575/2024-01-06 + +Mainnet+Halting+Event """ if recreate_on_first_tx: assert selfdestruct_on_first_tx, "invalid test" @@ -477,7 +485,8 @@ def test_dynamic_create2_selfdestruct_collision_multi_tx( create2_salt = 1 # Create EOA for sendall destination (receives selfdestruct funds) - sendall_destination = pre.fund_eoa(0) # Will be funded by selfdestruct calls + sendall_destination = pre.fund_eoa(0) # Will be funded by selfdestruct + # calls # Create storage contract that will be called during initialization address_create2_storage = pre.deploy_contract( @@ -540,7 +549,8 @@ def test_dynamic_create2_selfdestruct_collision_multi_tx( if recreate_on_first_tx: first_tx_code += ( - # Make a subcall that do CREATE2 collision and returns its address as the result + # Make a subcall that do CREATE2 collision and returns its address + # as the result Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE()) + Op.CALL(100000, address_code, second_create2_value, 0, Op.CALLDATASIZE(), 0, 32) + Op.SSTORE( @@ -551,7 +561,8 @@ def test_dynamic_create2_selfdestruct_collision_multi_tx( else: second_tx_code += ( - # Make a subcall that do CREATE2 collision and returns its address as the result + # Make a subcall that do CREATE2 collision and returns its address + # as the result Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE()) + Op.CALL(100000, address_code, second_create2_value, 0, Op.CALLDATASIZE(), 0, 32) + Op.SSTORE( @@ -566,7 +577,8 @@ def test_dynamic_create2_selfdestruct_collision_multi_tx( first_tx_code += Op.SSTORE(part_1_worked, 1) second_tx_code += Op.SSTORE(part_2_worked, 1) - # Create the main contract that uses conditional logic to handle both transactions + # Create the main contract that uses conditional logic to handle both + # transactions address_to = pre.deploy_contract( code=Conditional( # Depending on the tx, execute the first or second tx code @@ -585,8 +597,9 @@ def test_dynamic_create2_selfdestruct_collision_multi_tx( # Create2 address only exists if it was pre-existing and after cancun account_will_exist_with_code = not selfdestruct_on_first_tx and fork >= Cancun - # If the contract is self-destructed and we also attempt to recreate it on the first tx, - # the second call on the second tx will only place balance in the account + # If the contract is self-destructed and we also attempt to recreate it on + # the first tx, the second call on the second tx will only place balance in + # the account account_will_exist_with_balance = selfdestruct_on_first_tx and recreate_on_first_tx post[create2_address] = ( @@ -609,14 +622,16 @@ def test_dynamic_create2_selfdestruct_collision_multi_tx( part_2_worked: 0x01, # First create2 always works first_create2_result: create2_address, - # Second create2 only works if we successfully self-destructed on the first tx + # Second create2 only works if we successfully self-destructed on + # the first tx second_create2_result: ( create2_address if selfdestruct_on_first_tx and not recreate_on_first_tx else 0x00 ), } ) - # Calculate the destination account expected balance for the selfdestruct/sendall calls + # Calculate the destination account expected balance for the + # selfdestruct/sendall calls sendall_destination_balance = first_create2_value + first_call_value if not account_will_exist_with_balance: diff --git a/tests/cancun/eip6780_selfdestruct/test_reentrancy_selfdestruct_revert.py b/tests/cancun/eip6780_selfdestruct/test_reentrancy_selfdestruct_revert.py index 9a851c6b26c..6706ea1e08e 100644 --- a/tests/cancun/eip6780_selfdestruct/test_reentrancy_selfdestruct_revert.py +++ b/tests/cancun/eip6780_selfdestruct/test_reentrancy_selfdestruct_revert.py @@ -1,7 +1,4 @@ -""" -Suicide scenario requested test -https://github.com/ethereum/tests/issues/1325. -""" +"""Suicide scenario requested test https://github.com/ethereum/tests/issues/1325.""" from typing import SupportsBytes @@ -148,13 +145,11 @@ def test_reentrancy_selfdestruct_revert( """ Suicide reentrancy scenario. - Call|Callcode|Delegatecall the contract S. - S self destructs. - Call the revert proxy contract R. - R Calls|Callcode|Delegatecall S. - S self destructs (for the second time). - R reverts (including the effects of the second selfdestruct). - It is expected the S is self destructed after the transaction. + Call|Callcode|Delegatecall the contract S. S self destructs. Call the + revert proxy contract R. R Calls|Callcode|Delegatecall S. S self destructs + (for the second time). R reverts (including the effects of the second + selfdestruct). It is expected the S is self destructed after the + transaction. """ post = { # Second caller unchanged as call gets reverted @@ -163,12 +158,14 @@ def test_reentrancy_selfdestruct_revert( if first_suicide in [Op.CALLCODE, Op.DELEGATECALL]: if fork >= Cancun: - # On Cancun even callcode/delegatecall does not remove the account, so the value remain + # On Cancun even callcode/delegatecall does not remove the account, + # so the value remain post[executor_contract_address] = Account( storage={ 0x01: 0x01, # First call to contract S->suicide success 0x02: 0x00, # Second call to contract S->suicide reverted - 0x03: 16, # Reverted value to check that revert really worked + 0x03: 16, # Reverted value to check that revert really + # worked }, ) else: @@ -184,7 +181,8 @@ def test_reentrancy_selfdestruct_revert( balance=executor_contract_init_balance, ) - # On Cancun suicide no longer destroys the account from state, just cleans the balance + # On Cancun suicide no longer destroys the account from state, just cleans + # the balance if first_suicide in [Op.CALL]: post[executor_contract_address] = Account( storage={ @@ -194,7 +192,8 @@ def test_reentrancy_selfdestruct_revert( }, ) if fork >= Cancun: - # On Cancun suicide does not remove the account, just sends the balance + # On Cancun suicide does not remove the account, just sends the + # balance post[selfdestruct_contract_address] = Account( balance=0, code=selfdestruct_contract_bytecode, storage={} ) diff --git a/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py b/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py index b8396261625..00c13b642ed 100644 --- a/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py +++ b/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py @@ -1,8 +1,7 @@ """ -abstract: Tests [EIP-6780: SELFDESTRUCT only in same transaction](https://eips.ethereum.org/EIPS/eip-6780) - Tests for [EIP-6780: SELFDESTRUCT only in same transaction](https://eips.ethereum.org/EIPS/eip-6780). - -""" # noqa: E501 +abstract: Tests [EIP-6780: SELFDESTRUCT only in same +transaction](https://eips.ethereum.org/EIPS/eip-6780). +""" from itertools import cycle from typing import Dict, List @@ -37,8 +36,9 @@ Address of a pre-existing contract that self-destructs. """ -# Sentinel value to indicate that the self-destructing contract address should be used, only for -# use in `pytest.mark.parametrize`, not for use within the test method itself. +# Sentinel value to indicate that the self-destructing contract address should +# be used, only for use in `pytest.mark.parametrize`, not for use within the +# test method itself. SELF_ADDRESS = Address(0x01) # Sentinel value to indicate that the contract should not self-destruct. NO_SELFDESTRUCT = Address(0x00) @@ -59,9 +59,11 @@ def sendall_recipient_addresses(request: pytest.FixtureRequest, pre: Alloc) -> L """ List of addresses that receive the SENDALL operation in any test. - If the test case requires a pre-existing contract, it will be deployed here. + If the test case requires a pre-existing contract, it will be deployed + here. - By default the list is a single pre-deployed contract that unconditionally sets storage. + By default the list is a single pre-deployed contract that unconditionally + sets storage. """ address_list = getattr(request, "param", [PRE_DEPLOY_CONTRACT_1]) deployed_contracts: Dict[str, Address] = {} @@ -88,8 +90,8 @@ def selfdestruct_code_preset( bytecode = Op.SSTORE(0, Op.ADD(Op.SLOAD(0), 1)) if len(sendall_recipient_addresses) != 1: - # Load the recipient address from calldata, each test case needs to pass the addresses as - # calldata + # Load the recipient address from calldata, each test case needs to + # pass the addresses as calldata bytecode += Conditional( # We avoid having the caller to give us our own address by checking # against a constant that is a magic number @@ -119,8 +121,8 @@ def selfdestruct_code( sendall_recipient_addresses: List[Address], ) -> Bytecode: """ - Create default self-destructing bytecode, - which can be modified by each test if necessary. + Create default self-destructing bytecode, which can be modified by each + test if necessary. """ return selfdestruct_code_preset(sendall_recipient_addresses=sendall_recipient_addresses) @@ -190,19 +192,19 @@ def test_create_selfdestruct_same_tx( selfdestruct_contract_initial_balance: int, ): """ - Use CREATE or CREATE2 to create a self-destructing contract, and call it in the same - transaction. + Use CREATE or CREATE2 to create a self-destructing contract, and call it in + the same transaction. Behavior should be the same before and after EIP-6780. - Test using: - - Different send-all recipient addresses: single, multiple, including self - - Different initial balances for the self-destructing contract - - Different opcodes: CREATE, CREATE2 + Test using: - Different send-all recipient addresses: single, multiple, + including self - Different initial balances for the self-destructing + contract - Different opcodes: CREATE, CREATE2 """ selfdestruct_contract_initcode = Initcode(deploy_code=selfdestruct_code) initcode_copy_from_address = pre.deploy_contract(selfdestruct_contract_initcode) - # Our entry point is an initcode that in turn creates a self-destructing contract + # Our entry point is an initcode that in turn creates a self-destructing + # contract entry_code_storage = Storage() # Bytecode used to create the contract, can be CREATE or CREATE2 @@ -225,9 +227,11 @@ def test_create_selfdestruct_same_tx( ) selfdestruct_contract_current_balance = selfdestruct_contract_initial_balance - # Entry code that will be executed, creates the contract and then calls it in the same tx + # Entry code that will be executed, creates the contract and then calls it + # in the same tx entry_code = ( - # Initcode is already deployed at `initcode_copy_from_address`, so just copy it + # Initcode is already deployed at `initcode_copy_from_address`, so just + # copy it Op.EXTCODECOPY( initcode_copy_from_address, 0, @@ -252,8 +256,8 @@ def test_create_selfdestruct_same_tx( Op.EXTCODEHASH(selfdestruct_contract_address), ) - # Call the self-destructing contract multiple times as required, increasing the wei sent each - # time + # Call the self-destructing contract multiple times as required, increasing + # the wei sent each time entry_code_balance = 0 for i, sendall_recipient in zip(range(call_times), cycle(sendall_recipient_addresses)): entry_code += Op.MSTORE(0, sendall_recipient) @@ -276,8 +280,9 @@ def test_create_selfdestruct_same_tx( if sendall_recipient != selfdestruct_contract_address: sendall_final_balances[sendall_recipient] += selfdestruct_contract_current_balance - # Self-destructing contract must always have zero balance after the call because the - # self-destruct always happens in the same transaction in this test + # Self-destructing contract must always have zero balance after the + # call because the self-destruct always happens in the same transaction + # in this test selfdestruct_contract_current_balance = 0 entry_code += Op.SSTORE( @@ -296,8 +301,8 @@ def test_create_selfdestruct_same_tx( Op.EXTCODEHASH(selfdestruct_contract_address), ) - # Lastly return zero so the entry point contract is created and we can retain the stored - # values for verification. + # Lastly return zero so the entry point contract is created and we can + # retain the stored values for verification. entry_code += Op.RETURN(max(len(selfdestruct_contract_initcode), 32), 1) tx = Transaction( @@ -336,7 +341,8 @@ def test_self_destructing_initcode( selfdestruct_code: Bytecode, sendall_recipient_addresses: List[Address], create_opcode: Op, - call_times: int, # Number of times to call the self-destructing contract in the same tx + call_times: int, # Number of times to call the self-destructing contract + # in the same tx selfdestruct_contract_initial_balance: int, ): """ @@ -344,13 +350,13 @@ def test_self_destructing_initcode( Behavior is the same before and after EIP-6780. - Test using: - - Different initial balances for the self-destructing contract - - Different opcodes: CREATE, CREATE2 - - Different number of calls to the self-destructing contract in the same tx + Test using: - Different initial balances for the self-destructing contract + - Different opcodes: CREATE, CREATE2 - Different number of calls to the + self-destructing contract in the same tx """ initcode_copy_from_address = pre.deploy_contract(selfdestruct_code) - # Our entry point is an initcode that in turn creates a self-destructing contract + # Our entry point is an initcode that in turn creates a self-destructing + # contract entry_code_storage = Storage() sendall_amount = 0 @@ -364,9 +370,11 @@ def test_self_destructing_initcode( opcode=create_opcode, ) - # Entry code that will be executed, creates the contract and then calls it in the same tx + # Entry code that will be executed, creates the contract and then calls it + # in the same tx entry_code = ( - # Initcode is already deployed at `initcode_copy_from_address`, so just copy it + # Initcode is already deployed at `initcode_copy_from_address`, so just + # copy it Op.EXTCODECOPY( initcode_copy_from_address, 0, @@ -391,8 +399,8 @@ def test_self_destructing_initcode( Op.EXTCODEHASH(selfdestruct_contract_address), ) - # Call the self-destructing contract multiple times as required, increasing the wei sent each - # time + # Call the self-destructing contract multiple times as required, increasing + # the wei sent each time entry_code_balance = 0 for i in range(call_times): entry_code += Op.SSTORE( @@ -414,8 +422,8 @@ def test_self_destructing_initcode( Op.BALANCE(selfdestruct_contract_address), ) - # Lastly return zero so the entry point contract is created and we can retain the stored - # values for verification. + # Lastly return zero so the entry point contract is created and we can + # retain the stored values for verification. entry_code += Op.RETURN(max(len(selfdestruct_code), 32), 1) if selfdestruct_contract_initial_balance > 0: @@ -462,9 +470,8 @@ def test_self_destructing_initcode_create_tx( Behavior should be the same before and after EIP-6780. - Test using: - - Different initial balances for the self-destructing contract - - Different transaction value amounts + Test using: - Different initial balances for the self-destructing contract + - Different transaction value amounts """ tx = Transaction( sender=sender, @@ -476,7 +483,8 @@ def test_self_destructing_initcode_create_tx( selfdestruct_contract_address = tx.created_contract pre.fund_address(selfdestruct_contract_address, selfdestruct_contract_initial_balance) - # Our entry point is an initcode that in turn creates a self-destructing contract + # Our entry point is an initcode that in turn creates a self-destructing + # contract sendall_amount = selfdestruct_contract_initial_balance + tx_value post: Dict[Address, Account] = { @@ -487,7 +495,8 @@ def test_self_destructing_initcode_create_tx( state_test(pre=pre, post=post, tx=tx) -@pytest.mark.parametrize("create_opcode", [Op.CREATE2]) # Can only recreate using CREATE2 +@pytest.mark.parametrize("create_opcode", [Op.CREATE2]) # Can only recreate +# using CREATE2 @pytest.mark.parametrize( "sendall_recipient_addresses", [ @@ -514,18 +523,19 @@ def test_recreate_self_destructed_contract_different_txs( selfdestruct_contract_initial_balance: int, sendall_recipient_addresses: List[Address], create_opcode: Op, - recreate_times: int, # Number of times to recreate the contract in different transactions - call_times: int, # Number of times to call the self-destructing contract in the same tx + recreate_times: int, # Number of times to recreate the contract in + # different transactions + call_times: int, # Number of times to call the self-destructing contract + # in the same tx ): """ - Test that a contract can be recreated after it has self-destructed, over the lapse - of multiple transactions. + Test that a contract can be recreated after it has self-destructed, over + the lapse of multiple transactions. Behavior should be the same before and after EIP-6780. - Test using: - - Different initial balances for the self-destructing contract - - Contract creating opcodes that are not CREATE + Test using: - Different initial balances for the self-destructing contract + - Contract creating opcodes that are not CREATE """ selfdestruct_contract_initcode = Initcode(deploy_code=selfdestruct_code) initcode_copy_from_address = pre.deploy_contract(selfdestruct_contract_initcode) @@ -538,7 +548,8 @@ def test_recreate_self_destructed_contract_different_txs( # Entry code that will be executed, creates the contract and then calls it entry_code = ( - # Initcode is already deployed at initcode_copy_from_address, so just copy it + # Initcode is already deployed at initcode_copy_from_address, so just + # copy it Op.EXTCODECOPY( initcode_copy_from_address, 0, @@ -663,15 +674,16 @@ def test_selfdestruct_pre_existing( call_times: int, ): """ - Test calling a previously created account that contains a selfdestruct, and verify its balance - is sent to the destination address. + Test calling a previously created account that contains a selfdestruct, and + verify its balance is sent to the destination address. - After EIP-6780, the balance should be sent to the send-all recipient address, similar to - the behavior before the EIP, but the account is not deleted. + After EIP-6780, the balance should be sent to the send-all recipient + address, similar to the behavior before the EIP, but the account is not + deleted. - Test using: - - Different send-all recipient addresses: single, multiple, including self - - Different initial balances for the self-destructing contract + Test using: - Different send-all recipient addresses: single, multiple, + including self - Different initial balances for the self-destructing + contract """ selfdestruct_contract_address = pre.deploy_contract( selfdestruct_code, balance=selfdestruct_contract_initial_balance @@ -688,12 +700,12 @@ def test_selfdestruct_pre_existing( ) selfdestruct_contract_current_balance = selfdestruct_contract_initial_balance - # Entry code in this case will simply call the pre-existing self-destructing contract, - # as many times as required + # Entry code in this case will simply call the pre-existing self- + # destructing contract, as many times as required entry_code = Bytecode() - # Call the self-destructing contract multiple times as required, increasing the wei sent each - # time + # Call the self-destructing contract multiple times as required, increasing + # the wei sent each time entry_code_balance = 0 for i, sendall_recipient in zip(range(call_times), cycle(sendall_recipient_addresses)): entry_code += Op.MSTORE(0, sendall_recipient) @@ -716,8 +728,9 @@ def test_selfdestruct_pre_existing( if sendall_recipient != selfdestruct_contract_address: sendall_final_balances[sendall_recipient] += selfdestruct_contract_current_balance - # Balance is only kept by the self-destructing contract if we are sending to self and the - # EIP is activated, otherwise the balance is destroyed + # Balance is only kept by the self-destructing contract if we are + # sending to self and the EIP is activated, otherwise the balance is + # destroyed if sendall_recipient != selfdestruct_contract_address or not eip_enabled: selfdestruct_contract_current_balance = 0 @@ -737,8 +750,8 @@ def test_selfdestruct_pre_existing( Op.EXTCODEHASH(selfdestruct_contract_address), ) - # Lastly return zero so the entry point contract is created and we can retain the stored - # values for verification. + # Lastly return zero so the entry point contract is created and we can + # retain the stored values for verification. entry_code += Op.RETURN(32, 1) tx = Transaction( @@ -787,8 +800,9 @@ def test_selfdestruct_created_same_block_different_tx( call_times: int, ): """ - Test that if an account created in the same block that contains a selfdestruct is - called, its balance is sent to the send-all address, but the account is not deleted. + Test that if an account created in the same block that contains a + selfdestruct is called, its balance is sent to the send-all address, but + the account is not deleted. """ selfdestruct_code = selfdestruct_code_preset( sendall_recipient_addresses=sendall_recipient_addresses, @@ -800,11 +814,11 @@ def test_selfdestruct_created_same_block_different_tx( sendall_amount = selfdestruct_contract_initial_balance entry_code = Bytecode() - # Entry code in this case will simply call the pre-existing self-destructing contract, - # as many times as required + # Entry code in this case will simply call the pre-existing self- + # destructing contract, as many times as required - # Call the self-destructing contract multiple times as required, increasing the wei sent each - # time + # Call the self-destructing contract multiple times as required, increasing + # the wei sent each time entry_code_balance = 0 for i in range(call_times): entry_code += Op.SSTORE( @@ -838,8 +852,8 @@ def test_selfdestruct_created_same_block_different_tx( Op.EXTCODEHASH(selfdestruct_contract_address), ) - # Lastly return zero so the entry point contract is created and we can retain the stored - # values for verification. + # Lastly return zero so the entry point contract is created and we can + # retain the stored values for verification. entry_code += Op.RETURN(32, 1) post: Dict[Address, Account] = { @@ -890,15 +904,17 @@ def test_calling_from_new_contract_to_pre_existing_contract( selfdestruct_contract_initial_balance: int, ): """ - Test that if an account created in the current transaction delegate-call a previously created - account that executes self-destruct, the calling account is deleted. + Test that if an account created in the current transaction delegate-call a + previously created account that executes self-destruct, the calling account + is deleted. """ pre_existing_selfdestruct_address = pre.deploy_contract( selfdestruct_code_preset( sendall_recipient_addresses=sendall_recipient_addresses, ), ) - # Our entry point is an initcode that in turn creates a self-destructing contract + # Our entry point is an initcode that in turn creates a self-destructing + # contract entry_code_storage = Storage() sendall_amount = 0 @@ -915,9 +931,11 @@ def test_calling_from_new_contract_to_pre_existing_contract( # Bytecode used to create the contract, can be CREATE or CREATE2 create_bytecode = create_opcode(size=len(selfdestruct_contract_initcode)) - # Entry code that will be executed, creates the contract and then calls it in the same tx + # Entry code that will be executed, creates the contract and then calls it + # in the same tx entry_code = ( - # Initcode is already deployed at `initcode_copy_from_address`, so just copy it + # Initcode is already deployed at `initcode_copy_from_address`, so just + # copy it Op.EXTCODECOPY( initcode_copy_from_address, 0, @@ -942,8 +960,8 @@ def test_calling_from_new_contract_to_pre_existing_contract( Op.EXTCODEHASH(selfdestruct_contract_address), ) - # Call the self-destructing contract multiple times as required, increasing the wei sent each - # time + # Call the self-destructing contract multiple times as required, increasing + # the wei sent each time entry_code_balance = 0 for i in range(call_times): entry_code += Op.SSTORE( @@ -977,8 +995,8 @@ def test_calling_from_new_contract_to_pre_existing_contract( Op.EXTCODEHASH(selfdestruct_contract_address), ) - # Lastly return zero so the entry point contract is created and we can retain the stored - # values for verification. + # Lastly return zero so the entry point contract is created and we can + # retain the stored values for verification. entry_code += Op.RETURN(max(len(selfdestruct_contract_initcode), 32), 1) if selfdestruct_contract_initial_balance > 0: @@ -1025,9 +1043,9 @@ def test_calling_from_pre_existing_contract_to_new_contract( pre_existing_contract_initial_balance: int, ): """ - Test that if an account created in the current transaction contains a self-destruct and is - delegate-called by an account created before the current transaction, the calling account - is not deleted. + Test that if an account created in the current transaction contains a + self-destruct and is delegate-called by an account created before the + current transaction, the calling account is not deleted. """ selfdestruct_contract_initcode = Initcode(deploy_code=selfdestruct_code) initcode_copy_from_address = pre.deploy_contract( @@ -1051,13 +1069,16 @@ def test_calling_from_pre_existing_contract_to_new_contract( balance=pre_existing_contract_initial_balance, ) - # Our entry point is an initcode that in turn creates a self-destructing contract + # Our entry point is an initcode that in turn creates a self-destructing + # contract entry_code_storage = Storage() sendall_amount = pre_existing_contract_initial_balance - # Entry code that will be executed, creates the contract and then calls it in the same tx + # Entry code that will be executed, creates the contract and then calls it + # in the same tx entry_code = ( - # Initcode is already deployed at `initcode_copy_from_address`, so just copy it + # Initcode is already deployed at `initcode_copy_from_address`, so just + # copy it Op.EXTCODECOPY( initcode_copy_from_address, 0, @@ -1085,8 +1106,9 @@ def test_calling_from_pre_existing_contract_to_new_contract( Op.EXTCODEHASH(caller_address), ) - # Now instead of calling the newly created contract directly, we delegate call to it - # from a pre-existing contract, and the contract must not self-destruct + # Now instead of calling the newly created contract directly, we delegate + # call to it from a pre-existing contract, and the contract must not self- + # destruct entry_code_balance = selfdestruct_contract_initial_balance for i in range(call_times): entry_code += Op.SSTORE( @@ -1120,8 +1142,8 @@ def test_calling_from_pre_existing_contract_to_new_contract( Op.EXTCODEHASH(caller_address), ) - # Lastly return zero so the entry point contract is created and we can retain the stored - # values for verification. + # Lastly return zero so the entry point contract is created and we can + # retain the stored values for verification. entry_code += Op.RETURN(max(len(selfdestruct_contract_initcode), 32), 1) tx = Transaction( @@ -1177,8 +1199,9 @@ def test_create_selfdestruct_same_tx_increased_nonce( selfdestruct_contract_initial_balance: int, ): """ - Verify that a contract can self-destruct if it was created in the same transaction, even when - its nonce has been increased due to contract creation. + Verify that a contract can self-destruct if it was created in the same + transaction, even when its nonce has been increased due to contract + creation. """ initcode = Op.RETURN(0, 1) selfdestruct_pre_bytecode = Op.MSTORE(0, Op.PUSH32(bytes(initcode))) + Op.POP( @@ -1196,7 +1219,8 @@ def test_create_selfdestruct_same_tx_increased_nonce( ) if selfdestruct_contract_initial_balance > 0: pre.fund_address(selfdestruct_contract_address, selfdestruct_contract_initial_balance) - # Our entry point is an initcode that in turn creates a self-destructing contract + # Our entry point is an initcode that in turn creates a self-destructing + # contract entry_code_storage = Storage() # Create a dict to record the expected final balances @@ -1208,9 +1232,11 @@ def test_create_selfdestruct_same_tx_increased_nonce( # Bytecode used to create the contract, can be CREATE or CREATE2 create_bytecode = create_opcode(size=len(selfdestruct_contract_initcode)) - # Entry code that will be executed, creates the contract and then calls it in the same tx + # Entry code that will be executed, creates the contract and then calls it + # in the same tx entry_code = ( - # Initcode is already deployed at `initcode_copy_from_address`, so just copy it + # Initcode is already deployed at `initcode_copy_from_address`, so just + # copy it Op.EXTCODECOPY( initcode_copy_from_address, 0, @@ -1235,8 +1261,8 @@ def test_create_selfdestruct_same_tx_increased_nonce( Op.EXTCODEHASH(selfdestruct_contract_address), ) - # Call the self-destructing contract multiple times as required, increasing the wei sent each - # time + # Call the self-destructing contract multiple times as required, increasing + # the wei sent each time entry_code_balance = 0 for i, sendall_recipient in zip(range(call_times), cycle(sendall_recipient_addresses)): entry_code += Op.MSTORE(0, sendall_recipient) @@ -1259,8 +1285,9 @@ def test_create_selfdestruct_same_tx_increased_nonce( if sendall_recipient != selfdestruct_contract_address: sendall_final_balances[sendall_recipient] += selfdestruct_contract_current_balance - # Self-destructing contract must always have zero balance after the call because the - # self-destruct always happens in the same transaction in this test + # Self-destructing contract must always have zero balance after the + # call because the self-destruct always happens in the same transaction + # in this test selfdestruct_contract_current_balance = 0 entry_code += Op.SSTORE( @@ -1279,8 +1306,8 @@ def test_create_selfdestruct_same_tx_increased_nonce( Op.EXTCODEHASH(selfdestruct_contract_address), ) - # Lastly return zero so the entry point contract is created and we can retain the stored - # values for verification. + # Lastly return zero so the entry point contract is created and we can + # retain the stored values for verification. entry_code += Op.RETURN(max(len(selfdestruct_contract_initcode), 32), 1) tx = Transaction( @@ -1307,7 +1334,8 @@ def test_create_selfdestruct_same_tx_increased_nonce( for address, balance in sendall_final_balances.items(): post[address] = Account(balance=balance, storage={0: 1}) - # Check the new contracts created from the self-destructing contract were correctly created. + # Check the new contracts created from the self-destructing contract were + # correctly created. for address in [ compute_create_address(address=selfdestruct_contract_address, nonce=i + 1) for i in range(call_times) diff --git a/tests/cancun/eip6780_selfdestruct/test_selfdestruct_revert.py b/tests/cancun/eip6780_selfdestruct/test_selfdestruct_revert.py index c13dfb85266..0e5c86fde5c 100644 --- a/tests/cancun/eip6780_selfdestruct/test_selfdestruct_revert.py +++ b/tests/cancun/eip6780_selfdestruct/test_selfdestruct_revert.py @@ -1,4 +1,4 @@ -"""tests for selfdestruct interaction with revert.""" +"""Tests for selfdestruct interaction with revert.""" from typing import Dict @@ -63,10 +63,9 @@ def recursive_revert_contract_code( selfdestruct_with_transfer_contract_address: Address, ) -> Bytecode: """ - Contract code that: - Given selfdestructable contract A, transfer value to A and call A.selfdestruct. - Then, recurse into a new call which transfers value to A, - call A.selfdestruct, and reverts. + Contract code that: Given selfdestructable contract A, transfer value to A + and call A.selfdestruct. Then, recurse into a new call which transfers + value to A, call A.selfdestruct, and reverts. """ # Common prefix for all three cases: # case 1: selfdestruct_on_outer_call=1 @@ -244,7 +243,9 @@ def selfdestruct_with_transfer_contract_address( selfdestruct_with_transfer_contract_code: Bytecode, same_tx: bool, ) -> Address: - """Contract address for contract that can selfdestruct and receive value.""" + """ + Contract address for contract that can selfdestruct and receive value. + """ if same_tx: return compute_create_address(address=entry_code_address, nonce=1) # We need to deploy the contract before. @@ -303,7 +304,9 @@ def selfdestruct_with_transfer_initcode_copy_from_address( pre: Alloc, selfdestruct_with_transfer_contract_initcode: Bytecode, ) -> Address: - """Address of a pre-existing contract we use to simply copy initcode from.""" + """ + Address of a pre-existing contract we use to simply copy initcode from. + """ addr = pre.deploy_contract(selfdestruct_with_transfer_contract_initcode) return addr @@ -340,11 +343,13 @@ def test_selfdestruct_created_in_same_tx_with_revert( # noqa SC200 ): """ Given: - Contract A which has methods to receive balance and selfdestruct, and was created in current tx + Contract A which has methods to receive balance and selfdestruct, + and was created in current tx. + Test the following call sequence: - Transfer value to A and call A.selfdestruct. - Recurse into a new call from transfers value to A, calls A.selfdestruct, and reverts. - """ # noqa: E501 + Transfer value to A and call A.selfdestruct. Recurse into a new call + from transfers value to A, calls A.selfdestruct, and reverts. + """ entry_code = Op.EXTCODECOPY( selfdestruct_with_transfer_initcode_copy_from_address, 0, @@ -357,7 +362,9 @@ def test_selfdestruct_created_in_same_tx_with_revert( # noqa SC200 Op.CREATE( 0, 0, - len(bytes(selfdestruct_with_transfer_contract_initcode)), # Value # Offset + len(bytes(selfdestruct_with_transfer_contract_initcode)), # Value + # # + # Offset ), ) @@ -400,7 +407,8 @@ def test_selfdestruct_created_in_same_tx_with_revert( # noqa SC200 code=selfdestruct_with_transfer_contract_code, storage=Storage( { - # 2 value transfers (1 in outer call, 1 in reverted inner call) + # 2 value transfers (1 in outer call, 1 in reverted inner + # call) 0: 1, # type: ignore # 1 selfdestruct in reverted inner call 1: 0, # type: ignore @@ -454,8 +462,8 @@ def test_selfdestruct_not_created_in_same_tx_with_revert( recursive_revert_contract_code: Bytecode, ): """ - Same test as selfdestruct_created_in_same_tx_with_revert except selfdestructable contract - is pre-existing. + Same test as selfdestruct_created_in_same_tx_with_revert except + selfdestructable contract is pre-existing. """ entry_code = Op.CALL( Op.GASLIMIT(), @@ -477,7 +485,8 @@ def test_selfdestruct_not_created_in_same_tx_with_revert( code=selfdestruct_with_transfer_contract_code, storage=Storage( { - # 2 value transfers: 1 in outer call, 1 in reverted inner call + # 2 value transfers: 1 in outer call, 1 in reverted inner + # call 0: 1, # type: ignore # 1 selfdestruct in reverted inner call 1: 1, # type: ignore @@ -493,9 +502,11 @@ def test_selfdestruct_not_created_in_same_tx_with_revert( code=selfdestruct_with_transfer_contract_code, storage=Storage( { - # 2 value transfers: 1 in outer call, 1 in reverted inner call + # 2 value transfers: 1 in outer call, 1 in reverted inner + # call 0: 1, # type: ignore - # 2 selfdestructs: 1 in outer call, 1 in reverted inner call # noqa SC100 + # 2 selfdestructs: 1 in outer call, 1 in reverted inner + # call # noqa SC100 1: 0, # type: ignore } ), diff --git a/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py b/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py index 6f1f170ed80..b62257fae67 100644 --- a/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py +++ b/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py @@ -1,8 +1,7 @@ """ -abstract: Tests [EIP-7516: BLOBBASEFEE opcode](https://eips.ethereum.org/EIPS/eip-7516) - Test BLOBGASFEE opcode [EIP-7516: BLOBBASEFEE opcode](https://eips.ethereum.org/EIPS/eip-7516). - -""" # noqa: E501 +abstract: Tests [EIP-7516: BLOBBASEFEE +opcode](https://eips.ethereum.org/EIPS/eip-7516). +""" from itertools import count @@ -57,13 +56,19 @@ def caller_code( @pytest.fixture def caller_pre_storage() -> Storage: - """Storage of the account containing the bytecode that calls the test contract.""" + """ + Storage of the account containing the bytecode that calls the test + contract. + """ return Storage() @pytest.fixture def caller_address(pre: Alloc, caller_code: Bytecode, caller_pre_storage) -> Address: - """Address of the account containing the bytecode that calls the test contract.""" + """ + Address of the account containing the bytecode that calls the test + contract. + """ return pre.deploy_contract(caller_code) @@ -96,7 +101,10 @@ def test_blobbasefee_stack_overflow( tx: Transaction, call_fails: bool, ): - """Tests that the BLOBBASEFEE opcode produces a stack overflow by using it repeatedly.""" + """ + Tests that the BLOBBASEFEE opcode produces a stack overflow by using it + repeatedly. + """ post = { caller_address: Account( storage={1: 0 if call_fails else 1}, @@ -155,7 +163,10 @@ def test_blobbasefee_before_fork( callee_address: Address, tx: Transaction, ): - """Tests that the BLOBBASEFEE opcode results on exception when called before the fork.""" + """ + Tests that the BLOBBASEFEE opcode results on exception when called before + the fork. + """ # Fork happens at timestamp 15_000 timestamp = 7_500 post = { @@ -193,8 +204,8 @@ def test_blobbasefee_during_fork( tx: Transaction, ): """ - Tests that the BLOBBASEFEE opcode results on exception when called before the fork and - succeeds when called after the fork. + Tests that the BLOBBASEFEE opcode results on exception when called before + the fork and succeeds when called after the fork. """ code_caller_post_storage = Storage() diff --git a/tests/constantinople/eip1014_create2/test_create_returndata.py b/tests/constantinople/eip1014_create2/test_create_returndata.py index 3e64af7dae6..99b6690d053 100644 --- a/tests/constantinople/eip1014_create2/test_create_returndata.py +++ b/tests/constantinople/eip1014_create2/test_create_returndata.py @@ -1,7 +1,7 @@ """ -Return data management around create2 -Port call_outsize_then_create2_successful_then_returndatasizeFiller.json test -Port call_then_create2_successful_then_returndatasizeFiller.json test. +Return data management around create2 Port +call_outsize_then_create2_successful_then_returndatasizeFiller.json test Port +call_then_create2_successful_then_returndatasizeFiller.json test. """ import pytest @@ -36,7 +36,10 @@ def test_create2_return_data( pre: Alloc, state_test: StateTestFiller, ): - """Validate that create2 return data does not interfere with previously existing memory.""" + """ + Validate that create2 return data does not interfere with previously + existing memory. + """ # Storage vars slot_returndatasize_before_create = 0 slot_returndatasize_after_create = 1 @@ -104,7 +107,8 @@ def test_create2_return_data( slot_returndatacopy_before_create: expected_returndatacopy, slot_returndatacopy_before_create_2: 0, # - # the actual bytes returned by returndatacopy opcode after create + # the actual bytes returned by returndatacopy opcode after + # create slot_returndatacopy_after_create: ( return_data_in_create if return_type_in_create == Op.REVERT else 0 ), @@ -122,7 +126,8 @@ def test_create2_return_data( else keccak256(int.to_bytes(return_data_in_create, 32, byteorder="big")) ), # - # check that create 2 didn't mess up with initial memory space declared for return + # check that create 2 didn't mess up with initial memory space + # declared for return slot_begin_memory_after_create: expected_returndatacopy, } # type: ignore ) diff --git a/tests/constantinople/eip1014_create2/test_recreate.py b/tests/constantinople/eip1014_create2/test_recreate.py index 702eca9bb77..116bbeb4527 100644 --- a/tests/constantinople/eip1014_create2/test_recreate.py +++ b/tests/constantinople/eip1014_create2/test_recreate.py @@ -30,8 +30,8 @@ def test_recreate( recreate_on_separate_block: bool, ): """ - Test that the storage is cleared when a contract is first destructed then re-created using - CREATE2. + Test that the storage is cleared when a contract is first destructed then + re-created using CREATE2. """ creator_contract_code = Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE) + Op.CREATE2( 0, 0, Op.CALLDATASIZE, 0 diff --git a/tests/constantinople/eip145_bitwise_shift/spec.py b/tests/constantinople/eip145_bitwise_shift/spec.py index 5b272a9e22f..b2df9d87a41 100644 --- a/tests/constantinople/eip145_bitwise_shift/spec.py +++ b/tests/constantinople/eip145_bitwise_shift/spec.py @@ -21,27 +21,19 @@ class Spec: https://eips.ethereum.org/EIPS/eip-145. """ - # Below are GPT o4-mini-high implementation of shift functions - # It can contain bugs, treat it with caution and refer to EVM implementations + # Below are GPT o4-mini-high implementation of shift functions It can + # contain bugs, treat it with caution and refer to EVM implementations @staticmethod def sar(shift: int, value: int) -> int: """ Simulate the EVM SAR (Signed Arithmetic Right shift) operation. - Parameters - ---------- - shift : int - Number of bits to shift to the right (interpreted as full unsigned; - no low-8-bit truncation here). - value : int - The 256-bit value to shift, interpreted as a signed integer. - - Returns - ------- - int - The result of the arithmetic right shift, pushed as an unsigned - 256-bit integer on the EVM stack. + Parameters ---------- shift : int Number of bits to shift to the right + (interpreted as full unsigned; no low-8-bit truncation here). value : + int The 256-bit value to shift, interpreted as a signed integer. + Returns ------- int The result of the arithmetic right shift, pushed as + an unsigned 256-bit integer on the EVM stack. """ mask256 = (1 << 256) - 1 # Clamp value to 256 bits @@ -69,19 +61,12 @@ def shl(shift: int, value: int) -> int: """ Simulate the EVM SHL (Logical Left shift) operation. - Parameters - ---------- - shift : int - Number of bits to shift to the left. - value : int - The 256-bit value to shift, interpreted as an unsigned integer. - - Returns - ------- - int - The result of the logical left shift, pushed as an unsigned - 256-bit integer on the EVM stack. + Parameters ---------- shift : int Number of bits to shift to the left. + value : int The 256-bit value to shift, interpreted as an unsigned + integer. + Returns ------- int The result of the logical left shift, pushed as an + unsigned 256-bit integer on the EVM stack. """ mask256 = (1 << 256) - 1 # Clamp input to 256 bits @@ -99,19 +84,12 @@ def shr(shift: int, value: int) -> int: """ Simulate the EVM SHR (Logical Right shift) operation. - Parameters - ---------- - shift : int - Number of bits to shift to the right. - value : int - The 256-bit value to shift, interpreted as an unsigned integer. - - Returns - ------- - int - The result of the logical right shift, pushed as an unsigned - 256-bit integer on the EVM stack. + Parameters ---------- shift : int Number of bits to shift to the right. + value : int The 256-bit value to shift, interpreted as an unsigned + integer. + Returns ------- int The result of the logical right shift, pushed as an + unsigned 256-bit integer on the EVM stack. """ mask256 = (1 << 256) - 1 # Clamp input to 256 bits diff --git a/tests/frontier/create/test_create_one_byte.py b/tests/frontier/create/test_create_one_byte.py index 0cd90521e11..2c3a1312f49 100644 --- a/tests/frontier/create/test_create_one_byte.py +++ b/tests/frontier/create/test_create_one_byte.py @@ -1,6 +1,6 @@ """ -The test calls CREATE in a loop deploying 1-byte contracts with all possible byte values, -records in storage the values that failed to deploy. +The test calls CREATE in a loop deploying 1-byte contracts with all possible +byte values, records in storage the values that failed to deploy. """ import pytest diff --git a/tests/frontier/identity_precompile/common.py b/tests/frontier/identity_precompile/common.py index 6aef16f982c..fcf28be3eb4 100644 --- a/tests/frontier/identity_precompile/common.py +++ b/tests/frontier/identity_precompile/common.py @@ -39,18 +39,16 @@ def generate_identity_call_bytecode( call_succeeds: bool, ) -> Bytecode: """ - Generate bytecode for calling the identity precompile with given memory values. + Generate bytecode for calling the identity precompile with given memory + values. - Args: - storage (Storage): The storage object to use for storing values. - call_type (Op): The type of call opcode (CALL or CALLCODE). - memory_values (Tuple[int, ...]): Values to store in memory before the call. - call_args (CallArgs): Arguments for the CALL opcode. - call_succeeds (bool): Whether the call should succeed or not. - - Returns: - Bytecode: The generated bytecode for the identity precompile call. + Args: storage (Storage): The storage object to use for storing values. + call_type (Op): The type of call opcode (CALL or CALLCODE). memory_values + (Tuple[int, ...]): Values to store in memory before the call. call_args + (CallArgs): Arguments for the CALL opcode. call_succeeds (bool): Whether + the call should succeed or not. + Returns: Bytecode: The generated bytecode for the identity precompile call. """ code = Bytecode() @@ -65,7 +63,8 @@ def generate_identity_call_bytecode( if mstore_count > i + 1: mstore_offset += 0x20 - # Call the identity precompile, then check that the last value in memory has not changed + # Call the identity precompile, then check that the last value in memory + # has not changed code += ( Op.SSTORE( storage.store_next(call_succeeds), diff --git a/tests/frontier/identity_precompile/test_identity.py b/tests/frontier/identity_precompile/test_identity.py index dc3222cfaf8..67ff1ad1219 100644 --- a/tests/frontier/identity_precompile/test_identity.py +++ b/tests/frontier/identity_precompile/test_identity.py @@ -118,7 +118,10 @@ def test_call_identity_precompile( tx_gas_limit: int, contract_balance: int, ): - """Test identity precompile RETURNDATA is sized correctly based on the input size.""" + """ + Test identity precompile RETURNDATA is sized correctly based on the input + size. + """ env = Environment() storage = Storage() diff --git a/tests/frontier/identity_precompile/test_identity_returndatasize.py b/tests/frontier/identity_precompile/test_identity_returndatasize.py index 45538b0c944..4b07ff2acf0 100644 --- a/tests/frontier/identity_precompile/test_identity_returndatasize.py +++ b/tests/frontier/identity_precompile/test_identity_returndatasize.py @@ -37,7 +37,10 @@ def test_identity_precompile_returndata( output_size: int, expected_returndatasize: int, ): - """Test identity precompile RETURNDATA is sized correctly based on the input size.""" + """ + Test identity precompile RETURNDATA is sized correctly based on the input + size. + """ env = Environment() storage = Storage() diff --git a/tests/frontier/opcodes/test_all_opcodes.py b/tests/frontier/opcodes/test_all_opcodes.py index 458c332dd30..1d0301c7cef 100644 --- a/tests/frontier/opcodes/test_all_opcodes.py +++ b/tests/frontier/opcodes/test_all_opcodes.py @@ -1,6 +1,6 @@ """ -Call every possible opcode and test that the subcall is successful -if the opcode is supported by the fork supports and fails otherwise. +Call every possible opcode and test that the subcall is successful if the +opcode is supported by the fork supports and fails otherwise. """ from typing import Dict @@ -56,9 +56,9 @@ def prepare_suffix(opcode: Opcode) -> Bytecode: @pytest.mark.valid_from("Frontier") def test_all_opcodes(state_test: StateTestFiller, pre: Alloc, fork: Fork): """ - Test each possible opcode on the fork with a single contract that - calls each opcode in succession. Check that each subcall passes - if the opcode is supported and fails otherwise. + Test each possible opcode on the fork with a single contract that calls + each opcode in succession. Check that each subcall passes if the opcode is + supported and fails otherwise. """ code_worked = 1000 @@ -75,8 +75,8 @@ def test_all_opcodes(state_test: StateTestFiller, pre: Alloc, fork: Fork): code=sum( Op.SSTORE( Op.PUSH1(opcode.int()), - # Limit gas to limit the gas consumed by the exceptional aborts in each - # subcall that uses an undefined opcode. + # Limit gas to limit the gas consumed by the exceptional aborts + # in each subcall that uses an undefined opcode. Op.CALL(35_000, opcode_address, 0, 0, 0, 0, 0), ) for opcode, opcode_address in code_contract.items() diff --git a/tests/frontier/opcodes/test_call.py b/tests/frontier/opcodes/test_call.py index e7feb662db5..301d49d0fe9 100644 --- a/tests/frontier/opcodes/test_call.py +++ b/tests/frontier/opcodes/test_call.py @@ -14,8 +14,9 @@ from ethereum_test_vm import Opcodes as Op -# TODO: There's an issue with gas definitions on forks previous to Berlin, remove this when fixed. -# https://github.com/ethereum/execution-spec-tests/pull/1952#discussion_r2237634275 +# TODO: There's an issue with gas definitions on forks previous to Berlin, +# remove this when fixed. https://github.com/ethereum/execution-spec- +# tests/pull/1952#discussion_r2237634275 @pytest.mark.valid_from("Berlin") def test_call_large_offset_mstore( state_test: StateTestFiller, @@ -23,10 +24,11 @@ def test_call_large_offset_mstore( fork: Fork, ): """ - CALL with ret_offset larger than memory size and ret_size zero - Then do an MSTORE in that offset to see if memory was expanded in CALL. + CALL with ret_offset larger than memory size and ret_size zero Then do an + MSTORE in that offset to see if memory was expanded in CALL. - This is for bug in a faulty EVM implementation where memory is expanded when it shouldn't. + This is for bug in a faulty EVM implementation where memory is expanded + when it shouldn't. """ sender = pre.fund_eoa() @@ -35,14 +37,17 @@ def test_call_large_offset_mstore( call_measure = CodeGasMeasure( code=Op.CALL(gas=0, ret_offset=mem_offset, ret_size=0), - overhead_cost=gsc.G_VERY_LOW * len(Op.CALL.kwargs), # Cost of pushing CALL args + overhead_cost=gsc.G_VERY_LOW * len(Op.CALL.kwargs), # Cost of pushing + # CALL args extra_stack_items=1, # Because CALL pushes 1 item to the stack sstore_key=0, stop=False, # Because it's the first CodeGasMeasure ) mstore_measure = CodeGasMeasure( code=Op.MSTORE(offset=mem_offset, value=1), - overhead_cost=gsc.G_VERY_LOW * len(Op.MSTORE.kwargs), # Cost of pushing MSTORE args + overhead_cost=gsc.G_VERY_LOW * len(Op.MSTORE.kwargs), # Cost of + # pushing MSTORE + # args extra_stack_items=0, sstore_key=1, ) @@ -77,8 +82,9 @@ def test_call_large_offset_mstore( ) -# TODO: There's an issue with gas definitions on forks previous to Berlin, remove this when fixed. -# https://github.com/ethereum/execution-spec-tests/pull/1952#discussion_r2237634275 +# TODO: There's an issue with gas definitions on forks previous to Berlin, +# remove this when fixed. https://github.com/ethereum/execution-spec- +# tests/pull/1952#discussion_r2237634275 @pytest.mark.valid_from("Berlin") def test_call_memory_expands_on_early_revert( state_test: StateTestFiller, @@ -87,27 +93,31 @@ def test_call_memory_expands_on_early_revert( ): """ When CALL reverts early (e.g. because of not enough balance by the sender), - memory should be expanded anyway. - We check this with an MSTORE. + memory should be expanded anyway. We check this with an MSTORE. - This is for a bug in an EVM implementation where memory is expanded after executing a CALL, but - not when an early revert happens. + This is for a bug in an EVM implementation where memory is expanded after + executing a CALL, but not when an early revert happens. """ sender = pre.fund_eoa() gsc = fork.gas_costs() - ret_size = 128 # arbitrary number, greater than memory size to trigger an expansion + ret_size = 128 # arbitrary number, greater than memory size to trigger an + # expansion call_measure = CodeGasMeasure( code=Op.CALL(gas=0, value=100, ret_size=ret_size), # CALL with value - overhead_cost=gsc.G_VERY_LOW * len(Op.CALL.kwargs), # Cost of pushing CALL args + overhead_cost=gsc.G_VERY_LOW * len(Op.CALL.kwargs), # Cost of pushing + # CALL args extra_stack_items=1, # Because CALL pushes 1 item to the stack sstore_key=0, stop=False, # Because it's the first CodeGasMeasure ) mstore_measure = CodeGasMeasure( - code=Op.MSTORE(offset=ret_size // 2, value=1), # Low offset for not expanding memory - overhead_cost=gsc.G_VERY_LOW * len(Op.MSTORE.kwargs), # Cost of pushing MSTORE args + code=Op.MSTORE(offset=ret_size // 2, value=1), # Low offset for not + # expanding memory + overhead_cost=gsc.G_VERY_LOW * len(Op.MSTORE.kwargs), # Cost of + # pushing MSTORE + # args extra_stack_items=0, sstore_key=1, ) @@ -123,7 +133,8 @@ def test_call_memory_expands_on_early_revert( ) memory_expansion_gas_calc = fork.memory_expansion_gas_calculator() - # call cost: address_access_cost + new_acc_cost + memory_expansion_cost + value - stipend + # call cost: address_access_cost + new_acc_cost + memory_expansion_cost + + # value - stipend call_cost = ( gsc.G_COLD_ACCOUNT_ACCESS + gsc.G_NEW_ACCOUNT @@ -132,7 +143,8 @@ def test_call_memory_expands_on_early_revert( - gsc.G_CALL_STIPEND ) - # mstore cost: base cost. No memory expansion cost needed, it was expanded on CALL. + # mstore cost: base cost. No memory expansion cost needed, it was expanded + # on CALL. mstore_cost = gsc.G_MEMORY state_test( env=Environment(), @@ -149,8 +161,9 @@ def test_call_memory_expands_on_early_revert( ) -# TODO: There's an issue with gas definitions on forks previous to Berlin, remove this when fixed. -# https://github.com/ethereum/execution-spec-tests/pull/1952#discussion_r2237634275 +# TODO: There's an issue with gas definitions on forks previous to Berlin, +# remove this when fixed. https://github.com/ethereum/execution-spec- +# tests/pull/1952#discussion_r2237634275 @pytest.mark.with_all_call_opcodes @pytest.mark.valid_from("Berlin") def test_call_large_args_offset_size_zero( @@ -170,7 +183,9 @@ def test_call_large_args_offset_size_zero( call_measure = CodeGasMeasure( code=call_opcode(gas=0, args_offset=very_large_offset, args_size=0), - overhead_cost=gsc.G_VERY_LOW * len(call_opcode.kwargs), # Cost of pushing xCALL args + overhead_cost=gsc.G_VERY_LOW * len(call_opcode.kwargs), # Cost of + # pushing + # xCALL args extra_stack_items=1, # Because xCALL pushes 1 item to the stack sstore_key=0, ) diff --git a/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py b/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py index 740253dbb57..f0292e06e89 100644 --- a/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py +++ b/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py @@ -1,26 +1,28 @@ """ -abstract: Tests the nested CALL/CALLCODE opcode gas consumption with a positive value transfer. - This test is designed to investigate an issue identified in EthereumJS, as reported in: - https://github.com/ethereumjs/ethereumjs-monorepo/issues/3194. - - The issue pertains to the incorrect gas calculation for CALL/CALLCODE operations with a - positive value transfer, due to the pre-addition of the gas stipend (2300) to the currently - available gas instead of adding it to the new call frame. This bug was specific to the case - where insufficient gas was provided for the CALL/CALLCODE operation. Due to the pre-addition - of the stipend to the currently available gas, the case for insufficient gas was not properly - failing with an out-of-gas error. - - Test setup: Given two smart contract accounts, 0x0A (caller) and 0x0B (callee): - 1) An arbitrary transaction calls into the contract 0x0A. - 2) Contract 0x0A executes a CALL to contract 0x0B with a specific gas limit (X). - 3) Contract 0x0B then attempts a CALL/CALLCODE to a non-existent contract 0x0C, - with a positive value transfer (activating the gas stipend). - 4) If the gas X provided by contract 0x0A to 0x0B is sufficient, contract 0x0B - will push 0x01 onto the stack after returning to the call frame in 0x0A. Otherwise, it - should push 0x00, indicating the insufficiency of gas X (for the bug in EthereumJS, the - CALL/CALLCODE operation would return 0x01 due to the pre-addition of the gas stipend). - 5) The resulting stack value is saved into contract 0x0A's storage, allowing us to - verify whether the provided gas was sufficient or insufficient. +abstract: Tests the nested CALL/CALLCODE opcode gas consumption with a positive +value transfer. This test is designed to investigate an issue identified in +EthereumJS, as reported in: +https://github.com/ethereumjs/ethereumjs-monorepo/issues/3194. + +The issue pertains to the incorrect gas calculation for CALL/CALLCODE +operations with a positive value transfer, due to the pre-addition of the gas +stipend (2300) to the currently available gas instead of adding it to the new +call frame. This bug was specific to the case where insufficient gas was +provided for the CALL/CALLCODE operation. Due to the pre-addition of the +stipend to the currently available gas, the case for insufficient gas was not +properly failing with an out-of-gas error. + +Test setup: Given two smart contract accounts, 0x0A (caller) and 0x0B (callee): +1) An arbitrary transaction calls into the contract 0x0A. 2) Contract 0x0A +executes a CALL to contract 0x0B with a specific gas limit (X). 3) Contract +0x0B then attempts a CALL/CALLCODE to a non-existent contract 0x0C, with a +positive value transfer (activating the gas stipend). 4) If the gas X provided +by contract 0x0A to 0x0B is sufficient, contract 0x0B will push 0x01 onto the +stack after returning to the call frame in 0x0A. Otherwise, it should push +0x00, indicating the insufficiency of gas X (for the bug in EthereumJS, the +CALL/CALLCODE operation would return 0x01 due to the pre-addition of the gas +stipend). 5) The resulting stack value is saved into contract 0x0A's storage, +allowing us to verify whether the provided gas was sufficient or insufficient. """ from typing import Dict @@ -40,23 +42,29 @@ from ethereum_test_vm import Opcodes as Op """ -PUSH opcode cost is 3, GAS opcode cost is 2. -We need 6 PUSH's and one GAS to fill the stack for both CALL & CALLCODE, in the callee contract. + + +PUSH opcode cost is 3, GAS opcode cost is 2. We need 6 PUSH's and one GAS to +fill the stack for both CALL & CALLCODE, in the callee contract. """ CALLEE_INIT_STACK_GAS = 6 * 3 + 2 """ -CALL gas breakdowns: (https://www.evm.codes/#f1) -memory_exp_cost + code_exec_cost + address_access_cost + positive_value_cost + empty_account_cost + + +CALL gas breakdowns: (https://www.evm.codes/#f1) memory_exp_cost + +code_exec_cost + address_access_cost + positive_value_cost + empty_account_cost = 0 + 0 + 2600 + 9000 + 25000 = 36600 """ CALL_GAS = 36600 CALL_SUFFICIENT_GAS = CALL_GAS + CALLEE_INIT_STACK_GAS """ -CALLCODE gas breakdowns: (https://www.evm.codes/#f2) -memory_exp_cost + code_exec_cost + address_access_cost + positive_value_cost -= 0 + 0 + 2600 + 9000 = 11600 + + +CALLCODE gas breakdowns: (https://www.evm.codes/#f2) memory_exp_cost + +code_exec_cost + address_access_cost + positive_value_cost = 0 + 0 + 2600 + +9000 = 11600 """ CALLCODE_GAS = 11600 CALLCODE_SUFFICIENT_GAS = CALLCODE_GAS + CALLEE_INIT_STACK_GAS @@ -65,15 +73,12 @@ @pytest.fixture def callee_code(pre: Alloc, callee_opcode: Op) -> Bytecode: """ - Code called by the caller contract: - PUSH1 0x00 * 4 - PUSH1 0x01 <- for positive value transfer - PUSH2 Contract.nonexistent - GAS <- value doesn't matter - CALL/CALLCODE. + Code called by the caller contract: PUSH1 0x00 * 4 PUSH1 0x01 <- for + positive value transfer PUSH2 Contract.nonexistent GAS <- value doesn't + matter CALL/CALLCODE. """ - # The address needs to be empty and different for each execution of the fixture, - # otherwise the calculations (empty_account_cost) are incorrect. + # The address needs to be empty and different for each execution of the + # fixture, otherwise the calculations (empty_account_cost) are incorrect. return callee_opcode(Op.GAS(), pre.empty_account(), 1, 0, 0, 0, 0) @@ -92,13 +97,9 @@ def callee_address(pre: Alloc, callee_code: Bytecode) -> Address: @pytest.fixture def caller_code(caller_gas_limit: int, callee_address: Address) -> Bytecode: """ - Code to CALL the callee contract: - PUSH1 0x00 * 5 - PUSH2 Contract.callee - PUSH2 caller_gas <- gas limit set for CALL to callee contract - CALL - PUSH1 0x00 - SSTORE. + Code to CALL the callee contract: PUSH1 0x00 * 5 PUSH2 Contract.callee + PUSH2 caller_gas <- gas limit set for CALL to callee contract CALL PUSH1 + 0x00 SSTORE. """ return Op.SSTORE(0, Op.CALL(caller_gas_limit, callee_address, 0, 0, 0, 0, 0)) @@ -106,13 +107,9 @@ def caller_code(caller_gas_limit: int, callee_address: Address) -> Bytecode: @pytest.fixture def caller_address(pre: Alloc, caller_code: Bytecode) -> Address: """ - Code to CALL the callee contract: - PUSH1 0x00 * 5 - PUSH2 Contract.callee - PUSH2 caller_gas <- gas limit set for CALL to callee contract - CALL - PUSH1 0x00 - SSTORE. + Code to CALL the callee contract: PUSH1 0x00 * 5 PUSH2 Contract.callee + PUSH2 caller_gas <- gas limit set for CALL to callee contract CALL PUSH1 + 0x00 SSTORE. """ return pre.deploy_contract(caller_code, balance=0x03) @@ -151,5 +148,8 @@ def test_value_transfer_gas_calculation( caller_tx: Transaction, post: Dict[str, Account], ): - """Tests the nested CALL/CALLCODE opcode gas consumption with a positive value transfer.""" + """ + Tests the nested CALL/CALLCODE opcode gas consumption with a positive value + transfer. + """ state_test(env=Environment(), pre=pre, post=post, tx=caller_tx) diff --git a/tests/frontier/opcodes/test_calldataload.py b/tests/frontier/opcodes/test_calldataload.py index 41f03f12847..8dbd00d7542 100644 --- a/tests/frontier/opcodes/test_calldataload.py +++ b/tests/frontier/opcodes/test_calldataload.py @@ -52,11 +52,13 @@ def test_calldataload( """ Test `CALLDATALOAD` opcode. - Tests two scenarios: - - calldata_source is "contract": CALLDATALOAD reads from calldata passed by another contract - - calldata_source is "tx": CALLDATALOAD reads directly from transaction calldata + Tests two scenarios: - calldata_source is "contract": CALLDATALOAD reads + from calldata passed by another contract - calldata_source is "tx": + CALLDATALOAD reads directly from transaction calldata - Based on https://github.com/ethereum/tests/blob/ae4791077e8fcf716136e70fe8392f1a1f1495fb/src/GeneralStateTestsFiller/VMTests/vmTests/calldatacopyFiller.yml + Based on + https://github.com/ethereum/tests/blob/ae4791077e8fcf716136e70fe8392f1a1f1495fb + /src/GeneralStateTestsFiller/VMTests/vmTests/calldatacopyFiller.yml """ contract_address = pre.deploy_contract( Op.SSTORE(0, Op.CALLDATALOAD(offset=calldata_offset)) + Op.STOP, diff --git a/tests/frontier/opcodes/test_calldatasize.py b/tests/frontier/opcodes/test_calldatasize.py index d06a7330da6..9134290e48b 100644 --- a/tests/frontier/opcodes/test_calldatasize.py +++ b/tests/frontier/opcodes/test_calldatasize.py @@ -29,11 +29,13 @@ def test_calldatasize( """ Test `CALLDATASIZE` opcode. - Tests two scenarios: - - calldata_source is "contract": CALLDATASIZE reads from calldata passed by another contract - - calldata_source is "tx": CALLDATASIZE reads directly from transaction calldata + Tests two scenarios: - calldata_source is "contract": CALLDATASIZE reads + from calldata passed by another contract - calldata_source is "tx": + CALLDATASIZE reads directly from transaction calldata - Based on https://github.com/ethereum/tests/blob/81862e4848585a438d64f911a19b3825f0f4cd95/src/GeneralStateTestsFiller/VMTests/vmTests/calldatasizeFiller.yml + Based on + https://github.com/ethereum/tests/blob/81862e4848585a438d64f911a19b3825f0f4cd95 + /src/GeneralStateTestsFiller/VMTests/vmTests/calldatasizeFiller.yml """ contract_address = pre.deploy_contract(Op.SSTORE(key=0x0, value=Op.CALLDATASIZE)) calldata = b"\x01" * args_size diff --git a/tests/frontier/opcodes/test_dup.py b/tests/frontier/opcodes/test_dup.py index a4d3d3e85f5..6e1679184b7 100644 --- a/tests/frontier/opcodes/test_dup.py +++ b/tests/frontier/opcodes/test_dup.py @@ -1,8 +1,4 @@ -""" -abstract: Test DUP - Test the DUP opcodes. - -""" +"""abstract: Test DUP Test the DUP opcodes.""" import pytest @@ -43,9 +39,13 @@ def test_dup( """ Test the DUP1-DUP16 opcodes. - Note: Test case ported from [ethereum/tests](https://github.com/ethereum/tests) - Test ported from [ethereum/tests/GeneralStateTests/VMTests/vmTests/dup.json](https://github.com/ethereum/tests/blob/v14.0/GeneralStateTests/VMTests/vmTests/dup.json) by Ori Pomerantz. - """ # noqa: E501 + Note: Test case ported from + [ethereum/tests](https://github.com/ethereum/tests). + + Test ported from [ethereum/tests/GeneralStateTests/VMTests/ + vmTests/dup.json](https://github.com/ethereum/tests/blob/ + v14.0/GeneralStateTests/VMTests/vmTests/dup.json) by Ori Pomerantz. + """ env = Environment() sender = pre.fund_eoa() post = {} diff --git a/tests/frontier/opcodes/test_push.py b/tests/frontier/opcodes/test_push.py index a97abaa982c..400a658e2c1 100644 --- a/tests/frontier/opcodes/test_push.py +++ b/tests/frontier/opcodes/test_push.py @@ -1,7 +1,10 @@ """ A State test for the set of `PUSH*` opcodes. -Ported from: https://github.com/ethereum/tests/blob/4f65a0a7cbecf4442415c226c65e089acaaf6a8b/src/GeneralStateTestsFiller/VMTests/vmTests/pushFiller.yml. -""" # noqa: E501 +Ported from: +https://github.com/ethereum/tests/blob/ +4f65a0a7cbecf4442415c226c65e089acaaf6a8b/src/ +GeneralStateTestsFiller/VMTests/vmTests/pushFiller.yml. +""" import pytest @@ -30,7 +33,8 @@ def get_input_for_push_opcode(opcode: Op) -> bytes: ) @pytest.mark.parametrize( "push_opcode", - [getattr(Op, f"PUSH{i}") for i in range(1, 33)], # Dynamically parametrize PUSH opcodes + [getattr(Op, f"PUSH{i}") for i in range(1, 33)], # Dynamically parametrize + # PUSH opcodes ids=lambda op: str(op), ) @pytest.mark.valid_from("Frontier") @@ -38,9 +42,8 @@ def test_push(state_test: StateTestFiller, fork: Fork, pre: Alloc, push_opcode: """ The set of `PUSH*` opcodes pushes data onto the stack. - In this test, we ensure that the set of `PUSH*` opcodes writes - a portion of an excerpt from the Ethereum yellow paper to - storage. + In this test, we ensure that the set of `PUSH*` opcodes writes a portion of + an excerpt from the Ethereum yellow paper to storage. """ # Input used to test the `PUSH*` opcode. excerpt = get_input_for_push_opcode(push_opcode) @@ -48,14 +51,16 @@ def test_push(state_test: StateTestFiller, fork: Fork, pre: Alloc, push_opcode: env = Environment() """ - ** Bytecode explanation ** - +---------------------------------------------------+ - | Bytecode | Stack | Storage | - |---------------------------------------------------| - | PUSH* excerpt | excerpt | | - | PUSH1 0 | 0 excerpt | | - | SSTORE | | [0]: excerpt | - +---------------------------------------------------+ + + + ** Bytecode explanation ** + +---------------------------------------------------+ | Bytecode | + Stack | Storage | + |---------------------------------------------------| | PUSH* excerpt | + excerpt | | | PUSH1 0 | 0 excerpt | + | | SSTORE | | [0]: excerpt | + +---------------------------------------------------+ + """ contract_code = push_opcode(excerpt) + Op.PUSH1(0) + Op.SSTORE @@ -90,32 +95,39 @@ def test_push(state_test: StateTestFiller, fork: Fork, pre: Alloc, push_opcode: def test_stack_overflow( state_test: StateTestFiller, fork: Fork, pre: Alloc, push_opcode: Op, stack_height: int ): - """A test to ensure that the stack overflows when the stack limit of 1024 is exceeded.""" + """ + A test to ensure that the stack overflows when the stack limit of 1024 is + exceeded. + """ env = Environment() # Input used to test the `PUSH*` opcode. excerpt = get_input_for_push_opcode(push_opcode) """ - Essentially write a n-byte message to storage by pushing [1024,1025] times to stack. This - simulates a "jump" over the stack limit of 1024. - - The message is UTF-8 encoding of excerpt (say 0x45 for PUSH1). Within the stack limit, - the message is written to the to the storage at the same offset (0x45 for PUSH1). - The last iteration will overflow the stack and the storage slot will be empty. - - ** Bytecode explanation ** - +---------------------------------------------------+ - | Bytecode | Stack | Storage | - |---------------------------------------------------| - | PUSH* excerpt | excerpt | | - | PUSH1 0 | 0 excerpt | | - | SSTORE | | [0]: excerpt | - +---------------------------------------------------+ + + + Essentially write a n-byte message to storage by pushing [1024,1025] times + to stack. This simulates a "jump" over the stack limit of 1024. + + The message is UTF-8 encoding of excerpt (say 0x45 for PUSH1). Within the + stack limit, the message is written to the to the storage at the same + offset (0x45 for PUSH1). The last iteration will overflow the stack and the + storage slot will be empty. + + ** Bytecode explanation ** + +---------------------------------------------------+ | Bytecode | + Stack | Storage | + |---------------------------------------------------| | PUSH* excerpt | + excerpt | | | PUSH1 0 | 0 excerpt | + | | SSTORE | | [0]: excerpt | + +---------------------------------------------------+ + """ contract_code: Bytecode = Bytecode() for _ in range(stack_height - 2): - contract_code += Op.PUSH1(0) # mostly push 0 to avoid contract size limit exceeded + contract_code += Op.PUSH1(0) # mostly push 0 to avoid contract size + # limit exceeded contract_code += push_opcode(excerpt) * 2 + Op.SSTORE contract = pre.deploy_contract(contract_code) diff --git a/tests/frontier/opcodes/test_selfdestruct.py b/tests/frontier/opcodes/test_selfdestruct.py index e165684a0d8..bedddbf679b 100644 --- a/tests/frontier/opcodes/test_selfdestruct.py +++ b/tests/frontier/opcodes/test_selfdestruct.py @@ -10,9 +10,9 @@ @pytest.mark.valid_until("Homestead") def test_double_kill(blockchain_test: BlockchainTestFiller, pre: Alloc): """ - Test that when two transactions attempt to destruct a contract, - the second transaction actually resurrects the contract as an empty account (prior to Spurious - Dragon). + Test that when two transactions attempt to destruct a contract, the second + transaction actually resurrects the contract as an empty account (prior to + Spurious Dragon). """ sender = pre.fund_eoa() diff --git a/tests/frontier/precompiles/test_precompile_absence.py b/tests/frontier/precompiles/test_precompile_absence.py index 1982ad2f217..eeb0f65ca77 100644 --- a/tests/frontier/precompiles/test_precompile_absence.py +++ b/tests/frontier/precompiles/test_precompile_absence.py @@ -33,7 +33,10 @@ def test_precompile_absence( fork: Fork, calldata_size: int, ): - """Test that addresses close to zero are not precompiles unless active in the fork.""" + """ + Test that addresses close to zero are not precompiles unless active in the + fork. + """ active_precompiles = fork.precompiles() storage = Storage() call_code = Bytecode() diff --git a/tests/frontier/precompiles/test_precompiles.py b/tests/frontier/precompiles/test_precompiles.py index 24ef1b00457..4ec016cfd01 100644 --- a/tests/frontier/precompiles/test_precompiles.py +++ b/tests/frontier/precompiles/test_precompiles.py @@ -18,15 +18,15 @@ def precompile_addresses(fork: Fork) -> Iterator[Tuple[Address, bool]]: """ - Yield the addresses of precompiled contracts and their support status for a given fork. + Yield the addresses of precompiled contracts and their support status for a + given fork. - Args: - fork (Fork): The fork instance containing precompiled contract information. - - Yields: - Iterator[Tuple[str, bool]]: A tuple containing the address in hexadecimal format and a - boolean indicating whether the address is a supported precompile. + Args: fork (Fork): The fork instance containing precompiled contract + information. + Yields: Iterator[Tuple[str, bool]]: A tuple containing the address in + hexadecimal format and a boolean indicating whether the address is a + supported precompile. """ supported_precompiles = fork.precompiles() @@ -59,19 +59,17 @@ def test_precompiles( """ Tests the behavior of precompiled contracts in the Ethereum state test. - Args: - state_test (StateTestFiller): The state test filler object used to run the test. - address (str): The address of the precompiled contract to test. - precompile_exists (bool): A flag indicating whether the precompiled contract exists at the - given address. - pre (Alloc): The allocation object used to deploy the contract and set up the initial - state. - - This test deploys a contract that performs two CALL operations to the specified address and a - fixed address (0x10000), measuring the gas used for each call. It then stores the difference - in gas usage in storage slot 0. The test verifies the expected storage value based on - whether the precompiled contract exists at the given address. - + Args: state_test (StateTestFiller): The state test filler object used to + run the test. address (str): The address of the precompiled contract to + test. precompile_exists (bool): A flag indicating whether the precompiled + contract exists at the given address. pre (Alloc): The allocation object + used to deploy the contract and set up the initial state. + + This test deploys a contract that performs two CALL operations to the + specified address and a fixed address (0x10000), measuring the gas used for + each call. It then stores the difference in gas usage in storage slot 0. + The test verifies the expected storage value based on whether the + precompiled contract exists at the given address. """ env = Environment() diff --git a/tests/frontier/scenarios/common.py b/tests/frontier/scenarios/common.py index 7142ca685e5..ff72071545c 100644 --- a/tests/frontier/scenarios/common.py +++ b/tests/frontier/scenarios/common.py @@ -30,9 +30,9 @@ class ScenarioExpectOpcode(Enum): @dataclass class ScenarioEnvironment: """ - Scenario evm environment - Each scenario must define an environment on which program is executed - This is so post state verification could check results of evm opcodes. + Scenario evm environment Each scenario must define an environment on which + program is executed This is so post state verification could check results + of evm opcodes. """ code_address: Address # Op.ADDRESS, address scope for program @@ -62,11 +62,10 @@ class ProgramResult: """ Describe expected result of a program. - Attributes: - result (int | ScenarioExpectOpcode): The result of the program - from_fork (Fork): The result is only valid from this fork (default: Frontier) - static_support (bool): Can be verified in static context (default: True) - + Attributes: result (int | ScenarioExpectOpcode): The result of the program + from_fork (Fork): The result is only valid from this fork (default: + Frontier) static_support (bool): Can be verified in static context + (default: True) """ result: int | ScenarioExpectOpcode @@ -79,8 +78,8 @@ def translate_result( self, env: ScenarioEnvironment, exec_env: ExecutionEnvironment ) -> int | Address: """ - Translate expected program result code into concrete value, - given the scenario evm environment and test execution environment. + Translate expected program result code into concrete value, given the + scenario evm environment and test execution environment. """ if exec_env.fork < self.from_fork: return 0 @@ -153,12 +152,10 @@ class ScenarioGeneratorInput: """ Parameters for the scenario generator function. - Attributes: - fork (Fork): Fork for which we ask to generate scenarios - pre (Alloc): Access to the state to be able to deploy contracts into pre - operation (Bytecode): Evm bytecode program that will be tested - external_address (Address): Static external address for ext opcodes - + Attributes: fork (Fork): Fork for which we ask to generate scenarios pre + (Alloc): Access to the state to be able to deploy contracts into pre + operation (Bytecode): Evm bytecode program that will be tested + external_address (Address): Static external address for ext opcodes """ fork: Fork @@ -171,13 +168,11 @@ class Scenario: """ Describe test scenario that will be run in test for each program. - Attributes: - category (str): Scenario category name - name (str): Scenario name for the test vector - code (Address): Address that is an entry point for scenario code - env (ScenarioEnvironment): Evm values for ScenarioExpectAddress map - reverting (bool): If scenario reverts program execution, making result 0 (default: False) - + Attributes: category (str): Scenario category name name (str): Scenario + name for the test vector code (Address): Address that is an entry point for + scenario code env (ScenarioEnvironment): Evm values for + ScenarioExpectAddress map reverting (bool): If scenario reverts program + execution, making result 0 (default: False) """ category: str @@ -189,10 +184,10 @@ class Scenario: def make_gas_hash_contract(pre: Alloc) -> Address: """ - Contract that spends unique amount of gas based on input - Used for the values we can't predict, can be gas consuming on high values - So that if we can't check exact value in expect section, - we at least could spend unique gas amount. + Contract that spends unique amount of gas based on input Used for the + values we can't predict, can be gas consuming on high values So that if we + can't check exact value in expect section, we at least could spend unique + gas amount. """ gas_hash_address = pre.deploy_contract( code=Op.MSTORE(0, 0) @@ -215,8 +210,9 @@ def make_gas_hash_contract(pre: Alloc) -> Address: def make_invalid_opcode_contract(pre: Alloc, fork: Fork) -> Address: """ - Deploy a contract that will execute any asked byte as an opcode from calldataload - Deploy 20 empty stack elements. Jump to opcode instruction. if worked, return 0. + Deploy a contract that will execute any asked byte as an opcode from + calldataload Deploy 20 empty stack elements. Jump to opcode instruction. if + worked, return 0. """ invalid_opcode_caller = pre.deploy_contract( code=Op.PUSH1(0) * 20 diff --git a/tests/frontier/scenarios/programs/all_frontier_opcodes.py b/tests/frontier/scenarios/programs/all_frontier_opcodes.py index 83978c7509a..72d8fa459a4 100644 --- a/tests/frontier/scenarios/programs/all_frontier_opcodes.py +++ b/tests/frontier/scenarios/programs/all_frontier_opcodes.py @@ -1,4 +1,7 @@ -"""Define a program for scenario test that executes all frontier opcodes and entangles it's result.""" # noqa: E501 +""" +Define a program for scenario test that executes all frontier opcodes and +entangles it's result. +""" from functools import cached_property @@ -15,7 +18,9 @@ def make_all_opcode_program() -> Bytecode: - """Make a program that call each Frontier opcode and verifies it's result.""" + """ + Make a program that call each Frontier opcode and verifies it's result. + """ code: Bytecode = ( # Test opcode 01 - ADD Conditional( diff --git a/tests/frontier/scenarios/programs/context_calls.py b/tests/frontier/scenarios/programs/context_calls.py index 0693d181102..ea4d8938389 100644 --- a/tests/frontier/scenarios/programs/context_calls.py +++ b/tests/frontier/scenarios/programs/context_calls.py @@ -15,7 +15,9 @@ class ProgramAddress(ScenarioTestProgram): - """Check that ADDRESS is really the code execution address in all scenarios.""" + """ + Check that ADDRESS is really the code execution address in all scenarios. + """ def make_test_code(self, pre: Alloc, fork: Fork) -> Bytecode: """Test code.""" diff --git a/tests/frontier/scenarios/scenarios/call_combinations.py b/tests/frontier/scenarios/scenarios/call_combinations.py index e8e091307ce..f5b42c48695 100644 --- a/tests/frontier/scenarios/scenarios/call_combinations.py +++ b/tests/frontier/scenarios/scenarios/call_combinations.py @@ -55,16 +55,14 @@ def __init__(self, scenario_input: ScenarioGeneratorInput): def generate(self) -> List[Scenario]: """ - Generate Scenarios for call combinations - We take code that we want to test at scenario_input.operation_contract - and put it in the context of call combinations. - - Example: - root_contract -> call -> scenario_contract -> first_call -> sub_contract - sub_contact -> second_call -> code - We assume that code always returns it's result - That we pass as return value in scenario_contract for the post state verification + Generate Scenarios for call combinations We take code that we want to + test at scenario_input.operation_contract and put it in the context of + call combinations. + Example: root_contract -> call -> scenario_contract -> first_call -> + sub_contract sub_contact -> second_call -> code We assume that code + always returns it's result That we pass as return value in + scenario_contract for the post state verification """ scenarios_list: List[Scenario] = [] @@ -80,8 +78,8 @@ def generate(self) -> List[Scenario]: def _generate_one_call_scenario(self, first_call: Opcode) -> Scenario: """ - Generate scenario for only one call - root_contract -(CALL)-> scenario_contract -(first_call)-> operation_contract. + Generate scenario for only one call root_contract -(CALL)-> + scenario_contract -(first_call)-> operation_contract. """ scenario_input: ScenarioGeneratorInput = self.scenario_input pre: Alloc = scenario_input.pre @@ -162,15 +160,16 @@ def _generate_one_call_scenario(self, first_call: Opcode) -> Scenario: def _generate_two_call_scenario(self, first_call: Opcode, second_call: Opcode) -> Scenario: """ - Generate scenario for two types of calls combination - root_contract -(CALL)-> scenario_contract -(first_call)-> sub_contract - sub_contract -(second_call) -> operation_contract. + Generate scenario for two types of calls combination root_contract + -(CALL)-> scenario_contract -(first_call)-> sub_contract sub_contract + -(second_call) -> operation_contract. """ def _compute_code_caller() -> Address: """ - Calculate who is the code caller in program_contract's code in given sequence - root -CALL-> scenario_contract -(first_call)-> sub_contract -(second_call)-> program. + Calculate who is the code caller in program_contract's code in + given sequence root -CALL-> scenario_contract -(first_call)-> + sub_contract -(second_call)-> program. """ code_caller: Address = root_contract if first_call == Op.DELEGATECALL: @@ -188,8 +187,9 @@ def _compute_code_caller() -> Address: def _compute_selfbalance() -> int: """ - Calculate the result of Op.SELFBALANCE in program scope in given sequence - root -CALL-> scenario_contract -(first_call)-> sub_contract -(second_call)-> program. + Calculate the result of Op.SELFBALANCE in program scope in given + sequence root -CALL-> scenario_contract -(first_call)-> + sub_contract -(second_call)-> program. """ selfbalance: int = 0 if second_call in [Op.CALL]: @@ -214,7 +214,8 @@ def _compute_selfbalance() -> int: def _compute_callvalue() -> int: """ Calculate the expected callvalue in program scope given sequence: - root -CALL-> scenario_contract -(first_call)-> sub_contract -(second_call)-> program. + root -CALL-> scenario_contract -(first_call)-> sub_contract + -(second_call)-> program. """ if second_call == Op.STATICCALL: return 0 diff --git a/tests/frontier/scenarios/scenarios/create_combinations.py b/tests/frontier/scenarios/scenarios/create_combinations.py index d5603913246..0a5040a8735 100644 --- a/tests/frontier/scenarios/scenarios/create_combinations.py +++ b/tests/frontier/scenarios/scenarios/create_combinations.py @@ -27,7 +27,10 @@ def scenarios_create_combinations(scenario_input: ScenarioGeneratorInput) -> Lis """Generate Scenarios for create combinations.""" def _compute_selfbalance() -> int: - """Compute selfbalance opcode for root -> call -> scenario -> create | [call*] -> program.""" # noqa: E501 + """ + Compute selfbalance opcode for root -> call -> scenario -> + create | [call*] -> program. + """ if call in [Op.DELEGATECALL, Op.CALLCODE]: return ( balance.scenario_contract_balance + balance.root_call_value - balance.create_value @@ -51,7 +54,8 @@ def _compute_selfbalance() -> int: salt = [0] if create == Op.CREATE2 else [] operation_contract = scenario_input.pre.deploy_contract(code=scenario_input.operation_code) - # the code result in init code will be actually code of a deployed contract + # the code result in init code will be actually code of a deployed + # contract scenario_contract = scenario_input.pre.deploy_contract( balance=3, code=Op.EXTCODECOPY(operation_contract, 0, 0, Op.EXTCODESIZE(operation_contract)) diff --git a/tests/frontier/scenarios/test_scenarios.py b/tests/frontier/scenarios/test_scenarios.py index 585aa6aab73..bb820d81d04 100644 --- a/tests/frontier/scenarios/test_scenarios.py +++ b/tests/frontier/scenarios/test_scenarios.py @@ -1,6 +1,6 @@ """ -Call every possible opcode and test that the subcall is successful -if the opcode is supported by the fork and fails otherwise. +Call every possible opcode and test that the subcall is successful if the +opcode is supported by the fork and fails otherwise. """ from typing import List @@ -76,7 +76,10 @@ @pytest.fixture def scenarios(fork: Fork, pre: Alloc, test_program: ScenarioTestProgram) -> List[Scenario]: - """Define fixture vectors of all possible scenarios, given the current pre state input.""" + """ + Define fixture vectors of all possible scenarios, given the current pre + state input. + """ scenarios_list: List[Scenario] = [] scenario_input = ScenarioGeneratorInput( @@ -118,9 +121,13 @@ def scenarios(fork: Fork, pre: Alloc, test_program: ScenarioTestProgram) -> List @pytest.mark.valid_from("Frontier") @pytest.mark.parametrize( # select program to debug ("program_id","scenario_name") - # program="" select all programs - # scenario_name="" select all scenarios - # Example: [ScenarioDebug(program_id=ProgramSstoreSload().id, scenario_name="scenario_CALL_CALL")], # noqa: E501 + # program="" + # select all programs scenario_name="" + # select all scenarios + # + # Example: + # [ScenarioDebug(program_id=ProgramSstoreSload().id, + # scenario_name="scenario_CALL_CALL")] "debug", [ ScenarioDebug( @@ -178,13 +185,13 @@ def test_scenarios( scenarios, ): """ - Test given operation in different scenarios - Verify that it's return value equal to expected result on every scenario, - that is valid for the given fork. + Test given operation in different scenarios Verify that it's return value + equal to expected result on every scenario, that is valid for the given + fork. - Note: Don't use pytest parametrize for scenario production, because scenarios will be complex - Generate one test file for [each operation] * [each scenario] to save space - As well as operations will be complex too + Note: Don't use pytest parametrize for scenario production, because + scenarios will be complex Generate one test file for [each operation] * + [each scenario] to save space As well as operations will be complex too """ tx_env = Environment() tx_origin: Address = pre.fund_eoa() @@ -213,7 +220,8 @@ def test_scenarios( fork=fork, origin=tx_origin, gasprice=tx_gasprice, - timestamp=tx_env.timestamp, # we can't know timestamp before head, use gas hash + timestamp=tx_env.timestamp, # we can't know timestamp before head, + # use gas hash number=len(blocks) + 1, gaslimit=tx_env.gas_limit, coinbase=tx_env.fee_recipient, diff --git a/tests/homestead/coverage/test_coverage.py b/tests/homestead/coverage/test_coverage.py index b0120d113fb..52743076429 100644 --- a/tests/homestead/coverage/test_coverage.py +++ b/tests/homestead/coverage/test_coverage.py @@ -1,4 +1,7 @@ -"""Tests that address coverage gaps that result from updating `ethereum/tests` into EEST tests.""" +""" +Tests that address coverage gaps that result from updating `ethereum/tests` +into EEST tests. +""" import pytest @@ -17,11 +20,11 @@ def test_coverage( fork: Fork, ): """ - Cover gaps that result from transforming Yul code into - our Python opcode wrapper bytecode. + Cover gaps that result from transforming Yul code into our Python opcode + wrapper bytecode. - E.g. Yul tends to optimize stack items by using `SWAP1` and `DUP1` opcodes, which are not - regularly used in python code. + E.g. Yul tends to optimize stack items by using `SWAP1` and `DUP1` opcodes, + which are not regularly used in python code. Modify this test to cover more Yul code if required in the future. """ diff --git a/tests/istanbul/eip152_blake2/common.py b/tests/istanbul/eip152_blake2/common.py index 7081a31a2ec..b2f159dd080 100644 --- a/tests/istanbul/eip152_blake2/common.py +++ b/tests/istanbul/eip152_blake2/common.py @@ -13,17 +13,15 @@ class Blake2bInput(TestParameterGroup): Helper class that defines the BLAKE2b precompile inputs and creates the call data from them. Returns all inputs encoded as bytes. - Attributes: - rounds_length (int): An optional integer representing the bytes length - for the number of rounds. Defaults to the expected length of 4. - rounds (int | str): A hex string or integer value representing the number of rounds. - h (str): A hex string that represents the state vector. - m (str): A hex string that represents the message block vector. - t_0 (int | str): A hex string or integer value that represents the first offset counter. - t_1 (int | str): A hex string or integer value that represents the second offset counter. - f (bool): An optional boolean that represents the final block indicator flag. - Defaults to True. - + Attributes: rounds_length (int): An optional integer representing the bytes + length for the number of rounds. Defaults to the expected length of 4. + rounds (int | str): A hex string or integer value representing the number + of rounds. h (str): A hex string that represents the state vector. m (str): + A hex string that represents the message block vector. t_0 (int | str): A + hex string or integer value that represents the first offset counter. t_1 + (int | str): A hex string or integer value that represents the second + offset counter. f (bool): An optional boolean that represents the final + block indicator flag. Defaults to True. """ rounds_length: int = Spec.BLAKE2_PRECOMPILE_ROUNDS_LENGTH @@ -57,12 +55,10 @@ class ExpectedOutput(TestParameterGroup): """ Expected test result. - Attributes: - call_succeeds (str | bool): A hex string or boolean to indicate whether the call was - successful or not. - data_1 (str): String value of the first updated state vector. - data_2 (str): String value of the second updated state vector. - + Attributes: call_succeeds (str | bool): A hex string or boolean to indicate + whether the call was successful or not. data_1 (str): String value of the + first updated state vector. data_2 (str): String value of the second + updated state vector. """ call_succeeds: str | bool diff --git a/tests/istanbul/eip152_blake2/conftest.py b/tests/istanbul/eip152_blake2/conftest.py index ed544ec2911..a6fbc26be1c 100644 --- a/tests/istanbul/eip152_blake2/conftest.py +++ b/tests/istanbul/eip152_blake2/conftest.py @@ -11,8 +11,8 @@ @pytest.fixture def blake2b_contract_bytecode(call_opcode: Op) -> Bytecode: """ - Contract code that performs the provided opcode (CALL or CALLCODE) to the BLAKE2b precompile - and stores the result. + Contract code that performs the provided opcode (CALL or CALLCODE) to the + BLAKE2b precompile and stores the result. """ return ( Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE()) diff --git a/tests/istanbul/eip152_blake2/spec.py b/tests/istanbul/eip152_blake2/spec.py index 38413b71898..a338ef14c54 100644 --- a/tests/istanbul/eip152_blake2/spec.py +++ b/tests/istanbul/eip152_blake2/spec.py @@ -48,7 +48,17 @@ class SpecTestVectors: # The following constants are used to define common test parameters # Origin of vectors defined at https://datatracker.ietf.org/doc/html/rfc7693.html#appendix-A - BLAKE2_STATE_VECTOR = "48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b" # noqa:E501 - BLAKE2_MESSAGE_BLOCK_VECTOR = "6162630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" # noqa:E501 + BLAKE2_STATE_VECTOR = ( + "48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1" + "361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f" + "79217e1319cde05b" + ) + BLAKE2_MESSAGE_BLOCK_VECTOR = ( + "616263000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000" + ) BLAKE2_OFFSET_COUNTER_0 = 3 BLAKE2_OFFSET_COUNTER_1 = 0 diff --git a/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py b/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py index b7ed40ba4a3..39907e60149 100644 --- a/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py +++ b/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py @@ -1,4 +1,7 @@ -"""abstract: Test delegatecall to Blake2B Precompile before and after it was added.""" +""" +abstract: Test delegatecall to Blake2B Precompile before and after it was +added. +""" import pytest @@ -21,7 +24,10 @@ @pytest.mark.valid_from("ConstantinopleFix") def test_blake2_precompile_delegatecall(state_test: StateTestFiller, pre: Alloc, fork: Fork): - """Test delegatecall consumes specified gas for the Blake2B precompile when it exists.""" + """ + Test delegatecall consumes specified gas for the Blake2B precompile when it + exists. + """ env = Environment() account = pre.deploy_contract( @@ -43,7 +49,8 @@ def test_blake2_precompile_delegatecall(state_test: StateTestFiller, pre: Alloc, protected=True, ) - # If precompile exists, DELEGATECALL will fail, otherwise DELEGATECALL will succeed + # If precompile exists, DELEGATECALL will fail, otherwise DELEGATECALL will + # succeed post = { account: Account( storage={ diff --git a/tests/osaka/__init__.py b/tests/osaka/__init__.py index 5eceac229b0..81fc13f3537 100644 --- a/tests/osaka/__init__.py +++ b/tests/osaka/__init__.py @@ -1 +1,4 @@ -"""Test cases for EVM functionality introduced in Osaka, [EIP-7607: Hardfork Meta - Fusaka](https://eip.directory/eips/eip-7607).""" # noqa: E501 +""" +Test cases for EVM functionality introduced in Osaka, [EIP-7607: Hardfork Meta +- Fusaka](https://eip.directory/eips/eip-7607). +""" diff --git a/tests/osaka/eip7594_peerdas/__init__.py b/tests/osaka/eip7594_peerdas/__init__.py index 3b5d0449782..43cd5354b74 100644 --- a/tests/osaka/eip7594_peerdas/__init__.py +++ b/tests/osaka/eip7594_peerdas/__init__.py @@ -1,4 +1,5 @@ """ Test suite for -[EIP-7594: PeerDAS - Peer Data Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). +[EIP-7594: PeerDAS - Peer Data Availability +Sampling](https://eips.ethereum.org/EIPS/eip-7594). """ diff --git a/tests/osaka/eip7594_peerdas/test_get_blobs.py b/tests/osaka/eip7594_peerdas/test_get_blobs.py index 2d349fd93b3..fd60647d817 100644 --- a/tests/osaka/eip7594_peerdas/test_get_blobs.py +++ b/tests/osaka/eip7594_peerdas/test_get_blobs.py @@ -1,7 +1,7 @@ """ -abstract: Tests get blobs engine endpoint for [EIP-7594: PeerDAS - Peer Data Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594) - Test get blobs engine endpoint for [EIP-7594: PeerDAS - Peer Data Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). -""" # noqa: E501 +abstract: Tests get blobs engine endpoint for [EIP-7594: PeerDAS - Peer Data +Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). +""" from hashlib import sha256 from typing import List, Optional @@ -92,7 +92,8 @@ def excess_blob_gas( block_base_fee_per_gas: int, ) -> int | None: """ - Calculate the excess blob gas of the block under test from the parent block. + Calculate the excess blob gas of the block under test from the parent + block. Value can be overloaded by a test case to provide a custom excess blob gas. """ @@ -148,10 +149,10 @@ def tx_max_fee_per_blob_gas( # noqa: D103 @pytest.fixture def tx_error() -> Optional[TransactionException]: """ - Even though the final block we are producing in each of these tests is invalid, and some of the - transactions will be invalid due to the format in the final block, none of the transactions - should be rejected by the transition tool because they are being sent to it with the correct - format. + Even though the final block we are producing in each of these tests is + invalid, and some of the transactions will be invalid due to the format in + the final block, none of the transactions should be rejected by the + transition tool because they are being sent to it with the correct format. """ return None @@ -319,8 +320,8 @@ def test_get_blobs( txs: List[NetworkWrappedTransaction | Transaction], ): """ - Test valid blob combinations where one or more txs in the block - serialized version contain a full blob (network version) tx. + Test valid blob combinations where one or more txs in the block serialized + version contain a full blob (network version) tx. """ blobs_test(pre=pre, txs=txs) @@ -336,6 +337,9 @@ def test_get_blobs_nonexisting( pre: Alloc, txs: List[NetworkWrappedTransaction | Transaction], ): - """Test that ensures clients respond with 'null' when at least one requested blob is not available.""" # noqa: E501 + """ + Test that ensures clients respond with 'null' when at least one requested + blob is not available. + """ nonexisting_blob_hashes = [Hash(sha256(str(i).encode()).digest()) for i in range(5)] blobs_test(pre=pre, txs=txs, nonexisting_blob_hashes=nonexisting_blob_hashes) diff --git a/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py b/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py index c9d0114738d..67555783518 100644 --- a/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py +++ b/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py @@ -1,7 +1,7 @@ """ -abstract: Tests `MAX_BLOBS_PER_TX` limit for [EIP-7594: PeerDAS - Peer Data Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594) - Tests `MAX_BLOBS_PER_TX` limit for [EIP-7594: PeerDAS - Peer Data Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). -""" # noqa: E501 +abstract: Tests `MAX_BLOBS_PER_TX` limit for [EIP-7594: PeerDAS - Peer Data +Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). +""" import pytest @@ -88,9 +88,9 @@ def test_valid_max_blobs_per_tx( tx: Transaction, ): """ - Test that transactions with blob count from 1 to MAX_BLOBS_PER_TX are accepted. - Verifies that individual transactions can contain up to the maximum allowed - number of blobs per transaction. + Test that transactions with blob count from 1 to MAX_BLOBS_PER_TX are + accepted. Verifies that individual transactions can contain up to the + maximum allowed number of blobs per transaction. """ state_test( env=env, @@ -120,10 +120,10 @@ def test_invalid_max_blobs_per_tx( blob_count: int, ): """ - Test that transactions exceeding MAX_BLOBS_PER_TX are rejected. - Verifies that individual transactions cannot contain more than the maximum - allowed number of blobs per transaction, even if the total would be within - the block limit. + Test that transactions exceeding MAX_BLOBS_PER_TX are rejected. Verifies + that individual transactions cannot contain more than the maximum allowed + number of blobs per transaction, even if the total would be within the + block limit. """ state_test( env=env, diff --git a/tests/osaka/eip7823_modexp_upper_bounds/conftest.py b/tests/osaka/eip7823_modexp_upper_bounds/conftest.py index 9a89e91db31..1eb4fcafdf7 100644 --- a/tests/osaka/eip7823_modexp_upper_bounds/conftest.py +++ b/tests/osaka/eip7823_modexp_upper_bounds/conftest.py @@ -16,8 +16,8 @@ @pytest.fixture def call_contract_post_storage() -> Storage: """ - Storage of the test contract after the transaction is executed. - Note: Fixture `call_contract_code` fills the actual expected storage values. + Storage of the test contract after the transaction is executed. Note: + Fixture `call_contract_code` fills the actual expected storage values. """ return Storage() @@ -27,8 +27,8 @@ def call_succeeds( total_gas_used: int, fork: Fork, env: Environment, modexp_input: ModExpInput ) -> bool: """ - By default, depending on the expected output, we can deduce if the call is expected to succeed - or fail. + By default, depending on the expected output, we can deduce if the call is + expected to succeed or fail. """ # Transaction gas limit exceeded tx_gas_limit_cap = fork.transaction_gas_limit_cap() or env.gas_limit @@ -57,14 +57,12 @@ def gas_measure_contract( call_succeeds: bool, ) -> Address: """ - Deploys a contract that measures ModExp gas consumption and execution result. - - Always stored: - storage[0]: precompile call success - storage[1]: return data length from precompile - Only if the precompile call succeeds: - storage[2]: gas consumed by precompile - storage[3]: hash of return data from precompile + Deploys a contract that measures ModExp gas consumption and execution + result. + + Always stored: storage[0]: precompile call success storage[1]: return data + length from precompile Only if the precompile call succeeds: storage[2]: + gas consumed by precompile storage[3]: hash of return data from precompile """ call_code = Op.CALL( precompile_gas, @@ -122,14 +120,17 @@ def gas_measure_contract( @pytest.fixture def precompile_gas(fork: Fork, modexp_input: ModExpInput) -> int: - """Calculate gas cost for the ModExp precompile and verify it matches expected gas.""" + """ + Calculate gas cost for the ModExp precompile and verify it matches expected + gas. + """ spec = Spec if fork < Osaka else Spec7883 try: calculated_gas = spec.calculate_gas_cost(modexp_input) return calculated_gas except Exception: - # Used for `test_modexp_invalid_inputs` we expect the call to not succeed. - # Return is for completeness. + # Used for `test_modexp_invalid_inputs` we expect the call to not + # succeed. Return is for completeness. return 500 if fork >= Osaka else 200 @@ -153,7 +154,9 @@ def tx( def total_gas_used( fork: Fork, modexp_expected: bytes, modexp_input: ModExpInput, precompile_gas: int ) -> int: - """Transaction gas limit used for the test (Can be overridden in the test).""" + """ + Transaction gas limit used for the test (Can be overridden in the test). + """ intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator() memory_expansion_gas_calculator = fork.memory_expansion_gas_calculator() extra_gas = 500_000 @@ -170,7 +173,9 @@ def total_gas_used( @pytest.fixture def tx_gas_limit(total_gas_used: int, fork: Fork, env: Environment) -> int: - """Transaction gas limit used for the test (Can be overridden in the test).""" + """ + Transaction gas limit used for the test (Can be overridden in the test). + """ tx_gas_limit_cap = fork.transaction_gas_limit_cap() or env.gas_limit return min(tx_gas_limit_cap, total_gas_used) diff --git a/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py b/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py index fca1e181272..07c84d251c4 100644 --- a/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py +++ b/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py @@ -1,6 +1,7 @@ """ -abstract: Test [EIP-7823: Set upper bounds for MODEXP](https://eips.ethereum.org/EIPS/eip-7823) - Tests upper bounds of the MODEXP precompile. +abstract: Test [EIP-7823: Set upper bounds for +MODEXP](https://eips.ethereum.org/EIPS/eip-7823) Tests upper bounds of the +MODEXP precompile. """ from typing import Dict @@ -76,7 +77,8 @@ pytest.param( ModExpInput( base=b"", - # Non-zero exponent is cancelled with zero multiplication complexity pre EIP-7823. + # Non-zero exponent is cancelled with zero multiplication + # complexity pre EIP-7823. exponent=b"\xff" * (Spec.MAX_LENGTH_BYTES + 1), modulus=b"", ), @@ -293,7 +295,10 @@ def test_modexp_upper_bounds_fork_transition( modexp_input: ModExpInput, modexp_expected: bytes, ): - """Test MODEXP upper bounds enforcement transition from before to after Osaka hard fork.""" + """ + Test MODEXP upper bounds enforcement transition from before to after Osaka + hard fork. + """ call_code = Op.CALL( address=Spec.MODEXP_ADDRESS, args_size=Op.CALLDATASIZE, diff --git a/tests/osaka/eip7825_transaction_gas_limit_cap/spec.py b/tests/osaka/eip7825_transaction_gas_limit_cap/spec.py index 58a93203a49..319c70e3988 100644 --- a/tests/osaka/eip7825_transaction_gas_limit_cap/spec.py +++ b/tests/osaka/eip7825_transaction_gas_limit_cap/spec.py @@ -17,7 +17,9 @@ class ReferenceSpec: @dataclass(frozen=True) class Spec: - """Constants and helpers for the EIP-7825 Transaction Gas Limit Cap tests.""" + """ + Constants and helpers for the EIP-7825 Transaction Gas Limit Cap tests. + """ # Gas limit constants tx_gas_limit_cap = 2**24 # 16,777,216 diff --git a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py index 254cf62decf..f658050cf16 100644 --- a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py +++ b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py @@ -1,6 +1,7 @@ """ -abstract: Tests [EIP-7825 Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825) - Test cases for [EIP-7825 Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825)]. +abstract: Tests [EIP-7825 Transaction Gas Limit +Cap](https://eips.ethereum.org/EIPS/eip-7825) Test cases for [EIP-7825 +Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825)]. """ from typing import List @@ -37,12 +38,13 @@ def tx_gas_limit_cap_tests(fork: Fork) -> List[ParameterSet]: """ - Return a list of tests for transaction gas limit cap parametrized for each different - fork. + Return a list of tests for transaction gas limit cap parametrized for each + different fork. """ fork_tx_gas_limit_cap = fork.transaction_gas_limit_cap() if fork_tx_gas_limit_cap is None: - # Use a default value for forks that don't have a transaction gas limit cap + # Use a default value for forks that don't have a transaction gas limit + # cap return [ pytest.param(Spec.tx_gas_limit_cap + 1, None, id="tx_gas_limit_cap_none"), ] @@ -69,7 +71,9 @@ def test_transaction_gas_limit_cap( error: TransactionException | None, tx_type: int, ): - """Test the transaction gas limit cap behavior for all transaction types.""" + """ + Test the transaction gas limit cap behavior for all transaction types. + """ env = Environment() sender = pre.fund_eoa() @@ -179,7 +183,9 @@ def test_tx_gas_larger_than_block_gas_limit( fork: Fork, exceed_block_gas_limit: bool, ): - """Test multiple transactions with total gas larger than the block gas limit.""" + """ + Test multiple transactions with total gas larger than the block gas limit. + """ tx_gas_limit_cap = fork.transaction_gas_limit_cap() assert tx_gas_limit_cap is not None, "Fork does not have a transaction gas limit cap" @@ -302,14 +308,11 @@ def test_tx_gas_limit_cap_full_calldata( num_of_bytes += int(exceed_tx_gas_limit) - # Gas cost calculation based on EIP-7623: (https://eips.ethereum.org/EIPS/eip-7623) - # - # Simplified in this test case: - # - No execution gas used (no opcodes are executed) - # - Not a contract creation (no initcode) - # - # Token accounting: - # tokens_in_calldata = zero_bytes + 4 * non_zero_bytes + # Gas cost calculation based on EIP-7623: + # (https://eips.ethereum.org/EIPS/eip-7623) + # Simplified in this test case: - No execution gas used (no opcodes are + # executed) - Not a contract creation (no initcode) + # Token accounting: tokens_in_calldata = zero_bytes + 4 * non_zero_bytes byte_data = b"\x00" if zero_byte else b"\xff" @@ -377,16 +380,12 @@ def test_tx_gas_limit_cap_contract_creation( code = Op.JUMPDEST * num_of_bytes - # Craft a contract creation transaction that exceeds the transaction gas limit cap - # - # Total cost = - # intrinsic cost (base tx cost + contract creation cost) - # + calldata cost - # + init code execution cost - # - # The contract body is filled with JUMPDEST instructions, so: - # total cost = intrinsic cost + calldata cost + (num_of_jumpdest * 1 gas) - # + # Craft a contract creation transaction that exceeds the transaction gas + # limit cap + # Total cost = intrinsic cost (base tx cost + contract creation cost) + + # calldata cost + init code execution cost + # The contract body is filled with JUMPDEST instructions, so: total cost = + # intrinsic cost + calldata cost + (num_of_jumpdest * 1 gas) # If the total cost exceeds the tx limit cap, the transaction should fail total_cost = intrinsic_cost(contract_creation=True, calldata=code) + num_of_bytes @@ -424,7 +423,10 @@ def test_tx_gas_limit_cap_access_list_with_diff_keys( pre: Alloc, fork: Fork, ): - """Test the transaction gas limit cap behavior for access list with different storage keys.""" + """ + Test the transaction gas limit cap behavior for access list with different + storage keys. + """ intrinsic_cost = fork.transaction_intrinsic_cost_calculator() tx_gas_limit_cap = fork.transaction_gas_limit_cap() assert tx_gas_limit_cap is not None, "Fork does not have a transaction gas limit cap" @@ -500,7 +502,10 @@ def test_tx_gas_limit_cap_access_list_with_diff_addr( exceed_tx_gas_limit: bool, correct_intrinsic_cost_in_transaction_gas_limit: bool, ): - """Test the transaction gas limit cap behavior for access list with different addresses.""" + """ + Test the transaction gas limit cap behavior for access list with different + addresses. + """ intrinsic_cost = fork.transaction_intrinsic_cost_calculator() tx_gas_limit_cap = fork.transaction_gas_limit_cap() assert tx_gas_limit_cap is not None, "Fork does not have a transaction gas limit cap" @@ -588,15 +593,12 @@ def test_tx_gas_limit_cap_authorized_tx( ) # EIP-7702 authorization transaction cost: - # - # 21000 + 16 * non-zero calldata bytes + 4 * zero calldata bytes - # + 1900 * access list storage key count - # + 2400 * access list address count - # + PER_EMPTY_ACCOUNT_COST * authorization list length - # - # There is no calldata and no storage keys in this test case - # and the access address list count is equal to the authorization list length - # total cost = 21000 + (2400 + 25_000) * auth_list_length + # 21000 + 16 * non-zero calldata bytes + 4 * zero calldata bytes + 1900 * + # access list storage key count + 2400 * access list address count + + # PER_EMPTY_ACCOUNT_COST * authorization list length + # There is no calldata and no storage keys in this test case and the access + # address list count is equal to the authorization list length total cost = + # 21000 + (2400 + 25_000) * auth_list_length auth_address = pre.deploy_contract(code=Op.STOP) diff --git a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py index eb992e8ded1..dd4e230ff9a 100644 --- a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py +++ b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py @@ -1,6 +1,7 @@ """ -abstract: Tests [EIP-7825 Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825) - Test cases for [EIP-7825 Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825)]. +abstract: Tests [EIP-7825 Transaction Gas Limit +Cap](https://eips.ethereum.org/EIPS/eip-7825) Test cases for [EIP-7825 +Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825)]. """ import pytest @@ -44,8 +45,8 @@ def test_transaction_gas_limit_cap_at_transition( """ Test transaction gas limit cap behavior at the Osaka transition. - Before timestamp 15000: No gas limit cap (transactions with gas > 2^24 are valid) - At/after timestamp 15000: Gas limit cap of 2^24 is enforced + Before timestamp 15000: No gas limit cap (transactions with gas > 2^24 are + valid) At/after timestamp 15000: Gas limit cap of 2^24 is enforced """ contract_address = pre.deploy_contract( code=Op.SSTORE(Op.TIMESTAMP, Op.ADD(Op.SLOAD(Op.TIMESTAMP), 1)) + Op.STOP, @@ -58,7 +59,8 @@ def test_transaction_gas_limit_cap_at_transition( # Test boundary: cap + 1 should fail after fork activation above_cap = tx_gas_cap + 1 - # Before fork activation: both cap and above_cap transactions should succeed + # Before fork activation: both cap and above_cap transactions should + # succeed at_cap_tx_before_fork = Transaction( ty=0, # Legacy transaction to=contract_address, @@ -86,7 +88,8 @@ def test_transaction_gas_limit_cap_at_transition( blocks = [] - # Before transition (timestamp < 15000): both cap and above_cap transactions should succeed + # Before transition (timestamp < 15000): both cap and above_cap + # transactions should succeed blocks.append( Block( timestamp=14_999, diff --git a/tests/osaka/eip7883_modexp_gas_increase/conftest.py b/tests/osaka/eip7883_modexp_gas_increase/conftest.py index 1a685531549..559ceebd902 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/conftest.py +++ b/tests/osaka/eip7883_modexp_gas_increase/conftest.py @@ -42,8 +42,8 @@ def call_opcode() -> Op: @pytest.fixture def call_contract_post_storage() -> Storage: """ - Storage of the test contract after the transaction is executed. - Note: Fixture `call_contract_code` fills the actual expected storage values. + Storage of the test contract after the transaction is executed. Note: + Fixture `call_contract_code` fills the actual expected storage values. """ return Storage() @@ -83,9 +83,10 @@ def expected_tx_cap_fail() -> bool: @pytest.fixture def call_succeeds(exceeds_tx_gas_cap: bool, expected_tx_cap_fail: bool) -> bool: """ - Determine whether the ModExp precompile call should succeed or fail. - By default, depending on the expected output, we assume it succeeds. - Under EIP-7825, transactions requiring more gas than the cap should fail only if unexpected. + Determine whether the ModExp precompile call should succeed or fail. By + default, depending on the expected output, we assume it succeeds. Under + EIP-7825, transactions requiring more gas than the cap should fail only if + unexpected. """ if exceeds_tx_gas_cap and not expected_tx_cap_fail: pytest.fail( @@ -107,14 +108,12 @@ def gas_measure_contract( call_succeeds: bool, ) -> Address: """ - Deploys a contract that measures ModExp gas consumption and execution result. - - Always stored: - storage[0]: precompile call success - storage[1]: return data length from precompile - Only if the precompile call succeeds: - storage[2]: gas consumed by precompile - storage[3]: hash of return data from precompile + Deploys a contract that measures ModExp gas consumption and execution + result. + + Always stored: storage[0]: precompile call success storage[1]: return data + length from precompile Only if the precompile call succeeds: storage[2]: + gas consumed by precompile storage[3]: hash of return data from precompile """ assert call_opcode in [Op.CALL, Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL] value = [0] if call_opcode in [Op.CALL, Op.CALLCODE] else [] @@ -183,7 +182,10 @@ def gas_measure_contract( def precompile_gas( fork: Fork, modexp_input: ModExpInput, gas_old: int | None, gas_new: int | None ) -> int: - """Calculate gas cost for the ModExp precompile and verify it matches expected gas.""" + """ + Calculate gas cost for the ModExp precompile and verify it matches expected + gas. + """ spec = Spec if fork < Osaka else Spec7883 try: calculated_gas = spec.calculate_gas_cost(modexp_input) @@ -199,8 +201,8 @@ def precompile_gas( ) return calculated_gas except Exception: - # Used for `test_modexp_invalid_inputs` we expect the call to not succeed. - # Return is for completeness. + # Used for `test_modexp_invalid_inputs` we expect the call to not + # succeed. Return is for completeness. return 500 if fork >= Osaka else 200 @@ -228,7 +230,9 @@ def tx( @pytest.fixture def tx_gas_limit(total_tx_gas_needed: int, fork: Fork, env: Environment) -> int: - """Transaction gas limit used for the test (Can be overridden in the test).""" + """ + Transaction gas limit used for the test (Can be overridden in the test). + """ tx_gas_limit_cap = fork.transaction_gas_limit_cap() or env.gas_limit return min(tx_gas_limit_cap, total_tx_gas_needed) diff --git a/tests/osaka/eip7883_modexp_gas_increase/helpers.py b/tests/osaka/eip7883_modexp_gas_increase/helpers.py index 62819fea4be..dc1e05536fb 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/helpers.py +++ b/tests/osaka/eip7883_modexp_gas_increase/helpers.py @@ -31,7 +31,10 @@ class Vector(BaseModel): model_config = ConfigDict(alias_generator=to_pascal) def to_pytest_param(self): - """Convert the test vector to a tuple that can be used as a parameter in a pytest test.""" + """ + Convert the test vector to a tuple that can be used as a parameter in a + pytest test. + """ return pytest.param( self.modexp_input, self.modexp_expected, self.gas_old, self.gas_new, id=self.name ) diff --git a/tests/osaka/eip7883_modexp_gas_increase/spec.py b/tests/osaka/eip7883_modexp_gas_increase/spec.py index 74908e60b9e..bd399595aff 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/spec.py +++ b/tests/osaka/eip7883_modexp_gas_increase/spec.py @@ -18,8 +18,8 @@ class ReferenceSpec: def ceiling_division(a: int, b: int) -> int: """ - Calculate the ceil without using floating point. - Used by many of the EVM's formulas. + Calculate the ceil without using floating point. Used by many of the EVM's + formulas. """ return -(a // -b) @@ -63,9 +63,9 @@ def calculate_multiplication_complexity(cls, base_length: int, modulus_length: i @classmethod def calculate_iteration_count(cls, modexp_input: ModExpInput) -> int: """ - Calculate the iteration count of the ModExp precompile. - This handles length mismatch cases by using declared lengths from the raw input - and only the first 32 bytes of exponent data for iteration calculation. + Calculate the iteration count of the ModExp precompile. This handles + length mismatch cases by using declared lengths from the raw input and + only the first 32 bytes of exponent data for iteration calculation. """ _, exponent_length, _ = modexp_input.get_declared_lengths() exponent_head = modexp_input.get_exponent_head() @@ -83,8 +83,9 @@ def calculate_iteration_count(cls, modexp_input: ModExpInput) -> int: @classmethod def calculate_gas_cost(cls, modexp_input: ModExpInput) -> int: """ - Calculate the ModExp gas cost according to EIP-2565 specification, overridden by the - constants within `Spec7883` when calculating for the EIP-7883 specification. + Calculate the ModExp gas cost according to EIP-2565 specification, + overridden by the constants within `Spec7883` when calculating for the + EIP-7883 specification. """ base_length, _, modulus_length = modexp_input.get_declared_lengths() multiplication_complexity = cls.calculate_multiplication_complexity( @@ -97,8 +98,8 @@ def calculate_gas_cost(cls, modexp_input: ModExpInput) -> int: @dataclass(frozen=True) class Spec7883(Spec): """ - Constants and helpers for the ModExp gas cost increase EIP. - These override the original Spec class variables for EIP-7883. + Constants and helpers for the ModExp gas cost increase EIP. These override + the original Spec class variables for EIP-7883. """ MODEXP_ADDRESS = 0x05 @@ -110,7 +111,10 @@ class Spec7883(Spec): @classmethod def calculate_multiplication_complexity(cls, base_length: int, modulus_length: int) -> int: - """Calculate the multiplication complexity of the ModExp precompile for EIP-7883.""" + """ + Calculate the multiplication complexity of the ModExp precompile for + EIP-7883. + """ max_length = max(base_length, modulus_length) words = ceiling_division(max_length, cls.WORD_SIZE) complexity = 16 diff --git a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py index 4132bbfdf60..b1ea17bd303 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py +++ b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py @@ -1,6 +1,7 @@ """ -abstract: Tests [EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883) - Test cases for [EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883). +abstract: Tests [EIP-7883: ModExp Gas Cost +Increase](https://eips.ethereum.org/EIPS/eip-7883) Test cases for [EIP-7883: +ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883). """ from typing import Dict @@ -75,8 +76,8 @@ def test_vectors_from_legacy_tests( @pytest.mark.parametrize( "modexp_input,", [ - # These invalid inputs are from EIP-7823. - # Ref: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7823.md#analysis + # These invalid inputs are from EIP-7823. Ref: + # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7823.md#analysis pytest.param( bytes.fromhex("9e5faafc"), id="invalid-case-1", @@ -254,7 +255,10 @@ def test_modexp_gas_usage_contract_wrapper( tx: Transaction, post: Dict, ): - """Test ModExp gas cost with different gas modifiers using contract wrapper calls.""" + """ + Test ModExp gas cost with different gas modifiers using contract wrapper + calls. + """ state_test(pre=pre, tx=tx, post=post) @@ -306,7 +310,10 @@ def test_modexp_used_in_transaction_entry_points( tx_gas_limit: int, call_values: int, ): - """Test ModExp using in transaction entry points with different precompile gas modifiers.""" + """ + Test ModExp using in transaction entry points with different precompile gas + modifiers. + """ tx = Transaction( to=Spec.MODEXP_ADDRESS, sender=pre.fund_eoa(), @@ -459,11 +466,10 @@ def create_modexp_variable_gas_test_cases(): """ Create test cases for ModExp variable gas cost testing. - Returns: - List of pytest.param objects for the test cases - + Returns: List of pytest.param objects for the test cases """ - # Test case definitions: (base, exponent, modulus, expected_result, gas_usage, test_id) + # Test case definitions: (base, exponent, modulus, expected_result, + # gas_usage, test_id) test_cases = [ ("", "", "", "", 500, "Z0"), ("01" * 32, "00" * 32, "", "", 500, "Z1"), @@ -539,84 +545,93 @@ def create_modexp_variable_gas_test_cases(): ] # Gas calculation parameters: - # - # Please refer to EIP-7883 for details of each function in the gas calculation. - # Link: https://eips.ethereum.org/EIPS/eip-7883 - # - # - calculate_multiplication_complexity: - # - Comp: if max_length <= 32 bytes, it is Small (S), otherwise it is Large (L) - # - Rel (Length Relation): base < modulus (<), base = modulus (=), base > modulus (>) - # - # - calculate_iteration_count - # - Iter (Iteration Case): - # - A: exp≤32 and exp=0 - # - B: exp≤32 and exp≠0 - # - C: exp>32 and low256=0 - # - D: exp>32 and low256≠0 - # - # - calculate_gas_cost - # - Clamp: True if raw gas < 500 (clamped to 500), False if raw gas ≥ 500 (no clamping) + # Please refer to EIP-7883 for details of each function in the gas + # calculation. Link: https://eips.ethereum.org/EIPS/eip-7883 + # - calculate_multiplication_complexity: - Comp: if max_length <= 32 bytes, + # it is Small (S), otherwise it is Large (L) - Rel (Length Relation): base + # < modulus (<), base = modulus (=), base > modulus (>) + # - calculate_iteration_count - Iter (Iteration Case): - A: exp≤32 and + # exp=0 - B: exp≤32 and exp≠0 - C: exp>32 and low256=0 - D: exp>32 and + # low256≠0 + # - calculate_gas_cost - Clamp: True if raw gas < 500 (clamped to 500), + # False if raw gas ≥ 500 (no clamping) # Test case coverage table: - # ┌─────┬──────┬─────┬──────┬───────┬─────────┬───────────────────────────────────────────────┐ - # │ ID │ Comp │ Rel │ Iter │ Clamp │ Gas │ Description │ - # ├─────┼──────┼─────┼──────┼───────┼─────────┼───────────────────────────────────────────────┤ - # │ Z0 │ - │ - │ - │ - │ 500 │ Zero case – empty inputs │ - # │ Z1 │ S │ - │ A │ True │ 500 │ Non-zero base, zero exp, empty modulus │ - # │ Z2 │ L │ - │ A │ False │ 32768 │ Large base (1024B), zero exp, empty modulus │ - # │ Z3 │ S │ - │ C │ False |253952 │ Base, large zero exp (1024B), empty modulus │ - # │ Z4 │ S │ - │ D │ False │253952 │ Base, large exp (last byte=1), empty modulus │ - # │ Z5 │ S │ < │ A │ True │ 500 │ Empty base/exp, non-zero modulus only │ - # │ Z6 │ S │ < │ B │ False │ 3968 │ Empty base, non-zero exp and modulus │ - # │ Z7 │ L │ < │ B │ False │ 32768 │ Empty base, small exp, large modulus │ - # │ S0 │ S │ = │ A │ True │ 500 │ Small, equal, zero exp, clamped │ - # │ S1 │ S │ = │ B │ True │ 500 │ Small, equal, small exp, clamped │ - # │ S2 │ S │ = │ B │ False │ 4080 │ Small, equal, large exp, unclamped │ - # │ S3 │ S │ = │ C │ False │ 2048 │ Small, equal, large exp + zero low256 │ - # │ S4 │ S │ = │ D │ False │ 2048 │ Small, equal, large exp + non-zero low256 │ - # │ S5 │ S │ > │ A │ True │ 500 │ Small, base > mod, zero exp, clamped │ - # │ S6 │ S │ < │ B │ True │ 500 │ Small, base < mod, small exp, clamped │ - # │ L0 │ L │ = │ A │ True │ 500 │ Large, equal, zero exp, clamped │ - # │ L1 │ L │ = │ B │ False │ 12750 │ Large, equal, large exp, unclamped │ - # │ L2 │ L │ = │ C │ False │ 6400 │ Large, equal, large exp + zero low256 │ - # │ L3 │ L │ = │ D │ False │ 6400 │ Large, equal, large exp + non-zero low256 │ - # │ L4 │ L │ > │ B │ True │ 500 │ Large, base > mod, small exp, clamped │ - # │ L5 │ L │ < │ C │ False │ 9216 │ Large, base < mod, large exp + zero low256 │ - # │ B1 │ L │ < │ B │ True │ 500 │ Cross 32-byte boundary (31/33) │ - # │ B2 │ L │ > │ B │ True │ 500 │ Cross 32-byte boundary (33/31) │ - # │ B4 │ L │ = │ B │ True │ 500 │ Just over 32-byte boundary │ - # │ Z8 │ S │ = │ A │ True │ 500 │ All zeros except modulus │ - # │ Z9 │ S │ = │ A │ True │ 500 │ Zero modulus special case │ - # │ Z10 │ S │ = │ B │ False │ 3968 │ Zero base, large exponent │ - # │ Z11 │ S │ = │ C │ True │ 500 │ Zero base, 33B zero exp, non-zero modulus │ - # │ Z12 │ S │ = │ C │ False |253952 │ Zero base, large zero exp, non-zero modulus │ - # │ Z13 │ L │ > │ A │ False │ 32768 │ Large zero base, zero exp, non-zero modulus │ - # │ Z14 │ S │ = │ C │ False |253952 │ Base, large zero exp, zero modulus │ - # │ Z15 │ L │ < │ B │ False │ 32768 │ Base, small exp, large zero modulus │ - # │ Z16 │ L │ < │ C │ False │520060928│ Zero base, zero exp, large modulus (gas cap) | - # │ M1 │ L │ = │ D │ False │ 98176 │ Maximum values stress test │ - # │ M2 │ S │ = │ B │ True │ 500 │ Max base/mod, small exponent │ - # │ M3 │ L │ < │ D │ False │ 98176 │ Small base, max exponent/mod │ - # │ T2 │ S │ = │ B │ True │ 500 │ Tiny maximum values │ - # │ P2 │ S │ = │ B │ False │ 4080 │ High bit in exponent │ - # │ P3 │ L │ = │ D │ False │ 1150 │ Specific bit pattern in large exponent │ - # │ A1 │ L │ < │ C │ False │ 65536 │ Asymmetric: tiny base, large exp/mod │ - # │ A2 │ L │ > │ B │ True │ 500 │ Asymmetric: large base, tiny exp/mod │ - # │ A3 │ L │ > │ C │ False │ 65536 │ Asymmetric: large base/exp, tiny modulus │ - # │ W2 │ S │ = │ B │ True │ 500 │ Exactly 8-byte words │ - # │ E1 │ S │ = │ D │ True │ 500 │ Exponent exactly 33 bytes │ - # │ E2 │ S │ = │ B │ False │ 4080 │ High bit in exponent first byte │ - # │ E3 │ S │ = │ B │ True │ 500 │ High bit in exponent last byte │ - # │ E4 │ S │ = │ B │ False │ 4064 │ Maximum 32-byte exponent │ - # │ IC1 │ L │ = │ B │ True │ 500 │ Bit shift vs multiplication @ 33 bytes │ - # │ IC3 │ S │ = │ B │ True │ 500 │ Ceiling division at 7 bytes │ - # │ IC4 │ S │ = │ B │ True │ 500 │ Ceiling division at 9 bytes │ - # │ IC5 │ S │ = │ B │ False │ 2160 │ Bit counting in middle of exponent │ - # │ IC6 │ L │ = │ B │ True │ 500 │ Native library even byte optimization │ - # │ IC7 │ L │ = │ B │ True │ 500 │ Vector optimization 128-bit boundary │ - # │ IC9 │ S │ = │ B │ N/A │ N/A │ Zero modulus handling │ - # │ IC10│ S │ = │ B │ False │ 4080 │ Power-of-2 boundary with high bit │ - # └─────┴──────┴─────┴──────┴───────┴─────────┴───────────────────────────────────────────────┘ + # ┌─────┬──────┬─────┬──────┬───────┬─────────┬───────────────────────── + # │ ID │ Comp │ Rel │ Iter │ Clamp │ Gas │ Description + # │ + # ├─────┼──────┼─────┼──────┼───────┼─────────┼───────────────────────── + # │ Z0 │ - │ - │ - │ - │ 500 │ Zero case – empty inputs + # │ │ Z1 │ S │ - │ A │ True │ 500 │ Non-zero base, zero exp, + # empty modulus │ │ Z2 │ L │ - │ A │ False │ 32768 │ + # Large base (1024B), zero exp, empty modulus │ │ Z3 │ S │ - │ C + # │ False |253952 │ Base, large zero exp (1024B), empty modulus │ │ Z4 + # │ S │ - │ D │ False │253952 │ Base, large exp (last byte=1), + # empty modulus │ │ Z5 │ S │ < │ A │ True │ 500 │ Empty + # base/exp, non-zero modulus only │ │ Z6 │ S │ < │ B │ + # False │ 3968 │ Empty base, non-zero exp and modulus │ │ Z7 │ + # L │ < │ B │ False │ 32768 │ Empty base, small exp, large modulus + # │ │ S0 │ S │ = │ A │ True │ 500 │ Small, equal, zero exp, + # clamped │ │ S1 │ S │ = │ B │ True │ 500 │ + # Small, equal, small exp, clamped │ │ S2 │ S │ = │ B + # │ False │ 4080 │ Small, equal, large exp, unclamped │ │ S3 + # │ S │ = │ C │ False │ 2048 │ Small, equal, large exp + zero + # low256 │ │ S4 │ S │ = │ D │ False │ 2048 │ Small, + # equal, large exp + non-zero low256 │ │ S5 │ S │ > │ A │ True + # │ 500 │ Small, base > mod, zero exp, clamped │ │ S6 │ S + # │ < │ B │ True │ 500 │ Small, base < mod, small exp, clamped + # │ │ L0 │ L │ = │ A │ True │ 500 │ Large, equal, zero exp, + # clamped │ │ L1 │ L │ = │ B │ False │ 12750 │ + # Large, equal, large exp, unclamped │ │ L2 │ L │ = │ C + # │ False │ 6400 │ Large, equal, large exp + zero low256 │ │ L3 + # │ L │ = │ D │ False │ 6400 │ Large, equal, large exp + non- + # zero low256 │ │ L4 │ L │ > │ B │ True │ 500 │ Large, + # base > mod, small exp, clamped │ │ L5 │ L │ < │ C │ + # False │ 9216 │ Large, base < mod, large exp + zero low256 │ │ B1 │ + # L │ < │ B │ True │ 500 │ Cross 32-byte boundary (31/33) + # │ │ B2 │ L │ > │ B │ True │ 500 │ Cross 32-byte boundary + # (33/31) │ │ B4 │ L │ = │ B │ True │ 500 │ + # Just over 32-byte boundary │ │ Z8 │ S │ = │ A + # │ True │ 500 │ All zeros except modulus │ │ Z9 + # │ S │ = │ A │ True │ 500 │ Zero modulus special case + # │ │ Z10 │ S │ = │ B │ False │ 3968 │ Zero base, large exponent + # │ │ Z11 │ S │ = │ C │ True │ 500 │ Zero base, 33B zero exp, + # non-zero modulus │ │ Z12 │ S │ = │ C │ False |253952 │ Zero + # base, large zero exp, non-zero modulus │ │ Z13 │ L │ > │ A │ + # False │ 32768 │ Large zero base, zero exp, non-zero modulus │ │ Z14 │ + # S │ = │ C │ False |253952 │ Base, large zero exp, zero modulus + # │ │ Z15 │ L │ < │ B │ False │ 32768 │ Base, small exp, large + # zero modulus │ │ Z16 │ L │ < │ C │ False │520060928│ + # Zero base, zero exp, large modulus (gas cap) | │ M1 │ L │ = │ D + # │ False │ 98176 │ Maximum values stress test │ │ M2 + # │ S │ = │ B │ True │ 500 │ Max base/mod, small exponent + # │ │ M3 │ L │ < │ D │ False │ 98176 │ Small base, max + # exponent/mod │ │ T2 │ S │ = │ B │ True │ 500 + # │ Tiny maximum values │ │ P2 │ S │ = │ B + # │ False │ 4080 │ High bit in exponent │ │ P3 + # │ L │ = │ D │ False │ 1150 │ Specific bit pattern in large + # exponent │ │ A1 │ L │ < │ C │ False │ 65536 │ + # Asymmetric: tiny base, large exp/mod │ │ A2 │ L │ > │ B + # │ True │ 500 │ Asymmetric: large base, tiny exp/mod │ │ A3 + # │ L │ > │ C │ False │ 65536 │ Asymmetric: large base/exp, tiny + # modulus │ │ W2 │ S │ = │ B │ True │ 500 │ Exactly + # 8-byte words │ │ E1 │ S │ = │ D │ True + # │ 500 │ Exponent exactly 33 bytes │ │ E2 │ S + # │ = │ B │ False │ 4080 │ High bit in exponent first byte + # │ │ E3 │ S │ = │ B │ True │ 500 │ High bit in exponent last + # byte │ │ E4 │ S │ = │ B │ False │ 4064 │ + # Maximum 32-byte exponent │ │ IC1 │ L │ = │ B + # │ True │ 500 │ Bit shift vs multiplication @ 33 bytes │ │ IC3 + # │ S │ = │ B │ True │ 500 │ Ceiling division at 7 bytes + # │ │ IC4 │ S │ = │ B │ True │ 500 │ Ceiling division at 9 + # bytes │ │ IC5 │ S │ = │ B │ False │ 2160 │ + # Bit counting in middle of exponent │ │ IC6 │ L │ = │ B + # │ True │ 500 │ Native library even byte optimization │ │ IC7 + # │ L │ = │ B │ True │ 500 │ Vector optimization 128-bit + # boundary │ │ IC9 │ S │ = │ B │ N/A │ N/A │ Zero + # modulus handling │ │ IC10│ S │ = │ B │ + # False │ 4080 │ Power-of-2 boundary with high bit │ + # └─────┴──────┴─────┴──────┴───────┴─────────┴────────────────────────── for base, exponent, modulus, expected_result, gas_usage, test_id in test_cases: yield pytest.param( ModExpInput(base=base, exponent=exponent, modulus=modulus), @@ -662,13 +677,15 @@ def test_modexp_variable_gas_cost( @pytest.mark.valid_from("Berlin") def test_modexp_variable_gas_cost_exceed_tx_gas_cap(state_test, pre, tx, post): """ - Test ModExp variable gas cost. - Inputs with an expected gas cost over the EIP-7825 tx gas cap. + Test ModExp variable gas cost. Inputs with an expected gas cost over the + EIP-7825 tx gas cap. """ # Test case coverage table (gas cap): - # ┌─────┬──────┬─────┬──────┬───────┬─────────┬───────────────────────────────────────────────┐ - # │ ID │ Comp │ Rel │ Iter │ Clamp │ Gas │ Description │ - # ├─────┼──────┼─────┼──────┼───────┼─────────┼───────────────────────────────────────────────┤ - # │ Z16 │ L │ < │ C │ False │520060928│ Zero base, zero exp, large modulus (gas cap) | - # └─────┴──────┴─────┴──────┴───────┴─────────┴───────────────────────────────────────────────┘ + # ┌─────┬──────┬─────┬──────┬───────┬─────────┬───────────────────────── + # │ ID │ Comp │ Rel │ Iter │ Clamp │ Gas │ Description + # │ + # ├─────┼──────┼─────┼──────┼───────┼─────────┼───────────────────────── + # │ Z16 │ L │ < │ C │ False │520060928│ Zero base, zero exp, large + # modulus (gas cap) | + # └─────┴──────┴─────┴──────┴───────┴─────────┴───────────────────────── state_test(pre=pre, tx=tx, post=post) diff --git a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds_transition.py b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds_transition.py index 5c4499ace62..d6ff90b68de 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds_transition.py +++ b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds_transition.py @@ -1,4 +1,7 @@ -"""Test ModExp gas cost transition from EIP-7883 before and after the Osaka hard fork.""" +""" +Test ModExp gas cost transition from EIP-7883 before and after the Osaka hard +fork. +""" import pytest @@ -38,7 +41,10 @@ def test_modexp_fork_transition( modexp_input: ModExpInput, modexp_expected: bytes, ): - """Test ModExp gas cost transition from EIP-7883 before and after the Osaka hard fork.""" + """ + Test ModExp gas cost transition from EIP-7883 before and after the Osaka + hard fork. + """ call_code = Op.CALL( address=Spec.MODEXP_ADDRESS, args_size=Op.CALLDATASIZE, diff --git a/tests/osaka/eip7918_blob_reserve_price/conftest.py b/tests/osaka/eip7918_blob_reserve_price/conftest.py index 027cf971349..4f5f9d81bd5 100644 --- a/tests/osaka/eip7918_blob_reserve_price/conftest.py +++ b/tests/osaka/eip7918_blob_reserve_price/conftest.py @@ -56,7 +56,9 @@ def parent_excess_blob_gas( parent_excess_blobs: int | None, blob_gas_per_blob: int, ) -> int | None: - """Calculate the excess blob gas of the parent block from the excess blobs.""" + """ + Calculate the excess blob gas of the parent block from the excess blobs. + """ if parent_excess_blobs is None: return None assert parent_excess_blobs >= 0 @@ -68,7 +70,8 @@ def blobs_per_tx() -> int: """ Total number of blobs per transaction. - Can be overloaded by a test case to provide a custom blobs per transaction count. + Can be overloaded by a test case to provide a custom blobs per transaction + count. """ return 1 @@ -85,7 +88,10 @@ def block_base_fee_per_gas( parent_excess_blobs: int | None, block_base_fee_per_gas_delta: int, ) -> int: - """Block base fee per gas. Default is 7 unless a delta is provided or overloaded.""" + """ + Block base fee per gas. Default is 7 unless a delta is provided or + overloaded. + """ if block_base_fee_per_gas_delta != 0: if parent_excess_blobs is None: blob_base_fee = 1 @@ -106,7 +112,8 @@ def excess_blob_gas( block_base_fee_per_gas: int, ) -> int | None: """ - Calculate the excess blob gas of the block under test from the parent block. + Calculate the excess blob gas of the block under test from the parent + block. Value can be overloaded by a test case to provide a custom excess blob gas. """ @@ -127,7 +134,8 @@ def correct_excess_blob_gas( block_base_fee_per_gas: int, ) -> int: """ - Calculate the correct excess blob gas of the block under test from the parent block. + Calculate the correct excess blob gas of the block under test from the + parent block. Should not be overloaded by a test case. """ @@ -193,7 +201,9 @@ def env( block_base_fee_per_gas: int, genesis_excess_blob_gas: int, ) -> Environment: - """Prepare the environment of the genesis block for all blockchain tests.""" + """ + Prepare the environment of the genesis block for all blockchain tests. + """ return Environment( excess_blob_gas=genesis_excess_blob_gas, blob_gas_used=0, diff --git a/tests/osaka/eip7918_blob_reserve_price/spec.py b/tests/osaka/eip7918_blob_reserve_price/spec.py index 32c162bb45b..60d480da5af 100644 --- a/tests/osaka/eip7918_blob_reserve_price/spec.py +++ b/tests/osaka/eip7918_blob_reserve_price/spec.py @@ -20,8 +20,8 @@ class ReferenceSpec: @dataclass(frozen=True) class Spec(EIP4844Spec): """ - Parameters from the EIP-7918 specifications. - Extends EIP-4844 spec with the new reserve price constant and functionality. + Parameters from the EIP-7918 specifications. Extends EIP-4844 spec with the + new reserve price constant and functionality. """ BLOB_BASE_COST = 2**13 @@ -50,6 +50,8 @@ def calc_effective_blob_base_fee( base_fee_per_gas: int, blob_base_fee: int, ) -> int: - """Calculate the effective blob base fee considering the reserve price.""" + """ + Calculate the effective blob base fee considering the reserve price. + """ reserve_price = cls.get_reserve_price(base_fee_per_gas) return max(reserve_price, blob_base_fee) diff --git a/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py b/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py index 1b1d902b316..d68cce370fb 100644 --- a/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py +++ b/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py @@ -1,8 +1,7 @@ """ -abstract: [EIP-7918: Blob base fee bounded by execution cost](https://eips.ethereum.org/EIPS/eip-7918) - Test the blob base fee reserve price mechanism for [EIP-7918: Blob base fee bounded by execution cost](https://eips.ethereum.org/EIPS/eip-7918). - -""" # noqa: E501 +abstract: [EIP-7918: Blob base fee bounded by execution +cost](https://eips.ethereum.org/EIPS/eip-7918). +""" from typing import Dict, List @@ -145,7 +144,10 @@ def test_reserve_price_various_base_fee_scenarios( block: Block, post: Dict[Address, Account], ): - """Test reserve price mechanism across various block base fee and excess blob gas scenarios.""" + """ + Test reserve price mechanism across various block base fee and excess blob + gas scenarios. + """ blockchain_test( pre=pre, post=post, @@ -156,7 +158,8 @@ def test_reserve_price_various_base_fee_scenarios( @pytest.mark.parametrize_by_fork( "parent_excess_blobs", - # Keep max assuming this will be greater than 20 in the future, to test a blob fee of > 1 :) + # Keep max assuming this will be greater than 20 in the future, to test a + # blob fee of > 1 :) lambda fork: [0, 3, fork.target_blobs_per_block(), fork.max_blobs_per_block()], ) @pytest.mark.parametrize("block_base_fee_per_gas_delta", [-2, -1, 0, 1, 10, 100]) @@ -168,16 +171,29 @@ def test_reserve_price_boundary( post: Dict[Address, Account], ): """ - Tests the reserve price boundary mechanism. Note the default block base fee per gas is 7 (delta is 0). - With a non zero delta the block base fee per gas is set to (boundary * blob base fee) + delta. - - Example scenarios from parametrization, assume parent_excess_blobs = 3: - delta=-2: blob_base_fee=1, boundary=8, block_base_fee_per_gas=8+(-2)=6, 6 < 8, reserve inactive, effective_fee=1 - delta=0: blob_base_fee=1, boundary=8, block_base_fee_per_gas=7, 7 < 8, reserve inactive, effective_fee=1 - delta=100: blob_base_fee=1, boundary=8, block_base_fee_per_gas=8+100=108, 108 > 8, reserve active, effective_fee=max(108/8, 1)=13 - - All values give a blob base_ fee of 1 because we need a much higher excess blob gas - to increase the blob fee. This only increases to 2 at 20 excess blobs. + Tests the reserve price boundary mechanism. Note the default block base fee + per gas is 7 (delta is 0). With a non zero delta the block base fee per gas + is set to (boundary * blob base fee) + delta. + + Example scenarios from parametrization: + Assume + parent_excess_blobs = 3: + delta=-2: + blob_base_fee=1, + boundary=8, + block_base_fee_per_gas=8+(-2)=6, 6 < 8, + reserve inactive, + effective_fee=1 delta=0: + blob_base_fee=1, boundary=8, + block_base_fee_per_gas=7, 7 < 8, + reserve inactive, effective_fee=1 + delta=100: blob_base_fee=1, + boundary=8, block_base_fee_per_gas=8+100=108, 108 > 8, + reserve active, effective_fee=max(108/8, 1)=13 + + All values give a blob base_ fee of 1 because we need a much higher excess + blob gas to increase the blob fee. This only increases to 2 at 20 excess + blobs. """ # noqa: E501 blockchain_test( genesis_environment=env, diff --git a/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo.py b/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo.py index 07e1d69711b..2ee655bcaf7 100644 --- a/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo.py +++ b/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo.py @@ -1,8 +1,7 @@ """ -abstract: [EIP-7918: Blob base fee bounded by execution cost](https://eips.ethereum.org/EIPS/eip-7918) - Test the blob base fee reserve price mechanism for [EIP-7918: Blob base fee bounded by execution cost](https://eips.ethereum.org/EIPS/eip-7918). - -""" # noqa: E501 +abstract: [EIP-7918: Blob base fee bounded by execution +cost](https://eips.ethereum.org/EIPS/eip-7918). +""" import pytest diff --git a/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo_transitions.py b/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo_transitions.py index 7bf2883b265..b41b9eb298f 100644 --- a/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo_transitions.py +++ b/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo_transitions.py @@ -99,8 +99,8 @@ def genesis_base_fee_per_gas( parent_base_fee_per_gas: int, ) -> int: """Genesis base fee per gas.""" - # Base fee always drops from genesis to block 1 because the genesis block never uses - # any tx gas. + # Base fee always drops from genesis to block 1 because the genesis block + # never uses any tx gas. return (parent_base_fee_per_gas * fork.base_fee_max_change_denominator()) // 7 @@ -151,10 +151,12 @@ def env( ) -> Environment: """Environment for the test.""" return Environment( - # Excess blob gas always drops from genesis to block 1 because genesis uses no blob gas. + # Excess blob gas always drops from genesis to block 1 because genesis + # uses no blob gas. excess_blob_gas=genesis_excess_blob_gas, base_fee_per_gas=genesis_base_fee_per_gas, - gas_limit=16_000_000, # To make it easier to reach the requirement with a single tx + gas_limit=16_000_000, # To make it easier to reach the requirement + # with a single tx ) @@ -234,8 +236,8 @@ def parent_block_txs( """ Transactions included in the block prior to the fork transition fork. - Includes blob transactions to raise the `parent_blob_gas_used` and normal transactions - to raise/lower the base fee per gas. + Includes blob transactions to raise the `parent_blob_gas_used` and normal + transactions to raise/lower the base fee per gas. """ parent_block_blob_txs = get_blob_transactions( blob_count=parent_blob_count, @@ -386,8 +388,8 @@ def target_blob_gas_per_block(self) -> int: def calculate_excess_blob_gas(self, parent_header: ParentHeader) -> int: """ - Calculate the excess blob gas for the current block based - on the gas used in the parent block. + Calculate the excess blob gas for the current block based on the gas + used in the parent block. """ excess_blob_gas_calculator = self.fork.excess_blob_gas_calculator(timestamp=self.timestamp) return excess_blob_gas_calculator( @@ -400,8 +402,8 @@ def execution_base_fee_threshold_from_excess_blob_gas( self, excess_blob_gas: int ) -> int | None: """ - Return the minimum base fee required to trigger the reserve mechanism, or None - for blob schedules that don't have a reserve price mechanism. + Return the minimum base fee required to trigger the reserve mechanism, + or None for blob schedules that don't have a reserve price mechanism. """ if self.blob_base_cost is None: return None @@ -414,8 +416,8 @@ def execution_base_fee_threshold_from_excess_blob_gas( def get_fork_scenarios(fork: Fork) -> Iterator[ParameterSet]: """ - Return the list of scenarios at the fork boundary depending on the source fork and - transition fork properties. + Return the list of scenarios at the fork boundary depending on the source + fork and transition fork properties. """ source_blob_schedule = BlobSchedule(fork=fork, timestamp=0) transition_blob_schedule = BlobSchedule(fork=fork, timestamp=15_000) @@ -439,16 +441,16 @@ def get_fork_scenarios(fork: Fork) -> Iterator[ParameterSet]: source_execution_threshold != transition_execution_threshold and transition_execution_threshold is not None ): - # The source base fee reserve threshold is different from the transition one - # given the excess blob gas. - # We can verify that the BPO is activated correctly by using the a setup block - # with transition_execution_threshold to trigger the reserve. + # The source base fee reserve threshold is different from the + # transition one given the excess blob gas. We can verify that the + # BPO is activated correctly by using the a setup block with + # transition_execution_threshold to trigger the reserve. for source_blob_count in [0, source_blob_schedule.target, source_blob_schedule.max]: - # Scenario 1: Parent base fee per gas is below the threshold at the - # parent of the transition block, so even though the base fee increases on - # the transition block to reach the value required to activate the reserve, - # since the base fee per gas of the parent is used, the reserve must not be - # activated. + # Scenario 1: Parent base fee per gas is below the threshold at + # the parent of the transition block, so even though the base + # fee increases on the transition block to reach the value + # required to activate the reserve, since the base fee per gas + # of the parent is used, the reserve must not be activated. parent_base_fee = transition_execution_threshold - 1 transition_base_fee = transition_execution_threshold parent_header = ParentHeader( @@ -477,9 +479,9 @@ def get_fork_scenarios(fork: Fork) -> Iterator[ParameterSet]: ), ) - # Scenario 2: Parent base fee per gas is at the threshold, so the reserve - # is activated even though the base fee per gas decreases below the - # threshold on the transition block. + # Scenario 2: Parent base fee per gas is at the threshold, so + # the reserve is activated even though the base fee per gas + # decreases below the threshold on the transition block. parent_base_fee = transition_execution_threshold transition_base_fee = transition_execution_threshold - 1 parent_header = ParentHeader( @@ -509,7 +511,8 @@ def get_fork_scenarios(fork: Fork) -> Iterator[ParameterSet]: ) if fork == BPO2ToBPO3AtTime15k: - # Explicitly add the exact scenario that triggered the Fusaka Devnet-4 fork. + # Explicitly add the exact scenario that triggered the Fusaka Devnet-4 + # fork. yield pytest.param( 0x32, 0x125BF5F, @@ -541,7 +544,10 @@ def test_reserve_price_at_transition( transition_block: Block, env: Environment, ): - """Test reserve price mechanism across various block base fee and excess blob gas scenarios.""" + """ + Test reserve price mechanism across various block base fee and excess blob + gas scenarios. + """ blockchain_test( pre=pre, post={}, diff --git a/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py b/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py index 575c8c002c9..b8a93163794 100644 --- a/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py +++ b/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py @@ -1,6 +1,7 @@ """ -abstract: Test [EIP-7934: RLP Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934) - Tests for [EIP-7934: RLP Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934). +abstract: Test [EIP-7934: RLP Execution Block Size +Limit](https://eips.ethereum.org/EIPS/eip-7934) Tests for [EIP-7934: RLP +Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934). """ from functools import lru_cache @@ -59,7 +60,9 @@ def block_size_limit(fork: Fork) -> int: @pytest.fixture def block_errors() -> List[BlockException]: - """Block exceptions expected for blocks that exceed the `MAX_RLP_BLOCK_SIZE`.""" + """ + Block exceptions expected for blocks that exceed the `MAX_RLP_BLOCK_SIZE`. + """ return [BlockException.RLP_BLOCK_LIMIT_EXCEEDED] @@ -121,18 +124,15 @@ def exact_size_transactions( """ Generate transactions that fill a block to exactly the RLP size limit. - The calculation uses caching to avoid recalculating the same block rlp for each - fork. Calculate the block and fill with real sender for testing. - - Args: - sender: The sender account - block_size_limit: The target block RLP size limit - fork: The fork to generate transactions for - pre: Required if emit_logs is True, used to deploy the log contract - gas_limit: The gas limit for the block - emit_logs: If True, transactions will call a contract that emits logs - specific_transaction_to_include: If provided, this transaction will be included + The calculation uses caching to avoid recalculating the same block rlp for + each fork. Calculate the block and fill with real sender for testing. + Args: sender: The sender account block_size_limit: The target block RLP + size limit fork: The fork to generate transactions for pre: Required if + emit_logs is True, used to deploy the log contract gas_limit: The gas limit + for the block emit_logs: If True, transactions will call a contract that + emits logs specific_transaction_to_include: If provided, this transaction + will be included """ log_contract = None if emit_logs: @@ -190,8 +190,8 @@ def _exact_size_transactions_cached( emit_logs_contract: Address | None = None, ) -> Tuple[List[Transaction], int]: """ - Generate transactions that fill a block to exactly the RLP size limit. Abstracted - with hashable arguments for caching block calculations. + Generate transactions that fill a block to exactly the RLP size limit. + Abstracted with hashable arguments for caching block calculations. """ return _exact_size_transactions_impl( block_size_limit, @@ -212,8 +212,8 @@ def _exact_size_transactions_impl( emit_logs_contract: Address | None = None, ) -> Tuple[List[Transaction], int]: """ - Calculate the exact size of transactions to be included. Shared by both cached and - non-cached paths. + Calculate the exact size of transactions to be included. Shared by both + cached and non-cached paths. """ transactions = [] nonce = 0 @@ -224,9 +224,10 @@ def _exact_size_transactions_impl( data_large = Bytes(b"\x00" * 500_000) gas_limit_large = calculator(calldata=data_large) - # block with 16 transactions + large calldata remains safely below the limit - # add 15 generic transactions to fill the block and one typed transaction - # if tx_type is specified, otherwise just add 16 generic transactions + # block with 16 transactions + large calldata remains safely below the + # limit add 15 generic transactions to fill the block and one typed + # transaction if tx_type is specified, otherwise just add 16 generic + # transactions not_all_generic_txs = any( kwarg is not None for kwarg in [specific_transaction_to_include, emit_logs_contract] ) @@ -403,9 +404,8 @@ def test_block_at_rlp_size_limit_boundary( """ Test the block rlp size limit. - - At the limit - 1 byte, the block is valid - - At the limit, the block is valid - - At the limit + 1 byte, the block is invalid + - At the limit - 1 byte, the block is valid - At the limit, the block is + valid - At the limit + 1 byte, the block is invalid """ transactions, gas_used = exact_size_transactions( sender, @@ -492,7 +492,10 @@ def test_block_at_rlp_limit_with_logs( fork: Fork, block_size_limit: int, ): - """Test that a block at the RLP size limit is valid even when transactions emit logs.""" + """ + Test that a block at the RLP size limit is valid even when transactions + emit logs. + """ transactions, gas_used = exact_size_transactions( sender, block_size_limit, diff --git a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py index 04cb4f2a26e..571ba46d737 100644 --- a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py +++ b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py @@ -1,6 +1,7 @@ """ -abstract: Tests [EIP-7939: Count leading zeros (CLZ) opcode](https://eips.ethereum.org/EIPS/eip-7939) - Test cases for [EIP-7939: Count leading zeros (CLZ) opcode](https://eips.ethereum.org/EIPS/eip-7939). +abstract: Tests [EIP-7939: Count leading zeros (CLZ) +opcode](https://eips.ethereum.org/EIPS/eip-7939) Test cases for [EIP-7939: +Count leading zeros (CLZ) opcode](https://eips.ethereum.org/EIPS/eip-7939). """ import pytest @@ -96,14 +97,12 @@ def test_clz_opcode_scenarios( """ Test CLZ opcode functionality. - Cases: - - Format 0xb000...111: leading zeros followed by ones (2**256 - 1 >> bits) - - Format 0xb010...000: single bit set at position (1 << bits) + Cases: - Format 0xb000...111: leading zeros followed by ones (2**256 - 1 >> + bits) - Format 0xb010...000: single bit set at position (1 << bits) - Test coverage: - - Leading zeros pattern: 0b000...111 (0 to 256 leading zeros) - - Single bit pattern: 0b010...000 (bit at each possible position) - - Edge cases: CLZ(0) = 256, CLZ(2^256-1) = 0 + Test coverage: - Leading zeros pattern: 0b000...111 (0 to 256 leading + zeros) - Single bit pattern: 0b010...000 (bit at each possible position) - + Edge cases: CLZ(0) = 256, CLZ(2^256-1) = 0 """ sender = pre.fund_eoa() contract_address = pre.deploy_contract( @@ -186,7 +185,9 @@ def test_clz_gas_cost_boundary( @EIPChecklist.Opcode.Test.StackComplexOperations.StackHeights.Zero() @pytest.mark.valid_from("Osaka") def test_clz_stack_underflow(state_test: StateTestFiller, pre: Alloc): - """Test CLZ opcode with empty stack (should revert due to stack underflow).""" + """ + Test CLZ opcode with empty stack (should revert due to stack underflow). + """ sender = pre.fund_eoa() callee_address = pre.deploy_contract( code=Op.CLZ + Op.STOP, # No stack items, should underflow @@ -330,8 +331,10 @@ def test_clz_fork_transition(blockchain_test: BlockchainTestFiller, pre: Alloc): ), callee_address: Account( storage={ - 14_999: "0xdeadbeef", # CLZ not valid before fork, storage unchanged - 15_000: 155, # CLZ valid on transition block, CLZ(1 << 100) = 155 + 14_999: "0xdeadbeef", # CLZ not valid before fork, storage + # unchanged + 15_000: 155, # CLZ valid on transition block, CLZ(1 << + # 100) = 155 15_001: 155, # CLZ continues to be valid after transition } ), @@ -468,7 +471,10 @@ def test_clz_code_copy_operation(state_test: StateTestFiller, pre: Alloc, bits: address=target_address, dest_offset=0, offset=clz_code_offset, size=1 ) ) - + Op.SSTORE(storage.store_next(mload_value), Op.MLOAD(0)) # Store loaded CLZ byte + + Op.SSTORE(storage.store_next(mload_value), Op.MLOAD(0)) # Store + # loaded + # CLZ + # byte ), storage={"0x00": "0xdeadbeef"}, ) @@ -499,14 +505,10 @@ def test_clz_with_memory_operation(state_test: StateTestFiller, pre: Alloc, bits expected_value = 255 - bits - # Target code pattern: - # PUSH32 (1 << bits) - # PUSH0 - # MSTORE - # - # This sequence stores a 32-byte value in memory. - # Later, we copy the immediate value from the PUSH32 instruction into memory - # using CODECOPY or EXTCODECOPY, and then load it with MLOAD for the CLZ test. + # Target code pattern: PUSH32 (1 << bits) PUSH0 MSTORE + # This sequence stores a 32-byte value in memory. Later, we copy the + # immediate value from the PUSH32 instruction into memory using CODECOPY or + # EXTCODECOPY, and then load it with MLOAD for the CLZ test. target_code = Op.PUSH32(1 << bits) offset = 1 diff --git a/tests/osaka/eip7951_p256verify_precompiles/conftest.py b/tests/osaka/eip7951_p256verify_precompiles/conftest.py index 17833d4408f..e944f994572 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/conftest.py +++ b/tests/osaka/eip7951_p256verify_precompiles/conftest.py @@ -16,9 +16,11 @@ def vector_gas_value() -> int | None: """ Gas value from the test vector if any. - If `None` it means that the test scenario did not come from a file, so no comparison is needed. + If `None` it means that the test scenario did not come from a file, so no + comparison is needed. - The `vectors_from_file` function reads the gas value from the file and overwrites this fixture. + The `vectors_from_file` function reads the gas value from the file and + overwrites this fixture. """ return None @@ -38,9 +40,10 @@ def precompile_gas_modifier() -> int: """ Modify the gas passed to the precompile, for testing purposes. - By default the call is made with the exact gas amount required for the given opcode, - but when this fixture is overridden, the gas amount can be modified to, e.g., test - a lower amount and test if the precompile call fails. + By default the call is made with the exact gas amount required for the + given opcode, but when this fixture is overridden, the gas amount can be + modified to, e.g., test a lower amount and test if the precompile call + fails. """ return 0 @@ -58,8 +61,8 @@ def call_opcode() -> Op: @pytest.fixture def call_contract_post_storage() -> Storage: """ - Storage of the test contract after the transaction is executed. - Note: Fixture `call_contract_code` fills the actual expected storage values. + Storage of the test contract after the transaction is executed. Note: + Fixture `call_contract_code` fills the actual expected storage values. """ return Storage() @@ -67,8 +70,8 @@ def call_contract_post_storage() -> Storage: @pytest.fixture def call_succeeds() -> bool: """ - By default, depending on the expected output, we can deduce if the call is expected to succeed - or fail. + By default, depending on the expected output, we can deduce if the call is + expected to succeed or fail. """ return True @@ -130,7 +133,9 @@ def post(call_contract_address: Address, call_contract_post_storage: Storage): @pytest.fixture def tx_gas_limit(fork: Fork, input_data: bytes, precompile_gas: int) -> int: - """Transaction gas limit used for the test (Can be overridden in the test).""" + """ + Transaction gas limit used for the test (Can be overridden in the test). + """ intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator() memory_expansion_gas_calculator = fork.memory_expansion_gas_calculator() extra_gas = 100_000 diff --git a/tests/osaka/eip7951_p256verify_precompiles/helpers.py b/tests/osaka/eip7951_p256verify_precompiles/helpers.py index c220f0e517d..320f04e4e30 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/helpers.py +++ b/tests/osaka/eip7951_p256verify_precompiles/helpers.py @@ -9,7 +9,10 @@ def current_python_script_directory(*args: str) -> str: - """Get the current Python script directory, optionally appending additional path components.""" + """ + Get the current Python script directory, optionally appending additional + path components. + """ return os.path.join(os.path.dirname(os.path.realpath(__file__)), *args) @@ -24,7 +27,10 @@ class Vector(BaseModel): model_config = ConfigDict(alias_generator=to_pascal) def to_pytest_param(self): - """Convert the test vector to a tuple that can be used as a parameter in a pytest test.""" + """ + Convert the test vector to a tuple that can be used as a parameter in a + pytest test. + """ return pytest.param(self.input, self.expected, self.gas, id=self.name) @@ -38,7 +44,10 @@ class FailVector(BaseModel): model_config = ConfigDict(alias_generator=to_pascal) def to_pytest_param(self): - """Convert the test vector to a tuple that can be used as a parameter in a pytest test.""" + """ + Convert the test vector to a tuple that can be used as a parameter in a + pytest test. + """ return pytest.param(self.input, id=self.name) diff --git a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py index bd188a84ca1..ef31065bc5a 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py +++ b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py @@ -1,6 +1,8 @@ """ -abstract: Tests [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951) - Test cases for [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951)]. +abstract: Tests [EIP-7951: Precompile for secp256r1 Curve +Support](https://eips.ethereum.org/EIPS/eip-7951) Test cases for [EIP-7951: +Precompile for secp256r1 Curve +Support](https://eips.ethereum.org/EIPS/eip-7951)]. """ import pytest @@ -36,8 +38,9 @@ + vectors_from_file("secp256r1_u1_u2.json") + vectors_from_file("secp256r1_k_and_s.json") + vectors_from_file("secp256r1_public_key.json"), - # Test vectors generated from Wycheproof's ECDSA secp256r1 SHA-256 test suite, valid cases - # Source: https://github.com/C2SP/wycheproof/blob/main/testvectors/ecdsa_secp256r1_sha256_test.json + # Test vectors generated from Wycheproof's ECDSA secp256r1 SHA-256 test + # suite, valid cases are from this source: + # https://github.com/C2SP/wycheproof/blob/main/testvectors/ecdsa_secp256r1_sha256_test.json ) @pytest.mark.parametrize("precompile_address", [Spec.P256VERIFY], ids=[""]) @EIPChecklist.Precompile.Test.CallContexts.Normal() @@ -169,11 +172,13 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t id="near_field_boundary_p_minus_3", ), pytest.param( - # Invalid curve attack: This point satisfies y² = x³ - 3x + 1 (mod p) - # instead of the correct P-256 equation y² = x³ - 3x + b where - # b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B - # This tests that the implementation properly validates the curve equation - # and rejects points on different curves (CVE-2020-0601 class vulnerability) + # Invalid curve attack: This point satisfies y² = x³ - 3x + 1 (mod + # p) instead of the correct P-256 equation y² = x³ - 3x + b where b + # = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53... + # ...B0F63BCE3C3E27D2604B + # This tests that the implementation properly validates the curve + # equation and rejects points on different curves (CVE-2020-0601 + # class vulnerability) Spec.H0 + Spec.R0 + Spec.S0 @@ -182,10 +187,11 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t id="invalid_curve_attack_b_equals_one", ), pytest.param( - # Invalid curve attack: Singular curve with b = 0 - # Point satisfies y² = x³ - 3x (mod p) - a singular/degenerate curve - # Singular curves have discriminant = 0 and provide no security guarantees - # This tests rejection of points on curves with catastrophic security failures + # Invalid curve attack: Singular curve with b = 0 Point satisfies + # y² = x³ - 3x (mod p) - a singular/degenerate curve Singular + # curves have discriminant = 0 and provide no security guarantees + # This tests rejection of points on curves with catastrophic + # security failures Spec.H0 + Spec.R0 + Spec.S0 @@ -194,10 +200,10 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t id="invalid_curve_attack_singular_b_zero", ), pytest.param( - # Invalid curve attack: Boundary value b = p-1 - # Point satisfies y² = x³ - 3x + (p-1) (mod p) - # Tests proper parameter validation at modular arithmetic boundaries - # Ensures implementations handle field arithmetic edge cases correctly + # Invalid curve attack: Boundary value b = p-1 Point satisfies y² = + # x³ - 3x + (p-1) (mod p) Tests proper parameter validation at + # modular arithmetic boundaries Ensures implementations handle + # field arithmetic edge cases correctly Spec.H0 + Spec.R0 + Spec.S0 @@ -206,10 +212,10 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t id="invalid_curve_attack_b_equals_p_minus_1", ), pytest.param( - # Invalid curve attack: Small discriminant curve with b = 2 - # Point satisfies y² = x³ - 3x + 2 (mod p) - # Curves with small discriminants are vulnerable to specialized attacks - # Tests rejection of cryptographically weak curve parameters + # Invalid curve attack: Small discriminant curve with b = 2 Point + # satisfies y² = x³ - 3x + 2 (mod p) Curves with small + # discriminants are vulnerable to specialized attacks Tests + # rejection of cryptographically weak curve parameters Spec.H0 + Spec.R0 + Spec.S0 + X(0x1) + Y(0x0), id="invalid_curve_attack_small_discriminant", ), @@ -530,10 +536,12 @@ def test_precompile_will_return_success_with_tx_value( # This tests the modular comparison: r' ≡ r (mod N) pytest.param( Spec.H0 - # R: A value that when used in ECDSA verification produces an x-coordinate > N + # R: A value that when used in ECDSA verification produces an + # x-coordinate > N + R(0x000000000000000000000000000000004319055358E8617B0C46353D039CDAAB) + S(0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254E) - # X, Y: Public key coordinates that will produce x-coordinate > N during verification + # X, Y: Public key coordinates that will produce x-coordinate > N + # during verification + X(0x0AD99500288D466940031D72A9F5445A4D43784640855BF0A69874D2DE5FE103) + Y(0xC5011E6EF2C42DCD50D5D3D29F99AE6EBA2C80C9244F4C5422F0979FF0C3BA5E), Spec.SUCCESS_RETURN_VALUE, @@ -545,7 +553,8 @@ def test_precompile_will_return_success_with_tx_value( + Spec.S0 + Spec.X0 + Spec.Y0, - Spec.INVALID_RETURN_VALUE, # Should fail because R = 1 is not a valid signature + Spec.INVALID_RETURN_VALUE, # Should fail because R = 1 is not a + # valid signature id="r_equals_n_plus_one", ), pytest.param( @@ -554,7 +563,8 @@ def test_precompile_will_return_success_with_tx_value( + Spec.S0 + Spec.X0 + Spec.Y0, - Spec.INVALID_RETURN_VALUE, # Should fail because R = 2 is not a valid signature + Spec.INVALID_RETURN_VALUE, # Should fail because R = 2 is not a + # valid signature id="r_equals_n_plus_two", ), ], @@ -566,9 +576,9 @@ def test_modular_comparison(state_test: StateTestFiller, pre: Alloc, post: dict, """ Test the modular comparison condition for secp256r1 precompile. - This tests that when the x-coordinate of R' exceeds the curve order N, - the verification should use modular arithmetic: - r' ≡ r (mod N) instead of direct equality r' == r. + This tests that when the x-coordinate of R' exceeds the curve order N, the + verification should use modular arithmetic: r' ≡ r (mod N) instead of + direct equality r' == r. """ state_test(env=Environment(), pre=pre, post=post, tx=tx) diff --git a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify_before_fork.py b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify_before_fork.py index b331b55c369..5c8bafe5ae6 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify_before_fork.py +++ b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify_before_fork.py @@ -1,7 +1,9 @@ """ -abstract: Tests P256VERIFY precompiles of [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951) - Tests P256VERIFY precompiles of [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951) - before the Osaka hard fork is active. +abstract: Tests P256VERIFY precompiles of [EIP-7951: Precompile for secp256r1 +Curve Support](https://eips.ethereum.org/EIPS/eip-7951) Tests P256VERIFY +precompiles of [EIP-7951: Precompile for secp256r1 Curve +Support](https://eips.ethereum.org/EIPS/eip-7951) before the Osaka hard fork is +active. """ import pytest diff --git a/tests/paris/security/test_selfdestruct_balance_bug.py b/tests/paris/security/test_selfdestruct_balance_bug.py index 1122d2f460f..529d8f3565e 100644 --- a/tests/paris/security/test_selfdestruct_balance_bug.py +++ b/tests/paris/security/test_selfdestruct_balance_bug.py @@ -1,13 +1,13 @@ """ bug: Tests the Consensus Flaw During Block Processing related to SELFDESTRUCT - Tests the consensus-vulnerability reported in - [go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4). +Tests the consensus-vulnerability reported in +[go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4](https://github.com/ethere +um/go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4). To reproduce the issue with this test case: -1. Fill the test with the most recent geth evm version. -2. Run the fixture output within a vulnerable geth version: v1.9.20 > geth >= - v1.9.4. +1. Fill the test with the most recent geth evm version. 2. Run the fixture +output within a vulnerable geth version: v1.9.20 > geth >= v1.9.4. """ import pytest @@ -32,25 +32,24 @@ def test_tx_selfdestruct_balance_bug(blockchain_test: BlockchainTestFiller, pre: Test that the vulnerability is not present by checking the balance of the `0xaa` contract after executing specific transactions. - 1. Start with contract `0xaa` which has initial balance of 3 wei. - `0xaa` contract code simply performs a self-destruct to itself. + 1. Start with contract `0xaa` which has initial balance of 3 wei. `0xaa` + contract code simply performs a self-destruct to itself. - 2. Send a transaction (tx 1) to invoke caller contract `0xcc` (which - has a balance of 1 wei), which in turn invokes `0xaa` with a 1 wei call. + 2. Send a transaction (tx 1) to invoke caller contract `0xcc` (which has a + balance of 1 wei), which in turn invokes `0xaa` with a 1 wei call. - 3. Store the balance of `0xaa` after the first transaction - is processed. `0xaa` self-destructed. Expected outcome: 0 wei. + 3. Store the balance of `0xaa` after the first transaction is processed. + `0xaa` self-destructed. Expected outcome: 0 wei. 4. Send another transaction (tx 2) to call 0xaa with 5 wei. - 5. Store the balance of `0xaa` after the second transaction - is processed. No self-destruct. Expected outcome: 5 wei. + 5. Store the balance of `0xaa` after the second transaction is processed. + No self-destruct. Expected outcome: 5 wei. - 6. Verify that: - - Call within tx 1 is successful, i.e `0xaa` self-destructed. - - The balances of `0xaa` after each tx are correct. - - During tx 2, code in `0xaa` does not execute, - hence self-destruct mechanism does not trigger. + 6. Verify that: - Call within tx 1 is successful, i.e `0xaa` + self-destructed. - The balances of `0xaa` after each tx are correct. - + During tx 2, code in `0xaa` does not execute, hence self-destruct mechanism + does not trigger. TODO: EOF - This test could be parametrized for EOFCREATE """ diff --git a/tests/prague/__init__.py b/tests/prague/__init__.py index 9a0cd1ac6c8..473ba6bdead 100644 --- a/tests/prague/__init__.py +++ b/tests/prague/__init__.py @@ -1,11 +1,17 @@ """ -Test cases for EVM functionality introduced in Prague, [EIP-7600: Hardfork Meta - Pectra](https://eip.directory/eips/eip-7600). +Test cases for EVM functionality introduced in Prague, [EIP-7600: Hardfork Meta +- Pectra](https://eip.directory/eips/eip-7600). Devnet Specifications: -- [ethpandaops/pectra-devnet-5](https://notes.ethereum.org/@ethpandaops/pectra-devnet-5). -- [ethpandaops/pectra-devnet-4](https://notes.ethereum.org/@ethpandaops/pectra-devnet-4). -- [ethpandaops/pectra-devnet-3](https://notes.ethereum.org/@ethpandaops/pectra-devnet-3). -- [ethpandaops/pectra-devnet-2](https://notes.ethereum.org/@ethpandaops/pectra-devnet-2). -- [ethpandaops/pectra-devnet-1](https://notes.ethereum.org/@ethpandaops/pectra-devnet-1). -""" # noqa: E501 +- [ethpandaops/ +pectra-devnet-5](https://notes.ethereum.org/@ethpandaops/pectra-devnet-5). +- [ethpandaops/ +pectra-devnet-4](https://notes.ethereum.org/@ethpandaops/pectra-devnet-4). +- [ethpandaops/ +pectra-devnet-3](https://notes.ethereum.org/@ethpandaops/pectra-devnet-3). +- [ethpandaops/ +pectra-devnet-2](https://notes.ethereum.org/@ethpandaops/pectra-devnet-2). +- [ethpandaops/ +pectra-devnet-1](https://notes.ethereum.org/@ethpandaops/pectra-devnet-1). +""" diff --git a/tests/prague/eip2537_bls_12_381_precompiles/__init__.py b/tests/prague/eip2537_bls_12_381_precompiles/__init__.py index 2cede194058..fcff6bad1e4 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/__init__.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/__init__.py @@ -1,4 +1,5 @@ """ -abstract: Tests [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests for [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). -""" # noqa: E501 +abstract: Tests [EIP-2537: Precompile for BLS12-381 curve +operations](https://eips.ethereum.org/EIPS/eip-2537). + +""" diff --git a/tests/prague/eip2537_bls_12_381_precompiles/conftest.py b/tests/prague/eip2537_bls_12_381_precompiles/conftest.py index a4780065df7..880f85a5cd2 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/conftest.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/conftest.py @@ -17,9 +17,11 @@ def vector_gas_value() -> int | None: """ Gas value from the test vector if any. - If `None` it means that the test scenario did not come from a file, so no comparison is needed. + If `None` it means that the test scenario did not come from a file, so no + comparison is needed. - The `vectors_from_file` function reads the gas value from the file and overwrites this fixture. + The `vectors_from_file` function reads the gas value from the file and + overwrites this fixture. """ return None @@ -42,9 +44,10 @@ def precompile_gas_modifier() -> int: """ Modify the gas passed to the precompile, for testing purposes. - By default the call is made with the exact gas amount required for the given opcode, - but when this fixture is overridden, the gas amount can be modified to, e.g., test - a lower amount and test if the precompile call fails. + By default the call is made with the exact gas amount required for the + given opcode, but when this fixture is overridden, the gas amount can be + modified to, e.g., test a lower amount and test if the precompile call + fails. """ return 0 @@ -62,8 +65,8 @@ def call_opcode() -> Op: @pytest.fixture def call_contract_post_storage() -> Storage: """ - Storage of the test contract after the transaction is executed. - Note: Fixture `call_contract_code` fills the actual expected storage values. + Storage of the test contract after the transaction is executed. Note: + Fixture `call_contract_code` fills the actual expected storage values. """ return Storage() @@ -73,8 +76,8 @@ def call_succeeds( expected_output: bytes | SupportsBytes, ) -> bool: """ - By default, depending on the expected output, we can deduce if the call is expected to succeed - or fail. + By default, depending on the expected output, we can deduce if the call is + expected to succeed or fail. """ return len(bytes(expected_output)) > 0 @@ -92,26 +95,18 @@ def call_contract_code( """ Code of the test contract. - Args: - precompile_address: - Address of the precompile to call. - precompile_gas: - Gas cost for the precompile, which is automatically calculated by the `precompile_gas` - fixture, but can be overridden in the test. - precompile_gas_modifier: - Gas cost modifier for the precompile, which is automatically set to zero by the - `precompile_gas_modifier` fixture, but can be overridden in the test. - expected_output: - Expected output of the precompile call. This value is used to determine if the call is - expected to succeed or fail. - call_succeeds: - Boolean that indicates if the call is expected to succeed or fail. - call_opcode: - Type of call used to call the precompile (Op.CALL, Op.CALLCODE, Op.DELEGATECALL, - Op.STATICCALL). - call_contract_post_storage: - Storage of the test contract after the transaction is executed. - + Args: precompile_address: Address of the precompile to call. + precompile_gas: Gas cost for the precompile, which is automatically + calculated by the `precompile_gas` fixture, but can be overridden in the + test. precompile_gas_modifier: Gas cost modifier for the precompile, which + is automatically set to zero by the `precompile_gas_modifier` fixture, but + can be overridden in the test. expected_output: Expected output of the + precompile call. This value is used to determine if the call is expected to + succeed or fail. call_succeeds: Boolean that indicates if the call is + expected to succeed or fail. call_opcode: Type of call used to call the + precompile (Op.CALL, Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL). + call_contract_post_storage: Storage of the test contract after the + transaction is executed. """ expected_output = bytes(expected_output) @@ -177,7 +172,9 @@ def post(call_contract_address: Address, call_contract_post_storage: Storage): @pytest.fixture def tx_gas_limit(fork: Fork, input_data: bytes, precompile_gas: int) -> int: - """Transaction gas limit used for the test (Can be overridden in the test).""" + """ + Transaction gas limit used for the test (Can be overridden in the test). + """ intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator() memory_expansion_gas_calculator = fork.memory_expansion_gas_calculator() extra_gas = 100_000 diff --git a/tests/prague/eip2537_bls_12_381_precompiles/helpers.py b/tests/prague/eip2537_bls_12_381_precompiles/helpers.py index afadc8bb601..cf29cd03e9b 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/helpers.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/helpers.py @@ -14,7 +14,10 @@ def current_python_script_directory(*args: str) -> str: - """Get the current Python script directory, optionally appending additional path components.""" + """ + Get the current Python script directory, optionally appending additional + path components. + """ return os.path.join(os.path.dirname(os.path.realpath(__file__)), *args) @@ -29,7 +32,10 @@ class Vector(BaseModel): model_config = ConfigDict(alias_generator=to_pascal) def to_pytest_param(self): - """Convert the test vector to a tuple that can be used as a parameter in a pytest test.""" + """ + Convert the test vector to a tuple that can be used as a parameter in a + pytest test. + """ return pytest.param(self.input, self.expected, self.gas, id=self.name) @@ -43,7 +49,10 @@ class FailVector(BaseModel): model_config = ConfigDict(alias_generator=to_pascal) def to_pytest_param(self): - """Convert the test vector to a tuple that can be used as a parameter in a pytest test.""" + """ + Convert the test vector to a tuple that can be used as a parameter in a + pytest test. + """ return pytest.param(self.input, id=self.name) @@ -70,8 +79,8 @@ def vectors_from_file(filename: str) -> List: def add_points_g1(point_a: PointG1, point_b: PointG1) -> PointG1: """ - Add two points in G1 using standard formulas. - For points P = (x, y) and Q = (u, v), compute R = P + Q. + Add two points in G1 using standard formulas. For points P = (x, y) and Q = + (u, v), compute R = P + Q. """ if point_a.x == 0 and point_a.y == 0: return point_b @@ -87,8 +96,8 @@ def add_points_g1(point_a: PointG1, point_b: PointG1) -> PointG1: def add_points_g2(point_a: PointG2, point_b: PointG2) -> PointG2: """ - Add two points in G2 using standard formulas. - For points P = ((x_0, x_1), (y_0, y_1)) and Q = ((u_0, u_1), (v_0, v_1)), compute R = P + Q. + Add two points in G2 using standard formulas. For points P = ((x_0, x_1), + (y_0, y_1)) and Q = ((u_0, u_1), (v_0, v_1)), compute R = P + Q. """ if point_a.x == (0, 0) and point_a.y == (0, 0): return point_b @@ -108,14 +117,13 @@ class BLSPointGenerator: """ Generator for points on the BLS12-381 curve with various properties. - Provides methods to generate points with specific properties: - - on the standard curve - - in the correct r-order subgroup or not - - on the curve or not - - on an isomorphic curve (not standard curve) but in the correct r-order subgroup + Provides methods to generate points with specific properties: - on the + standard curve - in the correct r-order subgroup or not - on the curve or + not - on an isomorphic curve (not standard curve) but in the correct + r-order subgroup Additional resource that helped the class implementation: - https://hackmd.io/@benjaminion/bls12-381 + https://hackmd.io/@benjaminion/bls12-381 """ # Constants for G1 curve equations @@ -125,7 +133,8 @@ class BLSPointGenerator: # This is a known parameter of the BLS12-381 curve specification STANDARD_B_G1 = Spec.B_COEFFICIENT - # Isomorphic G1 curve uses b=24 (can be any b value for an isomorphic curve) + # Isomorphic G1 curve uses b=24 (can be any b value for an isomorphic + # curve) ISOMORPHIC_B_G1 = 24 # Isomorphic curve: y^2 = x^3 + 24 # Constants for G2 curve equations @@ -192,8 +201,8 @@ def check_in_g2_subgroup(point: PointG2) -> bool: @staticmethod def sqrt_fq(a: FQ) -> Optional[FQ]: """ - Compute smallest square root of FQ element (if it exists). Used when finding valid - y-coordinates for a given x-coordinate on the G1 curve. + Compute smallest square root of FQ element (if it exists). Used when + finding valid y-coordinates for a given x-coordinate on the G1 curve. """ assert field_modulus % 4 == 3, "This sqrt method requires p % 4 == 3" candidate = a ** ((field_modulus + 1) // 4) @@ -206,8 +215,8 @@ def sqrt_fq(a: FQ) -> Optional[FQ]: @staticmethod def sqrt_fq2(a: FQ2) -> Optional[FQ2]: """ - Compute square root of FQ2 element (if it exists). Used when finding valid - y-coordinates for a given x-coordinate on the G2 curve. + Compute square root of FQ2 element (if it exists). Used when finding + valid y-coordinates for a given x-coordinate on the G2 curve. """ if a == FQ2([0, 0]): return FQ2([0, 0]) @@ -222,8 +231,9 @@ def sqrt_fq2(a: FQ2) -> Optional[FQ2]: @classmethod def multiply_by_cofactor(cls, point: Any, is_g2: bool = False): """ - Multiply a point by the cofactor to ensure it's in the correct r-order subgroup. - Used for creating points in the correct r-order subgroup when using isomorphic curves. + Multiply a point by the cofactor to ensure it's in the correct r-order + subgroup. Used for creating points in the correct r-order subgroup when + using isomorphic curves. """ cofactor = cls.G2_COFACTOR if is_g2 else cls.G1_COFACTOR try: @@ -251,8 +261,8 @@ def multiply_by_cofactor(cls, point: Any, is_g2: bool = False): @memory.cache def find_g1_point_by_x(cls, x_value: int, in_subgroup: bool, on_curve: bool = True) -> PointG1: """ - Find a G1 point with x-coordinate at or near the given value, - with the specified subgroup membership and curve membership. + Find a G1 point with x-coordinate at or near the given value, with the + specified subgroup membership and curve membership. """ max_offset = 5000 isomorphic_b = cls.ISOMORPHIC_B_G1 @@ -267,7 +277,8 @@ def find_g1_point_by_x(cls, x_value: int, in_subgroup: bool, on_curve: bool = Tr try: x = FQ(try_x) - # Calculate y² = x³ + b (standard curve or isomorphic curve) + # Calculate y² = x³ + b (standard curve or isomorphic + # curve) b_value = cls.STANDARD_B_G1 if on_curve else isomorphic_b y_squared = x**3 + FQ(b_value) @@ -280,7 +291,8 @@ def find_g1_point_by_x(cls, x_value: int, in_subgroup: bool, on_curve: bool = Tr raw_point = (int(x), int(y)) raw_point2 = (int(x), Spec.P - int(y)) - # For isomorphic curve points in subgroup, apply cofactor multiplication + # For isomorphic curve points in subgroup, apply cofactor + # multiplication if not on_curve and in_subgroup: try: subgroup_point = cls.multiply_by_cofactor(raw_point, is_g2=False) @@ -327,8 +339,8 @@ def find_g2_point_by_x( cls, x_value: tuple, in_subgroup: bool, on_curve: bool = True ) -> PointG2: """ - Find a G2 point with x-coordinate at or near the given value, - with the specified subgroup membership and curve membership. + Find a G2 point with x-coordinate at or near the given value, with the + specified subgroup membership and curve membership. """ max_offset = 5000 isomorphic_b = cls.ISOMORPHIC_B_G2 @@ -344,7 +356,8 @@ def find_g2_point_by_x( try: x = FQ2(try_x) - # Calculate y² = x³ + b (standard curve or isomorphic curve) + # Calculate y² = x³ + b (standard curve or isomorphic + # curve) b_value = cls.STANDARD_B_G2 if on_curve else isomorphic_b y_squared = x**3 + FQ2(b_value) @@ -363,7 +376,8 @@ def find_g2_point_by_x( (Spec.P - int(y.coeffs[0]), Spec.P - int(y.coeffs[1])), ) - # For isomorphic curve points in subgroup, apply cofactor multiplication + # For isomorphic curve points in subgroup, apply cofactor + # multiplication if not on_curve and in_subgroup: try: subgroup_point = cls.multiply_by_cofactor(raw_point, is_g2=True) @@ -413,26 +427,36 @@ def find_g2_point_by_x( # G1 points by x coordinate (near or on the x value) @classmethod def generate_g1_point_in_subgroup_by_x(cls, x_value: int) -> PointG1: - """G1 point that is in the r-order subgroup with x-coordinate by/on the given value.""" + """ + G1 point that is in the r-order subgroup with x-coordinate by/on the + given value. + """ return cls.find_g1_point_by_x(x_value, in_subgroup=True, on_curve=True) @classmethod def generate_g1_point_not_in_subgroup_by_x(cls, x_value: int) -> PointG1: - """G1 point that is NOT in the r-order subgroup with x-coordinate by/on the given value.""" + """ + G1 point that is NOT in the r-order subgroup with x-coordinate by/on + the given value. + """ return cls.find_g1_point_by_x(x_value, in_subgroup=False, on_curve=True) @classmethod def generate_g1_point_not_on_curve_by_x(cls, x_value: int) -> PointG1: - """G1 point that is NOT on the curve with x-coordinate by/on the given value.""" + """ + G1 point that is NOT on the curve with x-coordinate by/on the given + value. + """ return cls.find_g1_point_by_x(x_value, in_subgroup=False, on_curve=False) @classmethod def generate_g1_point_on_isomorphic_curve_by_x(cls, x_value: int) -> PointG1: """ - G1 point that is on an isomorphic curve (not standard curve) - but in the r-order subgroup with x-coordinate by/on the given value. + G1 point that is on an isomorphic curve (not standard curve) but in the + r-order subgroup with x-coordinate by/on the given value. - Uses cofactor multiplication to ensure the point is in the correct subgroup. + Uses cofactor multiplication to ensure the point is in the correct + subgroup. """ return cls.find_g1_point_by_x(x_value, in_subgroup=True, on_curve=False) @@ -464,10 +488,11 @@ def generate_random_g1_point_not_on_curve(cls, seed: int) -> PointG1: @classmethod def generate_random_g1_point_on_isomorphic_curve(cls, seed: int) -> PointG1: """ - Generate a random G1 point that is on an isomorphic curve (not standard curve) - but in the r-order subgroup. + Generate a random G1 point that is on an isomorphic curve (not standard + curve) but in the r-order subgroup. - Uses cofactor multiplication to ensure the point is in the correct subgroup. + Uses cofactor multiplication to ensure the point is in the correct + subgroup. """ seed_bytes = seed.to_bytes(32, "big") hash_output = hashlib.sha384(seed_bytes + b"on_isomorphic_curve").digest() @@ -477,26 +502,36 @@ def generate_random_g1_point_on_isomorphic_curve(cls, seed: int) -> PointG1: # G2 point generators - by x coordinate (near or on the x value) @classmethod def generate_g2_point_in_subgroup_by_x(cls, x_value: tuple) -> PointG2: - """G2 point that is in the r-order subgroup with x-coordinate by/on the given value.""" + """ + G2 point that is in the r-order subgroup with x-coordinate by/on the + given value. + """ return cls.find_g2_point_by_x(x_value, in_subgroup=True, on_curve=True) @classmethod def generate_g2_point_not_in_subgroup_by_x(cls, x_value: tuple) -> PointG2: - """G2 point that is NOT in the r-order subgroup with x-coordinate by/on the given value.""" + """ + G2 point that is NOT in the r-order subgroup with x-coordinate by/on + the given value. + """ return cls.find_g2_point_by_x(x_value, in_subgroup=False, on_curve=True) @classmethod def generate_g2_point_not_on_curve_by_x(cls, x_value: tuple) -> PointG2: - """G2 point that is NOT on the curve with x-coordinate by/on the given value.""" + """ + G2 point that is NOT on the curve with x-coordinate by/on the given + value. + """ return cls.find_g2_point_by_x(x_value, in_subgroup=False, on_curve=False) @classmethod def generate_g2_point_on_isomorphic_curve_by_x(cls, x_value: tuple) -> PointG2: """ - G2 point that is on an isomorphic curve (not standard curve) - but in the r-order subgroup with x-coordinate near the given value. + G2 point that is on an isomorphic curve (not standard curve) but in the + r-order subgroup with x-coordinate near the given value. - Uses cofactor multiplication to ensure the point is in the correct subgroup. + Uses cofactor multiplication to ensure the point is in the correct + subgroup. """ return cls.find_g2_point_by_x(x_value, in_subgroup=True, on_curve=False) @@ -537,9 +572,9 @@ def generate_random_g2_point_not_on_curve(cls, seed: int) -> PointG2: @classmethod def generate_random_g2_point_on_isomorphic_curve(cls, seed: int) -> PointG2: """ - Generate a random G2 point that is on an isomorphic curve (not standard curve) - but in the r-order subgroup. - Uses cofactor multiplication to ensure the point is in the correct subgroup. + Generate a random G2 point that is on an isomorphic curve (not standard + curve) but in the r-order subgroup. Uses cofactor multiplication to + ensure the point is in the correct subgroup. """ seed_bytes = seed.to_bytes(32, "big") hash_output = hashlib.sha384(seed_bytes + b"g2_on_isomorphic_curve").digest() @@ -553,81 +588,127 @@ def generate_random_g2_point_on_isomorphic_curve(cls, seed: int) -> PointG2: @classmethod def generate_g1_map_isogeny_kernel_points(cls) -> List[FP]: """ - Return precomputed kernel points for the BLS12-381 G1 map to curve function. These map to - the G1 identity point `Spec.INF_G1`. They are generated using sage math externally with the - following script as its significantly faster than using `py_ecc` (200-1000x faster). - - For reference we can imagine the map to curve function as a simple 2 step process, where an - input t value is mapped to a point on the auxiliary curve via a SWU map, and then that - point is mapped to the BLS curve via an 11-isogeny. For reference: - - https://eips.ethereum.org/assets/eip-2537/field_to_curve + Return precomputed kernel points for the BLS12-381 G1 map to curve + function. These map to the G1 identity point `Spec.INF_G1`. They are + generated using sage math externally with the following script as its + significantly faster than using `py_ecc` (200-1000x faster). + + For reference we can imagine the map to curve function as a simple 2 + step process, where an input t value is mapped to a point on the + auxiliary curve via a SWU map, and then that point is mapped to the BLS + curve via an 11-isogeny. For reference: + https://eips.ethereum.org/assets/eip-2537/field_to_curve + + Note we cannot use sage math directly within EEST as it is not a pure + python library and requires an external dependency to be installed on + the system machine. + + Thanks to @petertdavies (Peter Miller) for the sage math script to + generate these points: ```sage + q = 0x1A0111EA397FE69A4B1BA7B6434BACD764774B84F3 + 8512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB - Note we cannot use sage math directly within EEST as it is not a pure python library and - requires an external dependency to be installed on the system machine. - - Thanks to @petertdavies (Peter Miller) for the sage math script to generate these points: - ```sage - q = 0x1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB Fq = GF(q) E1 = EllipticCurve(Fq, (0, 4)) # BLS12-381 curve - ISO_11_A = Fq(0x144698A3B8E9433D693A02C96D4982B0EA985383EE66A8D8E8981AEFD881AC98936F8DA0E0F97F5CF428082D584C1D) - ISO_11_B = Fq(0x12E2908D11688030018B12E8753EEE3B2016C1F0F24F4070A0B9C14FCEF35EF55A23215A316CEAA5D1CC48E98E172BE0) + + ISO_11_A = Fq(0x144698A3B8E9433D693A02C96D4982B0EA985383EE66A8D8E + 8981AEFD881AC98936F8DA0E0F97F5CF428082D584C1D) + + ISO_11_B = Fq(0x12E2908D11688030018B12E8753EEE3B2016C1F0F24F4070A0B + 9C14FCEF35EF55A23215A316CEAA5D1CC48E98E172BE0) + ISO_11_Z = Fq(11) + Ei = EllipticCurve(Fq, (ISO_11_A, ISO_11_B)) - iso = EllipticCurveIsogeny(E=E1, kernel=None, codomain=Ei, degree=11).dual() + + iso = EllipticCurveIsogeny( + E=E1, + kernel=None, + codomain=Ei, + degree=11).dual() + for (x, _) in iso.kernel_polynomial().roots(): discriminant = 1 - 4 / (ISO_11_A / ISO_11_B * x + 1) if not discriminant.is_square(): continue + for sign in [1, -1]: zt2 = (-1 + sign * discriminant.sqrt()) / 2 + t2 = zt2 / ISO_11_Z + if t2.is_square(): t = t2.sqrt() - assert x == -ISO_11_B / ISO_11_A * (1 + 1 / (ISO_11_Z**2 * t**4 + ISO_11_Z * t**2)) + assert x == -ISO_11_B / ISO_11_A * (1 + 1 / (ISO_11_Z**2 * + t**4 + ISO_11_Z * t**2)) + print(t) ``` - To reproduce, add the script contents to a file called `points.sage`, then run `sage points.sage`! + To reproduce, add the script contents to a file called `points.sage`, + then run `sage points.sage`! - Please see the sage math installation guide to replicate: - - https://doc.sagemath.org/html/en/installation/index.html + Please see the sage math installation guide to replicate: - + https://doc.sagemath.org/html/en/installation/index.html - As G1 uses an 11-degree isogeny, its kernel contains exactly 11 points on the auxiliary - curve that maps to the point at infinity on the BLS curve. This includes the point at - infinity (doesn't concern us as the initial SWU map can never output infinity from any int - t) and 10 other unique kernel points. + As G1 uses an 11-degree isogeny, its kernel contains exactly 11 points + on the auxiliary curve that maps to the point at infinity on the BLS + curve. This includes the point at infinity (doesn't concern us as the + initial SWU map can never output infinity from any int t) and 10 other + unique kernel points. - These 10 other kernel points correspond to 5 x-coords on the curve (since each x-coord - yields two points with y and -y). However, not all of these kernel points can be reached by - the SWU map, which is why we only have 4 unique t values below. + These 10 other kernel points correspond to 5 x-coords on the curve + (since each x-coord yields two points with y and -y). However, not all + of these kernel points can be reached by the SWU map, which is why we + only have 4 unique t values below. - The kernel polynomial has 5 roots (x-coords), and each root can potentially yield two - t values that map to kernel points via the SWU function. Analysis shows that only 2 of - these roots yield valid t values because the other 3 roots fail either the discriminant - square check or the t^2 square check in the SWU inverse calculation. From these 2 valid - roots, we get the 4 unique t values listed below. + The kernel polynomial has 5 roots (x-coords), and each root can + potentially yield two t values that map to kernel points via the SWU + function. Analysis shows that only 2 of these roots yield valid t + values because the other 3 roots fail either the discriminant square + check or the t^2 square check in the SWU inverse calculation. From + these 2 valid roots, we get the 4 unique t values listed below. The roots and their properties are as follows: - - Root 1 (x=3447232547282837364692125741875673748077489238391001187748258124039623697289612052402753422028380156396811587142615): - Fails because its discriminant is not a square. - - Root 2 (x=3086251397349454634226049654186198282625136597600255705376316455943570106637401671127489553534256598630507009270951): - Fails because its discriminant is not a square. - - Root 3 (x=2512099095366387796245759085729510986367032014959769672734622752070562589059815523018960565849753051338812932816014): - Has a square discriminant, but both sign options yield t^2 values that are not squares. - - Root 4 (x=2077344747421819657086473418925078480898358265217674456436079722467637536216749299440611432676849905020722484031356): - Yields two valid t values: - - 1731081574565817469321317449275278355306982786154072576198758675751495027640363897075486577327802192163339186341827 - - 861410691052762088300790587394810074303505896628048305535645284922135116676755956131724844456716837983264353875219 - - Root 5 (x=162902306530757011687648381458039960905879760854007434532151803806422383239905014872915974221245198317567396330740): - Yields two valid t values: - - 1006044755431560595281793557931171729984964515682961911911398807521437683216171091013202870577238485832047490326971 - - 1562001338336877267717400325455189014780228097985596277514975439801739125527323838522116502949589758528550231396418 - - Additionally we also have the additive inverses of these t values, which are also valid - kernel (non-unique) points. These are generated using the relationship: - `(-t) mod p === (p - t) mod p` - """ # noqa: E501 + - Root 1 + (x=3447232547282837364692125741875673748077489238391001187748258 + 124039623697289612052402753422028380156396811587142615): + Fails because its discriminant is not a square. + + - Root 2 + (x=3086251397349454634226049654186198282625136597600255705376316 + 455943570106637401671127489553534256598630507009270951): + Fails because its discriminant is not a square. + + - Root 3 + (x=2512099095366387796245759085729510986367032014959769672734622 + 752070562589059815523018960565849753051338812932816014): + Has a square discriminant, but both sign options yield t^2 values + that are not squares. + + - Root 4 + (x=2077344747421819657086473418925078480898358265217674456436079 + 722467637536216749299440611432676849905020722484031356): + Yields two valid t values: + - 173108157456581746932131744927527835530698278615407257619875 + 8675751495027640363897075486577327802192163339186341827 + and + - 861410691052762088300790587394810074303505896628048305535645 + 284922135116676755956131724844456716837983264353875219 + + - Root 5 + (x=1629023065307570116876483814580399609058797608540074345321518 + 03806422383239905014872915974221245198317567396330740): + Yields two valid t values: + - 100604475543156059528179355793117172998496451568296191191139 + 8807521437683216171091013202870577238485832047490326971 + - 15620013383368772677174003254551890147802280979855962 + 77514975439801739125527323838522116502949589758528550231396418 + + Additionally we also have the additive inverses of these t values, + which are also valid kernel (non-unique) points. These are generated + using the relationship: `(-t) mod p === (p - t) mod p` + """ unique_kernel_ts = [ 1731081574565817469321317449275278355306982786154072576198758675751495027640363897075486577327802192163339186341827, 861410691052762088300790587394810074303505896628048305535645284922135116676755956131724844456716837983264353875219, @@ -641,83 +722,76 @@ def generate_g1_map_isogeny_kernel_points(cls) -> List[FP]: @classmethod def generate_g2_map_isogeny_kernel_points(cls) -> List[FP2]: """ - Return precomputed kernel points for the BLS12-381 G2 map to curve function. These map to - the G2 identity point `Spec.INF_G2`. They are generated using sage math externally with the - following script as its significantly faster than using `py_ecc` (200-1000x faster). - - For reference we can imagine the map to curve function as a simple 2 step process, where an - input t value is mapped to a point on the auxiliary curve via a SWU map, and then that - point is mapped to the BLS curve via a 3-isogeny. For reference: - - https://eips.ethereum.org/assets/eip-2537/field_to_curve - - Note we cannot use sage math directly within EEST as it is not a pure python library and - requires an external dependency to be installed on the system machine. - - ```sage - q = 0x1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB - Fp = GF(q) - R. = PolynomialRing(Fp) - Fp2. = Fp.extension(x^2 + 1) - E2 = EllipticCurve(Fp2, [0, 4*(1+u)]) - ISO_3_A = 240 * u - ISO_3_B = 1012 * (1 + u) - ISO_3_Z = -(2 + u) - Ei = EllipticCurve(Fp2, [ISO_3_A, ISO_3_B]) - iso = EllipticCurveIsogeny(E=E2, kernel=None, codomain=Ei, degree=3).dual() - x_den_k0 = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63 * u - x_den_k1 = 0xc + 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9f * u - for (x, _) in iso.kernel_polynomial().roots(): - y_squared = x^3 + ISO_3_A * x + ISO_3_B - is_on_curve = y_squared.is_square() - print("Root is on curve:" if is_on_curve else "Warning: Root is not on the curve") - inv_factor = (x * ISO_3_A / -ISO_3_B) - 1 - if inv_factor == 0: - continue - discriminant = 1 + 4 / inv_factor - if not discriminant.is_square(): - continue - for sign in [1, -1]: - zt2 = (-1 + sign * discriminant.sqrt()) / 2 - t2 = zt2 / ISO_3_Z - if t2.is_square(): - t = t2.sqrt() - # Perform the proper SWU mapping - tv1_num = ISO_3_Z^2 * t^4 + ISO_3_Z * t^2 - tv1 = 1 / tv1_num - x1 = (-ISO_3_B / ISO_3_A) * (1 + tv1) - gx1 = x1^3 + ISO_3_A * x1 + ISO_3_B - x2 = ISO_3_Z * t^2 * x1 - swu_x = x1 if gx1.is_square() else x2 - x_den_value = swu_x^2 + x_den_k1 * swu_x + x_den_k0 - is_kernel_point = (x_den_value == 0) - print("Is a kernel point:", is_kernel_point) - print(t) - ``` - - Add the script contents to a file called `points.sage`, run `sage points.sage`! - - Please see the sage math installation guide to replicate: - - https://doc.sagemath.org/html/en/installation/index.html - - As G2 uses an 3-degree isogeny, its kernel contains exactly 3 points on the auxiliary - curve that maps to the point at infinity on the BLS curve. This includes the point at - infinity (doesn't concern us as the initial SWU map can never output infinity from any int - t) and 2 other kernel points. - - These 2 other kernel points correspond to 1 x-coord on the curve (since each x-coord - yields two points with y and -y). Note that this root yields two equal t values due - to specific properties of the isogeny in Fp2. - - However, the G2 case is different from G1 and requires additional verification for y, we - must check that the computed y^2 actually has a square root in Fp2. Unlike G1, the G2 - singular isogeny kernel polynomial root does not correspond to a valid point on the - auxiliary curve due to the failure of the additional check. - - - Root 1 (x=6*u + 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559781): - Fails because its y^2 is not a square in Fp2. - - Due to the failure of the first root, we have no valid kernel points in G2 that map to the - point at infinity on the BLS curve. This is why we return an empty list here. It is kept - for consistency with the G1 case, and documentation purposes. + Return precomputed kernel points for the BLS12-381 G2 map to curve + function. These map to the G2 identity point `Spec.INF_G2`. They are + generated using sage math externally with the following script as its + significantly faster than using `py_ecc` (200-1000x faster). + + For reference we can imagine the map to curve function as a simple 2 + step process, where an input t value is mapped to a point on the + auxiliary curve via a SWU map, and then that point is mapped to the BLS + curve via a 3-isogeny. For reference: - + https://eips.ethereum.org/assets/eip-2537/field_to_curve + + Note we cannot use sage math directly within EEST as it is not a pure + python library and requires an external dependency to be installed on + the system machine. + + ```sage q = + 0x1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153F + FFFB9FEFFFFFFFFAAAB Fp = GF(q) R. = PolynomialRing(Fp) Fp2. = + Fp.extension(x^2 + 1) E2 = EllipticCurve(Fp2, [0, 4*(1+u)]) ISO_3_A = + 240 * u ISO_3_B = 1012 * (1 + u) ISO_3_Z = -(2 + u) Ei = + EllipticCurve(Fp2, [ISO_3_A, ISO_3_B]) iso = EllipticCurveIsogeny(E=E2, + kernel=None, codomain=Ei, degree=3).dual() x_den_k0 = + 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153f + fffb9feffffffffaa63 * u x_den_k1 = 0xc + + 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153f + fffb9feffffffffaa9f * u for (x, _) in iso.kernel_polynomial().roots(): + y_squared = x^3 + ISO_3_A * x + ISO_3_B is_on_curve = + y_squared.is_square() print("Root is on curve:" if is_on_curve else + "Warning: Root is not on the curve") inv_factor = (x * ISO_3_A / + -ISO_3_B) - 1 if inv_factor == 0: continue discriminant = 1 + 4 / + inv_factor if not discriminant.is_square(): continue for sign in [1, + -1]: zt2 = (-1 + sign * discriminant.sqrt()) / 2 t2 = zt2 / ISO_3_Z if + t2.is_square(): t = t2.sqrt() # Perform the proper SWU mapping tv1_num + = ISO_3_Z^2 * t^4 + ISO_3_Z * t^2 tv1 = 1 / tv1_num x1 = (-ISO_3_B / + ISO_3_A) * (1 + tv1) gx1 = x1^3 + ISO_3_A * x1 + ISO_3_B x2 = ISO_3_Z * + t^2 * x1 swu_x = x1 if gx1.is_square() else x2 x_den_value = swu_x^2 + + x_den_k1 * swu_x + x_den_k0 is_kernel_point = (x_den_value == 0) + print("Is a kernel point:", is_kernel_point) print(t) ``` + + Add the script contents to a file called `points.sage`, run `sage + points.sage`! + + Please see the sage math installation guide to replicate: - + https://doc.sagemath.org/html/en/installation/index.html + + As G2 uses an 3-degree isogeny, its kernel contains exactly 3 points on + the auxiliary curve that maps to the point at infinity on the BLS + curve. This includes the point at infinity (doesn't concern us as the + initial SWU map can never output infinity from any int t) and 2 other + kernel points. + + These 2 other kernel points correspond to 1 x-coord on the curve (since + each x-coord yields two points with y and -y). Note that this root + yields two equal t values due to specific properties of the isogeny in + Fp2. + + However, the G2 case is different from G1 and requires additional + verification for y, we must check that the computed y^2 actually has a + square root in Fp2. Unlike G1, the G2 singular isogeny kernel + polynomial root does not correspond to a valid point on the auxiliary + curve due to the failure of the additional check. + + - Root 1 (x=6*u + + 4002409555221667393417789825735904156556882819939007885332058136124031650490837 + 864442687629129015664037894272559781): Fails because its y^2 is not a + square in Fp2. + + Due to the failure of the first root, we have no valid kernel points in + G2 that map to the point at infinity on the BLS curve. This is why we + return an empty list here. It is kept for consistency with the G1 case, + and documentation purposes. """ # noqa: E501 return [] diff --git a/tests/prague/eip2537_bls_12_381_precompiles/spec.py b/tests/prague/eip2537_bls_12_381_precompiles/spec.py index 591ede19347..15ce33d47c5 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/spec.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/spec.py @@ -249,7 +249,10 @@ def msm_discount(group: BLS12Group, k: int) -> int: def msm_gas_func_gen( group: BLS12Group, len_per_pair: int, multiplication_cost: int ) -> Callable[[int], int]: - """Generate a function that calculates the gas cost for the G1MSM and G2MSM precompiles.""" + """ + Generate a function that calculates the gas cost for the G1MSM and G2MSM + precompiles. + """ def msm_gas(input_length: int) -> int: """Calculate gas cost for the G1MSM and G2MSM precompiles.""" diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py index 4dab178a35f..929e6622128 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py @@ -1,7 +1,7 @@ """ -abstract: Tests BLS12_G1ADD precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests BLS12_G1ADD precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). -""" # noqa: E501 +abstract: Tests BLS12_G1ADD precompile of [EIP-2537: Precompile for BLS12-381 +curve operations](https://eips.ethereum.org/EIPS/eip-2537). +""" import pytest @@ -26,8 +26,8 @@ # Test vectors from the reference spec (from the cryptography team) vectors_from_file("add_G1_bls.json") + [ - # Identity (infinity) element test cases. - # Checks that any point added to the identity element (INF) equals itself. + # Identity (infinity) element test cases. Checks that any point added + # to the identity element (INF) equals itself. pytest.param( Spec.G1 + Spec.INF_G1, Spec.G1, @@ -114,15 +114,16 @@ None, id="point_plus_reflected_point", ), - # Not in the r-order subgroup test cases. - # Checks that any point on the curve but not in the subgroup is used for operations. + # Not in the r-order subgroup test cases. Checks that any point on the + # curve but not in the subgroup is used for operations. pytest.param( Spec.P1_NOT_IN_SUBGROUP + Spec.P1_NOT_IN_SUBGROUP, Spec.P1_NOT_IN_SUBGROUP_TIMES_2, None, id="non_sub_plus_non_sub", ), - pytest.param( # `P1_NOT_IN_SUBGROUP` has an small order subgroup of 3: 3P = INF. + pytest.param( # `P1_NOT_IN_SUBGROUP` has an small order subgroup of 3: + # 3P = INF. Spec.P1_NOT_IN_SUBGROUP + Spec.P1_NOT_IN_SUBGROUP_TIMES_2, Spec.INF_G1, None, @@ -164,7 +165,8 @@ None, id="doubled_non_sub_plus_neg", ), - # More not in the r-order subgroup test cases, but using random generated points. + # More not in the r-order subgroup test cases, but using random + # generated points. pytest.param( G1_POINTS_NOT_IN_SUBGROUP[0] + Spec.P1, add_points_g1(G1_POINTS_NOT_IN_SUBGROUP[0], Spec.P1), diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py index fb69d0e4060..690f98c5195 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py @@ -1,7 +1,7 @@ """ -abstract: Tests BLS12_G1MSM precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests BLS12_G1MSM precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). -""" # noqa: E501 +abstract: Tests BLS12_G1MSM precompile of [EIP-2537: Precompile for BLS12-381 +curve operations](https://eips.ethereum.org/EIPS/eip-2537). +""" import pytest @@ -69,7 +69,8 @@ None, id="multiple_points_zero_scalar", ), - # Cases with maximum discount table (test vector for gas cost calculation) + # Cases with maximum discount table (test vector for gas cost + # calculation) pytest.param( (Spec.P1 + Scalar(Spec.Q)) * (len(Spec.G1MSM_DISCOUNT_TABLE) - 1), Spec.INF_G1, @@ -173,7 +174,9 @@ def test_valid( id="scalar_too_large", ), pytest.param( - Spec.G1 + Scalar(1).x.to_bytes(16, byteorder="big"), # Invalid scalar length + Spec.G1 + Scalar(1).x.to_bytes(16, byteorder="big"), # Invalid + # scalar + # length id="scalar_too_short", ), pytest.param( @@ -198,7 +201,8 @@ def test_valid( id="y_above_p_pos_1", ), ], - # Input length tests can be found in ./test_bls12_variable_length_input_contracts.py + # Input length tests can be found in + # ./test_bls12_variable_length_input_contracts.py ) @pytest.mark.parametrize( "precompile_gas_modifier", [100_000], ids=[""] diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py index 721d63a50b5..b3d83026e2c 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py @@ -1,7 +1,7 @@ """ -abstract: Tests BLS12_G1MUL precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests BLS12_G1MUL precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). -""" # noqa: E501 +abstract: Tests BLS12_G1MUL precompile of [EIP-2537: Precompile for BLS12-381 +curve operations](https://eips.ethereum.org/EIPS/eip-2537). +""" import pytest @@ -182,7 +182,8 @@ def test_valid( id="swapped_coordinates_times_0", ), pytest.param( - PointG1(0x01, 0x07) + Scalar(0), # Point on wrong curve y^2 = x^3 + 5 + PointG1(0x01, 0x07) + Scalar(0), # Point on wrong curve y^2 = x^3 + # + 5 id="point_on_wrong_curve_times_0", ), pytest.param( @@ -294,7 +295,8 @@ def test_valid( Spec.P1_NOT_IN_SUBGROUP + Scalar(Spec.Q + 1), id="not_in_subgroup_times_q_plus_1", ), - # More not in the r-order subgroup test cases, but using random generated points. + # More not in the r-order subgroup test cases, but using random + # generated points. pytest.param( G1_POINTS_NOT_IN_SUBGROUP[0] + Scalar(1), id="rand_not_in_subgroup_0_times_1", diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py index 17282fdd926..7dd40890ac5 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py @@ -1,7 +1,7 @@ """ -abstract: Tests BLS12_G2ADD precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests BLS12_G2ADD precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). -""" # noqa: E501 +abstract: Tests BLS12_G2ADD precompile of [EIP-2537: Precompile for BLS12-381 +curve operations](https://eips.ethereum.org/EIPS/eip-2537). +""" import pytest @@ -26,8 +26,8 @@ # Test vectors from the reference spec (from the cryptography team) vectors_from_file("add_G2_bls.json") + [ - # Identity (infinity) element test cases. - # Checks that any point added to the identity element (INF) equals itself. + # Identity (infinity) element test cases. Checks that any point added + # to the identity element (INF) equals itself. pytest.param( Spec.G2 + Spec.INF_G2, Spec.G2, @@ -115,8 +115,8 @@ None, id="point_plus_reflected_point", ), - # Not in the r-order subgroup test cases. - # Checks that any point on the curve but not in the subgroup is used for operations. + # Not in the r-order subgroup test cases. Checks that any point on the + # curve but not in the subgroup is used for operations. pytest.param( Spec.P2_NOT_IN_SUBGROUP + Spec.P2_NOT_IN_SUBGROUP, Spec.P2_NOT_IN_SUBGROUP_TIMES_2, @@ -165,7 +165,8 @@ None, id="doubled_non_sub_plus_neg", ), - # More not in the r-order subgroup test cases, but using random generated points. + # More not in the r-order subgroup test cases, but using random + # generated points. pytest.param( G2_POINTS_NOT_IN_SUBGROUP[0] + Spec.P2, add_points_g2(G2_POINTS_NOT_IN_SUBGROUP[0], Spec.P2), diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py index c27b8f5599d..04391084f59 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py @@ -1,7 +1,7 @@ """ -abstract: Tests BLS12_G2MSM precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests BLS12_G2MSM precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). -""" # noqa: E501 +abstract: Tests BLS12_G2MSM precompile of [EIP-2537: Precompile for BLS12-381 +curve operations](https://eips.ethereum.org/EIPS/eip-2537). +""" import pytest @@ -69,7 +69,8 @@ None, id="multiple_points_zero_scalar", ), - # Cases with maximum discount table (test vector for gas cost calculation) + # Cases with maximum discount table (test vector for gas cost + # calculation) pytest.param( (Spec.P2 + Scalar(Spec.Q)) * (len(Spec.G2MSM_DISCOUNT_TABLE) - 1), Spec.INF_G2, @@ -171,7 +172,9 @@ def test_valid( id="scalar_too_large", ), pytest.param( - Spec.G2 + Scalar(1).x.to_bytes(16, byteorder="big"), # Invalid scalar length + Spec.G2 + Scalar(1).x.to_bytes(16, byteorder="big"), # Invalid + # scalar + # length id="scalar_too_short", ), pytest.param( @@ -224,7 +227,8 @@ def test_valid( id="y_c1_above_p_pos_1", ), ], - # Input length tests can be found in ./test_bls12_variable_length_input_contracts.py + # Input length tests can be found in + # ./test_bls12_variable_length_input_contracts.py ) @pytest.mark.parametrize( "precompile_gas_modifier", [100_000], ids=[""] diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py index db72f7d7563..b5abfdeee22 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py @@ -1,7 +1,7 @@ """ -abstract: Tests BLS12_G2MUL precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests BLS12_G2MUL precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). -""" # noqa: E501 +abstract: Tests BLS12_G2MUL precompile of [EIP-2537: Precompile for BLS12-381 +curve operations](https://eips.ethereum.org/EIPS/eip-2537). +""" import pytest @@ -312,7 +312,8 @@ def test_valid( Spec.P2_NOT_IN_SUBGROUP + Scalar(Spec.Q + 1), id="not_in_subgroup_times_q_plus_1", ), - # More not in the r-order subgroup test cases, but using random generated points. + # More not in the r-order subgroup test cases, but using random + # generated points. pytest.param( G2_POINTS_NOT_IN_SUBGROUP[0] + Scalar(1), id="rand_not_in_subgroup_0_times_1", diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py index d2da70d7e90..475f764a8e3 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py @@ -1,6 +1,8 @@ """ -abstract: Tests BLS12_MAP_FP2_TO_G2 precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests BLS12_MAP_FP2_TO_G2 precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). +abstract: Tests BLS12_MAP_FP2_TO_G2 precompile of [EIP-2537: Precompile for +BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) Tests +BLS12_MAP_FP2_TO_G2 precompile of [EIP-2537: Precompile for BLS12-381 curve +operations](https://eips.ethereum.org/EIPS/eip-2537). """ # noqa: E501 import pytest @@ -101,16 +103,18 @@ def test_isogeny_kernel_values( tx: Transaction, ): """ - Test the BLS12_MAP_FP2_TO_G2 precompile with isogeny kernel values. Note this test only exists - to align with the G1 test. `G2_FIELD_POINTS_MAP_TO_IDENTITY` is empty so there are no cases. - - The isogeny kernel is simply the set of special field values, that after the two step mapping - (first SWU onto an auxiliary curve, then a 3-degree isogeny back to G2), collapse exactly - to the identity point. - - For the G2 case the only kernel element is the point at infinity, and SWU never produces the - identity point from a finite input t. Hence `G2_FIELD_POINTS_MAP_TO_IDENTITY` is empty. Please - proceed to the generator in `helpers.py` for more details. + Test the BLS12_MAP_FP2_TO_G2 precompile with isogeny kernel values. Note + this test only exists to align with the G1 test. + `G2_FIELD_POINTS_MAP_TO_IDENTITY` is empty so there are no cases. + + The isogeny kernel is simply the set of special field values, that after + the two step mapping (first SWU onto an auxiliary curve, then a 3-degree + isogeny back to G2), collapse exactly to the identity point. + + For the G2 case the only kernel element is the point at infinity, and SWU + never produces the identity point from a finite input t. Hence + `G2_FIELD_POINTS_MAP_TO_IDENTITY` is empty. Please proceed to the generator + in `helpers.py` for more details. """ state_test( env=Environment(), diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py index 6612530513d..4fb826f5712 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py @@ -1,7 +1,7 @@ """ -abstract: Tests BLS12_MAP_FP_TO_G1 precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests BLS12_MAP_FP_TO_G1 precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). -""" # noqa: E501 +abstract: Tests BLS12_MAP_FP_TO_G1 precompile of [EIP-2537: Precompile for +BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). +""" import pytest @@ -88,12 +88,12 @@ def test_isogeny_kernel_values( """ Test the BLS12_MAP_FP_TO_G1 precompile with isogeny kernel inputs. - The isogeny kernel is simply the set of special field values, that after the two step mapping - (first SWU onto an auxiliary curve, then an 11-degree isogeny back to G1), collapse exactly - to the identity point. + The isogeny kernel is simply the set of special field values, that after + the two step mapping (first SWU onto an auxiliary curve, then an 11-degree + isogeny back to G1), collapse exactly to the identity point. - Please proceed to the generator in `helpers.py` to see how the isogeny kernel values are - generated. + Please proceed to the generator in `helpers.py` to see how the isogeny + kernel values are generated. """ state_test( env=Environment(), diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py index 4d1d5555ebb..bf22c7ed871 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py @@ -1,7 +1,7 @@ """ -abstract: Tests BLS12_PAIRING precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests BLS12_PAIRING precompile of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). -""" # noqa: E501 +abstract: Tests BLS12_PAIRING precompile of [EIP-2537: Precompile for BLS12-381 +curve operations](https://eips.ethereum.org/EIPS/eip-2537). +""" import pytest @@ -147,8 +147,8 @@ def test_valid_multi_inf( post: dict, ): """ - Test maximum input given the current environment gas limit for the BLS12_PAIRING - precompile. + Test maximum input given the current environment gas limit for the + BLS12_PAIRING precompile. """ intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator() memory_expansion_gas_calculator = fork.memory_expansion_gas_calculator() @@ -347,8 +347,8 @@ def test_invalid_multi_inf( post: dict, ): """ - Test maximum input given the current environment gas limit for the BLS12_PAIRING - precompile and an invalid tail. + Test maximum input given the current environment gas limit for the + BLS12_PAIRING precompile and an invalid tail. """ intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator() memory_expansion_gas_calculator = fork.memory_expansion_gas_calculator() diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py index 2e1cc8c0080..930101cc59c 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py @@ -1,8 +1,7 @@ """ -abstract: Tests BLS12 precompiles of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests BLS12 precompiles of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - before the Prague hard fork is active. -""" # noqa: E501 +abstract: Tests BLS12 precompiles of [EIP-2537: Precompile for BLS12-381 +curve operations](https://eips.ethereum.org/EIPS/eip-2537). +""" import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py index 527adb20096..24d86b5b8ca 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py @@ -1,7 +1,8 @@ """ -abstract: Tests minimum gas and input length for BLS12_G1MSM, BLS12_G2MSM, BLS12_PAIRING precompiles of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) - Tests minimum gas and input length for BLS12_G1MSM, BLS12_G2MSM, BLS12_PAIRING precompiles of [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). -""" # noqa: E501 +abstract: Tests minimum gas and input length for BLS12_G1MSM, BLS12_G2MSM, +BLS12_PAIRING precompiles of [EIP-2537: Precompile for BLS12-381 curve +operations](https://eips.ethereum.org/EIPS/eip-2537). +""" from typing import Callable, List, SupportsBytes @@ -29,7 +30,10 @@ @pytest.fixture def input_data() -> bytes: - """Calldata of the transaction is empty because all input in these tests is zero.""" + """ + Calldata of the transaction is empty because all input in these tests is + zero. + """ return b"" @@ -41,7 +45,9 @@ def gas_modifier() -> int: @pytest.fixture def input_length_modifier() -> int: - """Input length modifier to apply to each element of the precompile_gas_list.""" + """ + Input length modifier to apply to each element of the precompile_gas_list. + """ return 0 @@ -71,38 +77,31 @@ def call_contract_code( call_contract_post_storage: Storage, ) -> Bytecode: """ - Code of the test contract to validate minimum expected gas in precompiles, as well as - expected input lengths on all variable-length input precompiles. - - Code differs from the one used in all other tests in this file, because it accepts a list of - precompile gas values and a list of precompile data lengths, and for each pair of values, it - calls the precompile with the given gas and data length, data being passed to the precompile - is all zeros. - - Args: - precompile_address: - Address of the precompile to call. - precompile_gas_list: - List of gas values to be used to call the precompile, one for each call. - precompile_data_length_list: - List of data lengths to be used to call the precompile, one for each call. - gas_modifier: - Integer to add to the gas passed to the precompile. - input_length_modifier: - Integer to add to the length of the input passed to the precompile. - expected_output: - Expected output of the contract, it is only used to determine if the call is expected - to succeed or fail. - call_opcode: - Type of call used to call the precompile (Op.CALL, Op.CALLCODE, Op.DELEGATECALL, - Op.STATICCALL). - call_contract_post_storage: - Storage of the test contract after the transaction is executed. - + Code of the test contract to validate minimum expected gas in precompiles, + as well as expected input lengths on all variable-length input precompiles. + + Code differs from the one used in all other tests in this file, because it + accepts a list of precompile gas values and a list of precompile data + lengths, and for each pair of values, it calls the precompile with the + given gas and data length, data being passed to the precompile is all + zeros. + + Args: precompile_address: Address of the precompile to call. + precompile_gas_list: List of gas values to be used to call the precompile, + one for each call. precompile_data_length_list: List of data lengths to be + used to call the precompile, one for each call. gas_modifier: Integer to + add to the gas passed to the precompile. input_length_modifier: Integer to + add to the length of the input passed to the precompile. expected_output: + Expected output of the contract, it is only used to determine if the call + is expected to succeed or fail. call_opcode: Type of call used to call the + precompile (Op.CALL, Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL). + call_contract_post_storage: Storage of the test contract after the + transaction is executed. """ expected_output = bytes(expected_output) - # Depending on the expected output, we can deduce if the call is expected to succeed or fail. + # Depending on the expected output, we can deduce if the call is expected + # to succeed or fail. call_succeeds = len(expected_output) > 0 assert len(precompile_gas_list) == len(precompile_data_length_list) @@ -114,8 +113,9 @@ def call_contract_code( for precompile_gas, precompile_args_length in zip( precompile_gas_list, precompile_data_length_list, strict=False ): - # For each given precompile gas value, and given arguments length, call the precompile - # with the given gas and call data (all zeros) and compare the result. + # For each given precompile gas value, and given arguments length, call + # the precompile with the given gas and call data (all zeros) and + # compare the result. code += Op.SSTORE( call_contract_post_storage.store_next(1 if call_succeeds else 0), Op.CALL( @@ -135,7 +135,10 @@ def call_contract_code( def tx_gas_limit_calculator( fork: Fork, precompile_gas_list: List[int], max_precompile_input_length: int ) -> int: - """Calculate the gas used to execute the transaction with the given precompile gas list.""" + """ + Calculate the gas used to execute the transaction with the given precompile + gas list. + """ intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator() memory_expansion_gas_calculator = fork.memory_expansion_gas_calculator() extra_gas = 22_500 * len(precompile_gas_list) @@ -154,7 +157,9 @@ def tx_gas_limit( precompile_gas_list: List[int], precompile_data_length_list: List[int], ) -> int: - """Transaction gas limit used for the test (Can be overridden in the test).""" + """ + Transaction gas limit used for the test (Can be overridden in the test). + """ assert len(input_data) == 0, "Expected empty data in the transaction." return tx_gas_limit_calculator(fork, precompile_gas_list, max(precompile_data_length_list)) @@ -163,12 +168,13 @@ def get_split_discount_table_by_fork( gas_fn: Callable, discount_table_length: int, element_length: int ) -> Callable[[Fork], List[ParameterSet]]: """ - Get the number of test cases needed to cover the given discount table adjusted for the - fork transaction gas limit cap. + Get the number of test cases needed to cover the given discount table + adjusted for the fork transaction gas limit cap. - The function will return the full discount table as a single test case if the - fork has no transaction gas limit cap, otherwise it will iterate to determine the - splits required to fit the full discount table across multiple test cases. + The function will return the full discount table as a single test case if + the fork has no transaction gas limit cap, otherwise it will iterate to + determine the splits required to fit the full discount table across + multiple test cases. """ def parametrize_by_fork(fork: Fork) -> List[ParameterSet]: @@ -249,8 +255,9 @@ def test_valid_gas_g1msm( tx: Transaction, ): """ - Test the BLS12_G1MSM discount gas table in full, by expecting the call to succeed for - all possible input lengths because the appropriate amount of gas is provided. + Test the BLS12_G1MSM discount gas table in full, by expecting the call to + succeed for all possible input lengths because the appropriate amount of + gas is provided. If any of the calls fail, the test will fail. """ @@ -307,8 +314,9 @@ def test_invalid_gas_g1msm( tx: Transaction, ): """ - Test the BLS12_G1MSM discount gas table in full, by expecting the call to fail for - all possible input lengths because the appropriate amount of gas is not provided. + Test the BLS12_G1MSM discount gas table in full, by expecting the call to + fail for all possible input lengths because the appropriate amount of gas + is not provided. If any of the calls succeeds, the test will fail. """ @@ -371,8 +379,9 @@ def test_invalid_length_g1msm( tx: Transaction, ): """ - Test the BLS12_G1MSM discount gas table in full, by expecting the call to fail for - all possible input lengths provided because they are too long or short, or zero length. + Test the BLS12_G1MSM discount gas table in full, by expecting the call to + fail for all possible input lengths provided because they are too long or + short, or zero length. If any of the calls succeeds, the test will fail. """ @@ -402,8 +411,9 @@ def test_valid_gas_g2msm( tx: Transaction, ): """ - Test the BLS12_G2MSM discount gas table in full, by expecting the call to succeed for - all possible input lengths because the appropriate amount of gas is provided. + Test the BLS12_G2MSM discount gas table in full, by expecting the call to + succeed for all possible input lengths because the appropriate amount of + gas is provided. If any of the calls fail, the test will fail. """ @@ -460,8 +470,9 @@ def test_invalid_gas_g2msm( tx: Transaction, ): """ - Test the BLS12_G2MSM discount gas table in full, by expecting the call to fail for - all possible input lengths because the appropriate amount of gas is not provided. + Test the BLS12_G2MSM discount gas table in full, by expecting the call to + fail for all possible input lengths because the appropriate amount of gas + is not provided. If any of the calls succeeds, the test will fail. """ @@ -524,8 +535,9 @@ def test_invalid_length_g2msm( tx: Transaction, ): """ - Test the BLS12_G2MSM discount gas table in full, by expecting the call to fail for - all possible input lengths provided because they are too long or short, or zero length. + Test the BLS12_G2MSM discount gas table in full, by expecting the call to + fail for all possible input lengths provided because they are too long or + short, or zero length. If any of the calls succeeds, the test will fail. """ @@ -552,8 +564,8 @@ def test_valid_gas_pairing( tx: Transaction, ): """ - Test the BLS12_PAIRING precompile, by expecting the call to succeed for all possible input - lengths (up to k == PAIRINGS_TO_TEST). + Test the BLS12_PAIRING precompile, by expecting the call to succeed for all + possible input lengths (up to k == PAIRINGS_TO_TEST). If any of the calls fails, the test will fail. """ @@ -608,8 +620,9 @@ def test_invalid_gas_pairing( tx: Transaction, ): """ - Test the BLS12_PAIRING precompile, by expecting the call to fail for all possible input - lengths (up to k == PAIRINGS_TO_TEST) because the appropriate amount of gas is not provided. + Test the BLS12_PAIRING precompile, by expecting the call to fail for all + possible input lengths (up to k == PAIRINGS_TO_TEST) because the + appropriate amount of gas is not provided. If any of the calls succeeds, the test will fail. """ @@ -640,7 +653,9 @@ def test_invalid_zero_length_pairing( post: dict, tx: Transaction, ): - """Test the BLS12_PAIRING precompile by passing an input with zero length.""" + """ + Test the BLS12_PAIRING precompile by passing an input with zero length. + """ state_test( env=env, pre=pre, @@ -670,8 +685,9 @@ def test_invalid_length_pairing( tx: Transaction, ): """ - Test the BLS12_PAIRING precompile, by expecting the call to fail for all possible input - lengths (up to k == PAIRINGS_TO_TEST) because the incorrect input length was used. + Test the BLS12_PAIRING precompile, by expecting the call to fail for all + possible input lengths (up to k == PAIRINGS_TO_TEST) because the incorrect + input length was used. If any of the calls succeeds, the test will fail. """ diff --git a/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py b/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py index 5d9f77b801a..fbdc1abe93a 100644 --- a/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py +++ b/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935) - Test [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935). -""" # noqa: E501 +abstract: Tests [EIP-2935: Serve historical block hashes from +state](https://eips.ethereum.org/EIPS/eip-2935). +""" from typing import Dict, List @@ -33,15 +33,15 @@ def generate_block_check_code( check_contract_first: bool = False, ) -> Bytecode: """ - Generate EVM code to check that the block hashes are correctly stored in the state. - - Args: - check_block_number (int): The block number to check. - current_block_number (int): The current block number where the check is taking place. - fork_block_number (int): The block number of the fork transition. - storage (Storage): The storage object to use. - check_contract_first (bool): Whether to check the contract first, for slot warming checks. - + Generate EVM code to check that the block hashes are correctly stored in + the state. + + Args: check_block_number (int): The block number to check. + current_block_number (int): The current block number where the check is + taking place. fork_block_number (int): The block number of the fork + transition. storage (Storage): The storage object to use. + check_contract_first (bool): Whether to check the contract first, for slot + warming checks. """ contract_ret_offset = 32 @@ -108,13 +108,13 @@ def test_block_hashes_history_at_transition( blocks_after_fork: int, ): """ - Tests that block hashes are stored correctly at the system contract address after the fork - transition. Block hashes are stored incrementally at the transition until the - `HISTORY_SERVE_WINDOW` ring buffer is full. Afterwards the oldest block hash is replaced by the - new one. + Tests that block hashes are stored correctly at the system contract address + after the fork transition. Block hashes are stored incrementally at the + transition until the `HISTORY_SERVE_WINDOW` ring buffer is full. Afterwards + the oldest block hash is replaced by the new one. - Note: The block hashes before the fork are no longer stored in the contract at the moment of - the transition. + Note: The block hashes before the fork are no longer stored in the contract + at the moment of the transition. """ blocks: List[Block] = [] assert blocks_before_fork >= 1 and blocks_before_fork < Spec.FORK_TIMESTAMP @@ -127,9 +127,9 @@ def test_block_hashes_history_at_transition( for i in range(blocks_before_fork): txs: List[Transaction] = [] if i == blocks_before_fork - 1: - # On the last block before the fork, `BLOCKHASH` must return values for the last 256 - # blocks but not for the blocks before that. - # And `HISTORY_STORAGE_ADDRESS` should be empty. + # On the last block before the fork, `BLOCKHASH` must return values + # for the last 256 blocks but not for the blocks before that. And + # `HISTORY_STORAGE_ADDRESS` should be empty. code = Bytecode() storage = Storage() @@ -165,17 +165,18 @@ def test_block_hashes_history_at_transition( blocks.append(Block(timestamp=current_block_number, txs=txs)) current_block_number += 1 - # Add blocks after the fork transition to gradually fill up the `HISTORY_SERVE_WINDOW` + # Add blocks after the fork transition to gradually fill up the + # `HISTORY_SERVE_WINDOW` for i in range(blocks_after_fork): txs = [] - # On these blocks, `BLOCKHASH` will still return values for the last 256 blocks, and - # `HISTORY_STORAGE_ADDRESS` should now serve values for the previous blocks in the new - # fork. + # On these blocks, `BLOCKHASH` will still return values for the last + # 256 blocks, and `HISTORY_STORAGE_ADDRESS` should now serve values for + # the previous blocks in the new fork. code = Bytecode() storage = Storage() - # Check that each block can return previous blockhashes if `BLOCKHASH_OLD_WINDOW` and or - # `HISTORY_SERVE_WINDOW`. + # Check that each block can return previous blockhashes if + # `BLOCKHASH_OLD_WINDOW` and or `HISTORY_SERVE_WINDOW`. for j in range(current_block_number): code += generate_block_check_code( check_block_number=j, @@ -227,10 +228,10 @@ def test_block_hashes_history( check_contract_first: bool, ): """ - Tests that block hashes are stored correctly at the system contract address after the fork - transition. Block hashes are stored incrementally at the transition until the - `HISTORY_SERVE_WINDOW` ring buffer is full. Afterwards the oldest block hash is replaced by the - new one. + Tests that block hashes are stored correctly at the system contract address + after the fork transition. Block hashes are stored incrementally at the + transition until the `HISTORY_SERVE_WINDOW` ring buffer is full. Afterwards + the oldest block hash is replaced by the new one. """ blocks: List[Block] = [] @@ -245,9 +246,9 @@ def test_block_hashes_history( current_block_number += 1 txs = [] - # On these blocks, `BLOCKHASH` will still return values for the last 256 blocks, and - # `HISTORY_STORAGE_ADDRESS` should now serve values for the previous blocks in the new - # fork. + # On these blocks, `BLOCKHASH` will still return values for the last 256 + # blocks, and `HISTORY_STORAGE_ADDRESS` should now serve values for the + # previous blocks in the new fork. code = Bytecode() storage = Storage() @@ -321,7 +322,10 @@ def test_block_hashes_history( def test_block_hashes_call_opcodes( blockchain_test: BlockchainTestFiller, pre: Alloc, call_opcode: Op ): - """Test that the call opcodes can be used to call the history contract and get the block hashes.""" # noqa: E501 + """ + Test that the call opcodes can be used to call the history contract and get + the block hashes. + """ blocks = [] blocks.append(Block()) @@ -382,11 +386,11 @@ def test_invalid_history_contract_calls( reverts: bool, ): """ - Test calling the history contract with invalid block numbers, such as blocks from the future - or overflowing block numbers. + Test calling the history contract with invalid block numbers, such as + blocks from the future or overflowing block numbers. - Also test the BLOCKHASH opcode with the same block numbers, which should not affect the - behavior of the opcode, even after verkle. + Also test the BLOCKHASH opcode with the same block numbers, which should + not affect the behavior of the opcode, even after verkle. """ storage = Storage() diff --git a/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py b/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py index 2175b38338a..813f0dc7ab8 100644 --- a/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py +++ b/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935). - Test system contract deployment for [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935). -""" # noqa: E501 +abstract: Tests [EIP-2935: Serve historical block hashes from +state](https://eips.ethereum.org/EIPS/eip-2935). +""" from os.path import realpath from pathlib import Path @@ -44,7 +44,8 @@ def test_system_contract_deployment( **kwargs, ): """Verify deployment of the block hashes system contract.""" - # Deploy a contract that calls the history contract and verifies the block hashes. + # Deploy a contract that calls the history contract and verifies the block + # hashes. yield Block() # Empty block just to have more history in the contract. # We are going to query blocks even before contract deployment. @@ -77,27 +78,31 @@ def test_system_contract_deployment( storage: Dict if test_type == DeploymentTestType.DEPLOY_BEFORE_FORK: - # Fork happens at block 2, and the contract is already there, so from block number 1 and - # after, the block hashes should be there. + # Fork happens at block 2, and the contract is already there, so from + # block number 1 and after, the block hashes should be there. storage = { 1: 1, # Block prior to the fork, it's the first hash saved. 2: 1, # Fork block, hash should be there. - 3: 1, # Empty block added at the start of this function, hash should be there. + 3: 1, # Empty block added at the start of this function, hash + # should be there. } elif test_type == DeploymentTestType.DEPLOY_ON_FORK_BLOCK: # The contract should have the block hashes after contract deployment. storage = { 1: 1, # Fork and deployment block, the first hash that gets added. 2: 1, # Deployment block, hash should be there. - 3: 1, # Empty block added at the start of this function, hash should be there. + 3: 1, # Empty block added at the start of this function, hash + # should be there. } elif test_type == DeploymentTestType.DEPLOY_AFTER_FORK: # The contract should have the block hashes after contract deployment. storage = { 1: 0, # Fork block, but contract is not there yet. - 2: 1, # Deployment block, this is the first hash that gets added because it's added on + 2: 1, # Deployment block, this is the first hash that gets added + # because it's added on # the next block. - 3: 1, # Empty block added at the start of this function, hash should be there. + 3: 1, # Empty block added at the start of this function, hash + # should be there. } post[deployed_contract] = Account( diff --git a/tests/prague/eip6110_deposits/conftest.py b/tests/prague/eip6110_deposits/conftest.py index 4c3e88e2623..11d9a4bcab4 100644 --- a/tests/prague/eip6110_deposits/conftest.py +++ b/tests/prague/eip6110_deposits/conftest.py @@ -13,8 +13,8 @@ @pytest.fixture def update_pre(pre: Alloc, requests: List[DepositInteractionBase]): """ - Init state of the accounts. Every deposit transaction defines their own pre-state - requirements, and this fixture aggregates them all. + Init state of the accounts. Every deposit transaction defines their own + pre-state requirements, and this fixture aggregates them all. """ for d in requests: d.update_pre(pre) @@ -34,7 +34,10 @@ def txs( @pytest.fixture def block_body_override_requests() -> List[DepositRequest] | None: - """List of requests that overwrite the requests in the header. None by default.""" + """ + List of requests that overwrite the requests in the header. None by + default. + """ return None @@ -48,7 +51,9 @@ def exception() -> BlockException | None: def included_requests( requests: List[DepositInteractionBase], ) -> List[DepositRequest]: - """Return the list of deposit requests that should be included in each block.""" + """ + Return the list of deposit requests that should be included in each block. + """ valid_requests: List[DepositRequest] = [] for d in requests: diff --git a/tests/prague/eip6110_deposits/helpers.py b/tests/prague/eip6110_deposits/helpers.py index b664f8413ee..9634cdd4925 100644 --- a/tests/prague/eip6110_deposits/helpers.py +++ b/tests/prague/eip6110_deposits/helpers.py @@ -77,22 +77,19 @@ class DepositRequest(DepositRequestBase): """Deposit request descriptor.""" valid: bool = True - """ - Whether the deposit request is valid or not. - """ + """Whether the deposit request is valid or not.""" gas_limit: int = 1_000_000 - """ - Gas limit for the call. - """ + """Gas limit for the call.""" calldata_modifier: Callable[[bytes], bytes] = lambda x: x - """ - Calldata modifier function. - """ + """Calldata modifier function.""" extra_wei: int = 0 """ - Extra amount in wei to be sent with the deposit. - If this value modulo 10**9 is not zero, the deposit will be invalid. - The value can be negative but if the total value is negative, an exception will be raised. + + + Extra amount in wei to be sent with the deposit. If this value modulo 10**9 + is not zero, the deposit will be invalid. The value can be negative but if + the total value is negative, an exception will be raised. + """ interaction_contract_address: ClassVar[Address] = Address(Spec.DEPOSIT_CONTRACT_ADDRESS) @@ -100,8 +97,8 @@ class DepositRequest(DepositRequestBase): @cached_property def value(self) -> int: """ - Return the value of the deposit transaction, equal to the amount in gwei plus the - extra amount in wei. + Return the value of the deposit transaction, equal to the amount in + gwei plus the extra amount in wei. """ value = (self.amount * 10**9) + self.extra_wei if value < 0: @@ -123,14 +120,11 @@ def deposit_data_root(self) -> Hash: @cached_property def calldata(self) -> bytes: """ - Return the calldata needed to call the beacon chain deposit contract and make the deposit. + Return the calldata needed to call the beacon chain deposit contract + and make the deposit. - deposit( - bytes calldata pubkey, - bytes calldata withdrawal_credentials, - bytes calldata signature, - bytes32 deposit_data_root - ) + deposit( bytes calldata pubkey, bytes calldata withdrawal_credentials, + bytes calldata signature, bytes32 deposit_data_root ) """ offset_length = 32 pubkey_offset = offset_length * 3 + len(self.deposit_data_root) @@ -154,13 +148,8 @@ def log(self, *, include_abi_encoding: bool = True) -> bytes: """ Return the log data for the deposit event. - event DepositEvent( - bytes pubkey, - bytes withdrawal_credentials, - bytes amount, - bytes signature, - bytes index - ); + event DepositEvent( bytes pubkey, bytes withdrawal_credentials, bytes + amount, bytes signature, bytes index ); """ data = bytearray(576) if include_abi_encoding: @@ -199,17 +188,11 @@ class DepositInteractionBase: """Base class for all types of deposit transactions we want to test.""" sender_balance: int = 32_000_000_000_000_000_000 * 100 - """ - Balance of the account that sends the transaction. - """ + """Balance of the account that sends the transaction.""" sender_account: EOA | None = None - """ - Account that sends the transaction. - """ + """Account that sends the transaction.""" requests: List[DepositRequest] - """ - Deposit request to be included in the block. - """ + """Deposit request to be included in the block.""" def transactions(self) -> List[Transaction]: """Return a transaction for the deposit request.""" @@ -220,13 +203,19 @@ def update_pre(self, pre: Alloc): raise NotImplementedError def valid_requests(self, current_minimum_fee: int) -> List[DepositRequest]: - """Return the list of deposit requests that should be included in the block.""" + """ + Return the list of deposit requests that should be included in the + block. + """ raise NotImplementedError @dataclass(kw_only=True) class DepositTransaction(DepositInteractionBase): - """Class used to describe a deposit originated from an externally owned account.""" + """ + Class used to describe a deposit originated from an externally owned + account. + """ def transactions(self) -> List[Transaction]: """Return a transaction for the deposit request.""" @@ -248,7 +237,10 @@ def update_pre(self, pre: Alloc): self.sender_account = pre.fund_eoa(self.sender_balance) def valid_requests(self, current_minimum_fee: int) -> List[DepositRequest]: - """Return the list of deposit requests that should be included in the block.""" + """ + Return the list of deposit requests that should be included in the + block. + """ return [ request for request in self.requests @@ -261,38 +253,33 @@ class DepositContract(DepositInteractionBase): """Class used to describe a deposit originated from a contract.""" tx_gas_limit: int = 1_000_000 - """ - Gas limit for the transaction. - """ + """Gas limit for the transaction.""" tx_value: int = 0 - """ - Value to send with the transaction. - """ + """Value to send with the transaction.""" contract_balance: int = 32_000_000_000_000_000_000 * 100 - """ - Balance of the contract that sends the deposit requests. - """ + """Balance of the contract that sends the deposit requests.""" contract_address: Address | None = None - """ - Address of the contract that sends the deposit requests. - """ + """Address of the contract that sends the deposit requests.""" entry_address: Address | None = None - """ - Address to send the transaction to. - """ + """Address to send the transaction to.""" call_type: Op = field(default_factory=lambda: Op.CALL) - """ - Type of call to be made to the deposit contract. - """ + """Type of call to be made to the deposit contract.""" call_depth: int = 2 """ - Frame depth of the beacon chain deposit contract when it executes the deposit requests. + + + Frame depth of the beacon chain deposit contract when it executes the + deposit requests. + """ extra_code: Bytecode = field(default_factory=Bytecode) """ + + Extra code to be included in the contract that sends the deposit requests. + """ @property @@ -357,5 +344,8 @@ def update_pre(self, pre: Alloc): ) def valid_requests(self, current_minimum_fee: int) -> List[DepositRequest]: - """Return the list of deposit requests that should be included in the block.""" + """ + Return the list of deposit requests that should be included in the + block. + """ return [d for d in self.requests if d.valid and d.value >= current_minimum_fee] diff --git a/tests/prague/eip6110_deposits/test_deposits.py b/tests/prague/eip6110_deposits/test_deposits.py index 6e3d62fcc12..c9b8d20a68f 100644 --- a/tests/prague/eip6110_deposits/test_deposits.py +++ b/tests/prague/eip6110_deposits/test_deposits.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-6110: Supply validator deposits on chain](https://eips.ethereum.org/EIPS/eip-6110) - Test [EIP-6110: Supply validator deposits on chain](https://eips.ethereum.org/EIPS/eip-6110). -""" # noqa: E501 +abstract: Tests [EIP-6110: Supply validator deposits on +chain](https://eips.ethereum.org/EIPS/eip-6110). +""" from typing import List @@ -185,7 +185,8 @@ amount=32_000_000_000, signature=0x03, index=0x0, - # From traces, gas used by the first tx is 82,718 so reduce by one here + # From traces, gas used by the first tx is 82,718 + # so reduce by one here gas_limit=0x1431D, valid=False, ), @@ -218,7 +219,8 @@ amount=32_000_000_000, signature=0x03, index=0x0, - # From traces, gas used by the second tx is 68,594, reduce by one here + # From traces, gas used by the second tx is 68,594, + # reduce by one here gas_limit=0x10BF1, valid=False, ), @@ -838,8 +840,8 @@ valid=False, ) ], - # Send 32 ETH minus 1 wei to the contract, note `DepositRequest.amount` is in - # gwei + # Send 32 ETH minus 1 wei to the contract, note + # `DepositRequest.amount` is in gwei tx_value=32_000_000_000 * 10**9 - 1, contract_balance=0, ), @@ -1182,8 +1184,8 @@ def test_deposit_negative( blocks: List[Block], ): """ - Test producing a block with the incorrect deposits in the body of the block, - and/or Engine API payload. + Test producing a block with the incorrect deposits in the body of the + block, and/or Engine API payload. """ blockchain_test( pre=pre, diff --git a/tests/prague/eip6110_deposits/test_modified_contract.py b/tests/prague/eip6110_deposits/test_modified_contract.py index bbb1f4fba22..80f58a868d0 100644 --- a/tests/prague/eip6110_deposits/test_modified_contract.py +++ b/tests/prague/eip6110_deposits/test_modified_contract.py @@ -1,4 +1,7 @@ -"""Test variants of the deposit contract which adheres the log-style as described in EIP-6110.""" +""" +Test variants of the deposit contract which adheres the log-style as described +in EIP-6110. +""" import pytest @@ -44,8 +47,9 @@ DEFAULT_DEPOSIT_REQUEST_LOG_DATA_DICT = { "pubkey_data": bytes(DEFAULT_DEPOSIT_REQUEST.pubkey), "withdrawal_credentials_data": bytes(DEFAULT_DEPOSIT_REQUEST.withdrawal_credentials), - # Note: after converting to bytes, it is converted to little-endian by `[::-1]` - # (This happens on-chain also, but this is done by the solidity contract) + # Note: after converting to bytes, it is converted to little-endian by + # `[::-1]` (This happens on-chain also, but this is done by the solidity + # contract) "amount_data": bytes.fromhex("0" + DEFAULT_DEPOSIT_REQUEST.amount.hex()[2:])[::-1], "signature_data": bytes(DEFAULT_DEPOSIT_REQUEST.signature), "index_data": bytes(DEFAULT_DEPOSIT_REQUEST.index), @@ -77,36 +81,43 @@ def test_extra_logs( pre: Alloc, include_deposit_event: bool, ): - """Test deposit contract emitting more log event types than the ones in mainnet.""" - # Supplant mainnet contract with a variant that emits a `Transfer`` log - # If `include_deposit_event` is `True``, it will also emit a `DepositEvent` log` + """ + Test deposit contract emitting more log event types than the ones in + mainnet. + """ + # Supplant mainnet contract with a variant that emits a `Transfer`` log If + # `include_deposit_event` is `True``, it will also emit a `DepositEvent` + # log` # ERC20 token transfer log (Sepolia) - # https://sepolia.etherscan.io/tx/0x2d71f3085a796a0539c9cc28acd9073a67cf862260a41475f000dd101279f94f - # JSON RPC: - # curl https://sepolia.infura.io/v3/APIKEY \ - # -X POST \ - # -H "Content-Type: application/json" \ - # -d '{"jsonrpc": "2.0", "method": "eth_getLogs", - # "params": [{"address": "0x7f02C3E3c98b133055B8B348B2Ac625669Ed295D", - # "blockHash": "0x8062a17fa791f5dbd59ea68891422e3299ca4e80885a89acf3fc706c8bceef53"}], + # https://sepolia.etherscan.io/tx/ + # 0x2d71f3085a796a0539c9cc28acd9073a67cf862260a41475f000dd101279f94f + # JSON RPC: curl https://sepolia.infura.io/v3/APIKEY \ -X POST \ -H + # "Content-Type: application/json" \ -d '{"jsonrpc": "2.0", "method": + # "eth_getLogs", "params": [{"address": + # "0x7f02C3E3c98b133055B8B348B2Ac625669Ed295D", "blockHash": + # "0x8062a17fa791f5dbd59ea68891422e3299ca4e80885a89acf3fc706c8bceef53"}], # "id": 1}' # {"jsonrpc":"2.0","id":1,"result": # [{"removed":false,"logIndex":"0x80","transactionIndex":"0x56", - # "transactionHash":"0x2d71f3085a796a0539c9cc28acd9073a67cf862260a41475f000dd101279f94f", - # "blockHash":"0x8062a17fa791f5dbd59ea68891422e3299ca4e80885a89acf3fc706c8bceef53", + # "transactionHash": + # "0x2d71f3085a796a0539c9cc28acd9073a67cf862260a41475f000dd101279f94f", + # "blockHash": + # "0x8062a17fa791f5dbd59ea68891422e3299ca4e80885a89acf3fc706c8bceef53", # "blockNumber":"0x794fb5", # "address":"0x7f02c3e3c98b133055b8b348b2ac625669ed295d", - # "data":"0x0000000000000000000000000000000000000000000000000000000000000001", - # "topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + # "data": + # "0x0000000000000000000000000000000000000000000000000000000000000001", + # "topics": + # ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", # "0x0000000000000000000000006885e36bfcb68cb383dfe90023a462c03bcb2ae5", # "0x00000000000000000000000080b5dc88c98e528bf9cb4b7f0f076ac41da24651"] bytecode = Op.LOG3( - # ERC-20 token transfer log - # ERC-20 token transfers are LOG3, since the topic, the sender, and receiver - # are all topics (the sender and receiver are `indexed` in the solidity event) + # ERC-20 token transfer log ERC-20 token transfers are LOG3, since the + # topic, the sender, and receiver are all topics (the sender and + # receiver are `indexed` in the solidity event) 0, 32, 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF, @@ -171,7 +182,9 @@ def test_extra_logs( def test_invalid_layout( blockchain_test: BlockchainTestFiller, pre: Alloc, log_argument: str, value: str ): - """Test deposit contract emitting logs with invalid layouts (sizes/offsets).""" + """ + Test deposit contract emitting logs with invalid layouts (sizes/offsets). + """ log_params = {**DEFAULT_DEPOSIT_REQUEST_LOG_DATA_DICT} log_params[log_argument] = 0 if value == "zero" else 2**256 - 1 # type: ignore @@ -225,7 +238,10 @@ def test_invalid_layout( ) @pytest.mark.exception_test def test_invalid_log_length(blockchain_test: BlockchainTestFiller, pre: Alloc, slice_bytes: bool): - """Test deposit contract emitting logs with invalid log length (one byte more or less).""" + """ + Test deposit contract emitting logs with invalid log length (one byte more + or less). + """ changed_log = DEFAULT_REQUEST_LOG[:-1] if slice_bytes else DEFAULT_REQUEST_LOG + b"\x00" bytecode = Om.MSTORE(changed_log) + Op.LOG1( diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/conftest.py b/tests/prague/eip7002_el_triggerable_withdrawals/conftest.py index c134463011a..898537e70a4 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/conftest.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/conftest.py @@ -18,8 +18,8 @@ def update_pre( blocks_withdrawal_requests: List[List[WithdrawalRequestInteractionBase]], ): """ - Init state of the accounts. Every deposit transaction defines their own pre-state - requirements, and this fixture aggregates them all. + Init state of the accounts. Every deposit transaction defines their own + pre-state requirements, and this fixture aggregates them all. """ for requests in blocks_withdrawal_requests: for r in requests: @@ -31,7 +31,10 @@ def included_requests( update_pre: None, # Fixture is used for its side effects blocks_withdrawal_requests: List[List[WithdrawalRequestInteractionBase]], ) -> List[List[WithdrawalRequest]]: - """Return the list of withdrawal requests that should be included in each block.""" + """ + Return the list of withdrawal requests that should be included in each + block. + """ excess_withdrawal_requests = 0 carry_over_requests: List[WithdrawalRequest] = [] per_block_included_requests: List[List[WithdrawalRequest]] = [] diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/helpers.py b/tests/prague/eip7002_el_triggerable_withdrawals/helpers.py index 2a0f7216ad9..4c8cea1b399 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/helpers.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/helpers.py @@ -17,22 +17,19 @@ class WithdrawalRequest(WithdrawalRequestBase): fee: int = 0 """ - Fee to be paid to the system contract for the withdrawal request. - This is different from `amount` which is the amount of gwei to be withdrawn on the beacon - chain. + + + Fee to be paid to the system contract for the withdrawal request. This is + different from `amount` which is the amount of gwei to be withdrawn on the + beacon chain. + """ valid: bool = True - """ - Whether the withdrawal request is valid or not. - """ + """Whether the withdrawal request is valid or not.""" gas_limit: int = 1_000_000 - """ - Gas limit for the call. - """ + """Gas limit for the call.""" calldata_modifier: Callable[[bytes], bytes] = lambda x: x - """ - Calldata modifier function. - """ + """Calldata modifier function.""" interaction_contract_address: ClassVar[Address] = Address( Spec.WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS @@ -41,23 +38,26 @@ class WithdrawalRequest(WithdrawalRequestBase): @property def value(self) -> int: """ - Return the value of the call to the withdrawal request contract, equal to the fee - to be paid. + Return the value of the call to the withdrawal request contract, equal + to the fee to be paid. """ return self.fee @cached_property def calldata(self) -> bytes: """ - Return the calldata needed to call the withdrawal request contract and make the - withdrawal. + Return the calldata needed to call the withdrawal request contract and + make the withdrawal. """ return self.calldata_modifier( self.validator_pubkey + self.amount.to_bytes(8, byteorder="big") ) def with_source_address(self, source_address: Address) -> "WithdrawalRequest": - """Return a new instance of the withdrawal request with the source address set.""" + """ + Return a new instance of the withdrawal request with the source address + set. + """ return self.copy(source_address=source_address) @@ -66,17 +66,11 @@ class WithdrawalRequestInteractionBase: """Base class for all types of withdrawal transactions we want to test.""" sender_balance: int = 1_000_000_000_000_000_000 - """ - Balance of the account that sends the transaction. - """ + """Balance of the account that sends the transaction.""" sender_account: EOA | None = None - """ - Account that will send the transaction. - """ + """Account that will send the transaction.""" requests: List[WithdrawalRequest] - """ - Withdrawal request to be included in the block. - """ + """Withdrawal request to be included in the block.""" def transactions(self) -> List[Transaction]: """Return a transaction for the withdrawal request.""" @@ -87,13 +81,19 @@ def update_pre(self, pre: Alloc): raise NotImplementedError def valid_requests(self, current_minimum_fee: int) -> List[WithdrawalRequest]: - """Return the list of withdrawal requests that should be valid in the block.""" + """ + Return the list of withdrawal requests that should be valid in the + block. + """ raise NotImplementedError @dataclass(kw_only=True) class WithdrawalRequestTransaction(WithdrawalRequestInteractionBase): - """Class used to describe a withdrawal request originated from an externally owned account.""" + """ + Class used to describe a withdrawal request originated from an externally + owned account. + """ def transactions(self) -> List[Transaction]: """Return a transaction for the withdrawal request.""" @@ -129,35 +129,31 @@ class WithdrawalRequestContract(WithdrawalRequestInteractionBase): """Class used to describe a withdrawal originated from a contract.""" tx_gas_limit: int = 1_000_000 - """ - Gas limit for the transaction. - """ + """Gas limit for the transaction.""" contract_balance: int = 1_000_000_000_000_000_000 """ + + Balance of the contract that will make the call to the pre-deploy contract. + """ contract_address: Address | None = None """ + + Address of the contract that will make the call to the pre-deploy contract. + """ entry_address: Address | None = None - """ - Address to send the transaction to. - """ + """Address to send the transaction to.""" call_type: Op = field(default_factory=lambda: Op.CALL) - """ - Type of call to be used to make the withdrawal request. - """ + """Type of call to be used to make the withdrawal request.""" call_depth: int = 2 - """ - Frame depth of the pre-deploy contract when it executes the call. - """ + """Frame depth of the pre-deploy contract when it executes the call.""" extra_code: Bytecode = field(default_factory=Bytecode) - """ - Extra code to be added to the contract code. - """ + """Extra code to be added to the contract code.""" @property def contract_code(self) -> Bytecode: @@ -243,12 +239,12 @@ def get_n_fee_increments(n: int) -> List[int]: def get_n_fee_increment_blocks(n: int) -> List[List[WithdrawalRequestContract]]: """ - Return N blocks that should be included in the test such that each subsequent block has an - increasing fee for the withdrawal requests. + Return N blocks that should be included in the test such that each + subsequent block has an increasing fee for the withdrawal requests. - This is done by calculating the number of withdrawals required to reach the next fee increment - and creating a block with that number of withdrawal requests plus the number of withdrawals - required to reach the target. + This is done by calculating the number of withdrawals required to reach the + next fee increment and creating a block with that number of withdrawal + requests plus the number of withdrawals required to reach the target. """ blocks = [] previous_excess = 0 diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/spec.py b/tests/prague/eip7002_el_triggerable_withdrawals/spec.py index e30a15011be..30f98338726 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/spec.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/spec.py @@ -1,7 +1,8 @@ """ Common procedures to test -[EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). -""" # noqa: E501 +[EIP-7002: Execution layer triggerable +withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +""" from dataclasses import dataclass diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py index 90f690180ed..ce0661c78f2 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). - Test system contract deployment for [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). -""" # noqa: E501 +abstract: Tests [EIP-7002: Execution layer triggerable +withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +""" from os.path import realpath from pathlib import Path diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py index 7346a630ae1..035d0421ec5 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py @@ -1,8 +1,7 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002) - Test execution layer triggered exits [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). - -""" # noqa: E501 +abstract: Tests [EIP-7002: Execution layer triggerable +withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +""" from typing import List @@ -91,7 +90,10 @@ def test_extra_withdrawals( pre: Alloc, requests_list: List[WithdrawalRequest], ): - """Test how clients were to behave when more than 16 withdrawals would be allowed per block.""" + """ + Test how clients were to behave when more than 16 withdrawals would be + allowed per block. + """ modified_code: Bytecode = Bytecode() memory_offset: int = 0 amount_of_requests: int = 0 @@ -116,7 +118,8 @@ def test_extra_withdrawals( balance=0, ) - # given a list of withdrawal requests construct a withdrawal request transaction + # given a list of withdrawal requests construct a withdrawal request + # transaction withdrawal_request_transaction = WithdrawalRequestTransaction(requests=requests_list) # prepare withdrawal senders withdrawal_request_transaction.update_pre(pre=pre) @@ -144,8 +147,8 @@ def test_extra_withdrawals( ) def test_system_contract_errors(): """ - Test system contract raising different errors when called by the system account at the - end of the block execution. + Test system contract raising different errors when called by the system + account at the end of the block execution. To see the list of generated tests, please refer to the `generate_system_contract_error_test` decorator definition. diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py index d764ceccbc3..94502acfe29 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py @@ -1,8 +1,7 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002) - Test execution layer triggered exits [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). - -""" # noqa: E501 +abstract: Tests [EIP-7002: Execution layer triggerable +withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +""" from typing import List @@ -816,8 +815,8 @@ def test_withdrawal_requests_negative( exception: BlockException, ): """ - Test blocks where the requests list and the actual withdrawal requests that happened in the - block's transactions do not match. + Test blocks where the requests list and the actual withdrawal requests that + happened in the block's transactions do not match. """ for d in requests: d.update_pre(pre) diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py index e61cf87b7c6..cf7f60227b5 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py @@ -1,8 +1,7 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002) - Test execution layer triggered exits [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). - -""" # noqa: E501 +abstract: Tests [EIP-7002: Execution layer triggerable +withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +""" from os.path import realpath from pathlib import Path @@ -57,8 +56,9 @@ validator_pubkey=0x02, amount=0, fee=Spec.get_fee(10), - # First post-fork withdrawal request, will not be included - # because the inhibitor is cleared at the end of the block + # First post-fork withdrawal request, will not + # be included because the inhibitor is cleared + # at the end of the block valid=False, ) ], @@ -91,8 +91,12 @@ def test_withdrawal_requests_during_fork( blocks: List[Block], pre: Alloc, ): - """Test making a withdrawal request to the beacon chain at the time of the fork.""" - # We need to delete the deployed contract that comes by default in the pre state. + """ + Test making a withdrawal request to the beacon chain at the time of the + fork. + """ + # We need to delete the deployed contract that comes by default in the pre + # state. pre[Spec.WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS] = Account( balance=0, code=bytes(), diff --git a/tests/prague/eip7251_consolidations/conftest.py b/tests/prague/eip7251_consolidations/conftest.py index 3fd5b8be640..f116162ca47 100644 --- a/tests/prague/eip7251_consolidations/conftest.py +++ b/tests/prague/eip7251_consolidations/conftest.py @@ -18,8 +18,8 @@ def update_pre( blocks_consolidation_requests: List[List[ConsolidationRequestInteractionBase]], ): """ - Init state of the accounts. Every deposit transaction defines their own pre-state - requirements, and this fixture aggregates them all. + Init state of the accounts. Every deposit transaction defines their own + pre-state requirements, and this fixture aggregates them all. """ for requests in blocks_consolidation_requests: for r in requests: @@ -31,7 +31,10 @@ def included_requests( update_pre: None, # Fixture is used for its side effects blocks_consolidation_requests: List[List[ConsolidationRequestInteractionBase]], ) -> List[List[ConsolidationRequest]]: - """Return the list of consolidation requests that should be included in each block.""" + """ + Return the list of consolidation requests that should be included in each + block. + """ excess_consolidation_requests = 0 carry_over_requests: List[ConsolidationRequest] = [] per_block_included_requests: List[List[ConsolidationRequest]] = [] @@ -39,7 +42,8 @@ def included_requests( # Get fee for the current block current_minimum_fee = Spec.get_fee(excess_consolidation_requests) - # With the fee, get the valid consolidation requests for the current block + # With the fee, get the valid consolidation requests for the current + # block current_block_requests = [] for w in block_consolidation_requests: current_block_requests += w.valid_requests(current_minimum_fee) @@ -111,4 +115,5 @@ def blocks( header_verify=Header(requests_hash=Requests()), timestamp=timestamp, ) - ] # Add an empty block at the end to verify that no more consolidation requests are included + ] # Add an empty block at the end to verify that no more consolidation + # requests are included diff --git a/tests/prague/eip7251_consolidations/helpers.py b/tests/prague/eip7251_consolidations/helpers.py index 466afb8455a..05eeca37ac2 100644 --- a/tests/prague/eip7251_consolidations/helpers.py +++ b/tests/prague/eip7251_consolidations/helpers.py @@ -16,21 +16,13 @@ class ConsolidationRequest(ConsolidationRequestBase): """Class used to describe a consolidation request in a test.""" fee: int = 0 - """ - Fee to be paid to the system contract for the consolidation request. - """ + """Fee to be paid to the system contract for the consolidation request.""" valid: bool = True - """ - Whether the consolidation request is valid or not. - """ + """Whether the consolidation request is valid or not.""" gas_limit: int = 1_000_000 - """ - Gas limit for the call. - """ + """Gas limit for the call.""" calldata_modifier: Callable[[bytes], bytes] = lambda x: x - """ - Calldata modifier function. - """ + """Calldata modifier function.""" interaction_contract_address: ClassVar[Address] = Address( Spec.CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS @@ -39,40 +31,39 @@ class ConsolidationRequest(ConsolidationRequestBase): @property def value(self) -> int: """ - Return the value of the call to the consolidation request contract, equal to the fee - to be paid. + Return the value of the call to the consolidation request contract, + equal to the fee to be paid. """ return self.fee @cached_property def calldata(self) -> bytes: """ - Return the calldata needed to call the consolidation request contract and make the - consolidation. + Return the calldata needed to call the consolidation request contract + and make the consolidation. """ return self.calldata_modifier(self.source_pubkey + self.target_pubkey) def with_source_address(self, source_address: Address) -> "ConsolidationRequest": - """Return a new instance of the consolidation request with the source address set.""" + """ + Return a new instance of the consolidation request with the source + address set. + """ return self.copy(source_address=source_address) @dataclass(kw_only=True) class ConsolidationRequestInteractionBase: - """Base class for all types of consolidation transactions we want to test.""" - - sender_balance: int = 1_000_000_000_000_000_000 """ - Balance of the account that sends the transaction. + Base class for all types of consolidation transactions we want to test. """ + + sender_balance: int = 1_000_000_000_000_000_000 + """Balance of the account that sends the transaction.""" sender_account: EOA | None = None - """ - Account that will send the transaction. - """ + """Account that will send the transaction.""" requests: List[ConsolidationRequest] - """ - Consolidation requests to be included in the block. - """ + """Consolidation requests to be included in the block.""" def transactions(self) -> List[Transaction]: """Return a transaction for the consolidation request.""" @@ -83,13 +74,19 @@ def update_pre(self, pre: Alloc): raise NotImplementedError def valid_requests(self, current_minimum_fee: int) -> List[ConsolidationRequest]: - """Return the list of consolidation requests that should be valid in the block.""" + """ + Return the list of consolidation requests that should be valid in the + block. + """ raise NotImplementedError @dataclass(kw_only=True) class ConsolidationRequestTransaction(ConsolidationRequestInteractionBase): - """Class to describe a consolidation request originated from an externally owned account.""" + """ + Class to describe a consolidation request originated from an externally + owned account. + """ def transactions(self) -> List[Transaction]: """Return a transaction for the consolidation request.""" @@ -125,35 +122,43 @@ class ConsolidationRequestContract(ConsolidationRequestInteractionBase): """Class used to describe a consolidation originated from a contract.""" tx_gas_limit: int = 10_000_000 - """ - Gas limit for the transaction. - """ + """Gas limit for the transaction.""" contract_balance: int = 1_000_000_000_000_000_000 """ + + + + + + Balance of the contract that will make the call to the pre-deploy contract. + + + """ contract_address: Address | None = None """ + + + + + + Address of the contract that will make the call to the pre-deploy contract. + + + """ entry_address: Address | None = None - """ - Address to send the transaction to. - """ + """Address to send the transaction to.""" call_type: Op = field(default_factory=lambda: Op.CALL) - """ - Type of call to be used to make the consolidation request. - """ + """Type of call to be used to make the consolidation request.""" call_depth: int = 2 - """ - Frame depth of the pre-deploy contract when it executes the call. - """ + """Frame depth of the pre-deploy contract when it executes the call.""" extra_code: Bytecode = field(default_factory=Bytecode) - """ - Extra code to be added to the contract code. - """ + """Extra code to be added to the contract code.""" @property def contract_code(self) -> Bytecode: @@ -239,12 +244,13 @@ def get_n_fee_increments(n: int) -> List[int]: def get_n_fee_increment_blocks(n: int) -> List[List[ConsolidationRequestContract]]: """ - Return N blocks that should be included in the test such that each subsequent block has an - increasing fee for the consolidation requests. + Return N blocks that should be included in the test such that each + subsequent block has an increasing fee for the consolidation requests. - This is done by calculating the number of consolidations required to reach the next fee - increment and creating a block with that number of consolidation requests plus the number of - consolidations required to reach the target. + This is done by calculating the number of consolidations required to reach + the next fee increment and creating a block with that number of + consolidation requests plus the number of consolidations required to reach + the target. """ blocks = [] previous_excess = 0 diff --git a/tests/prague/eip7251_consolidations/test_consolidations.py b/tests/prague/eip7251_consolidations/test_consolidations.py index bd5f8d81e63..8622161174d 100644 --- a/tests/prague/eip7251_consolidations/test_consolidations.py +++ b/tests/prague/eip7251_consolidations/test_consolidations.py @@ -1,8 +1,7 @@ """ -abstract: Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251) - Test execution layer triggered consolidations [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). - -""" # noqa: E501 +abstract: Tests [EIP-7251: Increase the +MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). +""" from typing import List @@ -866,8 +865,8 @@ def test_consolidation_requests_negative( exception: BlockException, ): """ - Test blocks where the requests list and the actual consolidation requests that happened in the - block's transactions do not match. + Test blocks where the requests list and the actual consolidation requests + that happened in the block's transactions do not match. """ for d in requests: d.update_pre(pre) diff --git a/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py b/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py index 4731b3842f1..ef4cd67ea48 100644 --- a/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py +++ b/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py @@ -1,8 +1,7 @@ """ -abstract: Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251) - Test execution layer triggered consolidations [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). - -""" # noqa: E501 +abstract: Tests [EIP-7251: Increase the +MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). +""" from os.path import realpath from pathlib import Path @@ -57,8 +56,9 @@ source_pubkey=0x03, target_pubkey=0x04, fee=Spec.get_fee(10), - # First post-fork consolidation request, will not be included - # because the inhibitor is cleared at the end of the block + # First post-fork consolidation request, will + # not be included because the inhibitor is + # cleared at the end of the block valid=False, ) ], @@ -91,8 +91,12 @@ def test_consolidation_requests_during_fork( blocks: List[Block], pre: Alloc, ): - """Test making a consolidation request to the beacon chain at the time of the fork.""" - # We need to delete the deployed contract that comes by default in the pre state. + """ + Test making a consolidation request to the beacon chain at the time of the + fork. + """ + # We need to delete the deployed contract that comes by default in the pre + # state. pre[Spec.CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS] = Account( balance=0, code=bytes(), diff --git a/tests/prague/eip7251_consolidations/test_contract_deployment.py b/tests/prague/eip7251_consolidations/test_contract_deployment.py index f0a66d2b963..8ec30c26764 100644 --- a/tests/prague/eip7251_consolidations/test_contract_deployment.py +++ b/tests/prague/eip7251_consolidations/test_contract_deployment.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). - Test system contract deployment for [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). -""" # noqa: E501 +abstract: Tests [EIP-7251: Increase the +MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). +""" from os.path import realpath from pathlib import Path diff --git a/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py b/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py index d29c1177e20..7c747a4d6bd 100644 --- a/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py +++ b/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py @@ -1,8 +1,7 @@ """ -abstract: Tests [EIP-7251: Execution layer triggerable consolidation](https://eips.ethereum.org/EIPS/eip-7251) - Test execution layer triggered exits [EIP-7251: Execution layer triggerable consolidation](https://eips.ethereum.org/EIPS/eip-7251). - -""" # noqa: E501 +abstract: Tests [EIP-7251: Execution layer triggerable +consolidation](https://eips.ethereum.org/EIPS/eip-7251). +""" from typing import List @@ -91,7 +90,9 @@ def test_extra_consolidations( pre: Alloc, requests_list: List[ConsolidationRequest], ): - """Test how clients were to behave with more than 2 consolidations per block.""" + """ + Test how clients were to behave with more than 2 consolidations per block. + """ modified_code: Bytecode = Bytecode() memory_offset: int = 0 amount_of_requests: int = 0 @@ -116,7 +117,8 @@ def test_extra_consolidations( balance=0, ) - # given a list of consolidation requests construct a consolidation request transaction + # given a list of consolidation requests construct a consolidation request + # transaction consolidation_request_transaction = ConsolidationRequestTransaction(requests=requests_list) # prepare consolidation senders consolidation_request_transaction.update_pre(pre=pre) @@ -144,8 +146,8 @@ def test_extra_consolidations( ) def test_system_contract_errors(): """ - Test system contract raising different errors when called by the system account at the - end of the block execution. + Test system contract raising different errors when called by the system + account at the end of the block execution. To see the list of generated tests, please refer to the `generate_system_contract_error_test` decorator definition. diff --git a/tests/prague/eip7623_increase_calldata_cost/conftest.py b/tests/prague/eip7623_increase_calldata_cost/conftest.py index 5f0a4b50d0d..7e021f7184c 100644 --- a/tests/prague/eip7623_increase_calldata_cost/conftest.py +++ b/tests/prague/eip7623_increase_calldata_cost/conftest.py @@ -48,8 +48,8 @@ def to( @pytest.fixture def protected() -> bool: """ - Return whether the transaction is protected or not. - Only valid for type-0 transactions. + Return whether the transaction is protected or not. Only valid for type-0 + transactions. """ return True @@ -62,7 +62,10 @@ def access_list() -> List[AccessList] | None: @pytest.fixture def authorization_refund() -> bool: - """Return whether the transaction has an existing authority in the authorization list.""" + """ + Return whether the transaction has an existing authority in the + authorization list. + """ return False @@ -75,9 +78,9 @@ def authorization_list( """ Authorization-list for the transaction. - This fixture needs to be parametrized indirectly in order to generate the authorizations with - valid signers using `pre` in this function, and the parametrized value should be a list of - addresses. + This fixture needs to be parametrized indirectly in order to generate the + authorizations with valid signers using `pre` in this function, and the + parametrized value should be a list of addresses. """ if not hasattr(request, "param"): return None @@ -127,43 +130,42 @@ def tx_data( intrinsic_gas_data_floor_minimum_delta: int, ) -> Bytes: """ - All tests in this file use data that is generated dynamically depending on the case and the - attributes of the transaction in order to reach the edge cases where the floor gas cost is - equal or barely greater than the intrinsic gas cost. - - We have two different types of tests: - - FLOOR_GAS_COST_LESS_THAN_OR_EQUAL_TO_INTRINSIC_GAS: The floor gas cost is less than or equal - to the intrinsic gas cost, which means that the size of the tokens in the data are not - enough to trigger the floor gas cost. - - FLOOR_GAS_COST_GREATER_THAN_INTRINSIC_GAS: The floor gas cost is greater than the intrinsic - gas cost, which means that the size of the tokens in the data are enough to trigger the - floor gas cost. - - E.g. Given a transaction with a single access list and a single storage key, its intrinsic gas - cost (as of Prague fork) can be calculated as: - - 21,000 gas for the transaction - - 2,400 gas for the access list - - 1,900 gas for the storage key - - 16 gas for each non-zero byte in the data - - 4 gas for each zero byte in the data - - Its floor data gas cost can be calculated as: - - 21,000 gas for the transaction - - 40 gas for each non-zero byte in the data - - 10 gas for each zero byte in the data - - Notice that the data included in the transaction affects both the intrinsic gas cost and the - floor data cost, but at different rates. - - The purpose of this function is to find the exact amount of data where the floor data gas - cost starts exceeding the intrinsic gas cost. - - After a binary search we find that adding 717 tokens of data (179 non-zero bytes + - 1 zero byte) triggers the floor gas cost. - - Therefore, this function will return a Bytes object with 179 non-zero bytes and 1 zero byte - for `FLOOR_GAS_COST_GREATER_THAN_INTRINSIC_GAS` and a Bytes object with 179 non-zero bytes - and no zero bytes for `FLOOR_GAS_COST_LESS_THAN_OR_EQUAL_TO_INTRINSIC_GAS` + All tests in this file use data that is generated dynamically depending on + the case and the attributes of the transaction in order to reach the edge + cases where the floor gas cost is equal or barely greater than the + intrinsic gas cost. + + We have two different types of tests: - + FLOOR_GAS_COST_LESS_THAN_OR_EQUAL_TO_INTRINSIC_GAS: The floor gas cost is + less than or equal to the intrinsic gas cost, which means that the size of + the tokens in the data are not enough to trigger the floor gas cost. - + FLOOR_GAS_COST_GREATER_THAN_INTRINSIC_GAS: The floor gas cost is greater + than the intrinsic gas cost, which means that the size of the tokens in the + data are enough to trigger the floor gas cost. + + E.g. Given a transaction with a single access list and a single storage + key, its intrinsic gas cost (as of Prague fork) can be calculated as: - + 21,000 gas for the transaction - 2,400 gas for the access list - 1,900 gas + for the storage key - 16 gas for each non-zero byte in the data - 4 gas for + each zero byte in the data + + Its floor data gas cost can be calculated as: - 21,000 gas for the + transaction - 40 gas for each non-zero byte in the data - 10 gas for each + zero byte in the data + + Notice that the data included in the transaction affects both the intrinsic + gas cost and the floor data cost, but at different rates. + + The purpose of this function is to find the exact amount of data where the + floor data gas cost starts exceeding the intrinsic gas cost. + + After a binary search we find that adding 717 tokens of data (179 non-zero + bytes + 1 zero byte) triggers the floor gas cost. + + Therefore, this function will return a Bytes object with 179 non-zero bytes + and 1 zero byte for `FLOOR_GAS_COST_GREATER_THAN_INTRINSIC_GAS` and a Bytes + object with 179 non-zero bytes and no zero bytes for + `FLOOR_GAS_COST_LESS_THAN_OR_EQUAL_TO_INTRINSIC_GAS` """ def tokens_to_data(tokens: int) -> Bytes: @@ -188,11 +190,11 @@ def transaction_intrinsic_cost_calculator(tokens: int) -> int: def transaction_data_floor_cost_calculator(tokens: int) -> int: return fork_data_floor_cost_calculator(data=tokens_to_data(tokens)) - # Start with zero data and check the difference in the gas calculator between the - # intrinsic gas cost and the floor gas cost. + # Start with zero data and check the difference in the gas calculator + # between the intrinsic gas cost and the floor gas cost. if transaction_data_floor_cost_calculator(0) >= transaction_intrinsic_cost_calculator(0): - # Special case which is a transaction with no extra intrinsic gas costs other than the - # data cost, any data will trigger the floor gas cost. + # Special case which is a transaction with no extra intrinsic gas costs + # other than the data cost, any data will trigger the floor gas cost. if data_test_type == DataTestType.FLOOR_GAS_COST_LESS_THAN_OR_EQUAL_TO_INTRINSIC_GAS: return Bytes(b"") else: @@ -213,13 +215,15 @@ def tx_gas_delta() -> int: """ Gas delta to modify the gas amount included with the transaction. - If negative, the transaction will be invalid because the intrinsic gas cost is greater than the - gas limit. + If negative, the transaction will be invalid because the intrinsic gas cost + is greater than the gas limit. - This value operates regardless of whether the floor data gas cost is reached or not. + This value operates regardless of whether the floor data gas cost is + reached or not. - If the value is greater than zero, the transaction will also be valid and the test will check - that transaction processing does not consume more gas than it should. + If the value is greater than zero, the transaction will also be valid and + the test will check that transaction processing does not consume more gas + than it should. """ return 0 @@ -258,10 +262,11 @@ def tx_intrinsic_gas_cost_including_floor_data_cost( """ Transaction intrinsic gas cost. - The calculated value takes into account the normal intrinsic gas cost and the floor data gas - cost if it is greater than the intrinsic gas cost. + The calculated value takes into account the normal intrinsic gas cost and + the floor data gas cost if it is greater than the intrinsic gas cost. - In other words, this is the value that is required for the transaction to be valid. + In other words, this is the value that is required for the transaction to + be valid. """ intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator() return intrinsic_gas_cost_calculator( @@ -290,7 +295,8 @@ def tx_gas_limit( """ Gas limit for the transaction. - The gas delta is added to the intrinsic gas cost to generate different test scenarios. + The gas delta is added to the intrinsic gas cost to generate different test + scenarios. """ return tx_intrinsic_gas_cost_including_floor_data_cost + tx_gas_delta diff --git a/tests/prague/eip7623_increase_calldata_cost/helpers.py b/tests/prague/eip7623_increase_calldata_cost/helpers.py index d4235976c3a..fc4f94bd63c 100644 --- a/tests/prague/eip7623_increase_calldata_cost/helpers.py +++ b/tests/prague/eip7623_increase_calldata_cost/helpers.py @@ -16,16 +16,18 @@ def find_floor_cost_threshold( intrinsic_gas_cost_calculator: Callable[[int], int], ) -> int: """ - Find the minimum amount of tokens that will trigger the floor gas cost, by using a binary - search and the intrinsic gas cost and floor data calculators. + Find the minimum amount of tokens that will trigger the floor gas cost, by + using a binary search and the intrinsic gas cost and floor data + calculators. """ - # Start with 1000 tokens and if the intrinsic gas cost is greater than the floor gas cost, - # multiply the number of tokens by 2 until it's not. + # Start with 1000 tokens and if the intrinsic gas cost is greater than the + # floor gas cost, multiply the number of tokens by 2 until it's not. tokens = 1000 while floor_data_gas_cost_calculator(tokens) < intrinsic_gas_cost_calculator(tokens): tokens *= 2 - # Binary search to find the minimum number of tokens that will trigger the floor gas cost. + # Binary search to find the minimum number of tokens that will trigger the + # floor gas cost. left = 0 right = tokens while left < right: @@ -39,7 +41,8 @@ def find_floor_cost_threshold( if floor_data_gas_cost_calculator(tokens) > intrinsic_gas_cost_calculator(tokens): tokens -= 1 - # Verify that increasing the tokens by one would always trigger the floor gas cost. + # Verify that increasing the tokens by one would always trigger the floor + # gas cost. assert ( floor_data_gas_cost_calculator(tokens) <= intrinsic_gas_cost_calculator(tokens) ) and floor_data_gas_cost_calculator(tokens + 1) > intrinsic_gas_cost_calculator(tokens + 1), ( diff --git a/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py b/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py index c0ef506023e..7f52884153d 100644 --- a/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py +++ b/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py @@ -1,7 +1,7 @@ """ -abstract: Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623) - Test execution gas consumption after [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). -""" # noqa: E501 +abstract: Test [EIP-7623: Increase calldata +cost](https://eips.ethereum.org/EIPS/eip-7623). +""" from typing import List @@ -41,7 +41,10 @@ class TestGasConsumption: @pytest.fixture def intrinsic_gas_data_floor_minimum_delta(self) -> int: - """Force a minimum delta in order to have some gas to execute the invalid opcode.""" + """ + Force a minimum delta in order to have some gas to execute the invalid + opcode. + """ return 50_000 @pytest.fixture @@ -49,7 +52,10 @@ def to( self, pre: Alloc, ) -> Address | None: - """Return a contract that consumes all gas when executed by calling an invalid opcode.""" + """ + Return a contract that consumes all gas when executed by calling an + invalid opcode. + """ return pre.deploy_contract(Op.INVALID) @pytest.mark.parametrize( @@ -78,7 +84,10 @@ def test_full_gas_consumption( pre: Alloc, tx: Transaction, ) -> None: - """Test executing a transaction that fully consumes its execution gas allocation.""" + """ + Test executing a transaction that fully consumes its execution gas + allocation. + """ tx.expected_receipt = TransactionReceipt(gas_used=tx.gas_limit) state_test( pre=pre, @@ -136,8 +145,8 @@ def to( @pytest.mark.parametrize( "tx_gas_delta", [ - # Test with exact gas and extra gas, to verify that the refund is correctly applied - # to the full consumed execution gas. + # Test with exact gas and extra gas, to verify that the refund is + # correctly applied to the full consumed execution gas. pytest.param(0, id="exact_gas"), ], ) @@ -148,7 +157,9 @@ def test_gas_consumption_below_data_floor( tx: Transaction, tx_floor_data_cost: int, ) -> None: - """Test executing a transaction that almost consumes the floor data cost.""" + """ + Test executing a transaction that almost consumes the floor data cost. + """ tx.expected_receipt = TransactionReceipt(gas_used=tx_floor_data_cost) state_test( pre=pre, diff --git a/tests/prague/eip7623_increase_calldata_cost/test_refunds.py b/tests/prague/eip7623_increase_calldata_cost/test_refunds.py index 10781bb9e0f..a59a9cd2683 100644 --- a/tests/prague/eip7623_increase_calldata_cost/test_refunds.py +++ b/tests/prague/eip7623_increase_calldata_cost/test_refunds.py @@ -1,7 +1,7 @@ """ -abstract: Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623) - Test applied refunds for [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). -""" # noqa: E501 +abstract: Test [EIP-7623: Increase calldata +cost](https://eips.ethereum.org/EIPS/eip-7623). +""" from enum import Enum, Flag, auto from typing import Dict, List @@ -35,18 +35,22 @@ class RefundTestType(Enum): EXECUTION_GAS_MINUS_REFUND_GREATER_THAN_DATA_FLOOR = 0 """ - The execution gas minus the refund is greater than the data floor, hence the execution gas cost - is charged. + + + The execution gas minus the refund is greater than the data floor, hence + the execution gas cost is charged. + """ EXECUTION_GAS_MINUS_REFUND_LESS_THAN_DATA_FLOOR = 1 """ - The execution gas minus the refund is less than the data floor, hence the data floor cost is - charged. + + + The execution gas minus the refund is less than the data floor, hence the + data floor cost is charged. + """ EXECUTION_GAS_MINUS_REFUND_EQUAL_TO_DATA_FLOOR = 2 - """ - The execution gas minus the refund is equal to the data floor. - """ + """The execution gas minus the refund is equal to the data floor.""" class RefundType(Flag): @@ -56,7 +60,10 @@ class RefundType(Flag): """The storage is cleared from a non-zero value.""" AUTHORIZATION_EXISTING_AUTHORITY = auto() - """The authorization list contains an authorization where the authority exists in the state.""" + """ + The authorization list contains an authorization where the authority exists + in the state. + """ @pytest.fixture @@ -67,7 +74,10 @@ def data_test_type() -> DataTestType: @pytest.fixture def authorization_list(pre: Alloc, refund_type: RefundType) -> List[AuthorizationTuple] | None: - """Modify fixture from conftest to automatically read the refund_type information.""" + """ + Modify fixture from conftest to automatically read the refund_type + information. + """ if RefundType.AUTHORIZATION_EXISTING_AUTHORITY not in refund_type: return None return [AuthorizationTuple(signer=pre.fund_eoa(1), address=Address(1))] @@ -75,7 +85,10 @@ def authorization_list(pre: Alloc, refund_type: RefundType) -> List[Authorizatio @pytest.fixture def ty(refund_type: RefundType) -> int: - """Modify fixture from conftest to automatically read the refund_type information.""" + """ + Modify fixture from conftest to automatically read the refund_type + information. + """ if RefundType.AUTHORIZATION_EXISTING_AUTHORITY in refund_type: return 4 return 2 @@ -125,8 +138,8 @@ def code_storage(refund_type: RefundType) -> Dict: @pytest.fixture def contract_creating_tx() -> bool: """ - Override fixture in order to avoid a circular fixture dependency since - none of these tests are contract creating transactions. + Override fixture in order to avoid a circular fixture dependency since none + of these tests are contract creating transactions. """ return False @@ -137,12 +150,14 @@ def intrinsic_gas_data_floor_minimum_delta() -> int: Induce a minimum delta between the transaction intrinsic gas cost and the floor data gas cost. - Since at least one of the cases requires some execution gas expenditure (SSTORE clearing), - we need to introduce an increment of the floor data cost above the transaction intrinsic gas - cost, otherwise the floor data cost would always be the below the execution gas cost even - after the refund is applied. + Since at least one of the cases requires some execution gas expenditure + (SSTORE clearing), we need to introduce an increment of the floor data cost + above the transaction intrinsic gas cost, otherwise the floor data cost + would always be the below the execution gas cost even after the refund is + applied. - This value has been set as of Prague and should be adjusted if the gas costs change. + This value has been set as of Prague and should be adjusted if the gas + costs change. """ return 250 @@ -160,10 +175,11 @@ def execution_gas_used( This gas amount is on top of the transaction intrinsic gas cost. - If this value were zero it would result in the refund being applied to the execution gas cost - and the resulting amount being always below the floor data cost, hence we need to find a - higher value in this function to ensure we get both scenarios where the refund drives - the execution cost below the floor data cost and above the floor data cost. + If this value were zero it would result in the refund being applied to the + execution gas cost and the resulting amount being always below the floor + data cost, hence we need to find a higher value in this function to ensure + we get both scenarios where the refund drives the execution cost below the + floor data cost and above the floor data cost. """ def execution_gas_cost(execution_gas: int) -> int: @@ -177,7 +193,8 @@ def execution_gas_cost(execution_gas: int) -> int: "test to fail. Try increasing the intrinsic_gas_data_floor_minimum_delta fixture." ) - # Dumb for-loop to find the execution gas cost that will result in the expected refund. + # Dumb for-loop to find the execution gas cost that will result in the + # expected refund. while execution_gas_cost(execution_gas) < tx_floor_data_cost: execution_gas += 1 if refund_test_type == RefundTestType.EXECUTION_GAS_MINUS_REFUND_EQUAL_TO_DATA_FLOOR: @@ -212,7 +229,8 @@ def to( """ Return a contract that consumes the expected execution gas. - At the moment we naively use JUMPDEST to consume the gas, which can yield very big contracts. + At the moment we naively use JUMPDEST to consume the gas, which can yield + very big contracts. Ideally, we can use memory expansion to consume gas. """ @@ -232,7 +250,8 @@ def tx_gas_limit( """ Gas limit for the transaction. - The gas delta is added to the intrinsic gas cost to generate different test scenarios. + The gas delta is added to the intrinsic gas cost to generate different test + scenarios. """ tx_gas_limit = tx_intrinsic_gas_cost_before_execution + execution_gas_used assert tx_gas_limit >= tx_intrinsic_gas_cost_including_floor_data_cost @@ -265,7 +284,10 @@ def test_gas_refunds_from_data_floor( refund: int, refund_test_type: RefundTestType, ) -> None: - """Test gas refunds deducted from the execution gas cost and not the data floor.""" + """ + Test gas refunds deducted from the execution gas cost and not the data + floor. + """ gas_used = tx_intrinsic_gas_cost_before_execution + execution_gas_used - refund if refund_test_type == RefundTestType.EXECUTION_GAS_MINUS_REFUND_LESS_THAN_DATA_FLOOR: assert gas_used < tx_floor_data_cost @@ -277,18 +299,17 @@ def test_gas_refunds_from_data_floor( raise ValueError("Invalid refund test type") if gas_used < tx_floor_data_cost: gas_used = tx_floor_data_cost - # This is the actual test verification: - # - During test filling, the receipt returned by the transition tool (t8n) is verified against - # the expected receipt. - # - During test consumption, this is reflected in the balance difference and the state - # root. + # This is the actual test verification: - During test filling, the receipt + # returned by the transition tool (t8n) is verified against the expected + # receipt. - During test consumption, this is reflected in the balance + # difference and the state root. tx.expected_receipt = TransactionReceipt(gas_used=gas_used) state_test( pre=pre, post={ tx.to: { - # Verify that the storage was cleared (for storage clear refund). - # See `code_storage` fixture for more details. + # Verify that the storage was cleared (for storage clear + # refund). See `code_storage` fixture for more details. "storage": {0: 0}, } }, diff --git a/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py b/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py index 27457fc3287..16dfebf8c2c 100644 --- a/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py +++ b/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py @@ -1,7 +1,7 @@ """ -abstract: Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623) - Test transaction validity on [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). -""" # noqa: E501 +abstract: Test [EIP-7623: Increase calldata +cost](https://eips.ethereum.org/EIPS/eip-7623). +""" import pytest @@ -33,8 +33,9 @@ pytest.mark.parametrize( "tx_gas_delta", [ - # Test the case where the included gas is greater than the intrinsic gas to verify that - # the data floor does not consume more gas than it should. + # Test the case where the included gas is greater than the + # intrinsic gas to verify that the data floor does not consume more + # gas than it should. pytest.param(1, id="extra_gas"), pytest.param(0, id="exact_gas"), pytest.param(-1, id="insufficient_gas", marks=pytest.mark.exception_test), @@ -81,7 +82,10 @@ def test_transaction_validity_type_0( pre: Alloc, tx: Transaction, ) -> None: - """Test transaction validity for transactions without access lists and contract creation.""" + """ + Test transaction validity for transactions without access lists and + contract creation. + """ state_test( pre=pre, post={}, @@ -143,7 +147,10 @@ def test_transaction_validity_type_1_type_2( pre: Alloc, tx: Transaction, ) -> None: - """Test transaction validity for transactions with access lists and contract creation.""" + """ + Test transaction validity for transactions with access lists and contract + creation. + """ state_test( pre=pre, post={}, @@ -188,9 +195,9 @@ def test_transaction_validity_type_1_type_2( ], ) @pytest.mark.parametrize( - # Blobs don't really have an effect because the blob gas does is not considered in the - # intrinsic gas calculation, but we still test it to make sure that the transaction is - # correctly processed. + # Blobs don't really have an effect because the blob gas does is not + # considered in the intrinsic gas calculation, but we still test it to make + # sure that the transaction is correctly processed. "blob_versioned_hashes", [ pytest.param( @@ -219,8 +226,8 @@ def test_transaction_validity_type_3( tx: Transaction, ) -> None: """ - Test transaction validity for transactions with access lists, blobs, - but no contract creation. + Test transaction validity for transactions with access lists, blobs, but no + contract creation. """ state_test( pre=pre, @@ -289,8 +296,8 @@ def test_transaction_validity_type_4( tx: Transaction, ) -> None: """ - Test transaction validity for transactions with access lists, authorization lists, but no - contract creation. + Test transaction validity for transactions with access lists, authorization + lists, but no contract creation. """ state_test( pre=pre, diff --git a/tests/prague/eip7685_general_purpose_el_requests/conftest.py b/tests/prague/eip7685_general_purpose_el_requests/conftest.py index 1d347199a70..03fa406f0dc 100644 --- a/tests/prague/eip7685_general_purpose_el_requests/conftest.py +++ b/tests/prague/eip7685_general_purpose_el_requests/conftest.py @@ -29,7 +29,10 @@ def block_body_override_requests( request: pytest.FixtureRequest, ) -> List[DepositRequest | WithdrawalRequest | ConsolidationRequest] | None: - """List of requests that overwrite the requests in the header. None by default.""" + """ + List of requests that overwrite the requests in the header. None by + default. + """ if hasattr(request, "param"): return request.param return None @@ -38,9 +41,9 @@ def block_body_override_requests( @pytest.fixture def correct_requests_hash_in_header() -> bool: """ - Whether to include the correct requests hash in the header so the calculated - block hash is correct, even though the requests in the new payload parameters might - be wrong. + Whether to include the correct requests hash in the header so the + calculated block hash is correct, even though the requests in the new + payload parameters might be wrong. """ return False diff --git a/tests/prague/eip7685_general_purpose_el_requests/spec.py b/tests/prague/eip7685_general_purpose_el_requests/spec.py index 414e47d290c..758fe930762 100644 --- a/tests/prague/eip7685_general_purpose_el_requests/spec.py +++ b/tests/prague/eip7685_general_purpose_el_requests/spec.py @@ -1,7 +1,8 @@ """ Common procedures to test -[EIP-7685: General purpose execution layer requests](https://eips.ethereum.org/EIPS/eip-7685). -""" # noqa: E501 +[EIP-7685: General purpose execution +layer requests](https://eips.ethereum.org/EIPS/eip-7685). +""" from dataclasses import dataclass diff --git a/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py b/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py index d11e62cffdb..3988156634b 100644 --- a/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py +++ b/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py @@ -1,8 +1,10 @@ """ -abstract: Tests [EIP-7685: General purpose execution layer requests](https://eips.ethereum.org/EIPS/eip-7685) - Cross testing for withdrawal and deposit request for [EIP-7685: General purpose execution layer requests](https://eips.ethereum.org/EIPS/eip-7685). - -""" # noqa: E501 +abstract: Tests [EIP-7685: General purpose execution layer +requests](https://eips.ethereum.org/EIPS/eip-7685) +Cross testing for withdrawal and deposit request for [EIP-7685: +General purpose execution layer +requests](https://eips.ethereum.org/EIPS/eip-7685). +""" from itertools import permutations from typing import Callable, Dict, Generator, List, Tuple @@ -299,7 +301,8 @@ def get_contract_permutations(n: int = 3) -> Generator[ParameterSet, None, None] [ single_consolidation_from_contract(0), single_consolidation_from_contract(1), - # the following performs single_withdrawal_from_contract(0) to (16) + # the following performs single_withdrawal_from_contract(0) to + # (16) *[ single_withdrawal_from_contract(i) for i in range( @@ -307,10 +310,10 @@ def get_contract_permutations(n: int = 3) -> Generator[ParameterSet, None, None] 16, ) ], - # single_withdrawal_from_contract(16) not allowed cuz only - # 16 MAX WITHDRAWALS PER BLOCK (EIP-7002) - # - # the following performs single_deposit_from_contract(0) to (18) + # single_withdrawal_from_contract(16) not allowed cuz only 16 + # MAX WITHDRAWALS PER BLOCK (EIP-7002) + # the following performs single_deposit_from_contract(0) to + # (18) *[ single_deposit_from_contract(i) for i in range( @@ -354,8 +357,8 @@ def test_valid_multi_type_request_from_same_tx( fork: Fork, ): """ - Test making a deposit to the beacon chain deposit contract and a withdrawal in - the same tx. + Test making a deposit to the beacon chain deposit contract and a withdrawal + in the same tx. """ withdrawal_request_fee: int = 1 consolidation_request_fee: int = 1 @@ -440,8 +443,9 @@ def invalid_requests_block_combinations( """ Return a list of invalid request combinations for the given fork. - In the event of a new request type, the `all_request_types` dictionary should be updated - with the new request type and its corresponding request-generating transaction. + In the event of a new request type, the `all_request_types` dictionary + should be updated with the new request type and its corresponding + request-generating transaction. Returned parameters are: requests, block_body_override_requests, exception """ @@ -474,9 +478,10 @@ def func(fork: Fork) -> List[ParameterSet]: expected_exceptions: List[BlockException] = [BlockException.INVALID_REQUESTS] if correct_requests_hash_in_header: - # The client also might reject the block with an invalid-block-hash error because it - # might convert the requests in the new payload parameters to the requests hash in the - # header and compare it with the block hash. + # The client also might reject the block with an invalid-block-hash + # error because it might convert the requests in the new payload + # parameters to the requests hash in the header and compare it with + # the block hash. expected_exceptions.append(BlockException.INVALID_BLOCK_HASH) # - Empty requests list with invalid hash @@ -485,8 +490,10 @@ def func(fork: Fork) -> List[ParameterSet]: [], [ bytes([i]) for i in range(fork.max_request_type() + 1) - ], # Using empty requests, calculate the hash using an invalid calculation method: - # sha256(sha256(b"\0") ++ sha256(b"\1") ++ sha256(b"\2") ++ ...) + ], # Using empty requests, calculate the hash using an invalid + # calculation method: + # sha256(sha256(b"\0") ++ sha256(b"\1") ++ sha256(b"\2") ++ + # ...) expected_exceptions, id="no_requests_and_invalid_hash_calculation_method", ), @@ -494,7 +501,8 @@ def func(fork: Fork) -> List[ParameterSet]: [], [ bytes([]) for _ in range(fork.max_request_type() + 1) - ], # Using empty requests, calculate the hash using an invalid calculation method: + ], # Using empty requests, calculate the hash using an invalid + # calculation method: # sha256(sha256(b"") ++ sha256(b"") ++ sha256(b"") ++ ...) expected_exceptions, id="no_requests_and_invalid_hash_calculation_method_2", @@ -507,9 +515,8 @@ def func(fork: Fork) -> List[ParameterSet]: [ pytest.param( [eoa_request], - [ - block_request - ], # The request type byte missing because we need to use `Requests` + [block_request], # The request type byte missing because we need to + # use `Requests` expected_exceptions, id=f"single_{request_type}_missing_type_byte", ), @@ -636,10 +643,11 @@ def test_invalid_multi_type_requests( """ Negative testing for all request types in the same block. - In these tests, the requests hash in the header reflects what's received in the parameters - portion of the `engine_newPayloadVX` call, so the block hash calculation might pass if - a client copies the info received verbatim, but block validation must fail after - the block is executed (via RLP or Engine API). + In these tests, the requests hash in the header reflects what's received in + the parameters portion of the `engine_newPayloadVX` call, so the block hash + calculation might pass if a client copies the info received verbatim, but + block validation must fail after the block is executed (via RLP or Engine + API). """ blockchain_test( genesis_environment=Environment(), @@ -665,26 +673,26 @@ def test_invalid_multi_type_requests_engine( blocks: List[Block], ): """ - Negative testing for all request types in the same block with incorrect parameters - in the Engine API new payload parameters, but with the correct requests hash in the header - so the block hash is correct. - - In these tests, the requests hash in the header reflects what's actually in the executed block, - so the block might execute properly if the client ignores the requests in the new payload - parameters. - - Note that the only difference between the engine version produced by this test and - the ones produced by `test_invalid_multi_type_requests` is the - `blockHash` value in the new payloads, which is calculated using different request hashes - for each test, but since the request hash is not a value that is included in the payload, - it might not be immediately apparent. - - Also these tests would not fail if the block is imported via RLP (syncing from a peer), - so we only generate the BlockchainTestEngine for them. - - The client also might reject the block with an invalid-block-hash error because it might - convert the requests in the new payload parameters to the requests hash in the header - and compare it with the block hash. + Negative testing for all request types in the same block with incorrect + parameters in the Engine API new payload parameters, but with the correct + requests hash in the header so the block hash is correct. + + In these tests, the requests hash in the header reflects what's actually in + the executed block, so the block might execute properly if the client + ignores the requests in the new payload parameters. + + Note that the only difference between the engine version produced by this + test and the ones produced by `test_invalid_multi_type_requests` is the + `blockHash` value in the new payloads, which is calculated using different + request hashes for each test, but since the request hash is not a value + that is included in the payload, it might not be immediately apparent. + + Also these tests would not fail if the block is imported via RLP (syncing + from a peer), so we only generate the BlockchainTestEngine for them. + + The client also might reject the block with an invalid-block-hash error + because it might convert the requests in the new payload parameters to the + requests hash in the header and compare it with the block hash. """ blockchain_test( genesis_environment=Environment(), diff --git a/tests/prague/eip7702_set_code_tx/helpers.py b/tests/prague/eip7702_set_code_tx/helpers.py index 83bd4eb91b6..8cc21940297 100644 --- a/tests/prague/eip7702_set_code_tx/helpers.py +++ b/tests/prague/eip7702_set_code_tx/helpers.py @@ -1,12 +1,15 @@ -"""Helper types, functions and classes for testing EIP-7702 Set Code Transaction.""" +""" +Helper types, functions and classes for testing EIP-7702 Set Code Transaction. +""" from enum import Enum, auto class AddressType(Enum): """ - Different types of addresses used to specify the type of authority that signs an authorization, - and the type of address to which the authority authorizes to set the code to. + Different types of addresses used to specify the type of authority that + signs an authorization, and the type of address to which the authority + authorizes to set the code to. """ EMPTY_ACCOUNT = auto() diff --git a/tests/prague/eip7702_set_code_tx/test_gas.py b/tests/prague/eip7702_set_code_tx/test_gas.py index af634fc29d0..7629105b307 100644 --- a/tests/prague/eip7702_set_code_tx/test_gas.py +++ b/tests/prague/eip7702_set_code_tx/test_gas.py @@ -1,7 +1,7 @@ """ -abstract: Tests related to gas of set-code transactions from [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702) - Tests related to gas of set-code transactions from [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). -""" # noqa: E501 +abstract: Tests related to gas of set-code transactions from [EIP-7702: Set EOA +account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). +""" from dataclasses import dataclass from enum import Enum, auto @@ -43,7 +43,10 @@ class SignerType(Enum): - """Different cases of authorization lists for testing gas cost of set-code transactions.""" + """ + Different cases of authorization lists for testing gas cost of set-code + transactions. + """ SINGLE_SIGNER = auto() MULTIPLE_SIGNERS = auto() @@ -59,7 +62,10 @@ class AuthorizationInvalidityType(Enum): class AccessListType(Enum): - """Different cases of access lists for testing gas cost of set-code transactions.""" + """ + Different cases of access lists for testing gas cost of set-code + transactions. + """ EMPTY = auto() CONTAINS_AUTHORITY = auto() @@ -75,8 +81,8 @@ def contains_authority(self) -> bool: def contains_set_code_address(self) -> bool: """ - Return True if the access list contains the address to which the authority authorizes to - set the code to. + Return True if the access list contains the address to which the + authority authorizes to set the code to. """ return self in { AccessListType.CONTAINS_SET_CODE_ADDRESS, @@ -92,21 +98,30 @@ class AuthorityWithProperties: """Dataclass to hold the properties of the authority address.""" authority: EOA - """ - The address of the authority to be used in the transaction. - """ + """The address of the authority to be used in the transaction.""" address_type: AddressType - """ - The type of the address the authority was before the authorization. - """ + """The type of the address the authority was before the authorization.""" invalidity_type: AuthorizationInvalidityType | None """ - Whether the authorization will be invalid and if so, which type of invalidity it is. + + + + + + + Whether the authorization will be invalid and if so, which type of + invalidity it is. + + + """ @property def empty(self) -> bool: - """Return True if the authority address is an empty account before the authorization.""" + """ + Return True if the authority address is an empty account before the + authorization. + """ return self.address_type == AddressType.EMPTY_ACCOUNT @@ -189,28 +204,47 @@ class AuthorizationWithProperties: """Dataclass to hold the properties of the authorization list.""" tuple: AuthorizationTuple - """ - The authorization tuple to be used in the transaction. - """ + """The authorization tuple to be used in the transaction.""" invalidity_type: AuthorizationInvalidityType | None """ - Whether the authorization is invalid and if so, which type of invalidity it is. + + + + + + + Whether the authorization is invalid and if so, which type of invalidity it + is. + + + """ authority_type: AddressType - """ - The type of the address the authority was before the authorization. - """ + """The type of the address the authority was before the authorization.""" skip: bool """ - Whether the authorization should be skipped and therefore not included in the transaction. - Used for tests where the authorization was already in the state before the transaction was - created. + + + + + + Whether the authorization should be skipped and therefore not included in + the transaction. + + Used for tests where the authorization was already in the state before the + transaction was created. + + + """ @property def empty(self) -> bool: - """Return True if the authority address is an empty account before the authorization.""" + """ + Return True if the authority address is an empty account before the + authorization. + """ return self.authority_type == AddressType.EMPTY_ACCOUNT @@ -227,14 +261,17 @@ def authorization_list_with_properties( self_sponsored: bool, re_authorize: bool, ) -> List[AuthorizationWithProperties]: - """Fixture to return the authorization-list-with-properties for the given case.""" + """ + Fixture to return the authorization-list-with-properties for the given + case. + """ authorization_list: List[AuthorizationWithProperties] = [] environment_chain_id = chain_config.chain_id match signer_type: case SignerType.SINGLE_SIGNER: authority_with_properties = next(authority_iterator) - # We have to take into account the cases where the nonce has already been increased - # before the authorization is processed. + # We have to take into account the cases where the nonce has + # already been increased before the authorization is processed. increased_nonce = ( self_sponsored or authority_with_properties.address_type == AddressType.EOA_WITH_SET_CODE @@ -360,7 +397,10 @@ def authorization_list( @pytest.fixture() def authorize_to_address(request: pytest.FixtureRequest, pre: Alloc) -> Address: - """Fixture to return the address to which the authority authorizes to set the code to.""" + """ + Fixture to return the address to which the authority authorizes to set the + code to. + """ match request.param: case AddressType.EMPTY_ACCOUNT: return pre.fund_eoa(0) @@ -421,14 +461,18 @@ def gas_test_parameter_args( include_pre_authorized: bool = True, execution_gas_allowance: bool = False, ): - """Return the parametrize decorator that can be used in all gas test functions.""" + """ + Return the parametrize decorator that can be used in all gas test + functions. + """ multiple_authorizations_count = 2 defaults = { "signer_type": SignerType.SINGLE_SIGNER, "authorization_invalidity_type": None, "authorizations_count": 1, - "invalid_authorization_index": -1, # All authorizations are equally invalid + "invalid_authorization_index": -1, # All authorizations are equally + # invalid "chain_id_type": ChainIDType.GENERIC, "authorize_to_address": AddressType.EMPTY_ACCOUNT, "access_list_case": AccessListType.EMPTY, @@ -694,7 +738,8 @@ def gas_test_parameter_args( ] if include_many: - # Fit as many authorizations as possible within the transaction gas limit. + # Fit as many authorizations as possible within the transaction gas + # limit. max_gas = 16_777_216 - 21_000 if execution_gas_allowance: # Leave some gas for the execution of the test code. @@ -743,7 +788,10 @@ def test_gas_cost( access_list: List[AccessList], sender: EOA, ): - """Test gas at the execution start of a set-code transaction in multiple scenarios.""" + """ + Test gas at the execution start of a set-code transaction in multiple + scenarios. + """ # Calculate the intrinsic gas cost of the authorizations, by default the # full empty account cost is charged for each authorization. intrinsic_gas = fork.transaction_intrinsic_cost_calculator()( @@ -768,9 +816,10 @@ def test_gas_cost( Spec.PER_EMPTY_ACCOUNT_COST - Spec.PER_AUTH_BASE_COST ) * discounted_authorizations - # We calculate the exact gas required to execute the test code. - # We add SSTORE opcodes in order to make sure that the refund is less than one fifth (EIP-3529) - # of the total gas used, so we can see the full discount being reflected in most of the tests. + # We calculate the exact gas required to execute the test code. We add + # SSTORE opcodes in order to make sure that the refund is less than one + # fifth (EIP-3529) of the total gas used, so we can see the full discount + # being reflected in most of the tests. gas_costs = fork.gas_costs() gas_opcode_cost = gas_costs.G_BASE sstore_opcode_count = 10 @@ -781,8 +830,8 @@ def test_gas_cost( execution_gas = gas_opcode_cost + push_opcode_cost + sstore_opcode_cost + cold_storage_cost - # The first opcode that executes in the code is the GAS opcode, which costs 2 gas, so we - # subtract that from the expected gas measure. + # The first opcode that executes in the code is the GAS opcode, which costs + # 2 gas, so we subtract that from the expected gas measure. expected_gas_measure = execution_gas - gas_opcode_cost test_code_storage = Storage() @@ -801,7 +850,8 @@ def test_gas_cost( max_discount = tx_gas_limit // 5 if discount_gas > max_discount: - # Only one test hits this condition, but it's ok to also test this case. + # Only one test hits this condition, but it's ok to also test this + # case. discount_gas = max_discount gas_used = tx_gas_limit - discount_gas @@ -841,8 +891,12 @@ def test_account_warming( sender: EOA, check_delegated_account_first: bool, ): - """Test warming of the authority and authorized accounts for set-code transactions.""" - # Overhead cost is the single push operation required for the address to check. + """ + Test warming of the authority and authorized accounts for set-code + transactions. + """ + # Overhead cost is the single push operation required for the address to + # check. overhead_cost = 3 * len(Op.CALL.kwargs) # type: ignore cold_account_cost = 2600 @@ -850,8 +904,8 @@ def test_account_warming( access_list_addresses = {access_list.address for access_list in access_list} - # Dictionary to keep track of the addresses to check for warming, and the expected cost of - # accessing such account. + # Dictionary to keep track of the addresses to check for warming, and the + # expected cost of accessing such account. addresses_to_check: Dict[Address, int] = {} for authorization_with_properties in authorization_list_with_properties: @@ -861,9 +915,9 @@ def test_account_warming( authority_contains_delegation_after_authorization = ( authorization_with_properties.invalidity_type is None - # If the authority already contained a delegation prior to the transaction, - # even if the authorization is invalid, there will be a delegation when we - # check the address. + # If the authority already contained a delegation prior to the + # transaction, even if the authorization is invalid, there will be + # a delegation when we check the address. or authorization_with_properties.authority_type == AddressType.EOA_WITH_SET_CODE ) @@ -896,8 +950,9 @@ def test_account_warming( ) if authority_contains_delegation_after_authorization: - # The double charge for accessing the delegated account, only if the - # account ends up with a delegation in its code. + # The double charge for accessing the delegated account, + # only if the account ends up with a delegation in its + # code. access_cost += warm_account_cost addresses_to_check[authority] = access_cost @@ -920,8 +975,8 @@ def test_account_warming( access_cost = warm_account_cost if ( - # We can only charge the delegated account access cost if the authorization - # went through + # We can only charge the delegated account access cost if + # the authorization went through authority_contains_delegation_after_authorization ): if ( @@ -999,8 +1054,8 @@ def test_intrinsic_gas_cost( valid: bool, ): """ - Test sending a transaction with the exact intrinsic gas required and also insufficient - gas. + Test sending a transaction with the exact intrinsic gas required and also + insufficient gas. """ # Calculate the intrinsic gas cost of the authorizations, by default the # full empty account cost is charged for each authorization. @@ -1097,7 +1152,9 @@ def test_call_to_pre_authorized_oog( fork: Fork, call_opcode: Op, ): - """Test additional cost of delegation contract access in call instructions.""" + """ + Test additional cost of delegation contract access in call instructions. + """ # Delegation contract. It should never be reached by a call. delegation_code = Op.SSTORE(0, 1) delegation = pre.deploy_contract(delegation_code) diff --git a/tests/prague/eip7702_set_code_tx/test_invalid_tx.py b/tests/prague/eip7702_set_code_tx/test_invalid_tx.py index 75067b08a9d..949bbed4a3d 100644 --- a/tests/prague/eip7702_set_code_tx/test_invalid_tx.py +++ b/tests/prague/eip7702_set_code_tx/test_invalid_tx.py @@ -1,7 +1,7 @@ """ -abstract: Tests invalid set-code transactions from [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702) - Tests invalid set-code transactions from [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). -""" # noqa: E501 +abstract: Tests invalid set-code transactions from [EIP-7702: Set EOA account +code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). +""" from enum import Enum, auto from typing import List, Type @@ -102,7 +102,10 @@ def test_invalid_auth_signature( s: int, delegate_address: Address, ): - """Test sending a transaction where one of the signature elements is out of range.""" + """ + Test sending a transaction where one of the signature elements is out of + range. + """ tx = Transaction( gas_limit=100_000, to=0, @@ -150,8 +153,8 @@ def test_invalid_tx_invalid_auth_chain_id( delegate_address: Address, ): """ - Test sending a transaction where the chain id field of an authorization overflows the - maximum value. + Test sending a transaction where the chain id field of an authorization + overflows the maximum value. """ authorization = AuthorizationTuple( address=delegate_address, @@ -193,8 +196,8 @@ def test_invalid_tx_invalid_auth_chain_id_encoding( auth_chain_id: int, ): """ - Test sending a transaction where the chain id field of an authorization has an incorrect - encoding. + Test sending a transaction where the chain id field of an authorization has + an incorrect encoding. """ class ModifiedAuthorizationTuple(AuthorizationTuple): @@ -243,8 +246,8 @@ def test_invalid_tx_invalid_nonce( delegate_address: Address, ): """ - Test sending a transaction where the nonce field of an authorization overflows the maximum - value. + Test sending a transaction where the nonce field of an authorization + overflows the maximum value. """ auth_signer = pre.fund_eoa() @@ -291,8 +294,8 @@ def test_invalid_tx_invalid_nonce_as_list( delegate_address: Address, ): """ - Test sending a transaction where the nonce field of an authorization overflows the maximum - value. + Test sending a transaction where the nonce field of an authorization + overflows the maximum value. """ auth_signer = pre.fund_eoa() @@ -333,8 +336,8 @@ def test_invalid_tx_invalid_nonce_encoding( delegate_address: Address, ): """ - Test sending a transaction where the chain id field of an authorization has an incorrect - encoding. + Test sending a transaction where the chain id field of an authorization has + an incorrect encoding. """ class ModifiedAuthorizationTuple(AuthorizationTuple): @@ -391,8 +394,8 @@ def test_invalid_tx_invalid_address( address_type: Type[FixedSizeBytes], ): """ - Test sending a transaction where the address field of an authorization is incorrectly - serialized. + Test sending a transaction where the address field of an authorization is + incorrectly serialized. """ auth_signer = pre.fund_eoa() @@ -435,8 +438,8 @@ def test_invalid_tx_invalid_authorization_tuple_extra_element( extra_element_value: int, ): """ - Test sending a transaction where the authorization tuple field of the type-4 transaction - is serialized to contain an extra element. + Test sending a transaction where the authorization tuple field of the + type-4 transaction is serialized to contain an extra element. """ auth_signer = pre.fund_eoa() @@ -444,7 +447,9 @@ class ExtraElementAuthorizationTuple(AuthorizationTuple): extra_element: HexNumber # type: ignore def get_rlp_fields(self) -> List[str]: - """Append the extra field to the list of fields to be encoded in RLP.""" + """ + Append the extra field to the list of fields to be encoded in RLP. + """ rlp_fields = super().get_rlp_fields()[:] rlp_fields.append("extra_element") return rlp_fields @@ -496,8 +501,8 @@ def test_invalid_tx_invalid_authorization_tuple_missing_element( missing_index: int, ): """ - Test sending a transaction where the authorization tuple field of the type-4 transaction - is serialized to miss one element. + Test sending a transaction where the authorization tuple field of the + type-4 transaction is serialized to miss one element. """ auth_signer = pre.fund_eoa() @@ -505,7 +510,9 @@ class MissingElementAuthorizationTuple(AuthorizationTuple): missing_element_index: int def get_rlp_fields(self) -> List[str]: - """Remove the field that is specified by the missing element index.""" + """ + Remove the field that is specified by the missing element index. + """ rlp_fields = super().get_rlp_fields()[:] rlp_fields.pop(self.missing_element_index) return rlp_fields @@ -545,8 +552,9 @@ def test_invalid_tx_invalid_authorization_tuple_encoded_as_bytes( delegate_address: Address, ): """ - Test sending a transaction where the authorization tuple field of the type-4 transaction - is encoded in the outer element as bytes instead of a list of elements. + Test sending a transaction where the authorization tuple field of the + type-4 transaction is encoded in the outer element as bytes instead of a + list of elements. """ class ModifiedTransaction(Transaction): @@ -595,8 +603,8 @@ def test_invalid_tx_invalid_rlp_encoding( invalid_rlp_mode: InvalidRLPMode, ): """ - Test sending a transaction type-4 where the RLP encoding of the transaction is - invalid. + Test sending a transaction type-4 where the RLP encoding of the transaction + is invalid. """ auth_signer = pre.fund_eoa() diff --git a/tests/prague/eip7702_set_code_tx/test_set_code_txs.py b/tests/prague/eip7702_set_code_tx/test_set_code_txs.py index 090fea22fb4..b076db62df9 100644 --- a/tests/prague/eip7702_set_code_tx/test_set_code_txs.py +++ b/tests/prague/eip7702_set_code_tx/test_set_code_txs.py @@ -1,7 +1,7 @@ """ -abstract: Tests use of set-code transactions from [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702) - Tests use of set-code transactions from [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). -""" # noqa: E501 +abstract: Tests use of set-code transactions from [EIP-7702: Set EOA account +code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). +""" from enum import StrEnum from hashlib import sha256 @@ -88,11 +88,11 @@ def test_self_sponsored_set_code( """ Test the executing a self-sponsored set-code transaction. - The transaction is sent to the sender, and the sender is the signer of the only authorization - tuple in the authorization list. + The transaction is sent to the sender, and the sender is the signer of the + only authorization tuple in the authorization list. - The authorization tuple has a nonce of 1 because the self-sponsored transaction increases the - nonce of the sender from zero to one first. + The authorization tuple has a nonce of 1 because the self-sponsored + transaction increases the nonce of the sender from zero to one first. The expected nonce at the end of the transaction is 2. """ @@ -268,7 +268,10 @@ def test_set_code_to_sstore_then_sload( blockchain_test: BlockchainTestFiller, pre: Alloc, ): - """Test the executing a simple SSTORE then SLOAD in two separate set-code transactions.""" + """ + Test the executing a simple SSTORE then SLOAD in two separate set-code + transactions. + """ auth_signer = pre.fund_eoa(auth_account_start_balance) sender = pre.fund_eoa() @@ -346,8 +349,8 @@ def test_set_code_to_tstore_reentry( evm_code_type: EVMCodeType, ): """ - Test the executing a simple TSTORE in a set-code transaction, which also performs a - re-entry to TLOAD the value. + Test the executing a simple TSTORE in a set-code transaction, which also + performs a re-entry to TLOAD the value. """ auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -403,9 +406,10 @@ def test_set_code_to_tstore_available_at_correct_address( call_eoa_first: bool, ): """ - Test TLOADing from slot 2 and then SSTORE this in slot 1, then TSTORE 3 in slot 2. - This is done both from the EOA which is delegated to account A, and then A is called. - The storage should stay empty on both the EOA and the delegated account. + Test TLOADing from slot 2 and then SSTORE this in slot 1, then TSTORE 3 in + slot 2. This is done both from the EOA which is delegated to account A, and + then A is called. The storage should stay empty on both the EOA and the + delegated account. """ auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -522,7 +526,9 @@ def test_set_code_to_contract_creator( create_opcode: Op, evm_code_type: EVMCodeType, ): - """Test the executing a contract-creating opcode in a set-code transaction.""" + """ + Test the executing a contract-creating opcode in a set-code transaction. + """ storage = Storage() auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -677,8 +683,8 @@ def test_set_code_max_depth_call_stack( fork: Fork, ): """ - Test re-entry to delegated account until the max call stack depth possible in a - transaction is reached. + Test re-entry to delegated account until the max call stack depth possible + in a transaction is reached. """ storage = Storage() auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -867,7 +873,10 @@ def test_tx_into_self_delegating_set_code( state_test: StateTestFiller, pre: Alloc, ): - """Test a transaction that has entry-point into a set-code account that delegates to itself.""" + """ + Test a transaction that has entry-point into a set-code account that + delegates to itself. + """ auth_signer = pre.fund_eoa(auth_account_start_balance) tx = Transaction( @@ -902,8 +911,8 @@ def test_tx_into_chain_delegating_set_code( pre: Alloc, ): """ - Test a transaction that has entry-point into a set-code account that delegates to another - set-code account. + Test a transaction that has entry-point into a set-code account that + delegates to another set-code account. """ auth_signer_1 = pre.fund_eoa(auth_account_start_balance) auth_signer_2 = pre.fund_eoa(auth_account_start_balance) @@ -994,7 +1003,10 @@ def test_call_into_chain_delegating_set_code( pre: Alloc, call_opcode: Op, ): - """Test call into a set-code account that delegates to another set-code account.""" + """ + Test call into a set-code account that delegates to another set-code + account. + """ auth_signer_1 = pre.fund_eoa(auth_account_start_balance) auth_signer_2 = pre.fund_eoa(auth_account_start_balance) @@ -1310,8 +1322,8 @@ def test_set_code_address_and_authority_warm_state_call_types( ): """ Test set to code address and authority warm status after a call to - authority address, or vice-versa, using all available call opcodes - without using `GAS` opcode (unavailable in EOF). + authority address, or vice-versa, using all available call opcodes without + using `GAS` opcode (unavailable in EOF). """ auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -1376,7 +1388,10 @@ def test_ext_code_on_self_delegating_set_code( pre: Alloc, balance: int, ): - """Test different ext*code operations on a set-code address that delegates to itself.""" + """ + Test different ext*code operations on a set-code address that delegates to + itself. + """ auth_signer = pre.fund_eoa(balance) slot = count(1) @@ -1438,8 +1453,8 @@ def test_ext_code_on_chain_delegating_set_code( pre: Alloc, ): """ - Test different ext*code operations on a set-code address that references another delegated - address. + Test different ext*code operations on a set-code address that references + another delegated address. """ auth_signer_1_balance = 1 auth_signer_2_balance = 0 @@ -1601,8 +1616,9 @@ def test_set_code_to_account_deployed_in_same_tx( evm_code_type: EVMCodeType, ): """ - Test setting the code of an account to an address that is deployed in the same transaction, - and test calling the set-code address and the deployed contract. + Test setting the code of an account to an address that is deployed in the + same transaction, and test calling the set-code address and the deployed + contract. """ auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -1720,9 +1736,9 @@ def test_set_code_to_self_destructing_account_deployed_in_same_tx( balance: int, ): """ - Test setting the code of an account to an account that contains the SELFDESTRUCT opcode and - was deployed in the same transaction, and test calling the set-code address and the deployed - in both sequence orders. + Test setting the code of an account to an account that contains the + SELFDESTRUCT opcode and was deployed in the same transaction, and test + calling the set-code address and the deployed in both sequence orders. """ auth_signer = pre.fund_eoa(balance) if external_sendall_recipient: @@ -1818,8 +1834,8 @@ def test_set_code_multiple_first_valid_authorization_tuples_same_signer( pre: Alloc, ): """ - Test setting the code of an account with multiple authorization tuples - from the same signer. + Test setting the code of an account with multiple authorization tuples from + the same signer. """ auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -1866,8 +1882,9 @@ def test_set_code_multiple_valid_authorization_tuples_same_signer_increasing_non pre: Alloc, ): """ - Test setting the code of an account with multiple authorization tuples from the same signer - and each authorization tuple has an increasing nonce, therefore the last tuple is executed. + Test setting the code of an account with multiple authorization tuples from + the same signer and each authorization tuple has an increasing nonce, + therefore the last tuple is executed. """ auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -1914,9 +1931,10 @@ def test_set_code_multiple_valid_authorization_tuples_same_signer_increasing_non pre: Alloc, ): """ - Test setting the code of an account with multiple authorization tuples from the same signer - and each authorization tuple has an increasing nonce, therefore the last tuple is executed, - and the transaction is self-sponsored. + Test setting the code of an account with multiple authorization tuples from + the same signer and each authorization tuple has an increasing nonce, + therefore the last tuple is executed, and the transaction is + self-sponsored. """ auth_signer = pre.fund_eoa() @@ -1962,8 +1980,8 @@ def test_set_code_multiple_valid_authorization_tuples_first_invalid_same_signer( pre: Alloc, ): """ - Test setting the code of an account with multiple authorization tuples from the same signer - but the first tuple is invalid. + Test setting the code of an account with multiple authorization tuples from + the same signer but the first tuple is invalid. """ auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -2010,8 +2028,8 @@ def test_set_code_all_invalid_authorization_tuples( pre: Alloc, ): """ - Test setting the code of an account with multiple authorization tuples from the same signer - and all of them are invalid. + Test setting the code of an account with multiple authorization tuples from + the same signer and all of them are invalid. """ auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -2050,7 +2068,10 @@ def test_set_code_using_chain_specific_id( pre: Alloc, chain_config: ChainConfig, ): - """Test sending a transaction to set the code of an account using a chain-specific ID.""" + """ + Test sending a transaction to set the code of an account using a + chain-specific ID. + """ auth_signer = pre.fund_eoa(auth_account_start_balance) success_slot = 1 @@ -2113,7 +2134,10 @@ def test_set_code_using_valid_synthetic_signatures( r: int, s: int, ): - """Test sending a transaction to set the code of an account using synthetic signatures.""" + """ + Test sending a transaction to set the code of an account using synthetic + signatures. + """ success_slot = 1 set_code = Op.SSTORE(success_slot, 1) + Op.STOP @@ -2162,8 +2186,10 @@ def test_set_code_using_valid_synthetic_signatures( pytest.param(2, 1, 1, id="v=2"), pytest.param(27, 1, 1, id="v=27"), # Type-0 transaction valid value pytest.param(28, 1, 1, id="v=28"), # Type-0 transaction valid value - pytest.param(35, 1, 1, id="v=35"), # Type-0 replay-protected transaction valid value - pytest.param(36, 1, 1, id="v=36"), # Type-0 replay-protected transaction valid value + pytest.param(35, 1, 1, id="v=35"), # Type-0 replay-protected + # transaction valid value + pytest.param(36, 1, 1, id="v=36"), # Type-0 replay-protected + # transaction valid value pytest.param(2**8 - 1, 1, 1, id="v=2**8-1"), # R pytest.param(1, 0, 1, id="r=0"), @@ -2194,8 +2220,9 @@ def test_valid_tx_invalid_auth_signature( s: int, ): """ - Test sending a transaction to set the code of an account using synthetic signatures, - the transaction is valid but the authorization should not go through. + Test sending a transaction to set the code of an account using synthetic + signatures, the transaction is valid but the authorization should not go + through. """ success_slot = 1 @@ -2237,8 +2264,9 @@ def test_signature_s_out_of_range( chain_config: ChainConfig, ): """ - Test sending a transaction with an authorization tuple where the signature s value is out of - range by modifying its value to be `SECP256K1N - S` and flipping the v value. + Test sending a transaction with an authorization tuple where the signature + s value is out of range by modifying its value to be `SECP256K1N - S` and + flipping the v value. """ auth_signer = pre.fund_eoa(0) @@ -2309,8 +2337,8 @@ def test_valid_tx_invalid_chain_id( invalid_chain_id_case: InvalidChainID, ): """ - Test sending a transaction where the chain id field does not match - the current chain's id. + Test sending a transaction where the chain id field does not match the + current chain's id. """ auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -2405,11 +2433,11 @@ def test_nonce_validity( authorization_nonce: int, ): """ - Test sending a transaction where the nonce field of an authorization almost overflows the - maximum value. + Test sending a transaction where the nonce field of an authorization almost + overflows the maximum value. - Also test calling the account of the authorization signer in order to verify that the account - is not warm. + Also test calling the account of the authorization signer in order to + verify that the account is not warm. """ auth_signer = pre.fund_eoa(auth_account_start_balance, nonce=account_nonce) @@ -2470,8 +2498,8 @@ def test_nonce_overflow_after_first_authorization( pre: Alloc, ): """ - Test sending a transaction with two authorization where the first one bumps the nonce - to 2**64-1 and the second would result in overflow. + Test sending a transaction with two authorization where the first one bumps + the nonce to 2**64-1 and the second would result in overflow. """ nonce = 2**64 - 2 auth_signer = pre.fund_eoa(auth_account_start_balance, nonce=nonce) @@ -2547,7 +2575,10 @@ def test_set_code_to_log( pre: Alloc, log_opcode: Op, ): - """Test setting the code of an account to a contract that performs the log operation.""" + """ + Test setting the code of an account to a contract that performs the log + operation. + """ sender = pre.fund_eoa() log_kwargs = {} @@ -2604,8 +2635,8 @@ def test_set_code_to_precompile( call_opcode: Op, ): """ - Test setting the code of an account to a pre-compile address and executing all call - opcodes. + Test setting the code of an account to a pre-compile address and executing + all call opcodes. """ auth_signer = pre.fund_eoa(auth_account_start_balance) @@ -2663,8 +2694,8 @@ def test_set_code_to_precompile_not_enough_gas_for_precompile_execution( precompile: int, ): """ - Test set code to precompile and making direct call in same transaction with intrinsic gas - only, no extra gas for precompile execution. + Test set code to precompile and making direct call in same transaction with + intrinsic gas only, no extra gas for precompile execution. """ auth_signer = pre.fund_eoa(amount=1) auth = AuthorizationTuple(address=Address(precompile), nonce=0, signer=auth_signer) @@ -2738,10 +2769,12 @@ def test_set_code_to_system_contract( call_value = 0 - # Setup the initial storage of the account to mimic the system contract if required + # Setup the initial storage of the account to mimic the system contract if + # required match system_contract: case Address(0x00000000219AB540356CBB839CBE05303D7705FA): # EIP-6110 - # Deposit contract needs specific storage values, so we set them on the account + # Deposit contract needs specific storage values, so we set them on + # the account auth_signer = pre.fund_eoa( auth_account_start_balance, storage=deposit_contract_initial_storage() ) @@ -2788,8 +2821,8 @@ def test_set_code_to_system_contract( caller_payload = consolidation_request.calldata call_value = consolidation_request.value case Address(0x0000F90827F1C53A10CB7A02335B175320002935): # EIP-2935 - # This payload is used to identify the number of blocks to be subtracted from the - # latest block number + # This payload is used to identify the number of blocks to be + # subtracted from the latest block number caller_payload = Hash(1) caller_code_storage[call_return_data_size_slot] = 32 case _: @@ -2798,8 +2831,8 @@ def test_set_code_to_system_contract( # Setup the code to call the system contract match system_contract: case Address(0x0000F90827F1C53A10CB7A02335B175320002935): # EIP-2935 - # Do a trick here to get the block number of the penultimate block to ensure it is - # saved in the history contract + # Do a trick here to get the block number of the penultimate block + # to ensure it is saved in the history contract check_block_number = Op.SUB(Op.NUMBER, Op.CALLDATALOAD(0)) call_system_contract_code = Op.MSTORE(0, check_block_number) + Op.SSTORE( call_return_code_slot, @@ -2844,7 +2877,8 @@ def test_set_code_to_system_contract( blocks=[ Block( txs=txs, - requests_hash=Requests(), # Verify nothing slipped into the requests trie + requests_hash=Requests(), # Verify nothing slipped into the + # requests trie ) ], post={ @@ -2885,7 +2919,10 @@ def test_eoa_tx_after_set_code( evm_code_type: EVMCodeType, same_block: bool, ): - """Test sending a transaction from an EOA after code has been set to the account.""" + """ + Test sending a transaction from an EOA after code has been set to the + account. + """ auth_signer = pre.fund_eoa() set_code = Op.SSTORE(1, Op.ADD(Op.SLOAD(1), 1)) + Op.STOP @@ -3145,12 +3182,13 @@ def test_delegation_clearing( self_sponsored: bool, ): """ - Test clearing the delegation of an account under a variety of circumstances. - - - pre_set_delegation_code: The code to set on the account before clearing delegation, or None - if the account should not have any code set. - - self_sponsored: Whether the delegation clearing transaction is self-sponsored. + Test clearing the delegation of an account under a variety of + circumstances. + - pre_set_delegation_code: The code to set on the account before clearing + delegation, or None if the account should not have any code set. - + self_sponsored: Whether the delegation clearing transaction is + self-sponsored. """ # noqa: D417 pre_set_delegation_address: Address | None = None if pre_set_delegation_code is not None: @@ -3238,10 +3276,10 @@ def test_delegation_clearing_tx_to( """ Tests directly calling the account which delegation is being cleared. - - pre_set_delegation_code: The code to set on the account before clearing delegation, or None - if the account should not have any code set. - - self_sponsored: Whether the delegation clearing transaction is self-sponsored. - + - pre_set_delegation_code: The code to set on the account before clearing + delegation, or None if the account should not have any code set. - + self_sponsored: Whether the delegation clearing transaction is + self-sponsored. """ # noqa: D417 pre_set_delegation_address: Address | None = None if pre_set_delegation_code is not None: @@ -3295,11 +3333,11 @@ def test_delegation_clearing_and_set( pre_set_delegation_code: Bytecode | None, ): """ - Tests clearing and setting the delegation again in the same authorization list. - - - pre_set_delegation_code: The code to set on the account before clearing delegation, or None - if the account should not have any code set. + Tests clearing and setting the delegation again in the same authorization + list. + - pre_set_delegation_code: The code to set on the account before clearing + delegation, or None if the account should not have any code set. """ # noqa: D417 pre_set_delegation_address: Address | None = None if pre_set_delegation_code is not None: @@ -3361,7 +3399,10 @@ def test_delegation_clearing_failing_tx( pre: Alloc, entry_code: Bytecode, ): - """Test clearing the delegation of an account in a transaction that fails, OOGs or reverts.""" # noqa: D417 + """ + Test clearing the delegation of an account in a transaction that fails, + OOGs or reverts. + """ # noqa: D417 pre_set_delegation_code = Op.RETURN(0, 1) pre_set_delegation_address = pre.deploy_contract(pre_set_delegation_code) @@ -3459,8 +3500,8 @@ def test_creating_delegation_designation_contract( initcode_is_delegation_designation: bool, ): """ - Tx -> create -> pointer bytecode - Attempt to deploy contract with magic bytes result in no contract being created. + Tx -> create -> pointer bytecode Attempt to deploy contract with magic + bytes result in no contract being created. """ env = Environment() @@ -3522,14 +3563,16 @@ def test_many_delegations( signer_balance: int, ): """ - Perform as many delegations as possible in a transaction using the entire block gas limit. + Perform as many delegations as possible in a transaction using the entire + block gas limit. Every delegation comes from a different signer. - The account of can be empty or not depending on the `signer_balance` parameter. + The account of can be empty or not depending on the `signer_balance` + parameter. - The transaction is expected to succeed and the state after the transaction is expected to have - the code of the entry contract set to 1. + The transaction is expected to succeed and the state after the transaction + is expected to have the code of the entry contract set to 1. """ env = Environment() tx_gas_limit_cap = fork.transaction_gas_limit_cap() @@ -3587,8 +3630,8 @@ def test_invalid_transaction_after_authorization( pre: Alloc, ): """ - Test an invalid block due to a transaction reusing the same nonce as an authorization - included in a prior transaction. + Test an invalid block due to a transaction reusing the same nonce as an + authorization included in a prior transaction. """ auth_signer = pre.fund_eoa() recipient = pre.fund_eoa(amount=0) @@ -3636,8 +3679,8 @@ def test_authorization_reusing_nonce( pre: Alloc, ): """ - Test an authorization reusing the same nonce as a prior transaction included in the same - block. + Test an authorization reusing the same nonce as a prior transaction + included in the same block. """ auth_signer = pre.fund_eoa() sender = pre.fund_eoa() @@ -3694,12 +3737,12 @@ def test_set_code_from_account_with_non_delegating_code( self_sponsored: bool, ): """ - Test that a transaction is correctly rejected, - if the sender account has a non-delegating code set. + Test that a transaction is correctly rejected, if the sender account has a + non-delegating code set. - The auth transaction is sent from sender which has contract code (not delegating) - But at the same time it has auth tuple that will point this sender account - To be eoa, delegation, contract .. etc + The auth transaction is sent from sender which has contract code (not + delegating) But at the same time it has auth tuple that will point this + sender account To be eoa, delegation, contract .. etc """ sender = pre.fund_eoa(nonce=1) random_address = pre.fund_eoa(0) @@ -3719,7 +3762,8 @@ def test_set_code_from_account_with_non_delegating_code( raise ValueError(f"Unsupported set code type: {set_code_type}") callee_address = pre.deploy_contract(Op.SSTORE(0, 1) + Op.STOP) - # Set the sender account to have some code, that is specifically not a delegation. + # Set the sender account to have some code, that is specifically not a + # delegation. sender_account = pre[sender] assert sender_account is not None sender_account.code = Bytes(Op.STOP) @@ -3781,7 +3825,9 @@ def test_set_code_transaction_fee_validations( max_priority_fee_per_gas: int, expected_error: TransactionException, ): - """Test that a transaction with an insufficient max fee per gas is rejected.""" + """ + Test that a transaction with an insufficient max fee per gas is rejected. + """ set_to_code = pre.deploy_contract(Op.STOP) auth_signer = pre.fund_eoa(amount=0) tx = Transaction( diff --git a/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py b/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py index e6a622246e2..ba34205e9d1 100644 --- a/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py +++ b/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py @@ -40,8 +40,8 @@ def test_pointer_contract_pointer_loop(state_test: StateTestFiller, pre: Alloc): """ Tx -> call -> pointer A -> contract A -> pointer B -> contract loop C. - Call pointer that goes more level of depth to call a contract loop - Loop is created only if pointers are set with auth tuples + Call pointer that goes more level of depth to call a contract loop Loop is + created only if pointers are set with auth tuples """ env = Environment() @@ -137,8 +137,8 @@ def test_pointer_to_pointer(state_test: StateTestFiller, pre: Alloc): @pytest.mark.valid_from("Prague") def test_pointer_normal(blockchain_test: BlockchainTestFiller, pre: Alloc): """ - Tx -> call -> pointer A -> contract - Other normal tx can interact with previously assigned pointers. + Tx -> call -> pointer A -> contract Other normal tx can interact with + previously assigned pointers. """ env = Environment() @@ -197,9 +197,9 @@ def test_pointer_normal(blockchain_test: BlockchainTestFiller, pre: Alloc): @pytest.mark.valid_from("Prague") def test_pointer_measurements(blockchain_test: BlockchainTestFiller, pre: Alloc): """ - Check extcode* operations on pointer before and after pointer is set - Check context opcode results when called under pointer call - Opcodes have context of an original pointer account (balance, storage). + Check extcode* operations on pointer before and after pointer is set Check + context opcode results when called under pointer call Opcodes have context + of an original pointer account (balance, storage). """ env = Environment() @@ -208,7 +208,8 @@ def test_pointer_measurements(blockchain_test: BlockchainTestFiller, pre: Alloc) storage_normal: Storage = Storage() storage_pointer: Storage = Storage() - storage_pointer_code: Storage = Storage() # this storage will be applied to pointer address + storage_pointer_code: Storage = Storage() # this storage will be applied + # to pointer address pointer_code = pre.deploy_contract( balance=200, code=Op.SSTORE(storage_pointer_code.store_next(pointer, "address"), Op.ADDRESS()) @@ -327,9 +328,9 @@ def test_call_to_precompile_in_pointer_context( state_test: StateTestFiller, pre: Alloc, precompile: int ): """ - Tx -> call -> pointer A -> precompile contract - Make sure that gas consumed when calling precompiles in normal call are the same - As from inside the pointer context call. + Tx -> call -> pointer A -> precompile contract Make sure that gas consumed + when calling precompiles in normal call are the same As from inside the + pointer context call. """ env = Environment() @@ -400,11 +401,13 @@ def test_pointer_to_precompile(state_test: StateTestFiller, pre: Alloc, precompi """ Tx -> call -> pointer A -> precompile contract. - In case a delegation designator points to a precompile address, retrieved code is considered - empty and CALL, CALLCODE, STATICCALL, DELEGATECALL instructions targeting this account will - execute empty code, i.e. succeed with no execution given enough gas. + In case a delegation designator points to a precompile address, retrieved + code is considered empty and CALL, CALLCODE, STATICCALL, DELEGATECALL + instructions targeting this account will execute empty code, i.e. succeed + with no execution given enough gas. - So call to a pointer that points to a precompile is like call to an empty account + So call to a pointer that points to a precompile is like call to an empty + account """ env = Environment() @@ -440,7 +443,8 @@ def test_pointer_to_precompile(state_test: StateTestFiller, pre: Alloc, precompi ret_offset=1000, ret_size=32, ) - # pointer call to a precompile with 0 gas always return 1 as if calling empty address + # pointer call to a precompile with 0 gas always return 1 as if calling + # empty address + Op.SSTORE(storage.store_next(1, "pointer_call_result"), Op.MLOAD(1000)) ) @@ -727,9 +731,9 @@ def test_pointer_call_followed_by_direct_call( ): """ If we first call by pointer then direct call, will the call/sload be hot - The direct call will warm because pointer access marks it warm - But the sload is still cold because - storage marked hot from pointer's account in a pointer call. + The direct call will warm because pointer access marks it warm But the + sload is still cold because storage marked hot from pointer's account in a + pointer call. """ env = Environment() @@ -747,8 +751,10 @@ def test_pointer_call_followed_by_direct_call( ) direct_call_gas = ( gas_costs.G_STORAGE_SET - + gas_costs.G_WARM_ACCOUNT_ACCESS # since previous pointer call, contract is now warm - + gas_costs.G_COLD_SLOAD # but storage is cold, because it's contract's direct + + gas_costs.G_WARM_ACCOUNT_ACCESS # since previous pointer call, + # contract is now warm + + gas_costs.G_COLD_SLOAD # but storage is cold, because it's + # contract's direct + opcodes_price ) @@ -803,8 +809,8 @@ def test_pointer_call_followed_by_direct_call( @pytest.mark.valid_from("Prague") def test_pointer_to_static(state_test: StateTestFiller, pre: Alloc): """ - Tx -> call -> pointer A -> static -> static violation - Verify that static context is active when called under pointer. + Tx -> call -> pointer A -> static -> static violation Verify that static + context is active when called under pointer. """ env = Environment() storage: Storage = Storage() @@ -849,8 +855,8 @@ def test_pointer_to_static(state_test: StateTestFiller, pre: Alloc): @pytest.mark.valid_from("Prague") def test_static_to_pointer(state_test: StateTestFiller, pre: Alloc): """ - Tx -> staticcall -> pointer A -> static violation - Verify that static context is active when make sub call to pointer. + Tx -> staticcall -> pointer A -> static violation Verify that static + context is active when make sub call to pointer. """ env = Environment() storage: Storage = Storage() @@ -894,10 +900,7 @@ def test_static_to_pointer(state_test: StateTestFiller, pre: Alloc): @pytest.mark.valid_from("EOFv1") def test_pointer_to_eof(state_test: StateTestFiller, pre: Alloc): - """ - Tx -> call -> pointer A -> EOF - Pointer to eof contract works. - """ + """Tx -> call -> pointer A -> EOF Pointer to eof contract works.""" env = Environment() storage: Storage = Storage() sender = pre.fund_eoa() @@ -1013,8 +1016,9 @@ def test_contract_storage_to_pointer_with_storage( state_test: StateTestFiller, pre: Alloc, call_type: Op ): """ - Tx call -> contract with storage -> pointer A with storage -> storage/tstorage modify - Check storage/tstorage modifications when interacting with pointers. + Tx call -> contract with storage -> pointer A with storage -> + storage/tstorage modify Check storage/tstorage modifications when + interacting with pointers. """ env = Environment() @@ -1056,18 +1060,21 @@ def test_contract_storage_to_pointer_with_storage( code=Op.TSTORE(third_slot, 1) + call_type(address=pointer_b, gas=500_000) + Op.SSTORE(third_slot, Op.TLOAD(third_slot)) - # Verify tstorage in contract after interacting with pointer, it must be 0 + # Verify tstorage in contract after interacting with pointer, it must + # be 0 + Op.MSTORE(0, 1) + Op.CALL(address=contract_b, gas=500_000, args_offset=0, args_size=32), storage={ storage_a.store_next( - # caller storage is modified when calling pointer with delegate or callcode + # caller storage is modified when calling pointer with delegate + # or callcode 6 if call_type in [Op.DELEGATECALL, Op.CALLCODE] else 5, "first_slot", ): 5, storage_a.store_next(2, "second_slot"): 2, storage_a.store_next( - # TSTORE is modified when calling pointer with delegate or callcode + # TSTORE is modified when calling pointer with delegate or + # callcode 2 if call_type in [Op.DELEGATECALL, Op.CALLCODE] else 1, "third_slot", ): 3, @@ -1113,8 +1120,8 @@ class ReentryAction(IntEnum): @pytest.mark.valid_from("Prague") def test_pointer_reentry(state_test: StateTestFiller, pre: Alloc): """ - Check operations when reenter the pointer again - TODO: feel free to extend the code checks under given scenarios in switch case. + Check operations when reenter the pointer again TODO: feel free to extend + the code checks under given scenarios in switch case. """ env = Environment() arg_contract = 0 @@ -1152,7 +1159,8 @@ def test_pointer_reentry(state_test: StateTestFiller, pre: Alloc): + Op.STOP(), ), Case( - # This code is executed under pointer -> proxy -> pointer context + # This code is executed under pointer -> proxy -> pointer + # context condition=Op.EQ(Op.MLOAD(arg_action), ReentryAction.MEASURE_VALUES), action=Op.SSTORE(storage_pointer_b.store_next(sender, "origin"), Op.ORIGIN()) + Op.SSTORE(storage_pointer_b.store_next(pointer_b, "address"), Op.ADDRESS()) @@ -1170,9 +1178,9 @@ def test_pointer_reentry(state_test: StateTestFiller, pre: Alloc): ), ), Case( - # This code is executed under - # pointer -> proxy -> pointer -> contract - # so pointer calling the code of it's dest after reentry to itself + # This code is executed under pointer -> proxy -> pointer + # -> contract so pointer calling the code of it's dest + # after reentry to itself condition=Op.EQ(Op.MLOAD(arg_action), ReentryAction.MEASURE_VALUES_CONTRACT), action=Op.SSTORE(storage_b.store_next(sender, "origin"), Op.ORIGIN()) + Op.SSTORE(slot_reentry_address, Op.ADDRESS()) @@ -1216,9 +1224,9 @@ def test_pointer_reentry(state_test: StateTestFiller, pre: Alloc): @pytest.mark.valid_from("Prague") def test_eoa_init_as_pointer(state_test: StateTestFiller, pre: Alloc): """ - It was agreed before that senders don't have code - And there were issues with tests sending transactions from account's with code - With EIP7702 it is again possible, let's check the test runners are ok. + It was agreed before that senders don't have code And there were issues + with tests sending transactions from account's with code With EIP7702 it is + again possible, let's check the test runners are ok. """ env = Environment() storage = Storage() @@ -1249,13 +1257,14 @@ def test_call_pointer_to_created_from_create_after_oog_call_again( """ Set pointer to account that we are about to create. - Pointer is set to create address that is yet not in the state - During the call, address is created. pointer is called from init code to do nothing + Pointer is set to create address that is yet not in the state During the + call, address is created. pointer is called from init code to do nothing Then after account is created it is called again to run created code Then revert / no revert - Call pointer again from the upper level to ensure it does not call reverted code + Call pointer again from the upper level to ensure it does not call reverted + code """ env = Environment() @@ -1544,10 +1553,10 @@ def test_pointer_resets_an_empty_code_account_with_storage( pre: Alloc, ): """ - So in Block1 we create a sender with empty code, but non empty storage using pointers - In Block2 we create account that perform suicide, then we check that when calling - a pointer, that points to newly created account and runs suicide, - is not deleted as well as its storage. + So in Block1 we create a sender with empty code, but non empty storage + using pointers In Block2 we create account that perform suicide, then we + check that when calling a pointer, that points to newly created account and + runs suicide, is not deleted as well as its storage. This one is a little messy. """ @@ -1622,9 +1631,9 @@ def test_pointer_resets_an_empty_code_account_with_storage( sender=sender, ) - # Block 2 - # Sender with storage and pointer code calling selfdestruct on itself - # But it points to a newly created account, check that pointer storage is not deleted + # Block 2 Sender with storage and pointer code calling selfdestruct on + # itself But it points to a newly created account, check that pointer + # storage is not deleted suicide_dest = pre.fund_eoa(amount=0) deploy_code = Op.SSTORE(5, 5) + Op.SELFDESTRUCT(suicide_dest) sender_storage[5] = 5 @@ -1637,7 +1646,8 @@ def test_pointer_resets_an_empty_code_account_with_storage( + Op.SSTORE(1, Op.CREATE(0, 0, Op.CALLDATASIZE())) + Op.CALL(address=sender) # run suicide from pointer + Op.CALL(address=Op.SLOAD(1)) # run suicide directly - + Op.CALL(address=another_pointer) # run suicide from pointer that is not sender + + Op.CALL(address=another_pointer) # run suicide from pointer that is + # not sender ) newly_created_address = compute_create_address(address=contract_create, nonce=1) @@ -1678,10 +1688,9 @@ def test_pointer_resets_an_empty_code_account_with_storage( pre=pre, post=post, blocks=[ - # post = { - # pointer: Account(nonce=2, balance=0, storage=pointer_storage, code=bytes()), - # sender: Account(storage=pointer_storage, code=bytes()), - # } + # post = { pointer: Account(nonce=2, balance=0, + # storage=pointer_storage, code=bytes()), sender: + # Account(storage=pointer_storage, code=bytes()), } Block( txs=[ tx_set_pointer_storage, @@ -1710,7 +1719,8 @@ def test_set_code_type_tx_pre_fork( Reject blocks with set code type transactions before the Prague fork. This test was based on: - tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_self_sponsored_set_code + tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_self_sponsored_set_ + code """ storage = Storage() sender = pre.fund_eoa() @@ -1763,9 +1773,9 @@ def test_delegation_replacement_call_previous_contract( fork: Fork, ): """ - Test setting the code of an EOA that already has - delegation, calling the previous delegated contract. - Previous contract shouldn't be warm when doing the CALL. + Test setting the code of an EOA that already has delegation, calling the + previous delegated contract. Previous contract shouldn't be warm when doing + the CALL. """ pre_set_delegation_code = Op.STOP pre_set_delegation_address = pre.deploy_contract(pre_set_delegation_code) diff --git a/tests/shanghai/eip3855_push0/test_push0.py b/tests/shanghai/eip3855_push0/test_push0.py index c490d0d8fa1..de3ec5064c9 100644 --- a/tests/shanghai/eip3855_push0/test_push0.py +++ b/tests/shanghai/eip3855_push0/test_push0.py @@ -1,9 +1,10 @@ """ -abstract: Tests [EIP-3855: PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855) - Tests for [EIP-3855: PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855). +abstract: Tests [EIP-3855: PUSH0 +Instruction](https://eips.ethereum.org/EIPS/eip-3855) Tests for [EIP-3855: +PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855). -note: Tests ported from: - - [ethereum/tests/pull/1033](https://github.com/ethereum/tests/pull/1033). +note: Tests ported from: - +[ethereum/tests/pull/1033](https://github.com/ethereum/tests/pull/1033). """ import pytest @@ -92,16 +93,15 @@ def test_push0_contracts( class TestPush0CallContext: """ - Tests the PUSH0 operation during various call contexts including: - - CALL - - CALLCODE - - DELEGATECALL - - STATICCALL. + Tests the PUSH0 operation during various call contexts including: - CALL - + CALLCODE - DELEGATECALL - STATICCALL. """ @pytest.fixture def push0_contract_callee(self, pre: Alloc) -> Address: - """Deploys a PUSH0 contract callee to the pre alloc returning its address.""" + """ + Deploys a PUSH0 contract callee to the pre alloc returning its address. + """ push0_contract = pre.deploy_contract(Op.MSTORE8(Op.PUSH0, 0xFF) + Op.RETURN(Op.PUSH0, 1)) return push0_contract diff --git a/tests/shanghai/eip3860_initcode/test_initcode.py b/tests/shanghai/eip3860_initcode/test_initcode.py index 1b52b29b039..7eaf1c39a63 100644 --- a/tests/shanghai/eip3860_initcode/test_initcode.py +++ b/tests/shanghai/eip3860_initcode/test_initcode.py @@ -1,10 +1,11 @@ """ -abstract: Test [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860) - Tests for [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860). +abstract: Test [EIP-3860: Limit and meter +initcode](https://eips.ethereum.org/EIPS/eip-3860) Tests for [EIP-3860: Limit +and meter initcode](https://eips.ethereum.org/EIPS/eip-3860). -note: Tests ported from: - - [ethereum/tests/pull/990](https://github.com/ethereum/tests/pull/990) - - [ethereum/tests/pull/1012](https://github.com/ethereum/tests/pull/990) +note: Tests ported from: - +[ethereum/tests/pull/990](https://github.com/ethereum/tests/pull/990) - +[ethereum/tests/pull/1012](https://github.com/ethereum/tests/pull/990) """ from typing import List @@ -39,9 +40,7 @@ pytestmark = pytest.mark.valid_from("Shanghai") -""" -Initcode templates used throughout the tests -""" +"""Initcode templates used throughout the tests""" INITCODE_ONES_MAX_LIMIT = Initcode( deploy_code=INITCODE_RESULTING_DEPLOYED_CODE, initcode_length=Spec.MAX_INITCODE_SIZE, @@ -112,9 +111,7 @@ SINGLE_BYTE_INITCODE.deployment_gas = 0 SINGLE_BYTE_INITCODE.execution_gas = 0 -""" -Test cases using a contract creating transaction -""" +"""Test cases using a contract creating transaction""" @pytest.mark.xdist_group(name="bigmem") @@ -209,16 +206,14 @@ def valid_gas_test_case(initcode: Initcode, gas_test_case: str) -> bool: ) class TestContractCreationGasUsage: """ - Tests the following cases that verify the gas cost behavior of a - contract creating transaction. + Tests the following cases that verify the gas cost behavior of a contract + creating transaction. - 1. Test with exact intrinsic gas minus one, contract create fails - and tx is invalid. - 2. Test with exact intrinsic gas, contract create fails, - but tx is valid. - 3. Test with exact execution gas minus one, contract create fails, - but tx is valid. - 4. Test with exact execution gas, contract create succeeds. + 1. Test with exact intrinsic gas minus one, contract create fails and tx is + invalid. 2. Test with exact intrinsic gas, contract create fails, but tx is + valid. 3. Test with exact execution gas minus one, contract create fails, + but tx is valid. 4. Test with exact execution gas, contract create + succeeds. Initcode must be within a valid EIP-3860 length. """ @@ -226,8 +221,8 @@ class TestContractCreationGasUsage: @pytest.fixture def tx_access_list(self) -> List[AccessList]: """ - On EIP-7623, we need to use an access list to raise the intrinsic gas cost to - be above the floor data cost. + On EIP-7623, we need to use an access list to raise the intrinsic gas + cost to be above the floor data cost. """ return [AccessList(address=Address(i), storage_keys=[]) for i in range(1, 478)] @@ -341,7 +336,10 @@ def test_gas_usage( post: Alloc, tx: Transaction, ): - """Test transaction and contract creation behavior for different gas limits.""" + """ + Test transaction and contract creation behavior for different gas + limits. + """ state_test( env=env, pre=pre, @@ -380,7 +378,10 @@ def create2_salt(self) -> int: @pytest.fixture def creator_code(self, opcode: Op, create2_salt: int) -> Bytecode: - """Generate code for the creator contract which performs the CREATE/CREATE2 operation.""" + """ + Generate code for the creator contract which performs the + CREATE/CREATE2 operation. + """ return ( Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE) + Op.GAS @@ -415,7 +416,9 @@ def created_contract_address( # noqa: D103 initcode: Initcode, creator_contract_address: Address, ) -> Address: - """Calculate address of the contract created by the creator contract.""" + """ + Calculate address of the contract created by the creator contract. + """ return compute_create_address( address=creator_contract_address, nonce=1, @@ -426,7 +429,9 @@ def created_contract_address( # noqa: D103 @pytest.fixture def caller_code(self, creator_contract_address: Address) -> Bytecode: - """Generate code for the caller contract that calls the creator contract.""" + """ + Generate code for the caller contract that calls the creator contract. + """ return Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE) + Op.SSTORE( Op.CALL(5000000, creator_contract_address, 0, 0, Op.CALLDATASIZE, 0, 0), 1 ) diff --git a/tests/shanghai/eip3860_initcode/test_with_eof.py b/tests/shanghai/eip3860_initcode/test_with_eof.py index 433ba31d9fe..2dab4405b7f 100644 --- a/tests/shanghai/eip3860_initcode/test_with_eof.py +++ b/tests/shanghai/eip3860_initcode/test_with_eof.py @@ -1,4 +1,7 @@ -"""Tests interaction between edge case size CREATE / CREATE2 and EOF, including EIP-3860 limits.""" +""" +Tests interaction between edge case size CREATE / CREATE2 and EOF, including +EIP-3860 limits. +""" import itertools @@ -54,9 +57,10 @@ def test_legacy_create_edge_code_size( init_code: Bytecode, ): """ - Verifies that legacy initcode/deploycode having 0 or max size continues to work in the fork - where EOF is enabled. Handling of EOF magic prefix and version interferes with the handling - of legacy creation, so a specific test was proposed to test behavior doesn't change. + Verifies that legacy initcode/deploycode having 0 or max size continues to + work in the fork where EOF is enabled. Handling of EOF magic prefix and + version interferes with the handling of legacy creation, so a specific test + was proposed to test behavior doesn't change. """ env = Environment() diff --git a/tests/shanghai/eip4895_withdrawals/test_withdrawals.py b/tests/shanghai/eip4895_withdrawals/test_withdrawals.py index 44bbbeb9021..fbba806926f 100644 --- a/tests/shanghai/eip4895_withdrawals/test_withdrawals.py +++ b/tests/shanghai/eip4895_withdrawals/test_withdrawals.py @@ -1,7 +1,8 @@ """ -abstract: Tests [EIP-4895: Beacon chain withdrawals](https://eips.ethereum.org/EIPS/eip-4895) - Test cases for [EIP-4895: Beacon chain push withdrawals as - operations](https://eips.ethereum.org/EIPS/eip-4895). +abstract: Tests [EIP-4895: Beacon chain +withdrawals](https://eips.ethereum.org/EIPS/eip-4895) Test cases for [EIP-4895: +Beacon chain push withdrawals as +operations](https://eips.ethereum.org/EIPS/eip-4895). """ from enum import Enum, unique @@ -50,11 +51,11 @@ class TestUseValueInTx: """ Test that the value from a withdrawal can be used in a transaction. - 1. `tx_in_withdrawals_block`: Test that the withdrawal value can not be used by a transaction - in the same block as the withdrawal. + 1. `tx_in_withdrawals_block`: Test that the withdrawal value can not be + used by a transaction in the same block as the withdrawal. - 2. `tx_after_withdrawals_block`: Test that the withdrawal value can be used by a transaction - in the subsequent block. + 2. `tx_after_withdrawals_block`: Test that the withdrawal value can be used + by a transaction in the subsequent block. """ @pytest.fixture @@ -189,8 +190,8 @@ def test_use_value_in_contract( def test_balance_within_block(blockchain_test: BlockchainTestFiller, pre: Alloc): """ - Test Withdrawal balance increase within the same block, - inside contract call. + Test Withdrawal balance increase within the same block, inside contract + call. """ save_balance_on_block_number = Op.SSTORE( Op.NUMBER, @@ -304,8 +305,8 @@ def test_multiple_withdrawals_same_address( blocks: List[Block], ): """ - Test Withdrawals can be done to the same address multiple times in - the same block. + Test Withdrawals can be done to the same address multiple times in the + same block. """ # Expected post is the same for both test cases. post = {} @@ -323,8 +324,8 @@ def test_many_withdrawals( pre: Alloc, ): """ - Test Withdrawals with a count of N withdrawals in a single block where - N is a high number not expected to be seen in mainnet. + Test Withdrawals with a count of N withdrawals in a single block where N is + a high number not expected to be seen in mainnet. """ n = 400 withdrawals = [] @@ -361,9 +362,9 @@ def test_self_destructing_account( fork: Fork, ): """ - Test withdrawals can be done to self-destructed accounts. - Account `0x100` self-destructs and sends all its balance to `0x200`. - Then, a withdrawal is received at `0x100` with 99 wei. + Test withdrawals can be done to self-destructed accounts. Account `0x100` + self-destructs and sends all its balance to `0x200`. Then, a withdrawal is + received at `0x100` with 99 wei. """ self_destruct_code = Op.SELFDESTRUCT(Op.CALLDATALOAD(0)) sender = pre.fund_eoa() @@ -558,12 +559,10 @@ def test_zero_amount( are included in one block. 1. Two withdrawals of zero amount to two different addresses; one to an - untouched account, one to an account with a balance. - 2. As 1., but with an additional withdrawal with positive value. - 3. As 2., but with an additional withdrawal containing the maximum value - possible. - 4. As 3., but with order of withdrawals in the block reversed. - + untouched account, one to an account with a balance. 2. As 1., but with an + additional withdrawal with positive value. 3. As 2., but with an additional + withdrawal containing the maximum value possible. 4. As 3., but with order + of withdrawals in the block reversed. """ empty_accounts = [pre.fund_eoa(0) for _ in range(3)] zero_balance_contract = pre.deploy_contract(Op.STOP) @@ -657,8 +656,8 @@ def test_large_amount( pre: Alloc, ): """ - Test Withdrawals that have a large gwei amount, so that (gwei * 1e9) - could overflow uint64 but not uint256. + Test Withdrawals that have a large gwei amount, so that (gwei * 1e9) could + overflow uint64 but not uint256. """ withdrawals: List[Withdrawal] = [] amounts: List[int] = [ diff --git a/tests/unscheduled/__init__.py b/tests/unscheduled/__init__.py index c0bc59e8d52..f4907906a27 100644 --- a/tests/unscheduled/__init__.py +++ b/tests/unscheduled/__init__.py @@ -1 +1,4 @@ -"""Test cases for unscheduled EVM functionality. A temporary home for features that are not yet CFI'd for inclusion in the next hardfork.""" # noqa: E501 +""" +Test cases for unscheduled EVM functionality. A temporary home for features +that are not yet CFI'd for inclusion in the next hardfork. +""" diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py index de9eb0a8f92..bcde29f9137 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py @@ -1,5 +1,6 @@ """ -abstract: Test cases for [EIP-3540: EOF - EVM Object Format v1](https://eips.ethereum.org/EIPS/eip-3540) - EIP-3540 introduces a structured format for EVM bytecode, with separate sections for code and data. - Opcodes introduced: None (defines a new bytecode structure but no new opcodes). -""" # noqa: E501 +abstract: Test cases for [EIP-3540: EOF - EVM Object Format +v1](https://eips.ethereum.org/EIPS/eip-3540) EIP-3540 introduces a structured +format for EVM bytecode, with separate sections for code and data. Opcodes +introduced: None (defines a new bytecode structure but no new opcodes). +""" diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_all_opcodes_in_container.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_all_opcodes_in_container.py index c7310bcaf0a..0fa6a3de26b 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_all_opcodes_in_container.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_all_opcodes_in_container.py @@ -1,4 +1,7 @@ -"""EOF Container: check how every opcode behaves in the middle of the valid eof container code.""" +""" +EOF Container: check how every opcode behaves in the middle of the valid eof +container code. +""" import itertools from typing import Any, Dict, Generator, List, Tuple @@ -22,7 +25,8 @@ all_opcodes = set(Op) undefined_opcodes = set(UndefinedOpcodes) -# Invalid Opcodes will produce EOFException.UNDEFINED_INSTRUCTION when used in EOFContainer +# Invalid Opcodes will produce EOFException.UNDEFINED_INSTRUCTION when used in +# EOFContainer invalid_eof_opcodes = { Op.CODESIZE, Op.SELFDESTRUCT, @@ -44,7 +48,8 @@ valid_eof_opcodes = all_opcodes - invalid_eof_opcodes -# Halting the execution opcodes can be placed without STOP instruction at the end +# Halting the execution opcodes can be placed without STOP instruction at the +# end halting_opcodes = { Op.STOP, Op.RETURNCODE, @@ -53,7 +58,8 @@ Op.INVALID, } -# Opcodes that end the code section and can be placed without STOP instruction at the end +# Opcodes that end the code section and can be placed without STOP instruction +# at the end section_terminating_opcodes = { Op.RETF, Op.JUMPF, @@ -62,7 +68,8 @@ data_portion_opcodes = {op for op in all_opcodes if op.has_data_portion()} -# NOTE: `sorted` is used to ensure that the tests are collected in a deterministic order. +# NOTE: `sorted` is used to ensure that the tests are collected in a +# deterministic order. @pytest.mark.parametrize( @@ -74,8 +81,7 @@ def test_all_opcodes_in_container( opcode: Opcode, ): """ - Test all opcodes inside valid container - 257 because 0x5B is duplicated. + Test all opcodes inside valid container 257 because 0x5B is duplicated. """ data_portion = 1 if opcode == Op.CALLF else 0 opcode_with_data_portion = opcode[data_portion] if opcode.has_data_portion() else opcode @@ -134,7 +140,10 @@ def test_invalid_opcodes_after_stop( opcode: Opcode, terminating_opcode: Opcode, ): - """Test that an invalid opcode placed after STOP (terminating instruction) invalidates EOF.""" + """ + Test that an invalid opcode placed after STOP (terminating instruction) + invalidates EOF. + """ terminating_code = Bytecode(terminating_opcode) match terminating_opcode: # Enhance the code for complex opcodes. case Op.RETURNCODE: @@ -180,8 +189,9 @@ def test_all_invalid_terminating_opcodes( ): """Test all opcodes that are invalid as the last opcode in a container.""" if opcode.has_data_portion(): - # Add the appropriate data portion to the opcode by using the get_item method. - # On the CALLF opcode we need to reference the second code section, hence the [1] index. + # Add the appropriate data portion to the opcode by using the get_item + # method. On the CALLF opcode we need to reference the second code + # section, hence the [1] index. opcode = opcode[0] if opcode != Op.CALLF else opcode[1] bytecode = (Op.PUSH0 * opcode.min_stack_height) + opcode @@ -321,12 +331,12 @@ def test_all_unreachable_terminating_opcodes_before_stop( ) @pytest.mark.parametrize( "exception", - # We test two types of exceptions here: - # 1. Invalid max stack height, where we modify the `max_stack_height` field of the code section - # to the maximum stack height allowed by the EIP-3540, so the code still has to be checked - # for stack overflow. - # 2. Max stack height above limit, where we don't modify the `max_stack_height` field of the - # code section, so the actual code doesn't have to be verified for the stack overflow. + # We test two types of exceptions here: 1. Invalid max stack height, where + # we modify the `max_stack_height` field of the code section to the maximum + # stack height allowed by the EIP-3540, so the code still has to be checked + # for stack overflow. 2. Max stack height above limit, where we don't + # modify the `max_stack_height` field of the code section, so the actual + # code doesn't have to be verified for the stack overflow. [EOFException.INVALID_MAX_STACK_INCREASE, EOFException.MAX_STACK_INCREASE_ABOVE_LIMIT], ) def test_all_opcodes_stack_overflow( @@ -334,7 +344,9 @@ def test_all_opcodes_stack_overflow( opcode: Opcode, exception: EOFException, ): - """Test stack overflow on all opcodes that push more items than they pop.""" + """ + Test stack overflow on all opcodes that push more items than they pop. + """ opcode = opcode[0] if opcode.has_data_portion() else opcode assert opcode.pushed_stack_items - opcode.popped_stack_items == 1 @@ -347,7 +359,8 @@ def test_all_opcodes_stack_overflow( kwargs: Dict[str, Any] = {"code": bytecode} if exception == EOFException.INVALID_MAX_STACK_INCREASE: - # Lie about the max stack height to make the code be checked for stack overflow. + # Lie about the max stack height to make the code be checked for stack + # overflow. kwargs["max_stack_height"] = MAX_STACK_INCREASE_LIMIT sections = [Section.Code(**kwargs)] @@ -367,13 +380,17 @@ def valid_opcode_combinations( truncate_all_options: List[bool], opcodes: List[Opcode], ) -> Generator[Tuple[bool, bool, Opcode], None, None]: - """Create valid parameter combinations for test_truncated_data_portion_opcodes().""" + """ + Create valid parameter combinations for + test_truncated_data_portion_opcodes(). + """ for opcode, truncate_all, compute_max_stack_height in itertools.product( opcodes, truncate_all_options, compute_max_stack_height_options ): opcode_with_data_portion: bytes = bytes(opcode[1]) - # Skip invalid or redundant combinations to avoid using pytest.skip in the test + # Skip invalid or redundant combinations to avoid using pytest.skip in + # the test if len(opcode_with_data_portion) == 2 and truncate_all: continue if ( @@ -401,7 +418,8 @@ def test_truncated_data_portion_opcodes( """ opcode_with_data_portion: bytes = bytes(opcode[1]) - # Compose instruction bytes with empty imm bytes (truncate_all) or 1 byte shorter imm bytes. + # Compose instruction bytes with empty imm bytes (truncate_all) or 1 byte + # shorter imm bytes. opcode_bytes = opcode_with_data_portion[0:1] if truncate_all else opcode_with_data_portion[:-1] if opcode.min_stack_height > 0: diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_container_size.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_container_size.py index 1cc141fc03b..5dfbccb1734 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_container_size.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_container_size.py @@ -27,7 +27,8 @@ def test_max_size( over_limit: int, ): """Verify EOF container valid at maximum size, invalid above.""" - # Expand the minimal EOF code by more noop code, reaching the desired target container size. + # Expand the minimal EOF code by more noop code, reaching the desired + # target container size. code = Container( sections=[ Section.Code( @@ -52,7 +53,10 @@ def test_above_max_size_raw( eof_test: EOFTestFiller, size: int, ): - """Verify EOF container invalid above maximum size, regardless of header contents.""" + """ + Verify EOF container invalid above maximum size, regardless of header + contents. + """ code = Op.INVALID * size eof_test( container=Container(raw_bytes=code), @@ -101,7 +105,10 @@ def test_section_after_end_of_container( eof_test: EOFTestFiller, code: Container, ): - """Verify EOF container is invalid if any of sections declares above container size.""" + """ + Verify EOF container is invalid if any of sections declares above container + size. + """ eof_test( container=code, expect_exception=EOFException.INVALID_SECTION_BODIES_SIZE, diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py index 7e0875da28a..b06ab65fbec 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py @@ -406,13 +406,15 @@ def test_valid_containers( validity_error=EOFException.MISSING_CODE_HEADER, ), Container( - # EOF code containing multiple type headers, second one matches code length + # EOF code containing multiple type headers, second one matches + # code length name="multiple_type_headers_2", raw_bytes="ef0001010004010001ff00000000800000fe", validity_error=EOFException.MISSING_CODE_HEADER, ), Container( - # EOF code containing multiple type headers followed by 2 code sections + # EOF code containing multiple type headers followed by 2 code + # sections name="multiple_type_headers_3", sections=[ Section(kind=SectionKind.TYPE, data="00800000"), @@ -486,8 +488,8 @@ def test_valid_containers( ], ), # The basic `no_section_terminator` cases just remove the terminator - # and the `00` for zeroth section inputs looks like one. Error is because - # the sections are wrongly sized. + # and the `00` for zeroth section inputs looks like one. Error is + # because the sections are wrongly sized. Container( name="no_section_terminator", header_terminator=bytes(), @@ -521,9 +523,9 @@ def test_valid_containers( EOFException.INVALID_FIRST_SECTION_TYPE, ], ), - # The following cases just remove the terminator - # and the `00` for zeroth section inputs looks like one. Section bodies - # are as the size prescribes here, so the error is about the inputs of zeroth section. + # The following cases just remove the terminator and the `00` for + # zeroth section inputs looks like one. Section bodies are as the size + # prescribes here, so the error is about the inputs of zeroth section. Container( name="no_section_terminator_section_bodies_ok_1", header_terminator=bytes(), @@ -536,8 +538,8 @@ def test_valid_containers( sections=[Section.Code(code=Op.JUMPDEST * 2 + Op.STOP, custom_size=2)], validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, ), - # Here the terminator is missing but made to look like a different section - # or arbitrary byte + # Here the terminator is missing but made to look like a different + # section or arbitrary byte Container( name="no_section_terminator_nonzero", header_terminator=b"01", @@ -625,7 +627,8 @@ def test_valid_containers( Container( name="empty_code_section", sections=[Section.Code(code="0x")], - # TODO the exception must be about code section EOFException.INVALID_CODE_SECTION, + # TODO the exception must be about code section + # EOFException.INVALID_CODE_SECTION, validity_error=EOFException.ZERO_SECTION_SIZE, ), Container( @@ -634,7 +637,8 @@ def test_valid_containers( Section.Code(code="0x"), Section.Data(data="0xDEADBEEF"), ], - # TODO the exception must be about code section EOFException.INVALID_CODE_SECTION, + # TODO the exception must be about code section + # EOFException.INVALID_CODE_SECTION, validity_error=EOFException.ZERO_SECTION_SIZE, ), Container( @@ -684,7 +688,8 @@ def test_valid_containers( Container( name="data_section_without_code_section", sections=[Section.Data(data="0xDEADBEEF")], - # TODO the actual exception should be EOFException.MISSING_CODE_HEADER + # TODO the actual exception should be + # EOFException.MISSING_CODE_HEADER validity_error=[EOFException.ZERO_SECTION_SIZE, EOFException.UNEXPECTED_HEADER_KIND], ), Container( @@ -1059,7 +1064,8 @@ def test_valid_containers( Section.Code(code=Op.POP + Op.RETF, code_inputs=1), Section.Code(Op.STOP), ], - # TODO the actual exception should be EOFException.INVALID_TYPE_BODY, + # TODO the actual exception should be + # EOFException.INVALID_TYPE_BODY, validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, ), Container( @@ -1068,7 +1074,8 @@ def test_valid_containers( Section.Code(code=Op.PUSH0, code_outputs=1), Section.Code(Op.STOP), ], - # TODO the actual exception should be EOFException.INVALID_TYPE_BODY, + # TODO the actual exception should be + # EOFException.INVALID_TYPE_BODY, validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, ), Container( @@ -1158,7 +1165,8 @@ def test_valid_containers( max_stack_height=1024, ), ], - # TODO auto types section generation probably failed, the exception must be about code + # TODO auto types section generation probably failed, the exception + # must be about code validity_error=EOFException.MAX_STACK_INCREASE_ABOVE_LIMIT, ), ], diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_eof_example.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_eof_example.py index 3970dd5fd72..c8995a94653 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_eof_example.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_eof_example.py @@ -23,13 +23,16 @@ def test_eof_example(eof_test: EOFTestFiller): # TYPES section is constructed automatically based on CODE # CODE section Section.Code( - code=Op.CALLF[1](Op.PUSH0) + Op.STOP, # bytecode to be deployed in the body + code=Op.CALLF[1](Op.PUSH0) + Op.STOP, # bytecode to be + # deployed in the body # Code: call section 1 with a single zero as input, then stop. - max_stack_increase=1, # define code header (in body) stack size + max_stack_increase=1, # define code header (in body) stack + # size ), # There can be multiple code sections Section.Code( - # Remove input and call section 2 with no inputs, then remove output and return + # Remove input and call section 2 with no inputs, then remove + # output and return code=Op.POP + Op.CALLF[2]() + Op.POP + Op.RETF, code_inputs=1, code_outputs=0, @@ -64,45 +67,52 @@ def test_eof_example(eof_test: EOFTestFiller): def test_eof_example_custom_fields(eof_test: EOFTestFiller): """Example of python EOF container class tuning.""" - # if you need to overwrite certain structure bytes, you can use customization - # this is useful for unit testing the eof structure format, you can reorganize sections - # and overwrite the header bytes for testing purposes - # most of the combinations are covered by the unit tests + # if you need to overwrite certain structure bytes, you can use + # customization this is useful for unit testing the eof structure format, + # you can reorganize sections and overwrite the header bytes for testing + # purposes most of the combinations are covered by the unit tests # This features are subject for development and will change in the future eof_code = Container( name="valid_container_example_2", - magic=b"\xef\x00", # magic can be overwritten for test purposes, (default is 0xEF00) - version=b"\x01", # version can be overwritten for testing purposes (default is 0x01) - header_terminator=b"\x00", # terminator byte can be overwritten (default is 0x00) - extra=b"", # extra bytes to be trailed after the container body bytes (default is None) + magic=b"\xef\x00", # magic can be overwritten for test purposes, + # (default is 0xEF00) + version=b"\x01", # version can be overwritten for testing purposes + # (default is 0x01) + header_terminator=b"\x00", # terminator byte can be overwritten + # (default is 0x00) + extra=b"", # extra bytes to be trailed after the container body bytes + # (default is None) sections=[ # TYPES section is constructed automatically based on CODE # CODE section Section.Code( - code=Op.PUSH1(2) - + Op.STOP, # this is the actual bytecode to be deployed in the body + code=Op.PUSH1(2) + Op.STOP, # this is the actual bytecode to be deployed in the + # body max_stack_height=1, # define code header (in body) stack size ), # DATA section Section.Data( data="0xef", - # custom_size overrides the size bytes, so you can put only 1 byte into data - # but still make the header size of 2 to produce invalid section - # if custom_size != len(data), the section will be invalid + # custom_size overrides the size bytes, so you can put only 1 + # byte into data but still make the header size of 2 to produce + # invalid section if custom_size != len(data), the section will + # be invalid custom_size=1, ), ], # auto generate types section based on provided code sections - # AutoSection.ONLY_BODY - means the section will be generated only for the body bytes - # AutoSection.ONLY_BODY - means the section will be generated only for the header bytes + # AutoSection.ONLY_BODY - means the section will be generated only for + # the body bytes AutoSection.ONLY_BODY - means the section will be + # generated only for the header bytes auto_type_section=AutoSection.AUTO, # auto generate default data section (0x empty), by default is True auto_data_section=True, - # auto sort section by order 01 02 03 04 - # AutoSection.ONLY_BODY - means the sorting will be done only for the body bytes - # AutoSection.ONLY_BODY - means the section will be done only for the header bytes + # auto sort section by order 01 02 03 04 AutoSection.ONLY_BODY - means + # the sorting will be done only for the body bytes + # AutoSection.ONLY_BODY - means the section will be done only for the + # header bytes auto_sort_sections=AutoSection.AUTO, ) diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_opcodes_in_legacy.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_opcodes_in_legacy.py index 0dfabd04454..3916f8570ff 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_opcodes_in_legacy.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_opcodes_in_legacy.py @@ -48,7 +48,8 @@ pytest.param(Op.DATASIZE, id="DATASIZE"), pytest.param(Op.DATACOPY(0, 0, 32), id="DATACOPY"), pytest.param(Op.EOFCREATE[0](0, 0, 0, 0), id="EOFCREATE"), - # pytest.param(Op.TXCREATE(0, 0, 0, 0, 0), id="TXCREATE"), not EOF-only anymore + # pytest.param(Op.TXCREATE(0, 0, 0, 0, 0), id="TXCREATE"), not EOF-only + # anymore pytest.param(Op.RETURNCODE[0], id="RETURNCODE"), ] @@ -67,7 +68,8 @@ def test_opcodes_in_legacy(state_test: StateTestFiller, pre: Alloc, code: Opcode ) post = { - # assert the canary is not over-written. If it was written then the EOF opcode was valid + # assert the canary is not over-written. If it was written then the EOF + # opcode was valid address_test_contract: Account(storage={slot_code_executed: value_non_execution_canary}), } @@ -209,7 +211,8 @@ def test_opcodes_in_eof_calling_legacy( ) post = { - # assert the canary is not over-written. If it was written then the EOF opcode was valid + # assert the canary is not over-written. If it was written then the EOF + # opcode was valid address_test_contract: Account(storage={slot_code_executed: value_non_execution_canary}), address_entry_contract: Account( storage={ diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_header_body_mismatch.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_header_body_mismatch.py index 4292914e63d..d1b11bea5c1 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_header_body_mismatch.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_header_body_mismatch.py @@ -18,10 +18,14 @@ @pytest.mark.parametrize( **extend_with_defaults( defaults={ - "skip_header_listing": False, # second section is mentioned in code header array - "skip_body_listing": False, # second section code is in container's body - "skip_types_body_listing": False, # code input bytes not listed in container's body - "skip_types_header_listing": False, # code input bytes size not added to types section size # noqa: E501 + # second section is mentioned in code header array + "skip_header_listing": False, + # second section code is in container's body + "skip_body_listing": False, + # code input bytes not listed in container's body + "skip_types_body_listing": False, + # code input bytes size not added to types section size + "skip_types_header_listing": False, "expected_code": "", "expected_exception": None, }, @@ -30,7 +34,8 @@ { "skip_header_listing": True, "skip_body_listing": True, - "expected_code": "ef00010100080200010003ff00040000800001000000003050000bad60A7", # noqa: E501 + "expected_code": "ef00010100080200010003ff0004000080000" + "1000000003050000bad60A7", "expected_exception": [ EOFException.INVALID_TYPE_SECTION_SIZE, EOFException.INVALID_SECTION_BODIES_SIZE, @@ -42,7 +47,8 @@ { "skip_header_listing": True, "skip_body_listing": False, - "expected_code": "ef00010100080200010003ff00040000800001000000003050003050000bad60A7", # noqa: E501 + "expected_code": "ef00010100080200010003ff0004000080000" + "1000000003050003050000bad60A7", "expected_exception": [ EOFException.INVALID_TYPE_SECTION_SIZE, EOFException.INVALID_SECTION_BODIES_SIZE, @@ -54,7 +60,8 @@ { "skip_header_listing": False, "skip_body_listing": True, - "expected_code": "ef000101000802000200030003ff00040000800001000000003050000bad60A7", # noqa: E501 + "expected_code": "ef000101000802000200030003ff000400008" + "00001000000003050000bad60A7", "expected_exception": [ EOFException.UNREACHABLE_CODE_SECTIONS, EOFException.TOPLEVEL_CONTAINER_TRUNCATED, @@ -66,7 +73,8 @@ { "skip_header_listing": False, "skip_body_listing": False, - "expected_code": "ef000101000802000200030003ff00040000800001000000003050003050000bad60A7", # noqa: E501 + "expected_code": "ef000101000802000200030003ff000400008" + "00001000000003050003050000bad60A7", "expected_exception": EOFException.UNREACHABLE_CODE_SECTIONS, }, id="layout_ok_code_bad", @@ -125,7 +133,8 @@ def test_code_section_header_body_mismatch( skip_body_listing=skip_body_listing, # whether to not print its input bytes in containers body skip_types_body_listing=skip_types_body_listing, - # whether to not calculate its input bytes size in types section's header + # whether to not calculate its input bytes size in types + # section's header skip_types_header_listing=skip_types_header_listing, ), Section.Data("0x0bad60A7"), diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py index 8e5f7c6da0d..aae8c4af0b5 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py @@ -36,7 +36,9 @@ class CasePosition(Enum): def get_expected_code_exception( section_kind, section_test, test_position ) -> tuple[str, EOFExceptionInstanceOrList | None]: - """Verification vectors with code and exception based on test combinations.""" + """ + Verification vectors with code and exception based on test combinations. + """ match (section_kind, section_test, test_position): case (SectionKind.TYPE, SectionTest.MISSING, CasePosition.HEADER): return ( @@ -64,7 +66,8 @@ def get_expected_code_exception( case (SectionKind.TYPE, SectionTest.WRONG_ORDER, CasePosition.BODY): return ( "ef00010100040200010003ff00010030500000800001ef", - # TODO why invalid first section type? it should say that the body incorrect + # TODO why invalid first section type? it should say that the + # body incorrect EOFException.INVALID_FIRST_SECTION_TYPE, ) case (SectionKind.TYPE, SectionTest.WRONG_ORDER, CasePosition.BODY_AND_HEADER): @@ -80,8 +83,8 @@ def get_expected_code_exception( case (SectionKind.CODE, SectionTest.MISSING, CasePosition.BODY): return ( "ef00010100040200010003ff00010000800001ef", - # TODO should be an exception of empty code bytes, because it can understand that - # last byte is data section byte + # TODO should be an exception of empty code bytes, because it + # can understand that last byte is data section byte [EOFException.INVALID_SECTION_BODIES_SIZE, EOFException.UNEXPECTED_HEADER_KIND], ) case (SectionKind.CODE, SectionTest.MISSING, CasePosition.BODY_AND_HEADER): @@ -230,17 +233,17 @@ def test_container_section_order( test_position: CasePosition, ): """ - Test containers section being out of order in the header and/or body. - This extends and follows the convention of the test_section_order() - for the optional container section. + Test containers section being out of order in the header and/or body. This + extends and follows the convention of the test_section_order() for the + optional container section. """ if container_position == 2: pytest.skip("Skip valid container section position") section_code = Section.Code( code=Op.EOFCREATE[0](0, 0, 0, 0) - # TODO: Migrated tests had the following infinite loop, so it is kept here - # to equalize code coverage. + # TODO: Migrated tests had the following infinite loop, so it is kept + # here to equalize code coverage. + Op.RJUMP[0] + Op.STOP() ) @@ -270,7 +273,8 @@ def get_expected_exception(): return EOFException.INVALID_FIRST_SECTION_TYPE case 1, CasePosition.BODY: # Messes up with the code section return EOFException.UNDEFINED_INSTRUCTION - case 3, CasePosition.BODY: # Data section messes up with the container section + case 3, CasePosition.BODY: # Data section messes up with the + # container section return EOFException.INVALID_MAGIC case 0, CasePosition.HEADER | CasePosition.BODY_AND_HEADER: return EOFException.MISSING_TYPE_HEADER diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_size.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_size.py index 6fecfe17996..f5ea074b851 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_size.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_section_size.py @@ -120,7 +120,9 @@ def test_section_size( section_kind: SectionKind, exception: EOFExceptionInstanceOrList, ): - """Test custom_size is auto, more or less than the actual size of the section.""" + """ + Test custom_size is auto, more or less than the actual size of the section. + """ eof_code = Container() if section_size != SectionSize.NORMAL and section_kind == SectionKind.TYPE: @@ -183,8 +185,8 @@ def test_section_size( @pytest.mark.parametrize( "truncation_len, exception", [ - # The original container is not valid by itself because its 2-byte code section - # starts with the terminating instruction: INVALID. + # The original container is not valid by itself because its 2-byte code + # section starts with the terminating instruction: INVALID. pytest.param(0, EOFException.UNREACHABLE_INSTRUCTIONS), pytest.param(1, EOFException.INVALID_SECTION_BODIES_SIZE, id="EOF1_truncated_section_2"), pytest.param(3, EOFException.INVALID_SECTION_BODIES_SIZE, id="EOF1_truncated_section_1"), @@ -198,7 +200,8 @@ def test_truncated_container_without_data( ): """ Test takes a semi-valid container and removes some bytes from its tail. - Migrated from EOFTests/efValidation/EOF1_truncated_section_.json (cases without data section). + Migrated from EOFTests/efValidation/EOF1_truncated_section_.json (cases + without data section). """ container = Container(sections=[Section.Code(Op.INVALID + Op.INVALID)]) bytecode = bytes(container) @@ -222,8 +225,9 @@ def test_truncated_container_with_data( exception: EOFException, ): """ - Test takes a valid container with data and removes some bytes from its tail. - Migrated from EOFTests/efValidation/EOF1_truncated_section_.json (cases with data section). + Test takes a valid container with data and removes some bytes from its + tail. Migrated from EOFTests/efValidation/EOF1_truncated_section_.json + (cases with data section). """ data = b"\xaa\xbb" container = Container( diff --git a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py index 4eef21b71a5..2de612e3285 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py @@ -1,5 +1,7 @@ """ -abstract: Test cases for [EIP-4200: EOF - Static relative jumps](https://eips.ethereum.org/EIPS/eip-4200) - EIP-4200 replaces dynamic jump instructions with relative jump offsets for improved control flow predictability. - Opcodes introduced: `RJUMP` (`0xE0`), `RJUMPI` (`0xE1`), `RJUMPV` (`0xE2`). -""" # noqa: E501 +abstract: Test cases for [EIP-4200: EOF - Static relative +jumps](https://eips.ethereum.org/EIPS/eip-4200). +EIP-4200 replaces dynamic jump instructions with relative jump offsets +for improved control flow predictability. +Opcodes introduced: `RJUMP` (`0xE0`), `RJUMPI` (`0xE1`), `RJUMPV` (`0xE2`). +""" diff --git a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py index 0a2e407cc5a..490bea52976 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py @@ -39,7 +39,9 @@ def test_rjump_negative( def test_rjump_positive_negative( eof_state_test: EOFStateTestFiller, ): - """EOF1V4200_0001 (Valid) EOF code containing RJUMP (Positive, Negative).""" + """ + EOF1V4200_0001 (Valid) EOF code containing RJUMP (Positive, Negative). + """ eof_state_test( container=Container.Code( Op.PUSH0 @@ -68,7 +70,10 @@ def test_rjump_zero( def test_rjump_maxes( eof_state_test: EOFStateTestFiller, ): - """EOF1V4200_0003 EOF with RJUMP containing the max positive and negative offset (32767).""" + """ + EOF1V4200_0003 EOF with RJUMP containing the max positive and negative + offset (32767). + """ eof_state_test( container=Container.Code( Op.PUSH0 @@ -87,8 +92,8 @@ def test_rjump_max_bytecode_size( eof_test: EOFTestFiller, ): """ - EOF1V4200_0003 EOF with RJUMP containing the maximum offset that does not exceed the maximum - bytecode size. + EOF1V4200_0003 EOF with RJUMP containing the maximum offset that does not + exceed the maximum bytecode size. """ noop_count = MAX_BYTECODE_SIZE - 27 code = ( @@ -128,8 +133,8 @@ def test_rjump_into_header( offset: int, ): """ - EOF1I4200_0003 (Invalid) EOF code containing RJUMP with target outside code bounds - (Jumping into header). + EOF1I4200_0003 (Invalid) EOF code containing RJUMP with target outside code + bounds (Jumping into header). """ eof_test( container=Container.Code(Op.RJUMP[offset]), @@ -141,8 +146,8 @@ def test_rjump_before_header( eof_test: EOFTestFiller, ): """ - EOF1I4200_0004 (Invalid) EOF code containing RJUMP with target outside code bounds - (Jumping before code begin). + EOF1I4200_0004 (Invalid) EOF code containing RJUMP with target outside code + bounds (Jumping before code begin). """ eof_test( container=Container.Code(Op.RJUMP[-23]), @@ -154,8 +159,8 @@ def test_rjump_into_data( eof_test: EOFTestFiller, ): """ - EOF1I4200_0005 (Invalid) EOF code containing RJUMP with target outside code bounds - (Jumping into data section). + EOF1I4200_0005 (Invalid) EOF code containing RJUMP with target outside code + bounds (Jumping into data section). """ eof_test( container=Container( @@ -171,7 +176,10 @@ def test_rjump_into_data( def test_rjump_outside_other_section_before( eof_test: EOFTestFiller, ): - """EOF code containing RJUMP with target outside code bounds (prior code section).""" + """ + EOF code containing RJUMP with target outside code bounds (prior code + section). + """ eof_test( container=Container( sections=[ @@ -186,7 +194,10 @@ def test_rjump_outside_other_section_before( def test_rjump_outside_other_section_after( eof_test: EOFTestFiller, ): - """EOF code containing RJUMP with target outside code bounds (Subsequent code section).""" + """ + EOF code containing RJUMP with target outside code bounds (Subsequent code + section). + """ eof_test( container=Container( sections=[ @@ -203,8 +214,8 @@ def test_rjump_after_container( eof_test: EOFTestFiller, ): """ - EOF1I4200_0006 (Invalid) EOF code containing RJUMP with target outside code bounds - (Jumping after code end). + EOF1I4200_0006 (Invalid) EOF code containing RJUMP with target outside code + bounds (Jumping after code end). """ eof_test( container=Container.Code(Op.RJUMP[2]), @@ -216,8 +227,8 @@ def test_rjump_to_code_end( eof_test: EOFTestFiller, ): """ - EOF1I4200_0007 (Invalid) EOF code containing RJUMP with target outside code bounds - (Jumping to code end). + EOF1I4200_0007 (Invalid) EOF code containing RJUMP with target outside code + bounds (Jumping to code end). """ eof_test( container=Container.Code(Op.RJUMP[1] + Op.STOP), @@ -230,7 +241,10 @@ def test_rjump_into_self_data_portion( eof_test: EOFTestFiller, offset: int, ): - """EOF1I4200_0008 (Invalid) EOF code containing RJUMP with target self RJUMP immediate.""" + """ + EOF1I4200_0008 (Invalid) EOF code containing RJUMP with target self RJUMP + immediate. + """ eof_test( container=Container.Code(Op.RJUMP[-offset] + Op.STOP), expect_exception=EOFException.INVALID_RJUMP_DESTINATION, @@ -241,8 +255,8 @@ def test_rjump_into_self_remaining_code( eof_test: EOFTestFiller, ): """ - EOF1I4200_0008 (Invalid) EOF code containing RJUMP with target self RJUMP but remaining - unreachable code. + EOF1I4200_0008 (Invalid) EOF code containing RJUMP with target self RJUMP + but remaining unreachable code. """ eof_test( container=Container.Code(Op.RJUMP[-len(Op.RJUMP[0])] + Op.STOP), @@ -269,7 +283,10 @@ def test_rjump_into_self( def test_rjump_into_self_pre_code( eof_test: EOFTestFiller, ): - """EOF code containing RJUMP with target self RJUMP with non-zero stack before RJUMP.""" + """ + EOF code containing RJUMP with target self RJUMP with non-zero stack before + RJUMP. + """ eof_test( container=Container.Code(Op.PUSH1[0] + Op.RJUMP[-len(Op.RJUMP[0])]), ) @@ -455,8 +472,8 @@ def test_rjump_valid_forward( container: Container, ): """ - Validate a valid code section containing at least one forward RJUMP. - These tests exercise the stack height validation. + Validate a valid code section containing at least one forward RJUMP. These + tests exercise the stack height validation. """ eof_test(container=container) @@ -551,8 +568,8 @@ def test_rjump_valid_backward( container: Container, ): """ - Validate a valid code section containing at least one backward RJUMP. - These tests exercise the stack height validation. + Validate a valid code section containing at least one backward RJUMP. These + tests exercise the stack height validation. """ eof_test(container=container) @@ -560,7 +577,10 @@ def test_rjump_valid_backward( def test_rjump_into_stack_height_diff( eof_test: EOFTestFiller, ): - """EOF code containing RJUMP with target instruction that causes stack height difference.""" + """ + EOF code containing RJUMP with target instruction that causes stack height + difference. + """ eof_test( container=Container.Code(Op.PUSH1[0] + Op.RJUMP[-(len(Op.RJUMP[0]) + len(Op.PUSH1[0]))]), expect_exception=EOFException.STACK_HEIGHT_MISMATCH, @@ -570,7 +590,10 @@ def test_rjump_into_stack_height_diff( def test_rjump_into_stack_height_diff_2( eof_test: EOFTestFiller, ): - """EOF code containing RJUMP with target instruction that cause stack height difference.""" + """ + EOF code containing RJUMP with target instruction that cause stack height + difference. + """ eof_test( container=Container.Code( Op.PUSH1[0] + Op.POP + Op.RJUMP[-(len(Op.RJUMP[0]) + len(Op.POP))] @@ -757,8 +780,8 @@ def test_rjump_backward_invalid_max_stack_height( container: Container, ): """ - Validate a code section containing at least one backward RJUMP - invalid because of the incorrect max stack height. + Validate a code section containing at least one backward RJUMP invalid + because of the incorrect max stack height. """ eof_test(container=container, expect_exception=EOFException.STACK_HEIGHT_MISMATCH) @@ -766,7 +789,10 @@ def test_rjump_backward_invalid_max_stack_height( def test_rjump_into_stack_underflow( eof_test: EOFTestFiller, ): - """EOF code containing RJUMP with target instruction that cause stack underflow.""" + """ + EOF code containing RJUMP with target instruction that cause stack + underflow. + """ eof_test( container=Container.Code( Op.ORIGIN @@ -783,7 +809,10 @@ def test_rjump_into_stack_underflow( def test_rjump_into_rjump( eof_test: EOFTestFiller, ): - """EOF1I4200_0009 (Invalid) EOF code containing RJUMP with target other RJUMP immediate.""" + """ + EOF1I4200_0009 (Invalid) EOF code containing RJUMP with target other RJUMP + immediate. + """ eof_test( container=Container.Code(Op.RJUMP[1] + Op.RJUMP[0]), expect_exception=EOFException.INVALID_RJUMP_DESTINATION, @@ -793,7 +822,10 @@ def test_rjump_into_rjump( def test_rjump_into_rjumpi( eof_test: EOFTestFiller, ): - """EOF1I4200_0010 (Invalid) EOF code containing RJUMP with target RJUMPI immediate.""" + """ + EOF1I4200_0010 (Invalid) EOF code containing RJUMP with target RJUMPI + immediate. + """ eof_test( container=Container.Code(Op.RJUMP[5] + Op.STOP + Op.PUSH1[1] + Op.RJUMPI[-6] + Op.STOP), expect_exception=EOFException.INVALID_RJUMP_DESTINATION, @@ -802,7 +834,10 @@ def test_rjump_into_rjumpi( @pytest.mark.parametrize("jump", [JumpDirection.FORWARD, JumpDirection.BACKWARD]) def test_rjump_into_push_1(eof_test: EOFTestFiller, jump: JumpDirection): - """EOF1I4200_0011 (Invalid) EOF code containing RJUMP with target PUSH1 immediate.""" + """ + EOF1I4200_0011 (Invalid) EOF code containing RJUMP with target PUSH1 + immediate. + """ code = ( Op.PUSH1[1] + Op.RJUMP[-4] if jump == JumpDirection.BACKWARD else Op.RJUMP[1] + Op.PUSH1[1] ) + Op.STOP @@ -860,7 +895,10 @@ def test_rjump_into_push_n( jump: JumpDirection, data_portion_end: bool, ): - """EOF1I4200_0011 (Invalid) EOF code containing RJUMP with target PUSH2+ immediate.""" + """ + EOF1I4200_0011 (Invalid) EOF code containing RJUMP with target PUSH2+ + immediate. + """ data_portion_length = int.from_bytes(opcode, byteorder="big") - 0x5F if jump == JumpDirection.FORWARD: offset = data_portion_length if data_portion_end else 1 @@ -885,7 +923,10 @@ def test_rjump_into_rjumpv( target_rjumpv_table_size: int, data_portion_end: bool, ): - """EOF1I4200_0012 (Invalid) EOF code containing RJUMP with target RJUMPV immediate.""" + """ + EOF1I4200_0012 (Invalid) EOF code containing RJUMP with target RJUMPV + immediate. + """ invalid_destination = 4 + (2 * target_rjumpv_table_size) if data_portion_end else 4 target_jump_table = [0 for _ in range(target_rjumpv_table_size)] eof_test( @@ -909,7 +950,10 @@ def test_rjump_into_callf( eof_test: EOFTestFiller, data_portion_end: bool, ): - """EOF1I4200_0013 (Invalid) EOF code containing RJUMP with target CALLF immediate.""" + """ + EOF1I4200_0013 (Invalid) EOF code containing RJUMP with target CALLF + immediate. + """ invalid_destination = 2 if data_portion_end else 1 eof_test( container=Container( diff --git a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py index 3fa0e7f3f65..dd1647eb95a 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py @@ -129,7 +129,9 @@ def test_rjumpi_condition_zero( pre: Alloc, calldata: bytes, ): - """Test RJUMPI contract switching based on external input (condition zero).""" + """ + Test RJUMPI contract switching based on external input (condition zero). + """ env = Environment() sender = pre.fund_eoa(10**18) contract_address = pre.deploy_contract( @@ -221,7 +223,10 @@ def test_rjumpi_zero( def test_rjumpi_max_forward( eof_state_test: EOFStateTestFiller, ): - """EOF1V4200_0007 (Valid) EOF with RJUMPI containing the maximum offset (32767).""" + """ + EOF1V4200_0007 (Valid) EOF with RJUMPI containing the maximum offset + (32767). + """ eof_state_test( container=Container( sections=[ @@ -730,8 +735,8 @@ def test_rjumpi_valid_forward( container: Container, ): """ - Validate a valid code section containing at least one forward RJUMPI. - These tests exercise the stack height validation. + Validate a valid code section containing at least one forward RJUMPI. These + tests exercise the stack height validation. """ eof_test(container=container) @@ -909,8 +914,8 @@ def test_rjumpi_max_bytecode_size( eof_test: EOFTestFiller, ): """ - EOF1V4200_0003 EOF with RJUMPI containing the maximum offset that does not exceed the maximum - bytecode size. + EOF1V4200_0003 EOF with RJUMPI containing the maximum offset that does not + exceed the maximum bytecode size. """ noop_count = MAX_BYTECODE_SIZE - 24 code = Op.RJUMPI[len(Op.NOOP) * noop_count](Op.ORIGIN) + (Op.NOOP * noop_count) + Op.STOP @@ -957,8 +962,8 @@ def test_rjumpi_into_header( offset: int, ): """ - EOF1I4200_0016 (Invalid) EOF code containing RJUMPI with target outside code bounds - (Jumping into header). + EOF1I4200_0016 (Invalid) EOF code containing RJUMPI with target outside + code bounds (Jumping into header). """ eof_test( container=Container( @@ -976,8 +981,8 @@ def test_rjumpi_jump_before_header( eof_test: EOFTestFiller, ): """ - EOF1I4200_0017 (Invalid) EOF code containing RJUMPI with target outside code bounds - (Jumping to before code begin). + EOF1I4200_0017 (Invalid) EOF code containing RJUMPI with target outside + code bounds (Jumping to before code begin). """ eof_test( container=Container( @@ -995,8 +1000,8 @@ def test_rjumpi_into_data( eof_test: EOFTestFiller, ): """ - EOF1I4200_0018 (Invalid) EOF code containing RJUMPI with target outside code bounds - (Jumping into data section). + EOF1I4200_0018 (Invalid) EOF code containing RJUMPI with target outside + code bounds (Jumping into data section). """ eof_test( container=Container( @@ -1015,8 +1020,8 @@ def test_rjumpi_after_container( eof_test: EOFTestFiller, ): """ - EOF1I4200_0019 (Invalid) EOF code containing RJUMPI with target outside code bounds - (Jumping to after code end). + EOF1I4200_0019 (Invalid) EOF code containing RJUMPI with target outside + code bounds (Jumping to after code end). """ eof_test( container=Container( @@ -1034,8 +1039,8 @@ def test_rjumpi_to_code_end( eof_test: EOFTestFiller, ): """ - EOF1I4200_0020 (Invalid) EOF code containing RJUMPI with target outside code bounds - (Jumping to code end). + EOF1I4200_0020 (Invalid) EOF code containing RJUMPI with target outside + code bounds (Jumping to code end). """ eof_test( container=Container( @@ -1055,8 +1060,8 @@ def test_rjumpi_into_self_data_portion( offset: int, ): """ - EOF1I4200_0021 (Invalid) EOF code containing RJUMPI with target same RJUMPI immediate - (with offset). + EOF1I4200_0021 (Invalid) EOF code containing RJUMPI with target same RJUMPI + immediate (with offset). """ eof_test( container=Container( @@ -1076,8 +1081,8 @@ def test_rjumpi_into_self( stack_height_spread: int, ): """ - EOF code containing RJUMPI targeting itself (-3). - This can never be valid because this is backward jump and RJUMPI consumes one stack item. + EOF code containing RJUMPI targeting itself (-3). This can never be valid + because this is backward jump and RJUMPI consumes one stack item. """ # Create variadic stack height by the parametrized spread. stack_spread_code = Bytecode() @@ -1099,7 +1104,10 @@ def test_rjumpi_into_self( def test_rjumpi_into_stack_height_diff( eof_test: EOFTestFiller, ): - """EOF code containing RJUMPI with target instruction that causes stack height difference.""" + """ + EOF code containing RJUMPI with target instruction that causes stack height + difference. + """ eof_test( container=Container( sections=[ @@ -1118,7 +1126,10 @@ def test_rjumpi_into_stack_height_diff( def test_rjumpi_into_stack_underflow( eof_test: EOFTestFiller, ): - """EOF code containing RJUMPI with target instruction that cause stack underflow.""" + """ + EOF code containing RJUMPI with target instruction that cause stack + underflow. + """ eof_test( container=Container( sections=[ @@ -1134,7 +1145,10 @@ def test_rjumpi_into_stack_underflow( def test_rjumpi_skips_stack_underflow( eof_test: EOFTestFiller, ): - """EOF code containing RJUMPI where the default path produces a stack underflow.""" + """ + EOF code containing RJUMPI where the default path produces a stack + underflow. + """ eof_test( container=Container( sections=[ @@ -1148,7 +1162,10 @@ def test_rjumpi_skips_stack_underflow( def test_rjumpi_into_rjump( eof_test: EOFTestFiller, ): - """EOF1I4200_0023 (Invalid) EOF code containing RJUMPI with target RJUMP immediate.""" + """ + EOF1I4200_0023 (Invalid) EOF code containing RJUMPI with target RJUMP + immediate. + """ eof_test( container=Container( sections=[ @@ -1164,7 +1181,10 @@ def test_rjumpi_into_rjump( def test_rjumpi_into_rjumpi( eof_test: EOFTestFiller, ): - """EOF1I4200_0022 (Invalid) EOF code containing RJUMPI with target other RJUMPI immediate.""" + """ + EOF1I4200_0022 (Invalid) EOF code containing RJUMPI with target other + RJUMPI immediate. + """ eof_test( container=Container( sections=[ @@ -1187,7 +1207,10 @@ def test_rjumpi_into_push_1( eof_test: EOFTestFiller, jump: JumpDirection, ): - """EOF1I4200_0024 (Invalid) EOF code containing RJUMPI with target PUSH1 immediate.""" + """ + EOF1I4200_0024 (Invalid) EOF code containing RJUMPI with target PUSH1 + immediate. + """ code = ( Op.PUSH1[1] + Op.RJUMPI[-4] if jump == JumpDirection.BACKWARD @@ -1251,7 +1274,10 @@ def test_rjumpi_into_push_n( jump: JumpDirection, data_portion_end: bool, ): - """EOF1I4200_0024 (Invalid) EOF code containing RJUMPI with target PUSH2+ immediate.""" + """ + EOF1I4200_0024 (Invalid) EOF code containing RJUMPI with target PUSH2+ + immediate. + """ data_portion_length = int.from_bytes(opcode, byteorder="big") - 0x5F if jump == JumpDirection.FORWARD: offset = data_portion_length if data_portion_end else 1 @@ -1280,7 +1306,10 @@ def test_rjumpi_into_rjumpv( target_rjumpv_table_size: int, data_portion_end: bool, ): - """EOF1I4200_0025 (Invalid) EOF code containing RJUMPI with target RJUMPV immediate.""" + """ + EOF1I4200_0025 (Invalid) EOF code containing RJUMPI with target RJUMPV + immediate. + """ invalid_destination = 4 + (2 * target_rjumpv_table_size) if data_portion_end else 4 target_jump_table = [0 for _ in range(target_rjumpv_table_size)] eof_test( @@ -1309,7 +1338,10 @@ def test_rjumpi_into_callf( eof_test: EOFTestFiller, data_portion_end: bool, ): - """EOF1I4200_0026 (Invalid) EOF code containing RJUMPI with target CALLF immediate.""" + """ + EOF1I4200_0026 (Invalid) EOF code containing RJUMPI with target CALLF + immediate. + """ invalid_destination = 2 if data_portion_end else 1 eof_test( container=Container( @@ -1474,8 +1506,8 @@ def test_rjumpi_stack_validation( ): """ Check that you can get to the same opcode with two different stack heights - Spec now allows this: - 4.b in https://github.com/ipsilon/eof/blob/main/spec/eof.md#stack-validation. + Spec now allows this: 4.b in + https://github.com/ipsilon/eof/blob/main/spec/eof.md#stack-validation. """ container = Container.Code(code=Op.RJUMPI[1](1) + Op.ADDRESS + Op.NOOP + Op.STOP) eof_test( @@ -1490,7 +1522,8 @@ def test_rjumpi_at_the_end( """ Test invalid RJUMPI as the end of a code section. https://github.com/ipsilon/eof/blob/main/spec/eof.md#stack-validation 4.i: - This implies that the last instruction must be a terminating instruction or RJUMP. + This implies that the last instruction must be a terminating instruction or + RJUMP. """ eof_test( container=Container( @@ -1611,8 +1644,8 @@ def test_double_rjumpi_stack_height_mismatch( eof_test: EOFTestFiller, ): """ - Test stack height check of the backward RJUMP - targeted by two RJUMPIs with the non-uniform stack height range. + Test stack height check of the backward RJUMP targeted by two RJUMPIs with + the non-uniform stack height range. """ eof_test( container=Container( @@ -1635,8 +1668,8 @@ def test_double_rjumpi_invalid_max_stack_height( eof_test: EOFTestFiller, ): """ - Test max stack height of the final block - targeted by two RJUMPIs with the non-uniform stack height range. + Test max stack height of the final block targeted by two RJUMPIs with the + non-uniform stack height range. """ eof_test( container=Container( @@ -1848,7 +1881,7 @@ def test_rjumpi_backward_invalid_max_stack_height( container: Container, ): """ - Validate a code section containing at least one backward RJUMPI - invalid because of the incorrect max stack height. + Validate a code section containing at least one backward RJUMPI invalid + because of the incorrect max stack height. """ eof_test(container=container, expect_exception=EOFException.STACK_HEIGHT_MISMATCH) diff --git a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py index 7fe59d8ffaa..6d32799aaed 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py @@ -200,7 +200,10 @@ def test_rjumpv_full_table( eof_state_test: EOFStateTestFiller, target: int, ): - """EOF1V4200_0012/13/14/15 (Valid) EOF with RJUMPV table size 256 (target parameterized).""" + """ + EOF1V4200_0012/13/14/15 (Valid) EOF with RJUMPV table size 256 (target + parameterized). + """ eof_state_test( container=Container( sections=[ @@ -220,7 +223,10 @@ def test_rjumpv_full_table( def test_rjumpv_max_forwards( eof_state_test: EOFStateTestFiller, ): - """EOF1V4200_0016 (Valid) EOF with RJUMPV containing the maximum offset (32767).""" + """ + EOF1V4200_0016 (Valid) EOF with RJUMPV containing the maximum offset + (32767). + """ eof_state_test( container=Container( sections=[ @@ -240,7 +246,10 @@ def test_rjumpv_max_forwards( def test_rjumpv_truncated_empty( eof_test: EOFTestFiller, ): - """EOF1I4200_0027 (Invalid) EOF code containing RJUMPV with max_index 0 but no immediates.""" + """ + EOF1I4200_0027 (Invalid) EOF code containing RJUMPV with max_index 0 but no + immediates. + """ eof_test( container=Container( sections=[ @@ -290,8 +299,8 @@ def test_rjumpv_into_header( invalid_index: int, ): """ - EOF1I4200_0031 (Invalid) EOF code containing RJUMPV with target outside code bounds - (Jumping into header). + EOF1I4200_0031 (Invalid) EOF code containing RJUMPV with target outside + code bounds (Jumping into header). """ invalid_destination = -5 - (2 * table_size) jump_table = [0 for _ in range(table_size)] @@ -324,8 +333,8 @@ def test_rjumpv_before_container( offset: int, ): """ - EOF1I4200_0032 (Invalid) EOF code containing RJUMPV with target outside code bounds - (Jumping to before code begin). + EOF1I4200_0032 (Invalid) EOF code containing RJUMPV with target outside + code bounds (Jumping to before code begin). """ invalid_destination = offset - (2 * table_size) jump_table = [0 for _ in range(table_size)] @@ -356,8 +365,8 @@ def test_rjumpv_into_data( invalid_index: int, ): """ - EOF1I4200_0033 (Invalid) EOF code containing RJUMPV with target outside code bounds - (Jumping into data section). + EOF1I4200_0033 (Invalid) EOF code containing RJUMPV with target outside + code bounds (Jumping into data section). """ invalid_destination = 2 jump_table = [0 for _ in range(table_size)] @@ -389,8 +398,8 @@ def test_rjumpv_after_container( invalid_index: int, ): """ - EOF1I4200_0034 (Invalid) EOF code containing RJUMPV with target outside code bounds - (Jumping to after code end). + EOF1I4200_0034 (Invalid) EOF code containing RJUMPV with target outside + code bounds (Jumping to after code end). """ invalid_destination = 2 jump_table = [0 for _ in range(table_size)] @@ -421,8 +430,8 @@ def test_rjumpv_at_end( invalid_index: int, ): """ - EOF1I4200_0035 (Invalid) EOF code containing RJUMPV with target outside code bounds - (Jumping to code end). + EOF1I4200_0035 (Invalid) EOF code containing RJUMPV with target outside + code bounds (Jumping to code end). """ invalid_destination = 1 jump_table = [0 for _ in range(table_size)] @@ -458,7 +467,10 @@ def test_rjumpv_into_self_data_portion( invalid_index: int, data_portion_end: bool, ): - """EOF1I4200_0036 (Invalid) EOF code containing RJUMPV with target same RJUMPV immediate.""" + """ + EOF1I4200_0036 (Invalid) EOF code containing RJUMPV with target same RJUMPV + immediate. + """ invalid_destination = -1 if data_portion_end else -(2 * table_size) - 1 jump_table = [0 for _ in range(table_size)] jump_table[invalid_index] = invalid_destination @@ -490,8 +502,8 @@ def test_rjumpv_into_self( stack_height_spread: int, ): """ - EOF code containing RJUMPV targeting itself. - This can never be valid because this is backward jump and RJUMPV consumes one stack item. + EOF code containing RJUMPV targeting itself. This can never be valid + because this is backward jump and RJUMPV consumes one stack item. """ # Create variadic stack height by the parametrized spread. stack_spread_code = Bytecode() @@ -527,7 +539,10 @@ def test_rjumpv_into_stack_height_diff( table_size: int, invalid_index: int, ): - """EOF code containing RJUMPV with target instruction that causes stack height difference.""" + """ + EOF code containing RJUMPV with target instruction that causes stack height + difference. + """ jump_table = [0 for _ in range(table_size)] jump_table[invalid_index] = -(len(Op.RJUMPV[jump_table]) + len(Op.PUSH1[0]) + len(Op.PUSH1[0])) @@ -556,7 +571,10 @@ def test_rjumpv_into_stack_underflow( table_size: int, invalid_index: int, ): - """EOF code containing RJUMPV with target instruction that cause stack underflow.""" + """ + EOF code containing RJUMPV with target instruction that cause stack + underflow. + """ jump_table = [0 for _ in range(table_size)] jump_table[invalid_index] = 1 eof_test( @@ -580,7 +598,10 @@ def test_rjumpv_skips_stack_underflow( eof_test: EOFTestFiller, table_size: int, ): - """EOF code containing RJUMPV where the default path produces a stack underflow.""" + """ + EOF code containing RJUMPV where the default path produces a stack + underflow. + """ jump_table = [1 for _ in range(table_size)] eof_test( container=Container( @@ -611,7 +632,10 @@ def test_rjumpv_into_rjump( invalid_index: int, data_portion_end: bool, ): - """EOF1I4200_0037 (Invalid) EOF code containing RJUMPV with target RJUMP immediate.""" + """ + EOF1I4200_0037 (Invalid) EOF code containing RJUMPV with target RJUMP + immediate. + """ invalid_destination = 3 if data_portion_end else 2 jump_table = [0 for _ in range(table_size)] jump_table[invalid_index] = invalid_destination @@ -651,7 +675,10 @@ def test_rjumpv_into_rjumpi( invalid_index: int, data_portion_end: bool, ): - """EOF1I4200_0038 (Invalid) EOF code containing RJUMPV with target RJUMPI immediate.""" + """ + EOF1I4200_0038 (Invalid) EOF code containing RJUMPV with target RJUMPI + immediate. + """ invalid_destination = 5 if data_portion_end else 4 jump_table = [0 for _ in range(table_size)] jump_table[invalid_index] = invalid_destination @@ -692,7 +719,10 @@ def test_rjumpv_into_push_1( table_size: int, invalid_index: int, ): - """EOF1I4200_0039 (Invalid) EOF code containing RJUMPV with target PUSH1 immediate.""" + """ + EOF1I4200_0039 (Invalid) EOF code containing RJUMPV with target PUSH1 + immediate. + """ if jump == JumpDirection.FORWARD: invalid_destination = 2 jump_table = [0 for _ in range(table_size)] @@ -777,7 +807,10 @@ def test_rjumpv_into_push_n( invalid_index: int, data_portion_end: bool, ): - """EOF1I4200_0039 (Invalid) EOF code containing RJUMPV with target PUSHN immediate.""" + """ + EOF1I4200_0039 (Invalid) EOF code containing RJUMPV with target PUSHN + immediate. + """ data_portion_length = int.from_bytes(opcode, byteorder="big") - 0x5F if jump == JumpDirection.FORWARD: invalid_destination = data_portion_length + 1 if data_portion_end else 2 @@ -830,7 +863,10 @@ def test_rjumpv_into_rjumpv( invalid_index: int, data_portion_end: bool, ): - """EOF1I4200_0040 (Invalid) EOF code containing RJUMPV with target other RJUMPV immediate.""" + """ + EOF1I4200_0040 (Invalid) EOF code containing RJUMPV with target other + RJUMPV immediate. + """ invalid_destination = 4 + (2 * target_table_size) if data_portion_end else 4 source_jump_table = [0 for _ in range(source_table_size)] source_jump_table[invalid_index] = invalid_destination @@ -871,7 +907,10 @@ def test_rjumpv_into_callf( invalid_index: int, data_portion_end: bool, ): - """EOF1I4200_0041 (Invalid) EOF code containing RJUMPV with target CALLF immediate.""" + """ + EOF1I4200_0041 (Invalid) EOF code containing RJUMPV with target CALLF + immediate. + """ invalid_destination = 2 if data_portion_end else 1 jump_table = [0 for _ in range(table_size)] jump_table[invalid_index] = invalid_destination @@ -1104,7 +1143,8 @@ def test_rjumpv_at_the_end( ): """ https://github.com/ipsilon/eof/blob/main/spec/eof.md#stack-validation 4.i: - This implies that the last instruction may be a terminating instruction or RJUMPV. + This implies that the last instruction may be a terminating instruction or + RJUMPV. """ eof_test( container=Container( @@ -1546,8 +1586,8 @@ def test_rjumpv_valid_forward( container: Container, ): """ - Validate a valid code section containing at least one forward RJUMPV. - These tests exercise the stack height validation. + Validate a valid code section containing at least one forward RJUMPV. These + tests exercise the stack height validation. """ eof_test(container=container) @@ -1849,7 +1889,7 @@ def test_rjumpv_backward_invalid_max_stack_height( container: Container, ): """ - Validate a code section containing at least one backward RJUMPV - invalid because of the incorrect max stack height. + Validate a code section containing at least one backward RJUMPV invalid + because of the incorrect max stack height. """ eof_test(container=container, expect_exception=EOFException.STACK_HEIGHT_MISMATCH) diff --git a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py index 20c62ac7526..c7e591dd465 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py @@ -1,5 +1,8 @@ """ -abstract: Test cases for [EIP-4750: EOF - Functions](https://eips.ethereum.org/EIPS/eip-4750) - EIP-4750 formalizes functions in the EVM object format, introducing callable units of code. - Opcodes introduced: `CALLF` (`0xE3`), `RETF` (`0xE4`). -""" # noqa: E501 +abstract: Test cases for [EIP-4750: EOF - +Functions](https://eips.ethereum.org/EIPS/eip-4750). + +EIP-4750 formalizes functions in the EVM object format, introducing +callable units of code. +Opcodes introduced: `CALLF` (`0xE3`), `RETF` (`0xE4`). +""" diff --git a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_callf_execution.py b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_callf_execution.py index 30adfa59c2a..79df463246a 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_callf_execution.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_callf_execution.py @@ -73,7 +73,9 @@ def test_callf_factorial(eof_state_test: EOFStateTestFiller, n, result): ((0, 1), (1, 1), (13, 233), (27, 196418)), ) def test_callf_fibonacci(eof_state_test: EOFStateTestFiller, n, result): - """Test fibonacci sequence implementation with recursive CALLF instructions.""" + """ + Test fibonacci sequence implementation with recursive CALLF instructions. + """ eof_state_test( container=Container( sections=[ @@ -454,12 +456,13 @@ def test_callf_sneaky_stack_overflow( pre: Alloc, ): """ - CALLF where a normal execution would not overflow, but EIP-4750 CALLF rule #3 triggers. + CALLF where a normal execution would not overflow, but EIP-4750 CALLF rule + #3 triggers. - Code Section 0 - Mostly fills the stack - Code Section 1 - jumper to 2, so container verification passes (we want a runtime failure) - Code Section 2 - Could require too much stack, but doesn't as it JUMPFs to 3 - Code Section 3 - Writes canary values + Code Section 0 - Mostly fills the stack Code Section 1 - jumper to 2, so + container verification passes (we want a runtime failure) Code Section 2 - + Could require too much stack, but doesn't as it JUMPFs to 3 Code Section 3 + - Writes canary values The intent is to catch implementations of CALLF that don't enforce rule #3 """ @@ -552,17 +555,17 @@ def test_callf_max_stack( pre: Alloc, ): """ - CALLF where a normal execution would not overflow, but EIP-4750 CALLF rule #4 triggers. + CALLF where a normal execution would not overflow, but EIP-4750 CALLF rule + #4 triggers. - Code Section 0 - calls #1 with the configured height, but we load some operands so the - return stack does not overflow - Code Section 1 - expands stack, calls #2, THEN recursively calls itself until input is zero, - and returns. - Code Section 2 - Just returns, zero inputs, zero outputs + Code Section 0 - calls #1 with the configured height, but we load some + operands so the return stack does not overflow Code Section 1 - expands + stack, calls #2, THEN recursively calls itself until input is zero, and + returns. Code Section 2 - Just returns, zero inputs, zero outputs - This will catch CALLF execution rule #3: always fail if the operand stack is full. Not - checking rule 3 results in a call to section 2 and not overfilling the stack (as it is just - RETF). + This will catch CALLF execution rule #3: always fail if the operand stack + is full. Not checking rule 3 results in a call to section 2 and not + overfilling the stack (as it is just RETF). """ env = Environment() sender = pre.fund_eoa() diff --git a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_code_validation.py b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_code_validation.py index c705d197581..e1df510d68b 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_code_validation.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_code_validation.py @@ -379,7 +379,10 @@ def test_eof_validity( eof_test: EOFTestFiller, container: Container, ): - """Test EOF container validation for features around EIP-4750 / Functions / Code Sections.""" + """ + Test EOF container validation for features around EIP-4750 / Functions / + Code Sections. + """ eof_test(container=container) @@ -475,7 +478,9 @@ def test_invalid_code_section_index( eof_test: EOFTestFiller, container: Container, ): - """Test cases for CALLF instructions with invalid target code section index.""" + """ + Test cases for CALLF instructions with invalid target code section index. + """ eof_test(container=container, expect_exception=EOFException.INVALID_CODE_SECTION_INDEX) @@ -637,8 +642,8 @@ def test_unreachable_code_sections( container: Container, ): """ - Test cases for EOF unreachable code sections - (i.e. code sections not reachable from the code section 0). + Test cases for EOF unreachable code sections (i.e. code sections not + reachable from the code section 0). """ eof_test(container=container, expect_exception=EOFException.UNREACHABLE_CODE_SECTIONS) @@ -646,9 +651,10 @@ def test_unreachable_code_sections( @pytest.mark.parametrize("callee_outputs", [1, 2, MAX_CODE_OUTPUTS]) def test_callf_stack_height_limit_exceeded(eof_test, callee_outputs): """ - Test for invalid EOF code containing CALLF instruction exceeding the stack height limit. - The code reaches the maximum runtime stack height (1024) - which is above the EOF limit for the stack height in the type section (1023). + Test for invalid EOF code containing CALLF instruction exceeding the stack + height limit. The code reaches the maximum runtime stack height (1024) + which is above the EOF limit for the stack height in the type section + (1023). """ callf_stack_height = MAX_RUNTIME_STACK_HEIGHT - callee_outputs container = Container( @@ -669,7 +675,9 @@ def test_callf_stack_height_limit_exceeded(eof_test, callee_outputs): @pytest.mark.parametrize("stack_height", [512, 513, 1023]) def test_callf_stack_overflow(eof_test: EOFTestFiller, stack_height: int): - """Test CALLF instruction recursively calling itself causing stack overflow.""" + """ + Test CALLF instruction recursively calling itself causing stack overflow. + """ container = Container( sections=[ Section.Code(code=Op.CALLF[1] + Op.STOP), @@ -689,7 +697,10 @@ def test_callf_stack_overflow(eof_test: EOFTestFiller, stack_height: int): @pytest.mark.parametrize("stack_height", [1, 2]) def test_callf_stack_overflow_after_callf(eof_test: EOFTestFiller, stack_height: int): - """Test CALLF instruction calling next function causing stack overflow at validation time.""" + """ + Test CALLF instruction calling next function causing stack overflow at + validation time. + """ container = Container( sections=[ Section.Code(code=Op.CALLF[1] + Op.STOP), @@ -823,7 +834,10 @@ def test_callf_stack_overflow_variable_stack_4(eof_test: EOFTestFiller): @pytest.mark.parametrize("stack_height", [2, 3]) def test_callf_validate_outputs(eof_test: EOFTestFiller, stack_height: int): - """Test CALLF instruction when calling a function returning more outputs than expected.""" + """ + Test CALLF instruction when calling a function returning more outputs than + expected. + """ container = Container( sections=[ Section.Code(code=Op.CALLF[1] + Op.STOP, max_stack_height=1), @@ -1074,10 +1088,11 @@ def test_callf_with_inputs_stack_overflow_variable_stack( ) def test_callf_stack_overflow_by_outputs(eof_test, callee_outputs, max_stack_height): """ - Test for invalid EOF code containing CALLF instruction exceeding the runtime stack height limit - by calling a function with at least one output. The computed stack height of the code section 0 - is always above the maximum allowed in the EOF type section. Therefore, the test declares - an invalid max_stack_height. + Test for invalid EOF code containing CALLF instruction exceeding the + runtime stack height limit by calling a function with at least one output. + The computed stack height of the code section 0 is always above the maximum + allowed in the EOF type section. Therefore, the test declares an invalid + max_stack_height. """ callf_stack_height = (MAX_RUNTIME_STACK_HEIGHT + 1) - callee_outputs container = Container( @@ -1102,10 +1117,10 @@ def test_callf_stack_overflow_by_outputs(eof_test, callee_outputs, max_stack_hei ) def test_callf_stack_overflow_by_height(eof_test, callee_stack_height): """ - Test for invalid EOF code containing CALLF instruction exceeding the runtime stack height limit - by calling a function with 2+ maximum stack height. - The callee with the maximum stack height of 1 is valid because runtime limit (1024) - is 1 bigger than the EOF limit (1023). + Test for invalid EOF code containing CALLF instruction exceeding the + runtime stack height limit by calling a function with 2+ maximum stack + height. The callee with the maximum stack height of 1 is valid because + runtime limit (1024) is 1 bigger than the EOF limit (1023). """ container = Container( sections=[ @@ -1234,8 +1249,8 @@ def test_returning_section_aborts( eof_test: EOFTestFiller, ): """ - Test EOF container validation where in the same code section we have returning - and nonreturning terminating instructions. + Test EOF container validation where in the same code section we have + returning and nonreturning terminating instructions. """ container = Container( name="returning_section_aborts", diff --git a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py index fb5897d4ed4..3e81fe6764b 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py @@ -1,5 +1,8 @@ """ -abstract: Test cases for [EIP-5450: EOF - Stack Validation](https://eips.ethereum.org/EIPS/eip-5450) - EIP-5450 defines stack validation requirements to ensure consistent behavior during execution. - Opcodes introduced: None (specifies validation rules for stack usage). -""" # noqa: E501 +abstract: Test cases for [EIP-5450: EOF - Stack +Validation](https://eips.ethereum.org/EIPS/eip-5450). + +EIP-5450 defines stack validation requirements to ensure consistent +behavior during execution. +Opcodes introduced: None (specifies validation rules for stack usage). +""" diff --git a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/test_code_validation.py b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/test_code_validation.py index ed58e09c06a..f85edd1f12c 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/test_code_validation.py +++ b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/test_code_validation.py @@ -1,4 +1,7 @@ -"""Code validation of CALLF, JUMPF, RETF opcodes in conjunction with static relative jumps.""" +""" +Code validation of CALLF, JUMPF, RETF opcodes in conjunction with static +relative jumps. +""" import itertools from enum import Enum, auto, unique @@ -51,7 +54,9 @@ def __str__(self) -> str: @unique class RjumpSpot(Enum): - """Possible spots in the code section layout where the RJUMP* is injected.""" + """ + Possible spots in the code section layout where the RJUMP* is injected. + """ BEGINNING = auto() BEFORE_TERMINATION = auto() @@ -65,14 +70,16 @@ def rjump_code_with( rjump_kind: RjumpKind | None, code_so_far_len: int, next_code: Bytecode ) -> Tuple[Bytecode, bool, bool, bool]: """ - Unless `rjump_kind` is None generates a code snippet with an RJUMP* instruction. - For some kinds `code_so_far_len` must be code length in bytes preceding the snippet. - For some kinds `next_code_len` must be code length in bytes of some code which follows. + Unless `rjump_kind` is None generates a code snippet with an RJUMP* + instruction. For some kinds `code_so_far_len` must be code length in bytes + preceding the snippet. For some kinds `next_code_len` must be code length + in bytes of some code which follows. - It is expected that the snippet and the jump target are valid, but the resulting code - or its stack balance might not. + It is expected that the snippet and the jump target are valid, but the + resulting code or its stack balance might not. - Also returns some traits of the snippet: `is_backwards`, `pops` and `pushes` + Also returns some traits of the snippet: `is_backwards`, `pops` and + `pushes` """ body = Bytecode() @@ -124,8 +131,9 @@ def rjump_code_with( raise TypeError("unknown rjumps value" + str(rjump_kind)) if jumps_over_next: - # This is against intuition, but if the code we're jumping over pushes, the path - # which misses it will be short of stack items, as if the RJUMP* popped and vice versa. + # This is against intuition, but if the code we're jumping over pushes, + # the path which misses it will be short of stack items, as if the + # RJUMP* popped and vice versa. if next_code.pushed_stack_items > next_code.popped_stack_items: pops = True elif next_code.popped_stack_items > next_code.pushed_stack_items: @@ -136,10 +144,11 @@ def rjump_code_with( def call_code_with(inputs, outputs, call: Bytecode) -> Bytecode: """ - Generate code snippet with the `call` bytecode provided and its respective input/output - management. + Generate code snippet with the `call` bytecode provided and its respective + input/output management. - `inputs` and `outputs` are understood as those of the code section we're generating for. + `inputs` and `outputs` are understood as those of the code section we're + generating for. """ body = Bytecode() @@ -168,8 +177,8 @@ def section_code_with( """ Generate code section with RJUMP* and CALLF/RETF instructions. - Also returns some traits of the section: `has_invalid_back_jump`, `rjump_snippet_pops`, - `rjump_snippet_pushes`, `rjump_falls_off_code` + Also returns some traits of the section: `has_invalid_back_jump`, + `rjump_snippet_pops`, `rjump_snippet_pushes`, `rjump_falls_off_code` """ code = Bytecode() code.pushed_stack_items, code.max_stack_height = (inputs, inputs) @@ -214,7 +223,8 @@ def section_code_with( RjumpKind.RJUMPI_OVER_NEXT_NESTED, RjumpKind.RJUMPV_EMPTY_AND_OVER_NEXT, ]: - # Jump over termination or jump over body, but there is nothing after the body. + # Jump over termination or jump over body, but there is nothing + # after the body. rjump_falls_off_code = True code += termination @@ -260,10 +270,12 @@ def test_rjumps_callf_retf( """ Test EOF container validation for EIP-4200 vs EIP-4750 interactions. - Each test's code consists of `num_sections` code sections, which call into one another - and then return. Code may include RJUMP* snippets of `rjump_kind` in various `rjump_spots`. + Each test's code consists of `num_sections` code sections, which call into + one another and then return. Code may include RJUMP* snippets of + `rjump_kind` in various `rjump_spots`. """ - # Zeroth section has always 0 inputs and 0 outputs, so is excluded from param + # Zeroth section has always 0 inputs and 0 outputs, so is excluded from + # param inputs = (0,) + inputs outputs = (0,) + outputs @@ -316,7 +328,8 @@ def test_rjumps_callf_retf( container_has_invalid_back_jump = True if rjump_snippet_pops: container_has_rjump_pops = True - # Pushes to the stack never affect the zeroth section, because it `STOP`s and not `RETF`s. + # Pushes to the stack never affect the zeroth section, because it + # `STOP`s and not `RETF`s. if rjump_snippet_pushes and section_idx != 0: container_has_rjump_pushes = True if rjump_falls_off_code: @@ -371,10 +384,11 @@ def test_rjumps_jumpf_nonreturning( rjump_spot: RjumpSpot, ): """ - Test EOF container validation for EIP-4200 vs EIP-6206 interactions on non-returning - functions. + Test EOF container validation for EIP-4200 vs EIP-6206 interactions on + non-returning functions. """ - # Zeroth section has always 0 inputs and 0 outputs, so is excluded from param + # Zeroth section has always 0 inputs and 0 outputs, so is excluded from + # param inputs = (0,) + inputs sections = [] @@ -394,8 +408,9 @@ def test_rjumps_jumpf_nonreturning( call = None termination = Op.STOP - # `section_has_invalid_back_jump` - never happens: we excluded RJUMP from the end - # `rjump_snippet_pushes` - never happens: we never RETF where too large stack would fail + # `section_has_invalid_back_jump` - never happens: we excluded RJUMP + # from the end `rjump_snippet_pushes` - never happens: we never RETF + # where too large stack would fail ( code, _section_has_invalid_back_jump, @@ -463,8 +478,8 @@ def test_all_opcodes_stack_underflow( eof_test: EOFTestFiller, op: Op, stack_height: int, spread: int ): """ - Test EOF validation failing due to stack overflow - caused by the specific instruction `op`. + Test EOF validation failing due to stack overflow caused by the specific + instruction `op`. """ code = Bytecode() @@ -579,7 +594,9 @@ def test_all_opcodes_stack_underflow( ids=lambda x: x.name, ) def test_stack_underflow_examples(eof_test, container): - """Test EOF validation failing due to stack underflow at basic instructions.""" + """ + Test EOF validation failing due to stack underflow at basic instructions. + """ eof_test(container=container, expect_exception=EOFException.STACK_UNDERFLOW) diff --git a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/test_execution.py b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/test_execution.py index d72f12eb148..5c9fa2fa5ba 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/test_execution.py +++ b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/test_execution.py @@ -27,12 +27,13 @@ def test_execution_at_max_stack_height( eof_state_test: EOFStateTestFiller, code_inputs: int, call_op: Op ): """ - Test execution at the maximum runtime operand stack height (1024). - EOF doesn't allow to increase the stack height of a single code section more than 1023. - The effect of the maximum runtime stack height is achieved by using non-zero number - of the code section inputs and increasing the runtime stack to the limit accordingly. - The test pushes consecutive numbers starting from 0 (including inputs). - At the maximum stack height SSTORE is used so it should store 1022 at key 1023. + Test execution at the maximum runtime operand stack height (1024). EOF + doesn't allow to increase the stack height of a single code section more + than 1023. The effect of the maximum runtime stack height is achieved by + using non-zero number of the code section inputs and increasing the runtime + stack to the limit accordingly. The test pushes consecutive numbers + starting from 0 (including inputs). At the maximum stack height SSTORE is + used so it should store 1022 at key 1023. """ max_stack_increase = MAX_RUNTIME_STACK_HEIGHT - code_inputs container = Container( diff --git a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py index b2391ecb037..f833734006b 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py @@ -1,5 +1,6 @@ """ -abstract: Test cases for [EIP-6206: EOF - JUMPF and non-returning functions](https://eips.ethereum.org/EIPS/eip-6206) - EIP-6206 adds a conditional forward jump instruction and support for functions without return values. - Opcodes introduced: `JUMPF` (`0xE5`). -""" # noqa: E501 +abstract: Test cases for [EIP-6206: EOF - JUMPF and non-returning +functions](https://eips.ethereum.org/EIPS/eip-6206) EIP-6206 adds a conditional +forward jump instruction and support for functions without return values. +Opcodes introduced: `JUMPF` (`0xE5`). +""" diff --git a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_execution.py b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_execution.py index c8c21022b99..b85813b98a3 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_execution.py +++ b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_execution.py @@ -299,7 +299,10 @@ def test_jumpf_way_too_large( def test_jumpf_to_nonexistent_section( eof_state_test: EOFStateTestFiller, ): - """Tests JUMPF jumping to valid section number but where the section does not exist.""" + """ + Tests JUMPF jumping to valid section number but where the section does not + exist. + """ eof_state_test( container=Container( sections=[ @@ -358,7 +361,9 @@ def test_jumpf_stack_size_1024( def test_jumpf_with_inputs_stack_size_1024( eof_state_test: EOFStateTestFiller, ): - """Test stack reaching 1024 items in target function of JUMPF with inputs.""" + """ + Test stack reaching 1024 items in target function of JUMPF with inputs. + """ eof_state_test( container=Container( sections=[ @@ -381,7 +386,10 @@ def test_jumpf_with_inputs_stack_size_1024( def test_jumpf_stack_size_1024_at_push( eof_state_test: EOFStateTestFiller, ): - """Test stack reaching 1024 items in JUMPF target function at PUSH0 instruction.""" + """ + Test stack reaching 1024 items in JUMPF target function at PUSH0 + instruction. + """ eof_state_test( container=Container( sections=[ @@ -430,13 +438,15 @@ def test_jumpf_stack_overflow( eof_state_test: EOFStateTestFiller, ): """ - Test rule #2 in execution semantics, where we make sure we have enough stack to guarantee - safe execution (the "reserved stack rule") max possible stack will not exceed 1024. But some - executions may not overflow the stack, so we need to ensure the rule is checked. + Test rule #2 in execution semantics, where we make sure we have enough + stack to guarantee safe execution (the "reserved stack rule") max possible + stack will not exceed 1024. But some executions may not overflow the stack, + so we need to ensure the rule is checked. `no_overflow` - the stack does not overflow at JUMPF call, executes to end - `rule_overflow` - reserved stack rule triggers, but execution would not overflow if allowed - `execution_overflow` - execution would overflow (but still blocked by reserved stack rule) + `rule_overflow` - reserved stack rule triggers, but execution would not + overflow if allowed `execution_overflow` - execution would overflow (but + still blocked by reserved stack rule) """ eof_state_test( container=Container( @@ -482,7 +492,10 @@ def test_jumpf_stack_overflow( def test_jumpf_with_inputs_stack_size_1024_at_push( eof_state_test: EOFStateTestFiller, ): - """Test stack reaching 1024 items in JUMPF target function with inputs at PUSH0 instruction.""" + """ + Test stack reaching 1024 items in JUMPF target function with inputs at + PUSH0 instruction. + """ eof_state_test( container=Container( sections=[ @@ -520,7 +533,9 @@ def test_jumpf_with_inputs_stack_size_1024_at_push( def test_jumpf_with_inputs_stack_overflow( eof_state_test: EOFStateTestFiller, ): - """Test stack overflowing 1024 items in JUMPF target function with inputs.""" + """ + Test stack overflowing 1024 items in JUMPF target function with inputs. + """ eof_state_test( container=Container( sections=[ diff --git a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_stack.py b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_stack.py index 0831a8c9c24..f54946a3079 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_stack.py +++ b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_stack.py @@ -33,8 +33,8 @@ def test_jumpf_stack_non_returning_rules( stack_height: int, ): """ - Tests for JUMPF validation stack rules. Non-returning section cases. - Valid cases are executed. + Tests for JUMPF validation stack rules. Non-returning section cases. Valid + cases are executed. """ container = Container( name="stack-non-retuning_h-%d_ti-%d" % (stack_height, target_inputs), @@ -90,8 +90,8 @@ def test_jumpf_stack_returning_rules( stack_diff: int, ): """ - Tests for JUMPF validation stack rules. Returning section cases. - Valid cases are executed. + Tests for JUMPF validation stack rules. Returning section cases. Valid + cases are executed. """ if target_outputs > source_outputs: # These create invalid containers without JUMPF validation, Don't test. @@ -297,7 +297,10 @@ def test_jumpf_self_variadic_stack_overflow(eof_test: EOFTestFiller): def test_jumpf_variadic_stack_overflow( eof_test: EOFTestFiller, stack_height: int, callee_stack_height: int ): - """Test JUMPF stack validation causing stack overflow with variable stack height.""" + """ + Test JUMPF stack validation causing stack overflow with variable stack + height. + """ container = Container( sections=[ Section.Code( @@ -346,7 +349,10 @@ def test_jumpf_with_inputs_stack_overflow( def test_jumpf_with_inputs_stack_overflow_variable_stack( eof_test: EOFTestFiller, stack_height: int, callee_stack_increase: int ): - """Test JUMPF with variable stack depending on RJUMPI calling function with inputs.""" + """ + Test JUMPF with variable stack depending on RJUMPI calling function with + inputs. + """ container = Container( sections=[ Section.Code( diff --git a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_target.py b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_target.py index dcfd397430a..886a39e7586 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_target.py +++ b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_target.py @@ -32,8 +32,8 @@ def test_jumpf_target_rules( target_outputs: int, ): """ - Validate the target section rules of JUMPF, and execute valid cases. - We are not testing stack so a lot of the logic is to get correct stack values. + Validate the target section rules of JUMPF, and execute valid cases. We are + not testing stack so a lot of the logic is to get correct stack values. """ source_non_returning = source_outputs == NON_RETURNING_SECTION source_height = 0 if source_non_returning else source_outputs @@ -43,10 +43,11 @@ def test_jumpf_target_rules( target_height = 0 if target_non_returning else target_outputs target_section_index = 2 - # Because we are testing the target and not the stack height validation we need to do some work - # to make sure the stack passes validation. + # Because we are testing the target and not the stack height validation we + # need to do some work to make sure the stack passes validation. - # `source_extra_push` is how many more pushes we need to match our stack commitments + # `source_extra_push` is how many more pushes we need to match our stack + # commitments source_extra_push = max(0, source_height - target_height) source_section = Section.Code( code=Op.PUSH0 * (source_height) @@ -60,8 +61,9 @@ def test_jumpf_target_rules( max_stack_height=source_height + max(1, source_extra_push), ) - # `delta` is how many stack items the target output is from the input height, and tracks the - # number of pushes or (if negative) pops the target needs to do to match output commitments + # `delta` is how many stack items the target output is from the input + # height, and tracks the number of pushes or (if negative) pops the target + # needs to do to match output commitments delta = 0 if target_non_returning or source_non_returning else target_outputs - source_height target_section = Section.Code( code=((Op.PUSH0 * delta) if delta >= 0 else (Op.POP * -delta)) @@ -116,7 +118,7 @@ def test_jumpf_multi_target_rules( eof_state_test: EOFStateTestFiller, ): """ - NOT IMPLEMENTED: - Test a section that contains multiple JUMPF to different targets with different outputs. + NOT IMPLEMENTED: Test a section that contains multiple JUMPF to different + targets with different outputs. """ pass diff --git a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_validation.py b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_validation.py index 67a057df89c..4fe3100e934 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_validation.py +++ b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_validation.py @@ -111,7 +111,9 @@ def test_invalid_code_section_index( eof_test: EOFTestFiller, container: Container, ): - """Test cases for JUMPF instructions with invalid target code section index.""" + """ + Test cases for JUMPF instructions with invalid target code section index. + """ eof_test(container=container, expect_exception=EOFException.INVALID_CODE_SECTION_INDEX) @@ -119,8 +121,8 @@ def test_returning_section_aborts_jumpf( eof_test: EOFTestFiller, ): """ - Test EOF container validation where in the same code section we have returning - and nonreturning terminating instructions. + Test EOF container validation where in the same code section we have + returning and nonreturning terminating instructions. """ container = Container( sections=[ @@ -141,7 +143,10 @@ def test_returning_section_aborts_jumpf( @pytest.mark.parametrize("stack_height", [512, 513, 1023]) def test_jumpf_self_stack_overflow(eof_test: EOFTestFiller, stack_height: int): - """Test JUMPF instruction jumping to itself causing validation time stack overflow.""" + """ + Test JUMPF instruction jumping to itself causing validation time stack + overflow. + """ container = Container( sections=[ Section.Code( @@ -162,7 +167,10 @@ def test_jumpf_self_stack_overflow(eof_test: EOFTestFiller, stack_height: int): def test_jumpf_other_stack_overflow( eof_test: EOFTestFiller, stack_height: int, stack_height_other: int ): - """Test JUMPF instruction jumping to other section causing validation time stack overflow.""" + """ + Test JUMPF instruction jumping to other section causing validation time + stack overflow. + """ container = Container( sections=[ Section.Code( @@ -202,7 +210,10 @@ def test_jumpf_to_non_returning(eof_test: EOFTestFiller, stack_height: int, code @pytest.mark.parametrize("code_inputs", [0, 1, 3, 5]) def test_jumpf_to_non_returning_variable_stack(eof_test: EOFTestFiller, code_inputs: int): - """Test JUMPF jumping to a non-returning function with stack depending on RJUMPI.""" + """ + Test JUMPF jumping to a non-returning function with stack depending on + RJUMPI. + """ container = Container( sections=[ Section.Code( @@ -266,7 +277,10 @@ def test_jumpf_to_returning_variable_stack_1( code_outputs: int, stack_increase: int, ): - """Test JUMPF with variable stack jumping to a returning function increasing the stack.""" + """ + Test JUMPF with variable stack jumping to a returning function increasing + the stack. + """ exception = None if code_inputs >= 3 or code_outputs + 1 < 3: # 3 = Section 1's max stack exception = EOFException.STACK_UNDERFLOW @@ -305,7 +319,10 @@ def test_jumpf_to_returning_variable_stack_2( code_outputs: int, stack_decrease: int, ): - """Test JUMPF with variable stack jumping to a returning function decreasing the stack.""" + """ + Test JUMPF with variable stack jumping to a returning function decreasing + the stack. + """ exceptions = [] if code_inputs >= 3 or code_outputs + 1 < 3: # 3 = Section 1's max stack exceptions.append(EOFException.STACK_UNDERFLOW) @@ -336,7 +353,10 @@ def test_jumpf_to_returning_variable_stack_2( def test_jumpf_to_returning_variable_stack_3(eof_test: EOFTestFiller): - """Test JUMPF with variable stack jumping to a returning function increasing the stack.""" + """ + Test JUMPF with variable stack jumping to a returning function increasing + the stack. + """ container = Container( sections=[ Section.Code(code=Op.CALLF[1] + Op.STOP, max_stack_height=2), diff --git a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_nonreturning_validation.py b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_nonreturning_validation.py index c5bc912994e..d40bdb0eb7c 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_nonreturning_validation.py +++ b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_nonreturning_validation.py @@ -31,7 +31,9 @@ [0, 1, 0x7F, 0x81, 0xFF], ) def test_first_section_returning(eof_test: EOFTestFiller, code: Bytecode, outputs: int): - """Test EOF validation failing because the first section is not non-returning.""" + """ + Test EOF validation failing because the first section is not non-returning. + """ eof_test( container=Container( sections=[Section.Code(code, code_outputs=outputs)], @@ -62,7 +64,10 @@ def test_first_section_returning(eof_test: EOFTestFiller, code: Bytecode, output def test_first_section_with_inputs( eof_test: EOFTestFiller, code: Bytecode, inputs: int, outputs: int ): - """Test EOF validation failing because the first section has non-zero number of inputs.""" + """ + Test EOF validation failing because the first section has non-zero number + of inputs. + """ eof_test( container=Container( sections=[ @@ -94,7 +99,10 @@ def test_first_section_with_inputs( ], ) def test_returning_section_not_returning(eof_test: EOFTestFiller, code_section: Section): - """Test EOF validation failing due to returning section with no RETF or JUMPF-to-returning.""" + """ + Test EOF validation failing due to returning section with no RETF or + JUMPF-to-returning. + """ eof_test( container=Container( sections=[ @@ -118,8 +126,8 @@ def test_returning_section_not_returning(eof_test: EOFTestFiller, code_section: ) def test_returning_section_returncode(eof_test: EOFTestFiller, code_section: Section): """ - Test EOF validation failing because a returning section has no RETF or JUMPF-to-returning - - RETURNCODE version. + Test EOF validation failing because a returning section has no RETF or + JUMPF-to-returning - RETURNCODE version. """ eof_test( container=Container( @@ -148,7 +156,10 @@ def test_returning_section_returncode(eof_test: EOFTestFiller, code_section: Sec @first @code_prefix def test_retf_in_nonreturning(eof_test: EOFTestFiller, first: bool, code_prefix: Bytecode): - """Test EOF validation failing due to non-returning section with the RETF instruction.""" + """ + Test EOF validation failing due to non-returning section with the RETF + instruction. + """ sections = [Section.Code(code_prefix + Op.RETF, code_outputs=NON_RETURNING_SECTION)] if not first: # Prefix sections with additional valid JUMPF to invalid section sections = [Section.Code(Op.JUMPF[1])] + sections @@ -162,7 +173,10 @@ def test_retf_in_nonreturning(eof_test: EOFTestFiller, first: bool, code_prefix: @first @code_prefix def test_jumpf_in_nonreturning(eof_test: EOFTestFiller, first: bool, code_prefix: Bytecode): - """Test EOF validation failing due to non-returning section with the JUMPF instruction.""" + """ + Test EOF validation failing due to non-returning section with the JUMPF + instruction. + """ invalid_section = Section.Code( code_prefix + Op.JUMPF[1 if first else 2], code_outputs=NON_RETURNING_SECTION, diff --git a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py index d75f39a597d..34f1124ed97 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py @@ -1,8 +1,9 @@ """ -abstract: Test cases for [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663) - EIP-663 defines new stack manipulation instructions that allow accessing the stack at higher depths. - Opcodes introduced: `DUPN` (`0xE6`), `SWAPN` (`0xE7`), `EXCHANGEN` (`0xE8`). -""" # noqa: E501 +abstract: Test cases for [EIP-663: SWAPN, DUPN and EXCHANGE +instructions](https://eips.ethereum.org/EIPS/eip-663) EIP-663 defines new stack +manipulation instructions that allow accessing the stack at higher depths. +Opcodes introduced: `DUPN` (`0xE6`), `SWAPN` (`0xE7`), `EXCHANGEN` (`0xE8`). +""" REFERENCE_SPEC_GIT_PATH = "EIPS/eip-663.md" REFERENCE_SPEC_VERSION = "b658bb87fe039d29e9475d5cfaebca9b92e0fca2" diff --git a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py index 4285d6c8e0c..6f1966f9508 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py +++ b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663) - Tests for the DUPN instruction. -""" # noqa: E501 +abstract: Tests [EIP-663: SWAPN, DUPN and EXCHANGE +instructions](https://eips.ethereum.org/EIPS/eip-663). +""" import pytest diff --git a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py index 74e40d83f19..5b541a78a09 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py +++ b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663) - Tests for the EXCHANGE instruction. -""" # noqa: E501 +abstract: Tests [EIP-663: SWAPN, DUPN and EXCHANGE +instructions](https://eips.ethereum.org/EIPS/eip-663). +""" import pytest diff --git a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py index dedbd76771f..387bf477ae7 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py +++ b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663) - Tests for the SWAPN instruction. -""" # noqa: E501 +abstract: Tests [EIP-663: SWAPN, DUPN and EXCHANGE +instructions](https://eips.ethereum.org/EIPS/eip-663). +""" import pytest diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py index 63bedd7fd2f..f1976aeff22 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py @@ -1,8 +1,10 @@ """ -abstract: Test cases for [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069) - EIP-7069 proposes modifications to `CALL` instructions to align with the structured EOF format. - Opcodes introduced: `EXTCALL` (`0xF8`), `EXTDELEGATECALL` (`0xF9`), `EXTSTATICCALL` (`0xFB`), `RETURNDATALOAD` (`0xF7`). -""" # noqa: E501 +abstract: Test cases for [EIP-7069: Revamped CALL +instructions](https://eips.ethereum.org/EIPS/eip-7069) EIP-7069 proposes +modifications to `CALL` instructions to align with the structured EOF format. +Opcodes introduced: `EXTCALL` (`0xF8`), `EXTDELEGATECALL` (`0xF9`), +`EXTSTATICCALL` (`0xFB`), `RETURNDATALOAD` (`0xF7`). +""" REFERENCE_SPEC_GIT_PATH = "EIPS/eip-7069.md" REFERENCE_SPEC_VERSION = "1795943aeacc86131d5ab6bb3d65824b3b1d4cad" diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_address_space_extension.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_address_space_extension.py index feee36e6b2b..a2180dca078 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_address_space_extension.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_address_space_extension.py @@ -65,7 +65,10 @@ def test_address_space_extension( target_opcode: Op, target_account_type: str, ): - """Test contacts with possibly extended address and fail if address is too large.""" + """ + Test contacts with possibly extended address and fail if address is too + large. + """ env = Environment() ase_address = len(target_address) > 20 @@ -167,11 +170,12 @@ def test_address_space_extension( caller_storage[slot_target_returndata] = stripped_address case Op.CALLCODE | Op.DELEGATECALL: caller_storage[slot_target_call_status] = LEGACY_CALL_SUCCESS - # CALLCODE and DELEGATECALL call will call the stripped address - # but will change the sender to self + # CALLCODE and DELEGATECALL call will call the stripped + # address but will change the sender to self caller_storage[slot_target_returndata] = address_caller case Op.EXTCALL | Op.EXTSTATICCALL: - # EXTCALL and EXTSTATICCALL will fault if calling an ASE address + # EXTCALL and EXTSTATICCALL will fault if calling an ASE + # address if ase_address: caller_storage[slot_target_call_status] = value_exceptional_abort_canary caller_storage[slot_target_returndata] = value_exceptional_abort_canary diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py index 2bc3f36e839..182057b8d52 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py @@ -1,7 +1,8 @@ """ -abstract: Tests [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069) - Tests for the RETURNDATALOAD instruction. -""" # noqa: E501 +abstract: Tests [EIP-7069: Revamped CALL +instructions](https://eips.ethereum.org/EIPS/eip-7069) Tests for the +RETURNDATALOAD instruction. +""" import pytest @@ -61,8 +62,8 @@ def test_extcalls_inputdata( """ Tests call data into EXTCALL including multiple offset conditions. - Caller pushes data into memory, then calls the target. Target writes 64 bytes of call data - to storage and a success byte. + Caller pushes data into memory, then calls the target. Target writes 64 + bytes of call data to storage and a success byte. """ env = Environment() @@ -148,8 +149,8 @@ def test_extdelegatecall_inputdata( """ Tests call data into EXTDELEGATECALL including multiple offset conditions. - Caller pushes data into memory, then calls the target. Target writes 64 bytes of call data - to storage and a success byte. + Caller pushes data into memory, then calls the target. Target writes 64 + bytes of call data to storage and a success byte. """ env = Environment() @@ -232,8 +233,8 @@ def test_extstaticcall_inputdata( """ Tests call data into EXTSTATICCALL including multiple offset conditions. - Caller pushes data into memory, then calls the target. Target writes 64 bytes of call data - to storage and a success byte. + Caller pushes data into memory, then calls the target. Target writes 64 + bytes of call data to storage and a success byte. """ env = Environment() @@ -312,8 +313,8 @@ def test_calldata_remains_after_subcall( """ Tests call data remains after a call to another contract. - Caller pushes data into memory, then calls the target. Target calls 3rd contract. 3rd contract - returns. Target writes calldata to storage. + Caller pushes data into memory, then calls the target. Target calls 3rd + contract. 3rd contract returns. Target writes calldata to storage. """ env = Environment() @@ -494,18 +495,21 @@ def test_extcalls_input_offset( """ Tests call data into EXT*CALL including multiple offset conditions. - Returner returns a success value, which caller stores. If memory expansion cost is less than - 2 billion gas call succeeds. Else whole transaction aborts, leaving canaries in memory. + Returner returns a success value, which caller stores. If memory expansion + cost is less than 2 billion gas call succeeds. Else whole transaction + aborts, leaving canaries in memory. - The name id of `*-mem-cost` refers to the bit-length of the result of the calculated memory - expansion cost. Their length choice is designed to cause problems on shorter bit-length - representations with native integers. + The name id of `*-mem-cost` refers to the bit-length of the result of the + calculated memory expansion cost. Their length choice is designed to cause + problems on shorter bit-length representations with native integers. - The `offset_field` param indicates what part of the input data arguments are being tested, - either the offset of the data in memory or the size of the data in memory. + The `offset_field` param indicates what part of the input data arguments + are being tested, either the offset of the data in memory or the size of + the data in memory. - The `test_arg` param is the value passed into the field being tested (offset or size), - intending to trigger integer size bugs for that particular field. + The `test_arg` param is the value passed into the field being tested + (offset or size), intending to trigger integer size bugs for that + particular field. """ env = Environment(gas_limit=1_000_000_000) diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py index a6e6f0a3934..a1755efb86d 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py @@ -365,8 +365,8 @@ def test_eof_calls_eof_mstore( identity = Address(0x04) -# `blake2f`` is chosen for the test because it fails unless args_size == 213, which is what we are -# interested in. +# `blake2f`` is chosen for the test because it fails unless args_size == 213, +# which is what we are interested in. blake2f = Address(0x09) # `p256verify` / RIP-7212 has been in and out of prague and osaka. # Hence we need to test explicitly @@ -843,7 +843,9 @@ def test_eof_calls_static_flag_with_value( sender: EOA, opcode: Op, ): - """Test EOF contracts calls handle static flag and sending value correctly.""" + """ + Test EOF contracts calls handle static flag and sending value correctly. + """ env = Environment() noop_callee_address = pre.deploy_contract(Container.Code(Op.STOP)) @@ -922,13 +924,16 @@ def test_eof_calls_min_callee_gas( reverts: bool, ): """ - Test EOF contracts calls do light failure when retained/callee gas is not enough. + Test EOF contracts calls do light failure when retained/callee gas is not + enough. - Premise of the test is that there exists a range of `gas_limit` values, which are enough - for all instructions to execute, but call's returned value is 1, meaning not enough for gas - allowances (MIN_RETAINED_GAS and MIN_CALLEE_GAS) - ones marked with `reverts==False`. + Premise of the test is that there exists a range of `gas_limit` values, + which are enough for all instructions to execute, but call's returned value + is 1, meaning not enough for gas allowances (MIN_RETAINED_GAS and + MIN_CALLEE_GAS) - ones marked with `reverts==False`. - Once we provide both allowances, the RJUMPI condition is no longer met and `reverts==True`. + Once we provide both allowances, the RJUMPI condition is no longer met and + `reverts==True`. """ env = Environment() @@ -939,7 +944,8 @@ def test_eof_calls_min_callee_gas( Container.Code( Op.SSTORE(slot_code_worked, value_code_worked) + Op.EQ(opcode(address=noop_callee_address, value=value), EXTCALL_REVERT) - # If the return code isn't 1, it means gas was enough to cover the allowances. + # If the return code isn't 1, it means gas was enough to cover the + # allowances. + Op.RJUMPI[len(revert_block)] + revert_block + Op.STOP @@ -947,7 +953,8 @@ def test_eof_calls_min_callee_gas( balance=value, ) - # `no_oog_gas` is minimum amount of gas_limit which makes the transaction not go oog. + # `no_oog_gas` is minimum amount of gas_limit which makes the transaction + # not go oog. push_operations = 3 + len(opcode.kwargs) # type: ignore no_oog_gas = ( 21_000 @@ -994,7 +1001,10 @@ def test_eof_calls_with_value( balance: int, value: int, ): - """Test EOF contracts calls handle value calls with and without enough balance.""" + """ + Test EOF contracts calls handle value calls with and without enough + balance. + """ env = Environment() noop_callee_address = pre.deploy_contract(Container.Code(Op.STOP)) @@ -1046,25 +1056,25 @@ def test_eof_calls_msg_depth( opcode: Op, ): """ - Test EOF contracts calls handle msg depth limit correctly (1024). - NOTE: due to block gas limit and the 63/64th rule this limit is unlikely to be hit - on mainnet. + Test EOF contracts calls handle msg depth limit correctly (1024). NOTE: due + to block gas limit and the 63/64th rule this limit is unlikely to be hit on + mainnet. """ - # Not a precise gas_limit formula, but enough to exclude risk of gas causing the failure. + # Not a precise gas_limit formula, but enough to exclude risk of gas + # causing the failure. gas_limit = int(200000 * (64 / 63) ** 1024) env = Environment(gas_limit=gas_limit) - # Flow of the test: - # `callee_code` is recursively calling itself, passing msg depth as calldata - # (kept with the `MSTORE(0, ADD(...))`). When maximum msg depth is reached - # the call fails and starts returning. The deep-most frame returns: - # - current reached msg depth (expected to be the maximum 1024), with the - # `MSTORE(32, ADD(...))` - # - the respective return code of the EXT*CALL (expected to be 1 - light failure), with the - # `MSTORE(64, NOOP)`. Note the `NOOP` is just to appease the `Op.MSTORE` call, the return - # code value is actually coming from the `Op.DUP1` - # When unwinding the msg call stack, the intermediate frames return whatever the deeper callee - # returned with the `RETURNDATACOPY` instruction. + # Flow of the test: `callee_code` is recursively calling itself, passing + # msg depth as calldata (kept with the `MSTORE(0, ADD(...))`). When maximum + # msg depth is reached the call fails and starts returning. The deep-most + # frame returns: - current reached msg depth (expected to be the maximum + # 1024), with the `MSTORE(32, ADD(...))` - the respective return code of + # the EXT*CALL (expected to be 1 - light failure), with the `MSTORE(64, + # NOOP)`. Note the `NOOP` is just to appease the `Op.MSTORE` call, the + # return code value is actually coming from the `Op.DUP1` When unwinding + # the msg call stack, the intermediate frames return whatever the deeper + # callee returned with the `RETURNDATACOPY` instruction. # Memory offsets layout: # - 0 - input - msg depth @@ -1083,9 +1093,9 @@ def test_eof_calls_msg_depth( + opcode(address=Op.ADDRESS, args_size=32) # duplicate return code for the `returndatacopy_block` below + Op.DUP1 - # if return code was: - # - 1, we're in the deep-most frame, `deep_most_result_block` returns the actual result - # - 0, we're in an intermediate frame, `returndatacopy_block` only passes on the result + # if return code was: - 1, we're in the deep-most frame, + # `deep_most_result_block` returns the actual result - 0, we're in an + # intermediate frame, `returndatacopy_block` only passes on the result + Op.RJUMPI[rjump_offset] + returndatacopy_block + deep_most_result_block @@ -1139,8 +1149,8 @@ def test_extdelegate_call_targets( call_from_initcode: bool, ): """ - Test EOF contracts extdelegatecalling various targets, especially resolved via 7702 - delegation. + Test EOF contracts extdelegatecalling various targets, especially resolved + via 7702 delegation. """ env = Environment() diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py index e7b6ffa923c..00cd91b1d99 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069) - Tests gas consumption. -""" # noqa: E501 +abstract: Tests [EIP-7069: Revamped CALL +instructions](https://eips.ethereum.org/EIPS/eip-7069) Tests gas consumption. +""" import pytest @@ -32,9 +32,9 @@ def state_env() -> Environment: """ Prepare the environment for all state test cases. - Main difference is that the excess blob gas is not increased by the target, as - there is no genesis block -> block 1 transition, and therefore the excess blob gas - is not decreased by the target. + Main difference is that the excess blob gas is not increased by the target, + as there is no genesis block -> block 1 transition, and therefore the + excess blob gas is not decreased by the target. """ return Environment() @@ -124,7 +124,10 @@ def test_ext_calls_gas( new_account: bool, mem_expansion_bytes: int, ): - """Tests variations of EXT*CALL gas, both warm and cold, without and with mem expansions.""" + """ + Tests variations of EXT*CALL gas, both warm and cold, without and with mem + expansions. + """ address_target = ( pre.fund_eoa(0) if new_account else pre.deploy_contract(Container.Code(Op.STOP)) ) @@ -154,11 +157,12 @@ def test_transfer_gas_is_cleared( value: int, ): """ - Test that EXT*CALL call doesn't charge for value transfer, even if the outer call - transferred value. + Test that EXT*CALL call doesn't charge for value transfer, even if the + outer call transferred value. - NOTE: This is particularly possible for EXTDELEGATECALL, which carries over the value sent - in the outer call, however, we extend the test to all 3 EXT*CALL opcodes for good measure. + NOTE: This is particularly possible for EXTDELEGATECALL, which carries over + the value sent in the outer call, however, we extend the test to all 3 + EXT*CALL opcodes for good measure. """ noop_callee_address = pre.deploy_contract(Container.Code(Op.STOP)) @@ -176,8 +180,8 @@ def test_transfer_gas_is_cleared( subject_code=Op.EXTCALL, subject_balance=5 * value, tear_down_code=Op.STOP, - # NOTE: CALL_WITH_VALUE_GAS is charged only once on the outer EXTCALL, while the base - # call gas - twice. + # NOTE: CALL_WITH_VALUE_GAS is charged only once on the outer EXTCALL, + # while the base call gas - twice. cold_gas=2 * COLD_ACCOUNT_ACCESS_GAS + (CALL_WITH_VALUE_GAS if value > 0 else 0) + push_gas, @@ -196,8 +200,8 @@ def test_late_account_create( opcode: Op, ): """ - Test EXTCALL to a non-existent account after another EXT*CALL has called it and not - created it. + Test EXTCALL to a non-existent account after another EXT*CALL has called it + and not created it. """ empty_address = Address(0xDECAFC0DE) diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndatacopy_memory_expansion.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndatacopy_memory_expansion.py index f5b6112c0b9..7b997275943 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndatacopy_memory_expansion.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndatacopy_memory_expansion.py @@ -52,7 +52,10 @@ def subcall_exact_cost( dest: int, length: int, ) -> int: - """Return exact cost of the subcall, based on the initial memory and the length of the copy.""" + """ + Return exact cost of the subcall, based on the initial memory and the + length of the copy. + """ cost_memory_bytes = fork.memory_expansion_gas_calculator() returndatacopy_cost = 3 @@ -78,8 +81,9 @@ def bytecode_storage( memory_expansion_address: Address, ) -> Tuple[Bytecode, Storage.StorageDictType]: """ - Prepare bytecode and storage for the test, based on the expected result of the subcall - (whether it succeeds or fails depending on the length of the memory expansion). + Prepare bytecode and storage for the test, based on the expected result of + the subcall (whether it succeeds or fails depending on the length of the + memory expansion). """ bytecode = Bytecode() storage = {} @@ -213,7 +217,10 @@ def test_returndatacopy_memory_expansion( post: Mapping[str, Account], tx: Transaction, ): - """Perform RETURNDATACOPY operations that expand the memory, and verify the gas it costs.""" + """ + Perform RETURNDATACOPY operations that expand the memory, and verify the + gas it costs. + """ state_test( env=env, pre=pre, @@ -266,8 +273,8 @@ def test_returndatacopy_huge_memory_expansion( tx: Transaction, ): """ - Perform RETURNDATACOPY operations that expand the memory by huge amounts, and verify that it - correctly runs out of gas. + Perform RETURNDATACOPY operations that expand the memory by huge amounts, + and verify that it correctly runs out of gas. """ state_test( env=env, diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py index 53400fd80f9..9f9eccbc46a 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py @@ -1,7 +1,8 @@ """ -abstract: Tests [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069) - Tests for the RETURNDATALOAD instruction. -""" # noqa: E501 +abstract: Tests [EIP-7069: Revamped CALL +instructions](https://eips.ethereum.org/EIPS/eip-7069) Tests for the +RETURNDATALOAD instruction. +""" from typing import cast @@ -82,14 +83,16 @@ def test_returndatacopy_handling( size: int, ): """ - Tests ReturnDataLoad including multiple offset conditions and differing legacy vs. eof - boundary conditions. + Tests ReturnDataLoad including multiple offset conditions and differing + legacy vs. eof boundary conditions. entrypoint creates a "0xff" test area of memory, delegate calls to caller. - Caller is either EOF or legacy, as per parameter. Calls returner and copies the return data - based on offset and size params. Cases are expected to trigger boundary violations. + Caller is either EOF or legacy, as per parameter. Calls returner and + copies the return data based on offset and size params. Cases are expected + to trigger boundary violations. - Entrypoint copies the test area to storage slots, and the expected result is asserted. + Entrypoint copies the test area to storage slots, and the expected result + is asserted. """ env = Environment() @@ -215,9 +218,10 @@ def test_returndataload_handling( offset: int, ): """ - Much simpler than returndatacopy, no memory or boosted call. Returner is called - and results are stored in storage slot, which is asserted for expected values. - The parameters offset and return data are configured to test boundary conditions. + Much simpler than returndatacopy, no memory or boosted call. Returner is + called and results are stored in storage slot, which is asserted for + expected values. The parameters offset and return data are configured to + test boundary conditions. """ env = Environment() @@ -283,16 +287,17 @@ def test_returndatacopy_oob( opcode: Op, ): """ - Extends the RETURNDATACOPY test for correct out-of-bounds behavior, by checking if the - caller frame's context being EOF or legacy doesn't impact the execution logic of the - RETURNDATACOPY instance under test. + Extends the RETURNDATACOPY test for correct out-of-bounds behavior, by + checking if the caller frame's context being EOF or legacy doesn't impact + the execution logic of the RETURNDATACOPY instance under test. """ env = Environment() sender = pre.fund_eoa() - # Both callee codes below make an OOB (out-of-bounds) RETURNDATACOPY of one byte, - # which they then attempt to return (Legacy should exceptionally halt on RETURNDATACOPY). + # Both callee codes below make an OOB (out-of-bounds) RETURNDATACOPY of one + # byte, which they then attempt to return (Legacy should exceptionally halt + # on RETURNDATACOPY). address_callee_eof = pre.deploy_contract( code=Container( sections=[ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py index 845a31a74a8..b175120b31c 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py @@ -1,5 +1,7 @@ """ -abstract: Test cases for [EIP-7480: EOF - Data section access instructions](https://eips.ethereum.org/EIPS/eip-7480) - EIP-7480 specifies instructions for accessing data stored in the dedicated data section of the EOF format. - Opcodes introduced: `DATALOAD` (`0xD0`), `DATALOADN` (`0xD1`), `DATASIZE` (`0xD2`), `DATACOPY` (`0xD3`). -""" # noqa: E501 +abstract: Test cases for [EIP-7480: EOF - Data section access +instructions](https://eips.ethereum.org/EIPS/eip-7480) EIP-7480 specifies +instructions for accessing data stored in the dedicated data section of the EOF +format. Opcodes introduced: `DATALOAD` (`0xD0`), `DATALOADN` (`0xD1`), +`DATASIZE` (`0xD2`), `DATACOPY` (`0xD3`). +""" diff --git a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/test_data_opcodes.py b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/test_data_opcodes.py index 234ea530a78..2770011f6c5 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/test_data_opcodes.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/test_data_opcodes.py @@ -36,7 +36,10 @@ def test_dataloadn(eof_state_test: EOFStateTestFiller, index: int, suffix_len: i def create_data_test(offset: int, datasize: int): - """Generate data load operators test cases based on load offset and data section size.""" + """ + Generate data load operators test cases based on load offset and data + section size. + """ data = b"".join(i.to_bytes(length=2, byteorder="big") for i in range(1, datasize // 2 + 1)) assert len(data) == datasize overhang = min(32, offset + 32 - datasize) diff --git a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/test_datacopy_memory_expansion.py b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/test_datacopy_memory_expansion.py index 4c4e58d7bbf..90c2ec67568 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/test_datacopy_memory_expansion.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/test_datacopy_memory_expansion.py @@ -52,7 +52,10 @@ def subcall_exact_cost( dest: int, length: int, ) -> int: - """Return exact cost of the subcall, based on the initial memory and the length of the copy.""" + """ + Return exact cost of the subcall, based on the initial memory and the + length of the copy. + """ cost_memory_bytes = fork.memory_expansion_gas_calculator() datacopy_cost = 3 @@ -78,8 +81,9 @@ def bytecode_storage( memory_expansion_address: Address, ) -> Tuple[Bytecode, Storage.StorageDictType]: """ - Prepare bytecode and storage for the test, based on the expected result of the subcall - (whether it succeeds or fails depending on the length of the memory expansion). + Prepare bytecode and storage for the test, based on the expected result of + the subcall (whether it succeeds or fails depending on the length of the + memory expansion). """ bytecode = Bytecode() storage = {} @@ -223,7 +227,10 @@ def test_datacopy_memory_expansion( post: Mapping[str, Account], tx: Transaction, ): - """Perform DATACOPY operations that expand the memory, and verify the gas it costs to do so.""" + """ + Perform DATACOPY operations that expand the memory, and verify the gas it + costs to do so. + """ state_test( env=env, pre=pre, @@ -286,8 +293,8 @@ def test_datacopy_huge_memory_expansion( tx: Transaction, ): """ - Perform DATACOPY operations that expand the memory by huge amounts, and verify that it - correctly runs out of gas. + Perform DATACOPY operations that expand the memory by huge amounts, and + verify that it correctly runs out of gas. """ state_test( env=env, diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py index 886cfd7db23..0a6a65626e7 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py @@ -1,19 +1,22 @@ """ -abstract: Test cases for [EIP-7620: EOF Contract Creation](https://eips.ethereum.org/EIPS/eip-7620) - EIP-7620 replaces `CREATE` and `CREATE2` with `EOFCREATE` for deploying contracts in the EOF format. - Opcodes introduced: `EOFCREATE` (`0xEC`), `RETURNCODE` (`0xEE`). +abstract: Test cases for [EIP-7620: EOF Contract +Creation](https://eips.ethereum.org/EIPS/eip-7620) EIP-7620 replaces `CREATE` +and `CREATE2` with `EOFCREATE` for deploying contracts in the EOF format. +Opcodes introduced: `EOFCREATE` (`0xEC`), `RETURNCODE` (`0xEE`). EOFCREATE, RETURNCODE, and container tests evmone tests not ported -- create_tx_with_eof_initcode - This calls it invalid, it is now the way to add EOF contacts to state -- eofcreate_extcall_returncode - per the new initcode mode tests you cannot have RETURNCODE - in a deployed contract -- eofcreate_dataloadn_referring_to_auxdata - covered by - tests.unscheduled.eip7480_data_section.test_data_opcodes.test_data_section_succeed -- eofcreate_initcontainer_return - RETURN is banned in initcode containers -- eofcreate_initcontainer_stop - STOP is banned in initcode containers -- All TXCREATE tests. -""" # noqa: E501 +- create_tx_with_eof_initcode: This calls it invalid, it is now the way to add +EOF contacts to state +- eofcreate_extcall_returncode: Per the new initcode +mode tests you cannot have RETURNCODE in a deployed contract +- eofcreate_dataloadn_referring_to_auxdata: covered by +tests.unscheduled.eip7480_data_section.test_data_opcodes. +test_data_section_succeed +- eofcreate_initcontainer_return: RETURN is banned in initcode containers +- eofcreate_initcontainer_stop: STOP is banned in initcode containers - All +TXCREATE tests. +""" diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py index 3f4780368af..a3f6a54ed53 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py @@ -76,7 +76,10 @@ def test_eofcreate_then_dataload( state_test: StateTestFiller, pre: Alloc, ): - """Verifies that a contract returned with auxdata does not overwrite the parent data.""" + """ + Verifies that a contract returned with auxdata does not overwrite the + parent data. + """ env = Environment() sender = pre.fund_eoa() small_auxdata_container = Container( @@ -124,7 +127,9 @@ def test_eofcreate_then_call( state_test: StateTestFiller, pre: Alloc, ): - """Verifies a simple EOFCREATE case, and then calls the deployed contract.""" + """ + Verifies a simple EOFCREATE case, and then calls the deployed contract. + """ env = Environment() callable_contract = Container( sections=[ @@ -314,7 +319,9 @@ def test_eofcreate_in_initcode( state_test: StateTestFiller, pre: Alloc, ): - """Verifies an EOFCREATE occurring within initcode creates that contract.""" + """ + Verifies an EOFCREATE occurring within initcode creates that contract. + """ nested_initcode_subcontainer = Container( sections=[ Section.Code( @@ -368,7 +375,10 @@ def test_eofcreate_in_initcode_reverts( state_test: StateTestFiller, pre: Alloc, ): - """Verifies an EOFCREATE occurring in an initcode is rolled back when the initcode reverts.""" + """ + Verifies an EOFCREATE occurring in an initcode is rolled back when the + initcode reverts. + """ nested_initcode_subcontainer = Container( sections=[ Section.Code( @@ -422,7 +432,10 @@ def test_return_data_cleared( state_test: StateTestFiller, pre: Alloc, ): - """Verifies the return data is not reused from a extcall but is cleared upon eofcreate.""" + """ + Verifies the return data is not reused from a extcall but is cleared upon + eofcreate. + """ env = Environment() value_return_canary = 0x4158675309 value_return_canary_size = 5 @@ -518,8 +531,11 @@ def test_address_collision( contract_address: Account( storage={ slot_create_address: salt_zero_address, - slot_create_address_2: EOFCREATE_FAILURE, # had an in-transaction collision - slot_create_address_3: EOFCREATE_FAILURE, # had a pre-existing collision + slot_create_address_2: EOFCREATE_FAILURE, # had an in- + # transaction + # collision + slot_create_address_3: EOFCREATE_FAILURE, # had a pre-existing + # collision slot_code_worked: value_code_worked, } ) @@ -540,7 +556,10 @@ def test_eofcreate_revert_eof_returndata( state_test: StateTestFiller, pre: Alloc, ): - """Verifies the return data is not being deployed, even if happens to be valid EOF.""" + """ + Verifies the return data is not being deployed, even if happens to be valid + EOF. + """ env = Environment() code_reverts_with_calldata = Container( name="Initcode Subcontainer reverting with its calldata", @@ -638,7 +657,9 @@ def test_eofcreate_truncated_container( data_len: int, data_section_size: int, ): - """EOFCREATE instruction targeting a container with truncated data section.""" + """ + EOFCREATE instruction targeting a container with truncated data section. + """ assert data_len < data_section_size eof_test( container=Container( @@ -716,7 +737,8 @@ def test_eofcreate_context( elif expected_result == "selfbalance": expected_bytes = eofcreate_value elif expected_result == "factorybalance": - # Factory receives value from sender and passes on eofcreate_value as endowment. + # Factory receives value from sender and passes on eofcreate_value as + # endowment. expected_bytes = value - eofcreate_value else: raise TypeError("Unexpected expected_result", expected_result) @@ -747,7 +769,10 @@ def test_eofcreate_memory_context( state_test: StateTestFiller, pre: Alloc, ): - """Verifies an EOFCREATE frame enjoys a separate EVM memory from its caller frame.""" + """ + Verifies an EOFCREATE frame enjoys a separate EVM memory from its caller + frame. + """ env = Environment() destination_storage = Storage() contract_storage = Storage() diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py index 68f50eec3ee..6fa47cd4da9 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py @@ -142,8 +142,14 @@ def test_initcode_aborts( """ -Size of the factory portion of test_eofcreate_deploy_sizes, but as the runtime code is dynamic, we -have to use a pre-calculated size + + + + + + +Size of the factory portion of test_eofcreate_deploy_sizes, but as the runtime +code is dynamic, we have to use a pre-calculated size """ factory_size = 78 @@ -172,7 +178,10 @@ def test_eofcreate_deploy_sizes( pre: Alloc, target_deploy_size: int, ): - """Verifies a mix of runtime contract sizes mixing success and multiple size failure modes.""" + """ + Verifies a mix of runtime contract sizes mixing success and multiple size + failure modes. + """ env = Environment() runtime_container = Container( @@ -215,9 +224,9 @@ def test_eofcreate_deploy_sizes( sender = pre.fund_eoa() contract_address = pre.deploy_contract(code=factory_container) - # Storage in 0 should have the address, - # Storage 1 is a canary of 1 to make sure it tried to execute, which also covers cases of - # data+code being greater than initcode_size_max, which is allowed. + # Storage in 0 should have the address, Storage 1 is a canary of 1 to make + # sure it tried to execute, which also covers cases of data+code being + # greater than initcode_size_max, which is allowed. success = target_deploy_size <= MAX_BYTECODE_SIZE post = { contract_address: Account( @@ -260,8 +269,8 @@ def test_eofcreate_deploy_sizes_tx( target_deploy_size: int, ): """ - Verifies a mix of runtime contract sizes mixing success and multiple size failure modes - where the initcontainer is included in a transaction. + Verifies a mix of runtime contract sizes mixing success and multiple size + failure modes where the initcontainer is included in a transaction. """ raise NotImplementedError("Not implemented") @@ -278,7 +287,9 @@ def test_eofcreate_deploy_sizes_tx( ], ) def test_auxdata_size_failures(state_test: StateTestFiller, pre: Alloc, auxdata_size: int): - """Exercises a number of auxdata size violations, and one maxcode success.""" + """ + Exercises a number of auxdata size violations, and one maxcode success. + """ env = Environment() auxdata_bytes = b"a" * auxdata_size @@ -309,8 +320,9 @@ def test_auxdata_size_failures(state_test: StateTestFiller, pre: Alloc, auxdata_ deployed_container_size = len(smallest_runtime_subcontainer) + auxdata_size - # Storage in 0 will have address in first test, 0 in all other cases indicating failure - # Storage 1 in 1 is a canary to see if EOFCREATE opcode halted + # Storage in 0 will have address in first test, 0 in all other cases + # indicating failure Storage 1 in 1 is a canary to see if EOFCREATE opcode + # halted success = deployed_container_size <= MAX_BYTECODE_SIZE post = { contract_address: Account( @@ -351,8 +363,8 @@ def test_eofcreate_insufficient_stipend( value: int, ): """ - Exercises an EOFCREATE that fails because the calling account does not have enough ether to - pay the stipend. + Exercises an EOFCREATE that fails because the calling account does not have + enough ether to pay the stipend. """ env = Environment() initcode_container = Container( @@ -370,8 +382,8 @@ def test_eofcreate_insufficient_stipend( code=initcode_container, balance=value - 1, ) - # create will fail but not trigger a halt, so canary at storage 1 should be set - # also validate target created contract fails + # create will fail but not trigger a halt, so canary at storage 1 should be + # set also validate target created contract fails post = { contract_address: Account( storage={ @@ -395,7 +407,10 @@ def test_insufficient_initcode_gas( state_test: StateTestFiller, pre: Alloc, ): - """Exercises an EOFCREATE when there is not enough gas for the initcode charge.""" + """ + Exercises an EOFCREATE when there is not enough gas for the initcode + charge. + """ env = Environment() initcode_data = b"a" * 0x5000 @@ -455,7 +470,10 @@ def test_insufficient_gas_memory_expansion( state_test: StateTestFiller, pre: Alloc, ): - """Exercises EOFCREATE when the memory for auxdata has not been expanded but is requested.""" + """ + Exercises EOFCREATE when the memory for auxdata has not been expanded but + is requested. + """ env = Environment() auxdata_size = 0x5000 @@ -513,7 +531,10 @@ def test_insufficient_returncode_auxdata_gas( state_test: StateTestFiller, pre: Alloc, ): - """Exercises a RETURNCODE when there is not enough gas for the initcode charge.""" + """ + Exercises a RETURNCODE when there is not enough gas for the initcode + charge. + """ env = Environment() auxdata_size = 0x5000 @@ -583,7 +604,8 @@ def test_insufficient_returncode_auxdata_gas( Op.EXTSTATICCALL, ], ) -@pytest.mark.parametrize("endowment", [0, 1]) # included to verify static flag check comes first +@pytest.mark.parametrize("endowment", [0, 1]) # included to verify static flag +# check comes first @pytest.mark.parametrize( "initcode", [smallest_initcode_subcontainer, aborting_container], @@ -664,14 +686,17 @@ def test_eof_eofcreate_msg_depth( ): """ Test EOFCREATE handles msg depth limit correctly (1024). - NOTE: due to block gas limit and the 63/64th rule this limit is unlikely to be hit - on mainnet. - NOTE: See `tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py::test_eof_calls_msg_depth` - for more explanations and comments. Most notable deviation from that test is that here - calls and `EOFCREATE`s alternate in order to reach the max depth. `who_fails` decides - whether the failing depth 1024 will be on a call or on an `EOFCREATE` to happen. - """ # noqa: E501 - # Not a precise gas_limit formula, but enough to exclude risk of gas causing the failure. + NOTE: due to block gas limit and the 63/64th rule this limit is + unlikely to be hit on mainnet. + NOTE: See `tests/unscheduled/eip7692_eof_v1/eip7069_extcall/ + test_calls.py::test_eof_calls_msg_depth` for more explanations and + comments. Most notable deviation from that test is that here calls + and `EOFCREATE`s alternate in order to reach the max depth. + `who_fails` decides whether the failing depth 1024 will be on a call + or on an `EOFCREATE` to happen. + """ + # Not a precise gas_limit formula, but enough to exclude risk of gas + # causing the failure. gas_limit = int(20000000 * (64 / 63) ** 1024) env = Environment(gas_limit=gas_limit) sender = pre.fund_eoa() @@ -730,8 +755,9 @@ def test_eof_eofcreate_msg_depth( ) ) - # Only bumps the msg call depth "register" and forwards to the `calling_contract_address`. - # If it is used it makes the "failing" depth of 1024 to happen on EOFCREATE, instead of CALL. + # Only bumps the msg call depth "register" and forwards to the + # `calling_contract_address`. If it is used it makes the "failing" depth of + # 1024 to happen on EOFCREATE, instead of CALL. passthrough_address = pre.deploy_contract( Container.Code( Op.MSTORE(0, 1) + Op.EXTCALL(address=calling_contract_address, args_size=32) + Op.STOP @@ -768,12 +794,15 @@ def test_reentrant_eofcreate( state_test: StateTestFiller, pre: Alloc, ): - """Verifies a reentrant EOFCREATE case, where EIP-161 prevents conflict via nonce bump.""" + """ + Verifies a reentrant EOFCREATE case, where EIP-161 prevents conflict via + nonce bump. + """ env = Environment() # Calls into the factory contract with 1 as input. reenter_code = Op.MSTORE(0, 1) + Op.EXTCALL(address=Op.CALLDATALOAD(32), args_size=32) - # Initcode: if given 0 as 1st word of input will call into the factory again. - # 2nd word of input is the address of the factory. + # Initcode: if given 0 as 1st word of input will call into the factory + # again. 2nd word of input is the address of the factory. initcontainer = Container( sections=[ Section.Code( @@ -786,15 +815,17 @@ def test_reentrant_eofcreate( Section.Container(smallest_runtime_subcontainer), ] ) - # Factory: Passes on its input into the initcode. It's 0 first time, 1 the second time. - # Saves the result of deployment in slot 0 first time, 1 the second time. + # Factory: Passes on its input into the initcode. It's 0 first time, 1 the + # second time. Saves the result of deployment in slot 0 first time, 1 the + # second time. contract_address = pre.deploy_contract( code=Container( sections=[ Section.Code( Op.CALLDATACOPY(0, 0, 32) + Op.MSTORE(32, Op.ADDRESS) - # 1st word - copied from input (reenter flag), 2nd word - `this.address`. + # 1st word - copied from input (reenter flag), 2nd word - + # `this.address`. + Op.SSTORE(Op.CALLDATALOAD(0), Op.EOFCREATE[0](input_size=64)) + Op.STOP, ), @@ -803,13 +834,13 @@ def test_reentrant_eofcreate( ), storage={0: 0xB17D, 1: 0xB17D}, # a canary to be overwritten ) - # Flow is: reenter flag 0 -> factory -> reenter flag 0 -> initcode -> reenter -> - # reenter flag 1 -> factory -> reenter flag 1 -> (!) initcode -> stop, - # if the EIP-161 nonce bump is not implemented. If it is, it fails before second - # inicode marked (!). - # Storage in 0 should have the address from the outer EOFCREATE. - # Storage in 1 should have 0 from the inner EOFCREATE. - # For the created contract storage in `slot_counter` should be 1 as initcode executes only once + # Flow is: reenter flag 0 -> factory -> reenter flag 0 -> initcode -> + # reenter -> reenter flag 1 -> factory -> reenter flag 1 -> (!) initcode -> + # stop, if the EIP-161 nonce bump is not implemented. If it is, it fails + # before second inicode marked (!). Storage in 0 should have the address + # from the outer EOFCREATE. Storage in 1 should have 0 from the inner + # EOFCREATE. For the created contract storage in `slot_counter` should be 1 + # as initcode executes only once post = { contract_address: Account( storage={ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_gas.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_gas.py index f7cb2519a10..c3019da962e 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_gas.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_gas.py @@ -130,8 +130,9 @@ def test_eofcreate_gas( for a in salt_addresses: pre.fund_address(a, 1) - # Using `TLOAD` / `TSTORE` to work around warm/cold gas differences. We need a counter to pick - # a distinct salt on each `EOFCREATE` and avoid running into address conflicts. + # Using `TLOAD` / `TSTORE` to work around warm/cold gas differences. We + # need a counter to pick a distinct salt on each `EOFCREATE` and avoid + # running into address conflicts. code_increment_counter = ( Op.TLOAD(slot_counter) + Op.DUP1 + Op.TSTORE(slot_counter, Op.PUSH1(1) + Op.ADD) ) diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_legacy_eof_creates.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_legacy_eof_creates.py index 390b1ce089b..d6ab9c2a090 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_legacy_eof_creates.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_legacy_eof_creates.py @@ -56,7 +56,10 @@ def test_cross_version_creates_fail_light( legacy_create_opcode: Opcodes, initcode: Bytes | Container, ): - """Verifies that CREATE and CREATE2 cannot run EOF initcodes and fail early on attempt.""" + """ + Verifies that CREATE and CREATE2 cannot run EOF initcodes and fail early on + attempt. + """ env = Environment() sender = pre.fund_eoa() @@ -66,7 +69,8 @@ def test_cross_version_creates_fail_light( contract_address = pre.deploy_contract( code=Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE) + Op.SSTORE(slot_create_address, legacy_create_opcode(size=Op.CALLDATASIZE)) - # Approximates whether code until here consumed the 63/64th gas given to subcall + # Approximates whether code until here consumed the 63/64th gas given + # to subcall + Op.SSTORE(slot_all_subcall_gas_gone, Op.LT(Op.GAS, tx_gas_limit // 64)) + Op.SSTORE(slot_code_worked, value_code_worked) + Op.STOP @@ -126,8 +130,8 @@ def test_cross_version_creates_fail_hard( initcode: Bytes, ): """ - Verifies that CREATE and CREATE2 fail hard on attempt to run initcode starting with `EF` but - not `EF00`. + Verifies that CREATE and CREATE2 fail hard on attempt to run initcode + starting with `EF` but not `EF00`. """ env = Environment() @@ -138,7 +142,8 @@ def test_cross_version_creates_fail_hard( contract_address = pre.deploy_contract( code=Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE) + Op.SSTORE(slot_create_address, legacy_create_opcode(size=Op.CALLDATASIZE)) - # Approximates whether code until here consumed the 63/64th gas given to subcall + # Approximates whether code until here consumed the 63/64th gas given + # to subcall + Op.SSTORE(slot_all_subcall_gas_gone, Op.LT(Op.GAS, tx_gas_limit // 64)) + Op.SSTORE(slot_code_worked, value_code_worked) + Op.STOP diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_memory.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_memory.py index 67748507e67..15eed022aee 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_memory.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_memory.py @@ -62,18 +62,20 @@ def test_eofcreate_memory( """ Tests auxdata sizes in EOFCREATE including multiple offset conditions. - EOFCREATE either succeeds or fails based on memory access cost, resulting in new address - or zero in the create address slot. + EOFCREATE either succeeds or fails based on memory access cost, resulting + in new address or zero in the create address slot. - The name id of `*-mem-cost` refers to the bit-length of the result of the calculated memory - expansion cost. Their length choice is designed to cause problems on shorter bit-length - representations with native integers. + The name id of `*-mem-cost` refers to the bit-length of the result of the + calculated memory expansion cost. Their length choice is designed to cause + problems on shorter bit-length representations with native integers. - The `offset_field` param indicates what part of the input data arguments are being tested, - either the offset of the data in memory or the size of the data in memory. + The `offset_field` param indicates what part of the input data arguments + are being tested, either the offset of the data in memory or the size of + the data in memory. - The `test_arg` param is the value passed into the field being tested (offset or size), - intending to trigger integer size bugs for that particular field. + The `test_arg` param is the value passed into the field being tested + (offset or size), intending to trigger integer size bugs for that + particular field. """ env = Environment(gas_limit=2_000_000_000) diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_returncode.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_returncode.py index 3b50714dec5..e9457683717 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_returncode.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_returncode.py @@ -203,18 +203,21 @@ def test_returncode_memory_expansion( success: bool, ): """ - Attempts an EOFCREATE with a possibly too-large auxdata. Create either fails due to gas - or contract too large, resulting in address or zero on failure in the create address slot. + Attempts an EOFCREATE with a possibly too-large auxdata. Create either + fails due to gas or contract too large, resulting in address or zero on + failure in the create address slot. - The name id of `*-mem-cost` refers to the bit-length of the result of the calculated memory - expansion cost. Their length choice is designed to cause problems on shorter bit-length - representations with native integers. + The name id of `*-mem-cost` refers to the bit-length of the result of the + calculated memory expansion cost. Their length choice is designed to cause + problems on shorter bit-length representations with native integers. - The `offset_field` param indicates what part of the input data arguments are being tested, - either the offset of the data in memory or the size of the data in memory. + The `offset_field` param indicates what part of the input data arguments + are being tested, either the offset of the data in memory or the size of + the data in memory. - The `test_arg` param is the value passed into the field being tested (offset or size), - intending to trigger integer size bugs for that particular field. + The `test_arg` param is the value passed into the field being tested + (offset or size), intending to trigger integer size bugs for that + particular field. """ env = Environment(gas_limit=2_000_000_000) sender = pre.fund_eoa(10**27) diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py index 045e3dbbd39..8c796feb759 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py @@ -264,7 +264,10 @@ def test_container_combos_deeply_nested_valid( code_section: Section, first_sub_container: Container, ): - """Test valid subcontainer reference / opcode combos on a deep container nesting level.""" + """ + Test valid subcontainer reference / opcode combos on a deep container + nesting level. + """ valid_container = Container( sections=[ code_section, @@ -314,7 +317,10 @@ def test_container_combos_deeply_nested_invalid( code_section: Section, first_sub_container: Container, ): - """Test invalid subcontainer reference / opcode combos on a deep container nesting level.""" + """ + Test invalid subcontainer reference / opcode combos on a deep container + nesting level. + """ invalid_container = Container( sections=[ code_section, @@ -380,7 +386,10 @@ def test_container_combos_non_first_code_sections_valid( first_sub_container: Container, container_kind: ContainerKind, ): - """Test valid subcontainer reference / opcode combos in a non-first code section.""" + """ + Test valid subcontainer reference / opcode combos in a non-first code + section. + """ eof_test( container=Container( sections=[Section.Code(Op.JUMPF[i]) for i in range(1, 1024)] @@ -419,7 +428,10 @@ def test_container_combos_non_first_code_sections_invalid( first_sub_container: Container, container_kind: ContainerKind, ): - """Test invalid subcontainer reference / opcode combos in a non-first code section.""" + """ + Test invalid subcontainer reference / opcode combos in a non-first code + section. + """ eof_test( container=Container( sections=[Section.Code(Op.JUMPF[i]) for i in range(1, 1024)] @@ -431,7 +443,9 @@ def test_container_combos_non_first_code_sections_invalid( def test_container_both_kinds_same_sub(eof_test: EOFTestFiller): - """Test subcontainer conflicts (both EOFCREATE and RETURNCODE Reference).""" + """ + Test subcontainer conflicts (both EOFCREATE and RETURNCODE Reference). + """ eof_test( container=Container( sections=[ @@ -460,8 +474,8 @@ def test_container_ambiguous_kind( eof_test: EOFTestFiller, container_idx: int, sub_container: Section ): """ - Test ambiguous container kind: - a single subcontainer reference by both EOFCREATE and RETURNCODE. + Test ambiguous container kind: a single subcontainer reference by both + EOFCREATE and RETURNCODE. """ sections = [ Section.Code( @@ -504,7 +518,10 @@ def test_container_both_kinds_different_sub(eof_test: EOFTestFiller): def test_container_multiple_eofcreate_references(eof_test: EOFTestFiller): - """Test multiple references to the same subcontainer from an EOFCREATE operation.""" + """ + Test multiple references to the same subcontainer from an EOFCREATE + operation. + """ eof_test( container=Container( sections=[ @@ -518,7 +535,10 @@ def test_container_multiple_eofcreate_references(eof_test: EOFTestFiller): def test_container_multiple_returncode_references(eof_test: EOFTestFiller): - """Test multiple references to the same subcontainer from a RETURNCONTACT operation.""" + """ + Test multiple references to the same subcontainer from a RETURNCONTACT + operation. + """ eof_test( container=Container( sections=[ @@ -611,7 +631,8 @@ def test_deep_container( """ Test a very deeply nested container. - This test skips generating a state test because the initcode size is too large. + This test skips generating a state test because the initcode size is too + large. """ container = deepest_container last_container = deepest_container @@ -785,7 +806,8 @@ def test_wide_container(eof_test: EOFTestFiller, width: int, exception: EOFExcep ef0001010004020001000603000100000014ff000200008000016000e0000000ef000101000402000100 01ff00000000800000fe""", # Originally this test was "valid" but against the current spec - # it contains two errors: data section truncated and orphan subcontainer. + # it contains two errors: data section truncated and orphan + # subcontainer. validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, ), id="orphan_subcontainer_0_and_truncated_data", @@ -812,7 +834,8 @@ def test_wide_container(eof_test: EOFTestFiller, width: int, exception: EOFExcep Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), Section.Container("aabbccddeeff"), ], - # The original test has been modified to reference the subcontainer by EOFCREATE. + # The original test has been modified to reference the + # subcontainer by EOFCREATE. validity_error=EOFException.INVALID_MAGIC, ), id="subcontainer_0_with_invalid_prefix", @@ -896,7 +919,10 @@ def test_migrated_eofcreate(eof_test: EOFTestFiller, container: Container): def test_dangling_initcode_subcontainer_bytes( eof_test: EOFTestFiller, ): - """Initcode mode EOF Subcontainer test with subcontainer containing dangling bytes.""" + """ + Initcode mode EOF Subcontainer test with subcontainer containing dangling + bytes. + """ eof_test( container=Container( sections=[ @@ -916,7 +942,10 @@ def test_dangling_initcode_subcontainer_bytes( def test_dangling_runtime_subcontainer_bytes( eof_test: EOFTestFiller, ): - """Runtime mode EOF Subcontainer test with subcontainer containing dangling bytes.""" + """ + Runtime mode EOF Subcontainer test with subcontainer containing dangling + bytes. + """ eof_test( container=Container( sections=[ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py index b893e42d5a3..a7a83a36318 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py @@ -1,4 +1,5 @@ """ abstract: Test cases for -[EIP-7873: TXCREATE and InitcodeTransaction](https://eips.ethereum.org/EIPS/eip-7873). -""" # noqa: E501 +[EIP-7873: TXCREATE and +InitcodeTransaction](https://eips.ethereum.org/EIPS/eip-7873). +""" diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_creation_tx.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_creation_tx.py index 7d21916f292..842fd90e8ea 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_creation_tx.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_creation_tx.py @@ -99,9 +99,9 @@ def test_legacy_create_tx_prefix_initcode( initcode: Bytes, ): """ - Test that a legacy contract creation tx behaves as it did before EIP-7873 for - initcode stating with `EF`. - The transaction should be valid but fail on executing of the first byte `EF`. + Test that a legacy contract creation tx behaves as it did before EIP-7873 + for initcode stating with `EF`. The transaction should be valid but fail on + executing of the first byte `EF`. """ env = Environment() sender = pre.fund_eoa() diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate.py index 4d3b571f233..3b0e9d5d2f4 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate.py @@ -67,7 +67,10 @@ def test_txcreate_then_dataload( state_test: StateTestFiller, pre: Alloc, ): - """Verifies that a contract returned with auxdata does not overwrite the parent data.""" + """ + Verifies that a contract returned with auxdata does not overwrite the + parent data. + """ env = Environment() sender = pre.fund_eoa() small_auxdata_container = Container( @@ -110,7 +113,9 @@ def test_txcreate_then_dataload( @pytest.mark.with_all_evm_code_types def test_txcreate_then_call(state_test: StateTestFiller, pre: Alloc, evm_code_type: EVMCodeType): - """Verifies a simple TXCREATE case, and then calls the deployed contract.""" + """ + Verifies a simple TXCREATE case, and then calls the deployed contract. + """ env = Environment() callable_contract = Container( sections=[ @@ -294,8 +299,8 @@ def test_txcreate_in_initcode( """ Verifies an TXCREATE occurring within initcode creates that contract. - Via the `outer_create_reverts` also verifies a TXCREATE occurring in an initcode is rolled back - when the initcode reverts. + Via the `outer_create_reverts` also verifies a TXCREATE occurring in an + initcode is rolled back when the initcode reverts. """ smallest_initcode_subcontainer_hash = smallest_initcode_subcontainer.hash inner_create_bytecode = ( @@ -303,8 +308,8 @@ def test_txcreate_in_initcode( if inner_create_opcode == Op.TXCREATE else Op.EOFCREATE[1](0, 0, 0, 0) ) - # The terminating code of the inner initcontainer, the RJUMPI is a trick to not need to deal - # with the subcontainer indices + # The terminating code of the inner initcontainer, the RJUMPI is a trick to + # not need to deal with the subcontainer indices revert_code = Op.REVERT(0, 0) terminating_code = ( Op.RJUMPI[len(revert_code)](0) + revert_code + Op.RETURNCODE[0](0, 0) @@ -385,7 +390,10 @@ def test_return_data_cleared( pre: Alloc, evm_code_type: EVMCodeType, ): - """Verifies the return data is not reused from a extcall but is cleared upon TXCREATE.""" + """ + Verifies the return data is not reused from a extcall but is cleared upon + TXCREATE. + """ env = Environment() value_return_canary = 0x4158675309 value_return_canary_size = 5 @@ -472,8 +480,11 @@ def test_address_collision( contract_address: Account( storage={ slot_create_address: salt_zero_address, - slot_create_address_2: TXCREATE_FAILURE, # had an in-transaction collision - slot_create_address_3: TXCREATE_FAILURE, # had a pre-existing collision + slot_create_address_2: TXCREATE_FAILURE, # had an in- + # transaction + # collision + slot_create_address_3: TXCREATE_FAILURE, # had a pre-existing + # collision slot_code_worked: value_code_worked, } ) @@ -494,7 +505,10 @@ def test_txcreate_revert_eof_returndata( state_test: StateTestFiller, pre: Alloc, ): - """Verifies the return data is not being deployed, even if happens to be valid EOF.""" + """ + Verifies the return data is not being deployed, even if happens to be valid + EOF. + """ env = Environment() code_reverts_with_calldata = Container( name="Initcode Subcontainer reverting with its calldata", @@ -602,7 +616,8 @@ def test_txcreate_context( elif expected_result == "selfbalance": expected_bytes = txcreate_value elif expected_result == "factorybalance": - # Factory receives value from sender and passes on eofcreate_value as endowment. + # Factory receives value from sender and passes on eofcreate_value as + # endowment. expected_bytes = value - txcreate_value else: raise TypeError("Unexpected expected_result", expected_result) @@ -634,7 +649,10 @@ def test_txcreate_memory_context( state_test: StateTestFiller, pre: Alloc, ): - """Verifies an TXCREATE frame enjoys a separate EVM memory from its caller frame.""" + """ + Verifies an TXCREATE frame enjoys a separate EVM memory from its caller + frame. + """ env = Environment() destination_storage = Storage() contract_storage = Storage() @@ -680,7 +698,10 @@ def test_short_data_subcontainer( state_test: StateTestFiller, pre: Alloc, ): - """Deploy a subcontainer where the data is "short" and filled by deployment code.""" + """ + Deploy a subcontainer where the data is "short" and filled by deployment + code. + """ env = Environment() sender = pre.fund_eoa() diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py index d44588aaed5..36e21288b99 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py @@ -177,8 +177,14 @@ def test_initcode_aborts( """ -Size of the initcode portion of test_txcreate_deploy_sizes, but as the runtime code is dynamic, we -have to use a pre-calculated size + + + + + + +Size of the initcode portion of test_txcreate_deploy_sizes, but as the runtime +code is dynamic, we have to use a pre-calculated size """ initcode_size = 32 @@ -199,7 +205,10 @@ def test_txcreate_deploy_sizes( pre: Alloc, target_deploy_size: int, ): - """Verifies a mix of runtime contract sizes mixing success and multiple size failure modes.""" + """ + Verifies a mix of runtime contract sizes mixing success and multiple size + failure modes. + """ env = Environment() runtime_container = Container( @@ -237,9 +246,9 @@ def test_txcreate_deploy_sizes( + Op.SSTORE(slot_code_worked, value_code_worked) + Op.STOP ) - # Storage in 0 should have the address, - # Storage 1 is a canary of 1 to make sure it tried to execute, which also covers cases of - # data+code being greater than initcode_size_max, which is allowed. + # Storage in 0 should have the address, Storage 1 is a canary of 1 to make + # sure it tried to execute, which also covers cases of data+code being + # greater than initcode_size_max, which is allowed. success = target_deploy_size <= MAX_BYTECODE_SIZE post = { contract_address: Account( @@ -277,7 +286,9 @@ def test_txcreate_deploy_sizes( ], ) def test_auxdata_size_failures(state_test: StateTestFiller, pre: Alloc, auxdata_size: int): - """Exercises a number of auxdata size violations, and one maxcode success.""" + """ + Exercises a number of auxdata size violations, and one maxcode success. + """ env = Environment() auxdata_bytes = b"a" * auxdata_size @@ -305,8 +316,9 @@ def test_auxdata_size_failures(state_test: StateTestFiller, pre: Alloc, auxdata_ deployed_container_size = len(smallest_runtime_subcontainer) + auxdata_size - # Storage in 0 will have address in first test, 0 in all other cases indicating failure - # Storage 1 in 1 is a canary to see if TXCREATE opcode halted + # Storage in 0 will have address in first test, 0 in all other cases + # indicating failure Storage 1 in 1 is a canary to see if TXCREATE opcode + # halted success = deployed_container_size <= MAX_BYTECODE_SIZE post = { contract_address: Account( @@ -347,8 +359,8 @@ def test_txcreate_insufficient_stipend( value: int, ): """ - Exercises an TXCREATE that fails because the calling account does not have enough ether to - pay the stipend. + Exercises an TXCREATE that fails because the calling account does not have + enough ether to pay the stipend. """ env = Environment() sender = pre.fund_eoa(10**11) @@ -362,8 +374,8 @@ def test_txcreate_insufficient_stipend( + Op.STOP, balance=value - 1, ) - # create will fail but not trigger a halt, so canary at storage 1 should be set - # also validate target created contract fails + # create will fail but not trigger a halt, so canary at storage 1 should be + # set also validate target created contract fails post = { contract_address: Account( storage={ @@ -384,7 +396,9 @@ def test_txcreate_insufficient_stipend( @pytest.mark.with_all_evm_code_types def test_insufficient_initcode_gas(state_test: StateTestFiller, pre: Alloc, fork: Fork): - """Exercises an TXCREATE when there is not enough gas for the constant charge.""" + """ + Exercises an TXCREATE when there is not enough gas for the constant charge. + """ env = Environment() initcode_container = Container( @@ -440,7 +454,10 @@ def test_insufficient_gas_memory_expansion( pre: Alloc, fork: Fork, ): - """Exercises TXCREATE when the memory for auxdata has not been expanded but is requested.""" + """ + Exercises TXCREATE when the memory for auxdata has not been expanded but is + requested. + """ env = Environment() auxdata_size = 0x5000 @@ -493,7 +510,10 @@ def test_insufficient_returncode_auxdata_gas( pre: Alloc, fork: Fork, ): - """Exercises a RETURNCODE when there is not enough gas for the initcode charge.""" + """ + Exercises a RETURNCODE when there is not enough gas for the initcode + charge. + """ env = Environment() auxdata_size = 0x5000 @@ -517,8 +537,8 @@ def test_insufficient_returncode_auxdata_gas( slot_code_worked: value_canary_to_be_overwritten, }, ) - # 63/64ths is not enough to cover RETURNCODE memory expansion. Unfortunately the 1/64th left - # won't realistically accommodate a SSTORE + # 63/64ths is not enough to cover RETURNCODE memory expansion. + # Unfortunately the 1/64th left won't realistically accommodate a SSTORE auxdata_size_words = (auxdata_size + 31) // 32 gas_limit = ( 32_000 @@ -555,7 +575,8 @@ def test_insufficient_returncode_auxdata_gas( Op.EXTSTATICCALL, ], ) -@pytest.mark.parametrize("endowment", [0, 1]) # included to verify static flag check comes first +@pytest.mark.parametrize("endowment", [0, 1]) # included to verify static flag +# check comes first @pytest.mark.parametrize( "initcode", [smallest_initcode_subcontainer, aborting_container], @@ -582,7 +603,8 @@ def test_static_flag_txcreate( ) calling_address = pre.deploy_contract( calling_code, - # Need to override the global value from the `with_all_evm_code_types` marker. + # Need to override the global value from the `with_all_evm_code_types` + # marker. evm_code_type=EVMCodeType.EOF_V1 if opcode == Op.EXTSTATICCALL else EVMCodeType.LEGACY, ) @@ -626,14 +648,17 @@ def test_eof_txcreate_msg_depth( ): """ Test TXCREATE handles msg depth limit correctly (1024). - NOTE: due to block gas limit and the 63/64th rule this limit is unlikely to be hit - on mainnet. - NOTE: See `tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py::test_eof_calls_msg_depth` - for more explanations and comments. Most notable deviation from that test is that here - calls and `TXCREATE`s alternate in order to reach the max depth. `who_fails` decides - whether the failing depth 1024 will be on a call or on an `TXCREATE` to happen. - """ # noqa: E501 - # Not a precise gas_limit formula, but enough to exclude risk of gas causing the failure. + NOTE: due to block gas limit and the 63/64th rule this limit is + unlikely to be hit on mainnet. + NOTE: See + `tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py:: + test_eof_calls_msg_depth` for more explanations and comments. + Most notable deviation from that test is that here calls and `TXCREATE`s + alternate in order to reach the max depth. `who_fails` decides whether + the failing depth 1024 will be on a call or on an `TXCREATE` to happen. + """ + # Not a precise gas_limit formula, but enough to exclude risk of gas + # causing the failure. gas_limit = int(20000000 * (64 / 63) ** 1024) env = Environment(gas_limit=gas_limit) @@ -694,8 +719,9 @@ def test_eof_txcreate_msg_depth( ) ) - # Only bumps the msg call depth "register" and forwards to the `calling_contract_address`. - # If it is used it makes the "failing" depth of 1024 to happen on TXCREATE, instead of CALL. + # Only bumps the msg call depth "register" and forwards to the + # `calling_contract_address`. If it is used it makes the "failing" depth of + # 1024 to happen on TXCREATE, instead of CALL. passthrough_address = pre.deploy_contract( Container.Code( Op.MSTORE(0, 1) + Op.EXTCALL(address=calling_contract_address, args_size=32) + Op.STOP @@ -734,12 +760,15 @@ def test_reentrant_txcreate( state_test: StateTestFiller, pre: Alloc, ): - """Verifies a reentrant TXCREATE case, where EIP-161 prevents conflict via nonce bump.""" + """ + Verifies a reentrant TXCREATE case, where EIP-161 prevents conflict via + nonce bump. + """ env = Environment() # Calls into the factory contract with 1 as input. reenter_code = Op.MSTORE(0, 1) + Op.EXTCALL(address=Op.CALLDATALOAD(32), args_size=32) - # Initcode: if given 0 as 1st word of input will call into the factory again. - # 2nd word of input is the address of the factory. + # Initcode: if given 0 as 1st word of input will call into the factory + # again. 2nd word of input is the address of the factory. initcontainer = Container( sections=[ Section.Code( @@ -753,12 +782,14 @@ def test_reentrant_txcreate( ] ) initcode_hash = initcontainer.hash - # Factory: Passes on its input into the initcode. It's 0 first time, 1 the second time. - # Saves the result of deployment in slot 0 first time, 1 the second time. + # Factory: Passes on its input into the initcode. It's 0 first time, 1 the + # second time. Saves the result of deployment in slot 0 first time, 1 the + # second time. contract_address = pre.deploy_contract( code=Op.CALLDATACOPY(0, 0, 32) + Op.MSTORE(32, Op.ADDRESS) - # 1st word - copied from input (reenter flag), 2nd word - `this.address`. + # 1st word - copied from input (reenter flag), 2nd word - + # `this.address`. + Op.SSTORE( Op.CALLDATALOAD(0), Op.TXCREATE(tx_initcode_hash=initcode_hash, input_size=64), @@ -766,13 +797,13 @@ def test_reentrant_txcreate( + Op.STOP, storage={0: 0xB17D, 1: 0xB17D}, # a canary to be overwritten ) - # Flow is: reenter flag 0 -> factory -> reenter flag 0 -> initcode -> reenter -> - # reenter flag 1 -> factory -> reenter flag 1 -> (!) initcode -> stop, - # if the EIP-161 nonce bump is not implemented. If it is, it fails before second - # inicode marked (!). - # Storage in 0 should have the address from the outer TXCREATE. - # Storage in 1 should have 0 from the inner TXCREATE. - # For the created contract storage in `slot_counter` should be 1 as initcode executes only once + # Flow is: reenter flag 0 -> factory -> reenter flag 0 -> initcode -> + # reenter -> reenter flag 1 -> factory -> reenter flag 1 -> (!) initcode -> + # stop, if the EIP-161 nonce bump is not implemented. If it is, it fails + # before second inicode marked (!). Storage in 0 should have the address + # from the outer TXCREATE. Storage in 1 should have 0 from the inner + # TXCREATE. For the created contract storage in `slot_counter` should be 1 + # as initcode executes only once post = { contract_address: Account( storage={ @@ -814,7 +845,10 @@ def test_invalid_container_deployment( pre: Alloc, reason: str, ): - """Verify contract is not deployed when an invalid container deployment is attempted.""" + """ + Verify contract is not deployed when an invalid container deployment is + attempted. + """ env = Environment() sender = pre.fund_eoa() diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_validates.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_validates.py index 3dd9dc89652..05a57bd32ff 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_validates.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_validates.py @@ -88,8 +88,9 @@ def __str__(self) -> str: class Factory(Enum): """ - Kinds of systems leading up to a call to TXCREATE. DIRECT just puts the TXCREATE in the - code it generates, while *CALL ones call into another account which does the TXCREATE. + Kinds of systems leading up to a call to TXCREATE. DIRECT just puts the + TXCREATE in the code it generates, while *CALL ones call into another + account which does the TXCREATE. """ DIRECT = auto() @@ -107,9 +108,9 @@ def creation_snippet( input_size: int, ) -> Tuple[Bytecode, Address | None]: """ - Return snippet to cause TXCREATE to be called along with an address which - will end up in the `compute_eofcreate_address`, or None if that would be the snippet - itself. + Return snippet to cause TXCREATE to be called along with an address + which will end up in the `compute_eofcreate_address`, or None if that + would be the snippet itself. """ if evm_code_type not in [EVMCodeType.LEGACY, EVMCodeType.EOF_V1]: raise Exception(f"Test needs to be updated for {evm_code_type}") @@ -119,7 +120,8 @@ def creation_snippet( ) # Snippet which returns the TXCREATE result to caller callee_txcreate_code = Op.MSTORE(0, txcreate_code) + Op.RETURN(0, 32) - # Snippet which recovers the TXCREATE result from returndata (wipes memory afterwards) + # Snippet which recovers the TXCREATE result from returndata (wipes + # memory afterwards) returndataload_code = ( Op.RETURNDATALOAD if evm_code_type == EVMCodeType.EOF_V1 @@ -175,8 +177,8 @@ def test_txcreate_validates( access_list_a: bool, ): """ - Verifies proper validation of initcode on TXCREATE in various circumstances of the - opcode. + Verifies proper validation of initcode on TXCREATE in various circumstances + of the opcode. """ env = Environment() snippet_a, factory_address_a = factory_a.creation_snippet( diff --git a/tests/unscheduled/eip7692_eof_v1/gas_test.py b/tests/unscheduled/eip7692_eof_v1/gas_test.py index b2520dcbc8d..7a493b87d96 100644 --- a/tests/unscheduled/eip7692_eof_v1/gas_test.py +++ b/tests/unscheduled/eip7692_eof_v1/gas_test.py @@ -43,9 +43,9 @@ def gas_test( """ Create State Test to check the gas cost of a sequence of EOF code. - `setup_code` and `tear_down_code` are called multiple times during the test, and MUST NOT have - any side-effects which persist across message calls, and in particular, any effects on the gas - usage of `subject_code`. + `setup_code` and `tear_down_code` are called multiple times during the + test, and MUST NOT have any side-effects which persist across message + calls, and in particular, any effects on the gas usage of `subject_code`. """ if cold_gas <= 0: raise ValueError(f"Target gas allocations (cold_gas) must be > 0, got {cold_gas}") @@ -68,7 +68,8 @@ def gas_test( balance=subject_balance, address=subject_address, ) - # 2 times GAS, POP, CALL, 6 times PUSH1 - instructions charged for at every gas run + # 2 times GAS, POP, CALL, 6 times PUSH1 - instructions charged for at every + # gas run gas_single_gas_run = 2 * 2 + 2 + WARM_ACCOUNT_ACCESS_GAS + 6 * 3 address_legacy_harness = pre.deploy_contract( code=( @@ -109,11 +110,12 @@ def gas_test( + (Op.DUP2 + Op.SWAP1 + Op.SUB + Op.PUSH2(slot_cold_gas) + Op.SSTORE) + ( ( - # do an oog gas run, unless skipped with `out_of_gas_testing=False`: - # - DUP7 is the gas of the baseline gas run, after other CALL args were pushed - # - subtract the gas charged by the harness - # - add warm gas charged by the subject - # - subtract `oog_difference` to cause OOG exception (1 by default) + # do an oog gas run, unless skipped with + # `out_of_gas_testing=False`: - DUP7 is the gas of the + # baseline gas run, after other CALL args were pushed - + # subtract the gas charged by the harness - add warm gas + # charged by the subject - subtract `oog_difference` to + # cause OOG exception (1 by default) Op.SSTORE( slot_oog_call_result, Op.CALL( @@ -121,7 +123,8 @@ def gas_test( address=address_subject, ), ) - # sanity gas run: not subtracting 1 to see if enough gas makes the call succeed + # sanity gas run: not subtracting 1 to see if enough gas + # makes the call succeed + Op.SSTORE( slot_sanity_call_result, Op.CALL( @@ -135,7 +138,8 @@ def gas_test( else Op.STOP ) ), - evm_code_type=EVMCodeType.LEGACY, # Needs to be legacy to use GAS opcode + evm_code_type=EVMCodeType.LEGACY, # Needs to be legacy to use GAS + # opcode ) post = { From 3e8e342d9a550aad1affa036536c9d47d396c28e Mon Sep 17 00:00:00 2001 From: danceratopz Date: Mon, 22 Sep 2025 16:45:35 +0200 Subject: [PATCH 02/16] chore(tooling): check w505 in tox lint env --- .vscode/settings.json | 2 +- src/cli/check_fixtures.py | 17 +++--- src/cli/eest/commands/clean.py | 12 +++++ src/cli/eest/make/commands/test.py | 21 ++++---- src/cli/eofwrap.py | 4 +- src/cli/evm_bytes.py | 40 ++++++++++---- .../simulator_logic/test_via_engine.py | 9 ++-- .../simulator_logic/test_via_rlp.py | 4 +- .../simulator_logic/test_via_sync.py | 21 ++++---- .../consume/simulators/sync/conftest.py | 4 +- .../execute/eth_config/execute_eth_config.py | 5 +- src/pytest_plugins/execute/execute.py | 13 +++-- src/pytest_plugins/filler/filler.py | 13 +++-- .../filler/gen_test_doc/gen_test_doc.py | 16 ++++-- src/pytest_plugins/filler/ported_tests.py | 12 +++-- src/pytest_plugins/pytest_hive/pytest_hive.py | 4 +- src/pytest_plugins/shared/execute_fill.py | 13 +++-- .../test_block_access_lists_invalid.py | 5 +- tests/benchmark/__init__.py | 10 ++-- tests/benchmark/test_worst_blocks.py | 5 +- tests/benchmark/test_worst_bytecode.py | 5 +- tests/benchmark/test_worst_compute.py | 8 ++- tests/benchmark/test_worst_memory.py | 5 +- tests/benchmark/test_worst_opcode.py | 4 +- .../benchmark/test_worst_stateful_opcodes.py | 5 +- .../eip2929_gas_cost_increases/__init__.py | 3 +- .../test_precompile_warming.py | 9 ++-- tests/berlin/eip2930_access_list/__init__.py | 3 +- .../test_tx_intrinsic_gas.py | 7 ++- .../eip198_modexp_precompile/test_modexp.py | 7 ++- tests/cancun/eip1153_tstore/test_tstorage.py | 14 +++-- .../test_tstorage_create_contexts.py | 5 +- .../test_tstorage_execution_contexts.py | 5 +- .../test_tstorage_reentrancy_contexts.py | 16 +++--- .../test_tstorage_selfdestruct.py | 10 ++-- .../test_beacon_root_contract.py | 23 ++++---- tests/cancun/eip4844_blobs/test_blob_txs.py | 19 ++++--- .../eip4844_blobs/test_blob_txs_full.py | 5 +- .../eip4844_blobs/test_blobhash_opcode.py | 24 ++++----- .../test_blobhash_opcode_contexts.py | 3 +- .../eip4844_blobs/test_excess_blob_gas.py | 44 ++++++++-------- .../test_excess_blob_gas_fork_transition.py | 5 +- .../test_point_evaluation_precompile.py | 51 +++++++++--------- .../test_point_evaluation_precompile_gas.py | 5 +- tests/cancun/eip5656_mcopy/test_mcopy.py | 3 +- .../eip5656_mcopy/test_mcopy_contexts.py | 8 +-- .../test_mcopy_memory_expansion.py | 11 ++-- .../eip6780_selfdestruct/test_selfdestruct.py | 4 +- .../test_blobgasfee_opcode.py | 4 +- .../eip1014_create2/__init__.py | 4 +- .../eip145_bitwise_shift/__init__.py | 3 +- .../test_call_and_callcode_gas_calculation.py | 52 ++++++++++--------- tests/istanbul/eip1344_chainid/__init__.py | 3 +- .../istanbul/eip1344_chainid/test_chainid.py | 4 +- tests/istanbul/eip152_blake2/__init__.py | 4 +- .../eip152_blake2/test_blake2_delegatecall.py | 3 +- tests/osaka/eip7594_peerdas/test_get_blobs.py | 5 +- .../eip7594_peerdas/test_max_blob_per_tx.py | 5 +- .../eip7823_modexp_upper_bounds/__init__.py | 4 +- .../test_modexp_upper_bounds.py | 5 +- .../__init__.py | 2 +- .../test_tx_gas_limit.py | 6 +-- .../test_tx_gas_limit_transition_fork.py | 6 +-- .../eip7883_modexp_gas_increase/__init__.py | 3 +- .../test_modexp_thresholds.py | 6 +-- .../test_blob_base_fee.py | 2 +- .../osaka/eip7934_block_rlp_limit/__init__.py | 3 +- .../test_max_block_rlp_size.py | 4 +- .../test_count_leading_zeros.py | 6 +-- .../__init__.py | 4 +- .../test_p256verify.py | 5 +- .../__init__.py | 4 +- .../eip2537_bls_12_381_precompiles/helpers.py | 2 +- .../test_bls12_g1add.py | 6 ++- .../test_bls12_g1msm.py | 5 +- .../test_bls12_g1mul.py | 10 ++-- .../test_bls12_g2add.py | 6 ++- .../test_bls12_g2msm.py | 5 +- .../test_bls12_g2mul.py | 13 ++--- .../test_bls12_map_fp2_to_g2.py | 29 +++++------ .../test_bls12_map_fp_to_g1.py | 16 +++--- .../test_bls12_pairing.py | 6 ++- .../test_bls12_precompiles_before_fork.py | 6 ++- ...t_bls12_variable_length_input_contracts.py | 8 +-- .../test_block_hashes.py | 3 +- .../test_contract_deployment.py | 3 +- .../prague/eip6110_deposits/test_deposits.py | 6 ++- .../test_contract_deployment.py | 3 +- .../test_modified_withdrawal_contract.py | 3 +- .../test_withdrawal_requests.py | 3 +- .../test_withdrawal_requests_during_fork.py | 3 +- .../test_consolidations.py | 3 +- .../test_consolidations_during_fork.py | 3 +- .../test_contract_deployment.py | 3 +- .../test_modified_consolidation_contract.py | 3 +- .../__init__.py | 2 +- .../test_execution_gas.py | 3 +- .../test_refunds.py | 3 +- .../test_transaction_validity.py | 3 +- .../test_multi_type_requests.py | 8 ++- tests/prague/eip7702_set_code_tx/test_gas.py | 5 +- .../eip7702_set_code_tx/test_invalid_tx.py | 5 +- .../eip7702_set_code_tx/test_set_code_txs.py | 5 +- .../eip3651_warm_coinbase/__init__.py | 3 +- .../test_warm_coinbase.py | 4 +- tests/shanghai/eip3855_push0/test_push0.py | 7 ++- tests/shanghai/eip3860_initcode/__init__.py | 2 +- .../eip3860_initcode/test_initcode.py | 11 ++-- .../shanghai/eip4895_withdrawals/__init__.py | 5 +- .../eip4895_withdrawals/test_withdrawals.py | 6 +-- tests/unscheduled/eip7692_eof_v1/__init__.py | 8 +-- .../eip7692_eof_v1/eip3540_eof_v1/__init__.py | 11 ++-- .../eip4200_relative_jumps/__init__.py | 9 ++-- .../eip4750_functions/__init__.py | 10 ++-- .../eip7692_eof_v1/eip5450_stack/__init__.py | 11 ++-- .../eip7692_eof_v1/eip6206_jumpf/__init__.py | 7 ++- .../eip663_dupn_swapn_exchange/__init__.py | 9 ++-- .../eip663_dupn_swapn_exchange/test_dupn.py | 5 +- .../test_exchange.py | 3 +- .../eip663_dupn_swapn_exchange/test_swapn.py | 5 +- .../eip7069_extcall/__init__.py | 11 ++-- .../eip7069_extcall/test_calldata.py | 6 +-- .../eip7069_extcall/test_gas.py | 5 +- .../eip7069_extcall/test_returndataload.py | 6 +-- .../eip7480_data_section/__init__.py | 11 ++-- .../eip7620_eof_create/__init__.py | 34 ++++++------ .../eip7873_tx_create/__init__.py | 4 +- tox.ini | 3 ++ 128 files changed, 537 insertions(+), 529 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0965b9249c2..2dbc599589b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,7 +14,7 @@ "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[python]": { - "editor.rulers": [100], + "editor.rulers": [80, 100], "editor.formatOnSave": true, "editor.defaultFormatter": "charliermarsh.ruff", "editor.codeActionsOnSave": { diff --git a/src/cli/check_fixtures.py b/src/cli/check_fixtures.py index 9cc4df7a1d6..1497d5b2810 100644 --- a/src/cli/check_fixtures.py +++ b/src/cli/check_fixtures.py @@ -26,17 +26,16 @@ def count_json_files_exclude_index(start_path: Path) -> int: def check_json(json_file_path: Path): """ Check all fixtures in the specified json file: - 1. Load the json file into a - pydantic model. This checks there are no Validation errors when loading - fixtures into EEST models. - 2. Serialize the loaded pydantic model to "json" - (actually python data structures, ready to written as json). - 3. Load the serialized data back into a pydantic model - (to get an updated hash) from step 2. + 1. Load the json file into a pydantic model. This checks there are no + Validation errors when loading fixtures into EEST models. + 2. Serialize the loaded pydantic model to "json" (actually python data + structures, ready to written as json). + 3. Load the serialized data back into a pydantic model (to get an updated + hash) from step 2. 4. Compare hashes: a. Compare the newly calculated hashes from step 2. and 3. and - b. If present, compare info["hash"] with the calculated - hash from step 2. + b. If present, compare info["hash"] with the calculated hash from + step 2. """ fixtures: Fixtures = Fixtures.model_validate_json(json_file_path.read_text()) fixtures_json = to_json(fixtures) diff --git a/src/cli/eest/commands/clean.py b/src/cli/eest/commands/clean.py index 90c191c0712..946153e3e75 100644 --- a/src/cli/eest/commands/clean.py +++ b/src/cli/eest/commands/clean.py @@ -38,6 +38,18 @@ def clean(all_files: bool, dry_run: bool, verbose: bool): uv run eest clean --all -v + Output: + + \b + 🗑️ Deleted: .tox + 🗑️ Deleted: .venv + 🗑️ Deleted: src/cli/et/__pycache__ + 🗑️ Deleted: src/cli/et/commands/__pycache__ + 🗑️ Deleted: src/cli/et/make/__pycache__ + 🗑️ Deleted: src/cli/et/make/commands/__pycache__ + ... + 🧹 Cleanup complete! + """ # noqa: D417, D301 # List of items to remove can contain files and directories. items_to_remove = [ diff --git a/src/cli/eest/make/commands/test.py b/src/cli/eest/make/commands/test.py index dc14dabb408..2d30ee195bb 100644 --- a/src/cli/eest/make/commands/test.py +++ b/src/cli/eest/make/commands/test.py @@ -45,16 +45,19 @@ def test(): name. Based on the inputs, a test file is created in the appropriate directory with a rendered template. - Example: uv run eest make test + Example: + uv run eest make test + + \f +
+ +
- - - - -
""" # noqa: D301 test_type = input_select( "Choose the type of test to generate", choices=["State", "Blockchain"] diff --git a/src/cli/eofwrap.py b/src/cli/eofwrap.py index 65aad7940f9..9d8382a74c9 100644 --- a/src/cli/eofwrap.py +++ b/src/cli/eofwrap.py @@ -6,9 +6,9 @@ 1. Wrap tests -```console + ```console eofwrap -``` + ``` """ import json diff --git a/src/cli/evm_bytes.py b/src/cli/evm_bytes.py index 3cc4c5ee474..7f4a73f0966 100644 --- a/src/cli/evm_bytes.py +++ b/src/cli/evm_bytes.py @@ -174,18 +174,29 @@ def hex_string(hex_string: str, assembly: bool): HEX_STRING is a string containing EVM bytecode. - Returns: (str): The processed EVM opcodes in Python or assembly format. + Returns: + (str): The processed EVM opcodes in Python or assembly format. - Example 1: Convert a hex string to EEST Python `Opcodes`: + Example 1: Convert a hex string to EEST Python `Opcodes` uv run evm_bytes hex-string 604260005260206000F3 - Output 1: Op.PUSH1[0x42] + Op.PUSH1[0x0] + Op.MSTORE + Op.PUSH1[0x20] + - Op.PUSH1[0x0] + Op.RETURN + Output 1: + \b + Op.PUSH1[0x42] + Op.PUSH1[0x0] + Op.MSTORE + Op.PUSH1[0x20] + + Op.PUSH1[0x0] + Op.RETURN - Example 2: Convert a hex string to assembly: + Example 2: Convert a hex string to assembly uv run evm_bytes hex-string --assembly 604260005260206000F3 - Output 2: push1 0x42 push1 0x00 mstore push1 0x20 push1 0x00 return + Output 2: + \b + push1 0x42 + push1 0x00 + mstore + push1 0x20 + push1 0x00 + return + """ # noqa: D301 processed_output = process_evm_bytes_string(hex_string, assembly=assembly) click.echo(processed_output) @@ -201,14 +212,23 @@ def binary_file(binary_file, assembly: bool): BINARY_FILE is a binary file containing EVM bytes, use `-` to read from stdin. - Returns: (str): The processed EVM opcodes in Python or assembly format. + Returns: + (str): The processed EVM opcodes in Python or assembly format. - Example: Convert the Withdrawal Request contract to assembly: + Example: Convert the Withdrawal Request contract to assembly + \b uv run evm_bytes binary-file ./src/ethereum_test_forks/forks/ contracts/withdrawal_request.bin --assembly - Output: caller push20 0xfffffffffffffffffffffffffffffffffffffffe eq push1 - 0x90 jumpi ... + Output: + \b + caller + push20 0xfffffffffffffffffffffffffffffffffffffffe + eq + push1 0x90 + jumpi + ... + """ # noqa: D301 processed_output = format_opcodes(process_evm_bytes(binary_file.read()), assembly=assembly) click.echo(processed_output) diff --git a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_engine.py b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_engine.py index 8be888d79e3..1ef5a774dea 100644 --- a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_engine.py +++ b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_engine.py @@ -42,10 +42,11 @@ def test_blockchain_via_engine( ): """ 1. Check the client genesis block hash matches - `fixture.genesis.block_hash`. 2. Execute the test case fixture blocks - against the client under test using the `engine_newPayloadVX` method from - the Engine API. 3. For valid payloads a forkchoice update is performed to - finalize the chain. + `fixture.genesis.block_hash`. + 2. Execute the test case fixture blocks against the client under test using + the `engine_newPayloadVX` method from the Engine API. + 3. For valid payloads a forkchoice update is performed to finalize the + chain. """ # Send a initial forkchoice update with timing_data.time("Initial forkchoice update"): diff --git a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_rlp.py b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_rlp.py index b2936cfe3dc..e894947a305 100644 --- a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_rlp.py +++ b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_rlp.py @@ -25,8 +25,8 @@ def test_via_rlp( ): """ 1. Check the client genesis block hash matches - `fixture.genesis.block_hash`. 2. Check the client last block hash matches - `fixture.last_block_hash`. + `fixture.genesis.block_hash`. + 2. Check the client last block hash matches `fixture.last_block_hash`. """ with timing_data.time("Get genesis block"): logger.info("Calling getBlockByNumber to get genesis block...") diff --git a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py index 8765b34ee67..bfec67792da 100644 --- a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py +++ b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py @@ -4,10 +4,12 @@ simulator uses the `BlockchainEngineSyncFixtures` to test against clients with client synchronization. -This simulator: 1. Spins up two clients: one as the client under test and -another as the sync client 2. Executes payloads on the client under test 3. Has -the sync client synchronize from the client under test 4. Verifies that the -sync was successful +This simulator: +1. Spins up two clients: one as the client under test and another as the sync + client +2. Executes payloads on the client under test +3. Has the sync client synchronize from the client under test +4. Verifies that the sync was successful """ import time @@ -115,11 +117,12 @@ def test_blockchain_via_sync( """ Test blockchain synchronization between two clients. - 1. Initialize the client under test with the genesis block 2. Execute all - payloads on the client under test 3. Initialize the sync client with the - genesis block 4. Send sync payload and forkchoice_updated to the sync - client to trigger synchronization 5. Verify that the sync client - successfully syncs to the same state + 1. Initialize the client under test with the genesis block + 2. Execute all payloads on the client under test + 3. Initialize the sync client with the genesis block + 4. Send sync payload and forkchoice_updated to the sync client to trigger + synchronization + 5. Verify that the sync client successfully syncs to the same state """ # Initialize client under test with timing_data.time("Initialize client under test"): diff --git a/src/pytest_plugins/consume/simulators/sync/conftest.py b/src/pytest_plugins/consume/simulators/sync/conftest.py index 2bc30a68f37..9447ea47287 100644 --- a/src/pytest_plugins/consume/simulators/sync/conftest.py +++ b/src/pytest_plugins/consume/simulators/sync/conftest.py @@ -62,8 +62,8 @@ def pytest_collection_modifyitems(session, config, items): # client_param- # tests/path/to/test.py::test_name[test_params]-sync_client_param - # 1. Remove the client prefix from the beginning 2. Replace the - # -client_param part at the end with our new format + # 1. Remove the client prefix from the beginning + # 2. Replace the -client_param part at the end with our new format nodeid = item.nodeid prefix_index = item.nodeid.find("-tests/") if prefix_index != -1: diff --git a/src/pytest_plugins/execute/eth_config/execute_eth_config.py b/src/pytest_plugins/execute/eth_config/execute_eth_config.py index 7316551db8b..efdc3122f99 100644 --- a/src/pytest_plugins/execute/eth_config/execute_eth_config.py +++ b/src/pytest_plugins/execute/eth_config/execute_eth_config.py @@ -253,10 +253,11 @@ def test_eth_config_majority( continue assert client_to_hash_dict[h] == expected_hash, ( - "Critical consensus issue: Not all eth_config responses are the same!\n" + "Critical consensus issue: Not all eth_config responses are the " + " same!\n" "Here is an overview of client response hashes:\n" + "\n\t".join(f"{k}: {v}" for k, v in client_to_hash_dict.items()) - + "\n\n" # noqa: E501 + + "\n\n" "Here is an overview of which URLs were contacted:\n\t" + "\n\t".join(f"{k}: @{v.split('@')[1]}" for k, v in client_to_url_used_dict.items()) + "\n\n" diff --git a/src/pytest_plugins/execute/execute.py b/src/pytest_plugins/execute/execute.py index 6037cdf57aa..5e6353b70a9 100644 --- a/src/pytest_plugins/execute/execute.py +++ b/src/pytest_plugins/execute/execute.py @@ -121,16 +121,15 @@ def pytest_configure(config): Pytest hook called after command line options have been parsed and before test collection begins. - Couple of notes: 1. Register the plugin's custom markers and process - command-line options. + Couple of notes: + 1. Register the plugin's custom markers and process command-line options. - Custom marker registration: - https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom - -markers + Custom marker registration: + https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers 2. `@pytest.hookimpl(tryfirst=True)` is applied to ensure that this hook is - called before the pytest-html plugin's pytest_configure to ensure that it - uses the modified `htmlpath` option. + called before the pytest-html plugin's pytest_configure to ensure that + it uses the modified `htmlpath` option. """ # Modify the block gas limit if specified. if config.getoption("transaction_gas_limit"): diff --git a/src/pytest_plugins/filler/filler.py b/src/pytest_plugins/filler/filler.py index 765c272ac36..e22c3334719 100644 --- a/src/pytest_plugins/filler/filler.py +++ b/src/pytest_plugins/filler/filler.py @@ -610,16 +610,15 @@ def pytest_configure(config): Pytest hook called after command line options have been parsed and before test collection begins. - Couple of notes: 1. Register the plugin's custom markers and process - command-line options. + Couple of notes: + 1. Register the plugin's custom markers and process command-line options. - Custom marker registration: - https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html# registering- - # custom -markers + Custom marker registration: + https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers 2. `@pytest.hookimpl(tryfirst=True)` is applied to ensure that this hook is - called before the pytest-html plugin's pytest_configure to ensure that it - uses the modified `htmlpath` option. + called before the pytest-html plugin's pytest_configure to ensure that + it uses the modified `htmlpath` option. """ # Register custom markers # Modify the block gas limit if specified. diff --git a/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py b/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py index 66583ced925..dcf2f9c7949 100644 --- a/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py +++ b/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py @@ -16,17 +16,23 @@ In case mkdocs has polluted the `docs/` directory with intermediate files, run: -```console git restore docs/navigation.md # Careful if you have local -modifications! rm -rf docs/tests docs/docs site ``` +```console +git restore docs/navigation.md # Careful if you have local modifications! +rm -rf docs/tests docs/docs site +``` To test doc generation, run the plugin without mkdocs: -```console uv run fill -p pytest_plugins.filler.gen_test_doc.gen_test_doc ---gen-docs --fork= tests ``` +```console +uv run fill -p pytest_plugins.filler.gen_test_doc.gen_test_doc --gen-docs \ + --fork= tests +``` Or to build and view the site: -```console uv run mkdocs serve ``` +```console +uv run mkdocs serve +``` """ import glob diff --git a/src/pytest_plugins/filler/ported_tests.py b/src/pytest_plugins/filler/ported_tests.py index 3d0207d9951..b470e8e4e97 100644 --- a/src/pytest_plugins/filler/ported_tests.py +++ b/src/pytest_plugins/filler/ported_tests.py @@ -9,11 +9,13 @@ # Show PR URLs instead uv run fill --show-ported-from=prs tests/ -The plugin will: 1. Collect all test items with @pytest.mark.ported_from -markers 2. Extract either the file paths (first positional argument) or PR URLs -(pr keyword argument) 3. Output a deduplicated, sorted list, one per line 4. -Skip test execution (collection only) 5. Exclude tests with -coverage_missed_reason from output +The plugin will: +1. Collect all test items with @pytest.mark.ported_from markers +2. Extract either the file paths (first positional argument) or PR URLs (pr + keyword argument) +3. Output a deduplicated, sorted list, one per line +4. Skip test execution (collection only) +5. Exclude tests with coverage_missed_reason from output Marker Format: -------------- @pytest.mark.ported_from( ["path/to/static_filler1.json", "path/to/static_filler2.json"], pr=[ diff --git a/src/pytest_plugins/pytest_hive/pytest_hive.py b/src/pytest_plugins/pytest_hive/pytest_hive.py index aff20fbc8e5..d6effbb4d21 100644 --- a/src/pytest_plugins/pytest_hive/pytest_hive.py +++ b/src/pytest_plugins/pytest_hive/pytest_hive.py @@ -3,8 +3,8 @@ Simulators using this plugin must define two pytest fixtures: -1. `test_suite_name`: The name of the test suite. 2. `test_suite_description`: -The description of the test suite. +1. `test_suite_name`: The name of the test suite. +2. `test_suite_description`: The description of the test suite. These fixtures are used when creating the hive test suite. diff --git a/src/pytest_plugins/shared/execute_fill.py b/src/pytest_plugins/shared/execute_fill.py index 3708956dd0a..c47e217ea74 100644 --- a/src/pytest_plugins/shared/execute_fill.py +++ b/src/pytest_plugins/shared/execute_fill.py @@ -41,16 +41,15 @@ def pytest_configure(config: pytest.Config): Pytest hook called after command line options have been parsed and before test collection begins. - Couple of notes: 1. Register the plugin's custom markers and process - command-line options. + Couple of notes: + 1. Register the plugin's custom markers and process command-line options. - Custom marker registration: - https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html# registering- - # custom -markers + Custom marker registration: + https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers 2. `@pytest.hookimpl(tryfirst=True)` is applied to ensure that this hook is - called before the pytest-html plugin's pytest_configure to ensure that it - uses the modified `htmlpath` option. + called before the pytest-html plugin's pytest_configure to ensure that + it uses the modified `htmlpath` option. """ if config.pluginmanager.has_plugin("pytest_plugins.filler.filler"): for fixture_format in BaseFixture.formats.values(): diff --git a/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py b/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py index a08e0a3f35d..5bb5a3d2f37 100644 --- a/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py +++ b/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py @@ -1,7 +1,6 @@ """ -Test cases for invalid Block Access Lists. - -These tests verify that clients properly reject blocks with corrupted BALs +abstract: Test cases for invalid Block Access Lists. + These tests verify that clients properly reject blocks with corrupted BALs. """ import pytest diff --git a/tests/benchmark/__init__.py b/tests/benchmark/__init__.py index 8c37b7d6e0f..ee4b35674ba 100644 --- a/tests/benchmark/__init__.py +++ b/tests/benchmark/__init__.py @@ -1,8 +1,8 @@ """ abstract: Benchmark tests for EVMs. - Benchmark tests aim to maximize the usage of a specific opcode, - precompile, or operation within a transaction or block. These can - be executed against EVM implementations to ensure they handle - pathological cases efficiently and correctly, allowing Ethereum to - safely [Scale the L1](https://protocol.ethereum.foundation/). + Benchmark tests aim to maximize the usage of a specific opcode, precompile, + or operation within a transaction or block. These can be executed against + EVM implementations to ensure they handle pathological cases efficiently + and correctly, allowing Ethereum to safely + [Scale the L1](https://protocol.ethereum.foundation/). """ diff --git a/tests/benchmark/test_worst_blocks.py b/tests/benchmark/test_worst_blocks.py index 6d53ba43b5d..1b1735f8b89 100644 --- a/tests/benchmark/test_worst_blocks.py +++ b/tests/benchmark/test_worst_blocks.py @@ -1,8 +1,5 @@ """ -abstract: Tests that benchmark EVMs in worst-case block scenarios. Tests that -benchmark EVMs in worst-case block scenarios. - -Tests running worst-case block scenarios for EVMs. +abstract: Tests that benchmark EVMs in worst-case block scenarios. """ import random diff --git a/tests/benchmark/test_worst_bytecode.py b/tests/benchmark/test_worst_bytecode.py index 5a4a211847d..ac981f890a4 100644 --- a/tests/benchmark/test_worst_bytecode.py +++ b/tests/benchmark/test_worst_bytecode.py @@ -1,8 +1,5 @@ """ -abstract: Tests that benchmark EVMs in worst-case opcode scenarios. Tests that -benchmark EVMs in worst-case opcode scenarios. - -Tests that benchmark EVMs in worst-case opcode scenarios. +abstract: Tests that benchmark EVMs in worst-case opcode scenarios. """ import math diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index 052a791bd12..be121ebf886 100644 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -1,9 +1,7 @@ """ -abstract: Tests that benchmark EVMs in worst-case compute scenarios. Tests that -benchmark EVMs in worst-case compute scenarios. - -Tests that benchmark EVMs when running worst-case compute opcodes and -precompile scenarios. +abstract: Tests that benchmark EVMs in worst-case compute scenarios. + Tests that benchmark EVMs when running worst-case compute opcodes and + precompile scenarios. """ import math diff --git a/tests/benchmark/test_worst_memory.py b/tests/benchmark/test_worst_memory.py index 6e061cfc186..7a0fde24d22 100644 --- a/tests/benchmark/test_worst_memory.py +++ b/tests/benchmark/test_worst_memory.py @@ -1,8 +1,5 @@ """ -abstract: Tests that benchmark EVMs in the worst-case memory opcodes. Tests -that benchmark EVMs in the worst-case memory opcodes. - -Tests that benchmark EVMs in the worst-case memory opcodes. +abstract: Tests that benchmark EVMs in the worst-case memory opcodes. """ import pytest diff --git a/tests/benchmark/test_worst_opcode.py b/tests/benchmark/test_worst_opcode.py index e4e6e3bcf1b..a640e5cbcdb 100644 --- a/tests/benchmark/test_worst_opcode.py +++ b/tests/benchmark/test_worst_opcode.py @@ -1,8 +1,6 @@ """ abstract: Tests benchmark worst-case opcode scenarios. - Tests benchmark worst-case opcode scenarios. - -Tests running worst-case opcodes scenarios for benchmarking purposes. + Tests running worst-case opcodes scenarios for benchmarking purposes. """ import pytest diff --git a/tests/benchmark/test_worst_stateful_opcodes.py b/tests/benchmark/test_worst_stateful_opcodes.py index 75af5b2c0ec..b2d462659cf 100644 --- a/tests/benchmark/test_worst_stateful_opcodes.py +++ b/tests/benchmark/test_worst_stateful_opcodes.py @@ -1,8 +1,5 @@ """ -abstract: Tests that benchmark EVMs for worst-case stateful opcodes. Tests that -benchmark EVMs for worst-case stateful opcodes. - -Tests that benchmark EVMs for worst-case stateful opcodes. +abstract: Tests that benchmark EVMs for worst-case stateful opcodes. """ import math diff --git a/tests/berlin/eip2929_gas_cost_increases/__init__.py b/tests/berlin/eip2929_gas_cost_increases/__init__.py index 9a9455074e7..1516ab785f2 100644 --- a/tests/berlin/eip2929_gas_cost_increases/__init__.py +++ b/tests/berlin/eip2929_gas_cost_increases/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-2929: Gas cost increases for -state access opcodes](https://eips.ethereum.org/EIPS/eip-2929). +abstract: Tests for [EIP-2929: Gas cost increases for state access opcodes](https://eips.ethereum.org/EIPS/eip-2929). """ diff --git a/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py b/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py index 620cdedd4fb..216d07c878e 100644 --- a/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py +++ b/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py @@ -1,8 +1,9 @@ """ -abstract: Tests [EIP-2929: Gas cost increases for state access -opcodes](https://eips.ethereum.org/EIPS/eip-2929) Test cases for [EIP-2929: Gas -cost increases for state access -opcodes](https://eips.ethereum.org/EIPS/eip-2929). +abstract: Tests precompile warming behavior. + + Tests precompile warming behavior across fork transitions from + [EIP-2929: Gas cost increases for state access opcodes] + (https://eips.ethereum.org/EIPS/eip-2929). """ from typing import Iterator, Tuple diff --git a/tests/berlin/eip2930_access_list/__init__.py b/tests/berlin/eip2930_access_list/__init__.py index 24be6dfd092..6ac96b8cde0 100644 --- a/tests/berlin/eip2930_access_list/__init__.py +++ b/tests/berlin/eip2930_access_list/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-2930: Optional access lists](https://eips.ethereum.org/EIPS/eip-2930) - Test cases for [EIP-2930: Optional access lists](https://eips.ethereum.org/EIPS/eip-2930). +abstract: Tests for [EIP-2930: Optional access lists](https://eips.ethereum.org/EIPS/eip-2930). """ diff --git a/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py b/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py index f3bd1023f6c..86abea16253 100644 --- a/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py +++ b/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py @@ -1,8 +1,7 @@ """ -abstract: Tests [EIP-2930: Access list -transaction](https://eips.ethereum.org/EIPS/eip-2930). Original test by Ori: -https://github.com/ethereum/tests/blob/v15.0/src/GeneralStateTestsFiller/stEIP1 -559/intrinsicGen.js. +abstract: Tests [EIP-2930: Access list transaction](https://eips.ethereum.org/EIPS/eip-2930). + Original test by Ori: + https://github.com/ethereum/tests/blob/v15.0/src/GeneralStateTestsFiller/stEIP1559/intrinsicGen.js. """ from typing import List diff --git a/tests/byzantium/eip198_modexp_precompile/test_modexp.py b/tests/byzantium/eip198_modexp_precompile/test_modexp.py index f676324487f..079bf972db2 100644 --- a/tests/byzantium/eip198_modexp_precompile/test_modexp.py +++ b/tests/byzantium/eip198_modexp_precompile/test_modexp.py @@ -1,8 +1,7 @@ """ -abstract: Test [EIP-198: MODEXP -Precompile](https://eips.ethereum.org/EIPS/eip-198) Tests the MODEXP -precompile, located at address 0x0000..0005. Test cases from the EIP are -labelled with `EIP-198-caseX` in the test id. +abstract: Test [EIP-198: MODEXP Precompile](https://eips.ethereum.org/EIPS/eip-198). + Tests the MODEXP precompile, located at address 0x0000..0005. Test cases + from the EIP are labelled with `EIP-198-caseX` in the test id. """ import pytest diff --git a/tests/cancun/eip1153_tstore/test_tstorage.py b/tests/cancun/eip1153_tstore/test_tstorage.py index 5b25168eafe..939d515327e 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage.py +++ b/tests/cancun/eip1153_tstore/test_tstorage.py @@ -1,12 +1,10 @@ """ -abstract: Tests [EIP-1153: Transient Storage -Opcodes](https://eips.ethereum.org/EIPS/eip-1153). - -Ports and extends some tests from -[ethereum/tests/src/EIPTestsFiller/StateTests/ -stEIP1153-transientStorage/](https://github.com/ethereum/tests/blob/ -9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/ -StateTests/stEIP1153-transientStorage). +abstract: Transient storage opcodes tests. + Tests for [EIP-1153: Transient Storage + Opcodes](https://eips.ethereum.org/EIPS/eip-1153). + + Ports and extends some tests from + [ethereum/tests/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage). """ from enum import unique diff --git a/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py index 343bcee0166..d5bcc0857a0 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py @@ -1,6 +1,7 @@ """ -abstract: Tests for [EIP-1153: Transient -Storage](https://eips.ethereum.org/EIPS/eip-1153). +abstract: Transient storage in contract creation contexts tests + Tests for transient storage behavior in contract creation contexts from + [EIP-1153: Transient Storage](https://eips.ethereum.org/EIPS/eip-1153). """ from enum import unique diff --git a/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py index 4e5943d6cc7..5c2a49fa690 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py @@ -1,6 +1,7 @@ """ -abstract: Tests for [EIP-1153: Transient -Storage](https://eips.ethereum.org/EIPS/eip-1153). +abstract: EIP-1153 Transient Storage execution contexts tests + Tests for transient storage behavior in execution contexts from + [EIP-1153: Transient Storage](https://eips.ethereum.org/EIPS/eip-1153). """ from enum import EnumMeta, unique diff --git a/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py index c8fdfdcb4eb..7b479262c26 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py @@ -1,6 +1,9 @@ """ -abstract: Tests for [EIP-1153: Transient -Storage](https://eips.ethereum.org/EIPS/eip-1153). +abstract: Tests transient storage in reentrancy contexts. + + Tests transient storage behavior in various reentrancy contexts from + [EIP-1153: Transient Storage] + (https://eips.ethereum.org/EIPS/eip-1153). """ from enum import EnumMeta, unique @@ -89,11 +92,12 @@ def __new__(cls, name, bases, classdict): # noqa: D102 classdict[f"{opcode._name_}_UNDOES_ALL"] = { "description": ( f"{opcode._name_} undoes all the transient storage writes " - "to the same key from a failed call. ", - "TSTORE(x, y), CALL(self, ...), TSTORE(x, z), ", - f"TSTORE(x, z + 1) {opcode._name_}, TLOAD(x) returns y.", + "to the same key from a failed call. " + "TSTORE(x, y), CALL(self, ...), TSTORE(x, z), " + f"TSTORE(x, z + 1) {opcode._name_}, TLOAD(x) returns y." "", - "Based on [ethereum/tests/.../09_revertUndoesAllFiller.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/09_revertUndoesAllFiller.yml).", # noqa: E501 + "Based on " + "[ethereum/tests/.../09_revertUndoesAllFiller.yml](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/09_revertUndoesAllFiller.yml).", ), "bytecode": Conditional( condition=SETUP_CONDITION, diff --git a/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py b/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py index 16d2f23986a..d8f5a1a136f 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py @@ -1,10 +1,10 @@ """ -abstract: Tests for [EIP-1153: Transient -Storage](https://eips.ethereum.org/EIPS/eip-1153). +abstract: EIP-1153 Transient Storage with selfdestruct tests. + Tests for transient storage behavior with selfdestruct from [EIP-1153: + Storage](https://eips.ethereum.org/EIPS/eip-1153). -Test cases for `TSTORE` and -`TLOAD` opcode calls in reentrancy after self-destruct, taking into account -the changes in EIP-6780. + Test cases for `TSTORE` and `TLOAD` opcode calls in reentrancy after + self-destruct, taking into account the changes in EIP-6780. """ from enum import unique diff --git a/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py b/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py index b26294bc6cd..bae31eff72e 100644 --- a/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py +++ b/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py @@ -1,19 +1,18 @@ """ -abstract: Tests beacon block root for [EIP-4788: Beacon block root in the -EVM](https://eips.ethereum.org/EIPS/eip-4788). +abstract: Tests beacon block root for [EIP-4788: Beacon block root in the EVM](https://eips.ethereum.org/EIPS/eip-4788) + Note: To add a new test, add a function that is named `test_`. -Note: Adding a new test Add a function that is named `test_` and -takes at least the following arguments: + It must take at least the following arguments: -- state_test -- env -- pre -- tx -- post -- valid_call + - `state_test` + - `env` + - `pre` + - `tx` + - `post` + - `valid_call` -All other `pytest.fixtures` can be parametrized to generate new combinations -and test cases. + All other `pytest.fixtures` can be parametrized to generate new + combinations and test cases. """ from itertools import count diff --git a/tests/cancun/eip4844_blobs/test_blob_txs.py b/tests/cancun/eip4844_blobs/test_blob_txs.py index 0d4aa02575b..f4bb577c3e0 100644 --- a/tests/cancun/eip4844_blobs/test_blob_txs.py +++ b/tests/cancun/eip4844_blobs/test_blob_txs.py @@ -1,17 +1,16 @@ """ -abstract: Tests blob type transactions for [EIP-4844: Shard Blob -Transactions](https://eips.ethereum.org/EIPS/eip-4844). +Tests blob type transactions for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). + Note: To add a new test, add a function that is named `test_`. -Note: Adding a new test Add a function that is named `test_` and -takes at least the following arguments: + It must at least use the following arguments: -- blockchain_test or state_test -- pre -- env -- block or txs + - `blockchain_test` or `state_test` + - `pre` + - `env` + - `block` or `txs`. -All other `pytest.fixture` fixtures can be parametrized to generate new -combinations and test cases. + All other `pytest.fixture` fixtures can be parametrized to generate new + combinations and test cases. """ from typing import List, Optional, Tuple diff --git a/tests/cancun/eip4844_blobs/test_blob_txs_full.py b/tests/cancun/eip4844_blobs/test_blob_txs_full.py index 01f1b3b417f..d71b81f22c0 100644 --- a/tests/cancun/eip4844_blobs/test_blob_txs_full.py +++ b/tests/cancun/eip4844_blobs/test_blob_txs_full.py @@ -1,7 +1,4 @@ -""" -abstract: Tests full blob type transactions for [EIP-4844: Shard Blob -Transactions](https://eips.ethereum.org/EIPS/eip-4844). -""" +"""Tests full blob type transactions for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844).""" from typing import List, Optional diff --git a/tests/cancun/eip4844_blobs/test_blobhash_opcode.py b/tests/cancun/eip4844_blobs/test_blobhash_opcode.py index 7a9e4bd3935..30218e0887c 100644 --- a/tests/cancun/eip4844_blobs/test_blobhash_opcode.py +++ b/tests/cancun/eip4844_blobs/test_blobhash_opcode.py @@ -1,19 +1,19 @@ """ -abstract: Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob -Transactions](https://eips.ethereum.org/EIPS/eip-4844). +abstract: Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) + Note: Adding a new test Add a function that is named `test_` and + takes at least the following arguments. -Note: Adding a new test Add a function that is named `test_` and -takes at least the following arguments: + Required arguments: + - `blockchain_test` + - `pre` + - `tx` + - `post` -- blockchain_test -- pre -- tx -- post + Additional custom `pytest.fixture` fixtures can be added and parametrized + for + new test cases. -Additional custom `pytest.fixture` fixtures can be added and parametrized for -new test cases. - -There is no specific structure to follow within this test module. + There is no specific structure to follow within this test module. """ from typing import List diff --git a/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py b/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py index d1c365a11f5..a56a6979074 100644 --- a/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py +++ b/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py @@ -1,6 +1,5 @@ """ -abstract: Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob -Transactions](https://eips.ethereum.org/EIPS/eip-4844). +abstract: Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). """ from enum import Enum diff --git a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py index dbbee95c393..7cbdcf78cc6 100644 --- a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py +++ b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py @@ -1,25 +1,27 @@ """ -abstract: Tests `excessBlobGas` and `blobGasUsed` block fields for [EIP-4844: -Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). - -Note: Adding a new test Add a function that is named `test_` and -takes at least the following arguments: - -- blockchain_test -- env -- pre -- blocks -- post -- correct_excess_blob_gas - -The following arguments can be parametrized to generate new combinations and -test cases: - -- new_blobs: Number of blobs in the block (automatically split across -transactions as needed) - -All other `pytest.fixture` fixtures can be parametrized to generate new -combinations and test cases. +abstract: Tests `excessBlobGas` and `blobGasUsed` block fields for EIP-4844. + Tests `excessBlobGas` and `blobGasUsed` block fields for + [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) + Note: Adding a new test Add a function that is named `test_` and + takes at least the following arguments. + + Required arguments: + - `blockchain_test` + - `env` + - `pre` + - `blocks` + - `post` + - `correct_excess_blob_gas` + + The following arguments can be parametrized to generate new combinations + and + test cases: + + - new_blobs: Number of blobs in the block (automatically split across + transactions as needed) + + All other `pytest.fixture` fixtures can be parametrized to generate new + combinations and test cases. """ import itertools diff --git a/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py b/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py index 23056e9ff04..5c5c579077b 100644 --- a/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py +++ b/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py @@ -1,7 +1,6 @@ """ -abstract: Tests `excessBlobGas` and `blobGasUsed` block fields for [EIP-4844: -Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) at fork -transition. +abstract: Test `excessBlobGas` & `blobGasUsed` block fields at fork transition + Tests for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). """ from typing import List, Mapping diff --git a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py index c039b7a85e6..9250a04bcd6 100644 --- a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py +++ b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py @@ -1,30 +1,29 @@ """ -abstract: Tests point evaluation precompile for [EIP-4844: Shard Blob -Transactions](https://eips.ethereum.org/EIPS/eip-4844). - -Note: Adding a new test Add a function that is named `test_` and -takes at least the following arguments: - -- blockchain_test | state_test -- pre -- tx -- post - -The following arguments *need* to be parametrized or the test will not be -generated: - -- versioned_hash -- kzg_commitment -- z -- y -- kzg_proof -- result - -These values correspond to a single call of the precompile, and `result` refers -to whether the call should succeed or fail. - -All other `pytest.fixture` fixtures can be parametrized to generate new -combinations and test cases. +abstract: Tests point evaluation precompile for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). + Note: Adding a new test Add a function that is named `test_` and + takes at least the following arguments. + + Required arguments: + - `blockchain_test` or `state_test` + - `pre` + - `tx` + - `post` + + The following arguments *need* to be parametrized or the test will not be + generated: + + - `versioned_hash` + - `kzg_commitment` + - `z` + - `y` + - `kzg_proof` + - `result` + + These values correspond to a single call of the precompile, and `result` + refers to whether the call should succeed or fail. + + All other `pytest.fixture` fixtures can be parametrized to generate new + combinations and test cases. """ import glob diff --git a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py index e3d0cfec4a8..a16d3bdfd09 100644 --- a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py +++ b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py @@ -1,6 +1,7 @@ """ -abstract: Tests gas usage on point evaluation precompile for [EIP-4844: Shard -Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). +abstract: Tests gas usage on point evaluation precompile for EIP-4844. + Tests gas usage on point evaluation precompile for + [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). """ from typing import Dict, Literal diff --git a/tests/cancun/eip5656_mcopy/test_mcopy.py b/tests/cancun/eip5656_mcopy/test_mcopy.py index f2b2b3d3efc..0895b1e27fb 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-5656: MCOPY - Memory copying -instruction](https://eips.ethereum.org/EIPS/eip-5656). +abstract: Tests [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656). """ from typing import Mapping diff --git a/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py b/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py index ea03d058038..c9bd455f672 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py @@ -1,10 +1,6 @@ """ -abstract: Tests [EIP-5656: MCOPY - Memory copying -instruction](https://eips.ethereum.org/EIPS/eip-5656). - -Test memory copy under -different call contexts [EIP-5656: MCOPY - Memory copying -instruction](https://eips.ethereum.org/EIPS/eip-5656). +abstract: Test memory copy under different call contexts. + Tests for [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656). """ from itertools import cycle, islice diff --git a/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py b/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py index 669a800e8b6..945fd994370 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py @@ -1,11 +1,8 @@ """ -abstract: Tests [EIP-5656: MCOPY - Memory copying -instruction](https://eips.ethereum.org/EIPS/eip-5656). - -Test copy operations of -[EIP-5656: MCOPY - Memory copying -instruction](https://eips.ethereum.org/EIPS/eip-5656) that produce a memory -expansion, and potentially an out-of-gas error. +abstract: Test MCOPY with memory expansion and potential OOG errors + Test copy operations of [EIP-5656: MCOPY - Memory copying +instruction](https://eips.ethereum.org/EIPS/eip-5656) that produce + a memory expansion, and potentially an out-of-gas error. """ import itertools diff --git a/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py b/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py index 00c13b642ed..deccb85bc1d 100644 --- a/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py +++ b/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py @@ -1,6 +1,6 @@ """ -abstract: Tests [EIP-6780: SELFDESTRUCT only in same -transaction](https://eips.ethereum.org/EIPS/eip-6780). +abstract: SELFDESTRUCT only in same transaction tests + Tests for [EIP-6780: SELFDESTRUCT only in same transaction](https://eips.ethereum.org/EIPS/eip-6780). """ from itertools import cycle diff --git a/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py b/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py index b62257fae67..970920236e4 100644 --- a/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py +++ b/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py @@ -1,6 +1,6 @@ """ -abstract: Tests [EIP-7516: BLOBBASEFEE -opcode](https://eips.ethereum.org/EIPS/eip-7516). +abstract: BLOBBASEFEE opcode tests + Tests for [EIP-7516: BLOBBASEFEE opcode](https://eips.ethereum.org/EIPS/eip-7516). """ from itertools import count diff --git a/tests/constantinople/eip1014_create2/__init__.py b/tests/constantinople/eip1014_create2/__init__.py index c63c990d8b0..658cd0bbdfa 100644 --- a/tests/constantinople/eip1014_create2/__init__.py +++ b/tests/constantinople/eip1014_create2/__init__.py @@ -1,5 +1,3 @@ """ -abstract: Test [EIP-1014: Skinny CREATE2](https://eips.ethereum.org/EIPS/eip-1014). - - Tests for [EIP-1014: Skinny CREATE2](https://eips.ethereum.org/EIPS/eip-1014). +abstract: Tests for [EIP-1014: Skinny CREATE2](https://eips.ethereum.org/EIPS/eip-1014). """ diff --git a/tests/constantinople/eip145_bitwise_shift/__init__.py b/tests/constantinople/eip145_bitwise_shift/__init__.py index 5fc43725bb7..eef4aab5831 100644 --- a/tests/constantinople/eip145_bitwise_shift/__init__.py +++ b/tests/constantinople/eip145_bitwise_shift/__init__.py @@ -1,5 +1,4 @@ """ abstract: Test [EIP-145: Bitwise shifting instructions in EVM](https://eips.ethereum.org/EIPS/eip-145). - - Tests for [EIP-145: Bitwise shifting instructions in EVM](https://eips.ethereum.org/EIPS/eip-145). + Tests for [EIP-145: Bitwise shifting instructions in EVM](https://eips.ethereum.org/EIPS/eip-145). """ diff --git a/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py b/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py index f0292e06e89..e05433c38bc 100644 --- a/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py +++ b/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py @@ -1,28 +1,32 @@ """ -abstract: Tests the nested CALL/CALLCODE opcode gas consumption with a positive -value transfer. This test is designed to investigate an issue identified in -EthereumJS, as reported in: -https://github.com/ethereumjs/ethereumjs-monorepo/issues/3194. - -The issue pertains to the incorrect gas calculation for CALL/CALLCODE -operations with a positive value transfer, due to the pre-addition of the gas -stipend (2300) to the currently available gas instead of adding it to the new -call frame. This bug was specific to the case where insufficient gas was -provided for the CALL/CALLCODE operation. Due to the pre-addition of the -stipend to the currently available gas, the case for insufficient gas was not -properly failing with an out-of-gas error. - -Test setup: Given two smart contract accounts, 0x0A (caller) and 0x0B (callee): -1) An arbitrary transaction calls into the contract 0x0A. 2) Contract 0x0A -executes a CALL to contract 0x0B with a specific gas limit (X). 3) Contract -0x0B then attempts a CALL/CALLCODE to a non-existent contract 0x0C, with a -positive value transfer (activating the gas stipend). 4) If the gas X provided -by contract 0x0A to 0x0B is sufficient, contract 0x0B will push 0x01 onto the -stack after returning to the call frame in 0x0A. Otherwise, it should push -0x00, indicating the insufficiency of gas X (for the bug in EthereumJS, the -CALL/CALLCODE operation would return 0x01 due to the pre-addition of the gas -stipend). 5) The resulting stack value is saved into contract 0x0A's storage, -allowing us to verify whether the provided gas was sufficient or insufficient. +abstract: Tests nested CALL/CALLCODE gas usage with positive value transfer + This test investigates an issue identified in EthereumJS, as reported in: + https://github.com/ethereumjs/ethereumjs-monorepo/issues/3194. + + The issue pertains to the incorrect gas calculation for CALL/CALLCODE + operations with a positive value transfer, due to the pre-addition of the + gas stipend (2300) to the currently available gas instead of adding it to + the new call frame. This bug was specific to the case where insufficient + gas was provided for the CALL/CALLCODE operation. Due to the pre-addition + of the stipend to the currently available gas, the case for insufficient + gas was not properly failing with an out-of-gas error. + + Test setup: + + Given two smart contract accounts, 0x0A (caller) and 0x0B (callee): + 1. An arbitrary transaction calls into the contract 0x0A. + 2. Contract 0x0A executes a CALL to contract 0x0B with a specific gas limit + (X). + 3. Contract 0x0B then attempts a CALL/CALLCODE to a non-existent contract + 0x0C, with a positive value transfer (activating the gas stipend). + 4. If the gas X provided by contract 0x0A to 0x0B is sufficient, contract + 0x0B will push 0x01 onto the stack after returning to the call frame in + 0x0A. Otherwise, it should push 0x00, indicating the insufficiency of + gas X (for the bug in EthereumJS, the CALL/CALLCODE operation would + return 0x01 due to the pre-addition of the gas stipend). + 5. The resulting stack value is saved into contract 0x0A's storage, + allowing us to verify whether the provided gas was sufficient or + insufficient. """ from typing import Dict diff --git a/tests/istanbul/eip1344_chainid/__init__.py b/tests/istanbul/eip1344_chainid/__init__.py index bb41fcd2e72..db7dbcd6e73 100644 --- a/tests/istanbul/eip1344_chainid/__init__.py +++ b/tests/istanbul/eip1344_chainid/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-1344: ChainID Opcode](https://eips.ethereum.org/EIPS/eip-1344) - Test cases for [EIP-1344: ChainID Opcode](https://eips.ethereum.org/EIPS/eip-1344). +abstract: Tests for [EIP-1344: ChainID Opcode](https://eips.ethereum.org/EIPS/eip-1344). """ diff --git a/tests/istanbul/eip1344_chainid/test_chainid.py b/tests/istanbul/eip1344_chainid/test_chainid.py index 72c670268cf..7f3070d9a90 100644 --- a/tests/istanbul/eip1344_chainid/test_chainid.py +++ b/tests/istanbul/eip1344_chainid/test_chainid.py @@ -1,6 +1,6 @@ """ -abstract: Tests [EIP-1344: CHAINID opcode](https://eips.ethereum.org/EIPS/eip-1344) - Test cases for [EIP-1344: CHAINID opcode](https://eips.ethereum.org/EIPS/eip-1344). +abstract: Tests [EIP-1344: CHAINID opcode](https://eips.ethereum.org/EIPS/eip-1344). + Test cases for EIP-1344: CHAINID opcode. """ import pytest diff --git a/tests/istanbul/eip152_blake2/__init__.py b/tests/istanbul/eip152_blake2/__init__.py index 1f034e456fb..1c9a85f63bb 100644 --- a/tests/istanbul/eip152_blake2/__init__.py +++ b/tests/istanbul/eip152_blake2/__init__.py @@ -1,4 +1,4 @@ """ -abstract: Tests [EIP-152: BLAKE2 compression precompile](https://eips.ethereum.org/EIPS/eip-152) - Test cases for [EIP-152: BLAKE2 compression precompile](https://eips.ethereum.org/EIPS/eip-152). +abstract: Tests [EIP-152: BLAKE2 compression precompile](https://eips.ethereum.org/EIPS/eip-152). + Test cases for EIP-152: BLAKE2 compression precompile. """ diff --git a/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py b/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py index 39907e60149..9a78779e2ea 100644 --- a/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py +++ b/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py @@ -1,6 +1,5 @@ """ -abstract: Test delegatecall to Blake2B Precompile before and after it was -added. +abstract: Test delegatecall to Blake2B Precompile before and after added. """ import pytest diff --git a/tests/osaka/eip7594_peerdas/test_get_blobs.py b/tests/osaka/eip7594_peerdas/test_get_blobs.py index fd60647d817..c0745000162 100644 --- a/tests/osaka/eip7594_peerdas/test_get_blobs.py +++ b/tests/osaka/eip7594_peerdas/test_get_blobs.py @@ -1,6 +1,7 @@ """ -abstract: Tests get blobs engine endpoint for [EIP-7594: PeerDAS - Peer Data -Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). +abstract: Get blobs engine endpoint tests + Tests for get blobs engine endpoint in [EIP-7594: PeerDAS - Peer Data + Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). """ from hashlib import sha256 diff --git a/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py b/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py index 67555783518..f83ebb23028 100644 --- a/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py +++ b/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py @@ -1,6 +1,7 @@ """ -abstract: Tests `MAX_BLOBS_PER_TX` limit for [EIP-7594: PeerDAS - Peer Data -Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). +abstract: MAX_BLOBS_PER_TX limit tests + Tests for `MAX_BLOBS_PER_TX` limit in [EIP-7594: PeerDAS - Peer Data + Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). """ import pytest diff --git a/tests/osaka/eip7823_modexp_upper_bounds/__init__.py b/tests/osaka/eip7823_modexp_upper_bounds/__init__.py index 20ebfaec013..3c635edb962 100644 --- a/tests/osaka/eip7823_modexp_upper_bounds/__init__.py +++ b/tests/osaka/eip7823_modexp_upper_bounds/__init__.py @@ -1,4 +1,4 @@ """ -abstract: Tests [EIP-7823: Set upper bounds for MODEXP](https://eips.ethereum.org/EIPS/eip-7823) - Test cases for [EIP-7823: Set upper bounds for MODEXP](https://eips.ethereum.org/EIPS/eip-7823). +abstract: Tests [EIP-7823: Set upper bounds for MODEXP](https://eips.ethereum.org/EIPS/eip-7823). + Test cases for EIP-7823: Set upper bounds for MODEXP. """ diff --git a/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py b/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py index 07c84d251c4..2863bdff43d 100644 --- a/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py +++ b/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py @@ -1,7 +1,6 @@ """ -abstract: Test [EIP-7823: Set upper bounds for -MODEXP](https://eips.ethereum.org/EIPS/eip-7823) Tests upper bounds of the -MODEXP precompile. +abstract: Test [EIP-7823: Set upper bounds for MODEXP](https://eips.ethereum.org/EIPS/eip-7823) + Tests upper bounds of the MODEXP precompile. """ from typing import Dict diff --git a/tests/osaka/eip7825_transaction_gas_limit_cap/__init__.py b/tests/osaka/eip7825_transaction_gas_limit_cap/__init__.py index ecc57bb22ba..24f15f932eb 100644 --- a/tests/osaka/eip7825_transaction_gas_limit_cap/__init__.py +++ b/tests/osaka/eip7825_transaction_gas_limit_cap/__init__.py @@ -1,4 +1,4 @@ """ abstract: Tests [EIP-7825: Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825). - Test cases for [EIP-7825: Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825). + Test cases for EIP-7825: Transaction Gas Limit Cap. """ diff --git a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py index f658050cf16..c1921b694b0 100644 --- a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py +++ b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-7825 Transaction Gas Limit -Cap](https://eips.ethereum.org/EIPS/eip-7825) Test cases for [EIP-7825 -Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825)]. +abstract: Transaction gas limit cap tests + Tests for transaction gas limit cap in [EIP-7825: Transaction Gas Limit + Cap](https://eips.ethereum.org/EIPS/eip-7825). """ from typing import List diff --git a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py index dd4e230ff9a..baf57654f97 100644 --- a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py +++ b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-7825 Transaction Gas Limit -Cap](https://eips.ethereum.org/EIPS/eip-7825) Test cases for [EIP-7825 -Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825)]. +abstract: Transaction gas limit cap fork transition tests + Tests for fork transition behavior in [EIP-7825: Transaction Gas Limit + Cap](https://eips.ethereum.org/EIPS/eip-7825). """ import pytest diff --git a/tests/osaka/eip7883_modexp_gas_increase/__init__.py b/tests/osaka/eip7883_modexp_gas_increase/__init__.py index 4b43f2c9ed4..133f473b9ae 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/__init__.py +++ b/tests/osaka/eip7883_modexp_gas_increase/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883) - Test cases for [EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883). +abstract: Tests for [EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883). """ diff --git a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py index b1ea17bd303..da6b018f890 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py +++ b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-7883: ModExp Gas Cost -Increase](https://eips.ethereum.org/EIPS/eip-7883) Test cases for [EIP-7883: -ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883). +abstract: EIP-7883 ModExp gas cost increase tests + Tests for ModExp gas cost increase in + [EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883). """ from typing import Dict diff --git a/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py b/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py index d68cce370fb..09a8e67ed65 100644 --- a/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py +++ b/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py @@ -194,7 +194,7 @@ def test_reserve_price_boundary( All values give a blob base_ fee of 1 because we need a much higher excess blob gas to increase the blob fee. This only increases to 2 at 20 excess blobs. - """ # noqa: E501 + """ blockchain_test( genesis_environment=env, pre=pre, diff --git a/tests/osaka/eip7934_block_rlp_limit/__init__.py b/tests/osaka/eip7934_block_rlp_limit/__init__.py index 5c84ada8706..562bf665681 100644 --- a/tests/osaka/eip7934_block_rlp_limit/__init__.py +++ b/tests/osaka/eip7934_block_rlp_limit/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-7934: RLP Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934) - Test cases for [EIP-7934: RLP Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934). +abstract: Tests for [EIP-7934: RLP Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934). """ diff --git a/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py b/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py index b8a93163794..df4eb79d688 100644 --- a/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py +++ b/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py @@ -1,7 +1,5 @@ """ -abstract: Test [EIP-7934: RLP Execution Block Size -Limit](https://eips.ethereum.org/EIPS/eip-7934) Tests for [EIP-7934: RLP -Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934). +abstract: Tests for [EIP-7934: RLP Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934). """ from functools import lru_cache diff --git a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py index 571ba46d737..40541a1f853 100644 --- a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py +++ b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-7939: Count leading zeros (CLZ) -opcode](https://eips.ethereum.org/EIPS/eip-7939) Test cases for [EIP-7939: -Count leading zeros (CLZ) opcode](https://eips.ethereum.org/EIPS/eip-7939). +abstract: Tests [EIP-7939: Count leading zeros (CLZ)](https://eips.ethereum.org/EIPS/eip-7939) + Test cases for + [EIP-7939: Count leading zeros (CLZ) opcode](https://eips.ethereum.org/EIPS/eip-7939). """ import pytest diff --git a/tests/osaka/eip7951_p256verify_precompiles/__init__.py b/tests/osaka/eip7951_p256verify_precompiles/__init__.py index dc20209ead1..3e17ffea1e5 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/__init__.py +++ b/tests/osaka/eip7951_p256verify_precompiles/__init__.py @@ -1,4 +1,4 @@ """ -abstract: Tests [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951) - Test cases for [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951)]. +abstract: Tests [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951). + Test cases for EIP-7951: Precompile for secp256r1 Curve Support. """ diff --git a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py index ef31065bc5a..089f8bbb9cc 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py +++ b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py @@ -1,8 +1,5 @@ """ -abstract: Tests [EIP-7951: Precompile for secp256r1 Curve -Support](https://eips.ethereum.org/EIPS/eip-7951) Test cases for [EIP-7951: -Precompile for secp256r1 Curve -Support](https://eips.ethereum.org/EIPS/eip-7951)]. +abstract: Tests for [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/__init__.py b/tests/prague/eip2537_bls_12_381_precompiles/__init__.py index fcff6bad1e4..660915e8076 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/__init__.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/__init__.py @@ -1,5 +1,3 @@ """ -abstract: Tests [EIP-2537: Precompile for BLS12-381 curve -operations](https://eips.ethereum.org/EIPS/eip-2537). - +abstract: Tests [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). """ diff --git a/tests/prague/eip2537_bls_12_381_precompiles/helpers.py b/tests/prague/eip2537_bls_12_381_precompiles/helpers.py index cf29cd03e9b..c9720581c08 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/helpers.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/helpers.py @@ -793,5 +793,5 @@ def generate_g2_map_isogeny_kernel_points(cls) -> List[FP2]: G2 that map to the point at infinity on the BLS curve. This is why we return an empty list here. It is kept for consistency with the G1 case, and documentation purposes. - """ # noqa: E501 + """ return [] diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py index 929e6622128..08e6a5059b1 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py @@ -1,6 +1,8 @@ """ -abstract: Tests BLS12_G1ADD precompile of [EIP-2537: Precompile for BLS12-381 -curve operations](https://eips.ethereum.org/EIPS/eip-2537). +abstract: Tests BLS12_G1ADD precompile + Tests the BLS12_G1ADD precompile implementation from [EIP-2537: + Precompile for BLS12-381 curve operations] + (https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py index 690f98c5195..f72da72428f 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py @@ -1,6 +1,7 @@ """ -abstract: Tests BLS12_G1MSM precompile of [EIP-2537: Precompile for BLS12-381 -curve operations](https://eips.ethereum.org/EIPS/eip-2537). +abstract: Test the BLS12_G1MSM precompile + Test the BLS12_G1MSM precompile introduced in + [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py index b3d83026e2c..f18a51fc52a 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py @@ -1,6 +1,8 @@ """ -abstract: Tests BLS12_G1MUL precompile of [EIP-2537: Precompile for BLS12-381 -curve operations](https://eips.ethereum.org/EIPS/eip-2537). +abstract: Tests BLS12_G1MUL precompile + Tests the BLS12_G1MUL precompile implementation from [EIP-2537: + Precompile for BLS12-381 curve operations] + (https://eips.ethereum.org/EIPS/eip-2537). """ import pytest @@ -84,8 +86,8 @@ pytest.param( Spec.P1 + Scalar(2**256 - 1), PointG1( - 0x3DA1F13DDEF2B8B5A46CD543CE56C0A90B8B3B0D6D43DEC95836A5FD2BACD6AA8F692601F870CF22E05DDA5E83F460B, # noqa: E501 - 0x18D64F3C0E9785365CBDB375795454A8A4FA26F30B9C4F6E33CA078EB5C29B7AEA478B076C619BC1ED22B14C95569B2D, # noqa: E501 + 0x3DA1F13DDEF2B8B5A46CD543CE56C0A90B8B3B0D6D43DEC95836A5FD2BACD6AA8F692601F870CF22E05DDA5E83F460B, + 0x18D64F3C0E9785365CBDB375795454A8A4FA26F30B9C4F6E33CA078EB5C29B7AEA478B076C619BC1ED22B14C95569B2D, ), None, id="max_scalar_times_point", diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py index 7dd40890ac5..19807f81164 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py @@ -1,6 +1,8 @@ """ -abstract: Tests BLS12_G2ADD precompile of [EIP-2537: Precompile for BLS12-381 -curve operations](https://eips.ethereum.org/EIPS/eip-2537). +abstract: Tests BLS12_G2ADD precompile + Tests the BLS12_G2ADD precompile implementation from [EIP-2537: + Precompile for BLS12-381 curve operations] + (https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py index 04391084f59..ef1eebde9c7 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py @@ -1,6 +1,7 @@ """ -abstract: Tests BLS12_G2MSM precompile of [EIP-2537: Precompile for BLS12-381 -curve operations](https://eips.ethereum.org/EIPS/eip-2537). +abstract: Test the BLS12_G2MSM precompile + Test the BLS12_G2MSM precompile introduced in + [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py index b5abfdeee22..defc47c0994 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py @@ -1,6 +1,7 @@ """ -abstract: Tests BLS12_G2MUL precompile of [EIP-2537: Precompile for BLS12-381 -curve operations](https://eips.ethereum.org/EIPS/eip-2537). +abstract: Test the BLS12_G2MUL precompile + Test the BLS12_G2MUL precompile introduced in + [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). """ import pytest @@ -85,12 +86,12 @@ Spec.P2 + Scalar(2**256 - 1), PointG2( ( - 0x2663E1C3431E174CA80E5A84489569462E13B52DA27E7720AF5567941603475F1F9BC0102E13B92A0A21D96B94E9B22, # noqa: E501 - 0x6A80D056486365020A6B53E2680B2D72D8A93561FC2F72B960936BB16F509C1A39C4E4174A7C9219E3D7EF130317C05, # noqa: E501 + 0x2663E1C3431E174CA80E5A84489569462E13B52DA27E7720AF5567941603475F1F9BC0102E13B92A0A21D96B94E9B22, + 0x6A80D056486365020A6B53E2680B2D72D8A93561FC2F72B960936BB16F509C1A39C4E4174A7C9219E3D7EF130317C05, ), ( - 0xC49EAD39E9EB7E36E8BC25824299661D5B6D0E200BBC527ECCB946134726BF5DBD861E8E6EC946260B82ED26AFE15FB, # noqa: E501 - 0x5397DAD1357CF8333189821B737172B18099ECF7EE8BDB4B3F05EBCCDF40E1782A6C71436D5ACE0843D7F361CBC6DB2, # noqa: E501 + 0xC49EAD39E9EB7E36E8BC25824299661D5B6D0E200BBC527ECCB946134726BF5DBD861E8E6EC946260B82ED26AFE15FB, + 0x5397DAD1357CF8333189821B737172B18099ECF7EE8BDB4B3F05EBCCDF40E1782A6C71436D5ACE0843D7F361CBC6DB2, ), ), None, diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py index 475f764a8e3..9a75b31c35b 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py @@ -1,9 +1,8 @@ """ -abstract: Tests BLS12_MAP_FP2_TO_G2 precompile of [EIP-2537: Precompile for -BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537) Tests -BLS12_MAP_FP2_TO_G2 precompile of [EIP-2537: Precompile for BLS12-381 curve -operations](https://eips.ethereum.org/EIPS/eip-2537). -""" # noqa: E501 +abstract: Test the BLS12_MAP_FP2_TO_G2 precompile + Test the BLS12_MAP_FP2_TO_G2 precompile introduced in + [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). +""" import pytest @@ -24,12 +23,12 @@ G2_POINT_ZERO_FP = PointG2( ( - 0x18320896EC9EEF9D5E619848DC29CE266F413D02DD31D9B9D44EC0C79CD61F18B075DDBA6D7BD20B7FF27A4B324BFCE, # noqa: E501 - 0xA67D12118B5A35BB02D2E86B3EBFA7E23410DB93DE39FB06D7025FA95E96FFA428A7A27C3AE4DD4B40BD251AC658892, # noqa: E501 + 0x18320896EC9EEF9D5E619848DC29CE266F413D02DD31D9B9D44EC0C79CD61F18B075DDBA6D7BD20B7FF27A4B324BFCE, + 0xA67D12118B5A35BB02D2E86B3EBFA7E23410DB93DE39FB06D7025FA95E96FFA428A7A27C3AE4DD4B40BD251AC658892, ), ( - 0x260E03644D1A2C321256B3246BAD2B895CAD13890CBE6F85DF55106A0D334604FB143C7A042D878006271865BC35941, # noqa: E501 - 0x4C69777A43F0BDA07679D5805E63F18CF4E0E7C6112AC7F70266D199B4F76AE27C6269A3CEEBDAE30806E9A76AADF5C, # noqa: E501 + 0x260E03644D1A2C321256B3246BAD2B895CAD13890CBE6F85DF55106A0D334604FB143C7A042D878006271865BC35941, + 0x4C69777A43F0BDA07679D5805E63F18CF4E0E7C6112AC7F70266D199B4F76AE27C6269A3CEEBDAE30806E9A76AADF5C, ), ) @@ -49,12 +48,12 @@ FP2((Spec.P - 1, Spec.P - 1)), PointG2( ( - 0x9BF1B857D8C15F317F649ACCFA7023EF21CFC03059936B83B487DB476FF9D2FE64C6147140A5F0A436B875F51FFDF07, # noqa: E501 - 0xBB10E09BDF236CB2951BD7BCC044E1B9A6BB5FD4B2019DCC20FFDE851D52D4F0D1A32382AF9D7DA2C5BA27E0F1C69E6, # noqa: E501 + 0x9BF1B857D8C15F317F649ACCFA7023EF21CFC03059936B83B487DB476FF9D2FE64C6147140A5F0A436B875F51FFDF07, + 0xBB10E09BDF236CB2951BD7BCC044E1B9A6BB5FD4B2019DCC20FFDE851D52D4F0D1A32382AF9D7DA2C5BA27E0F1C69E6, ), ( - 0xDD416A927AB1C15490AB753C973FD377387B12EFCBE6BED2BF768B9DC95A0CA04D1A8F0F30DBC078A2350A1F823CFD3, # noqa: E501 - 0x171565CE4FCD047B35EA6BCEE4EF6FDBFEC8CC73B7ACDB3A1EC97A776E13ACDFEFFC21ED6648E3F0EEC53DDB6C20FB61, # noqa: E501 + 0xDD416A927AB1C15490AB753C973FD377387B12EFCBE6BED2BF768B9DC95A0CA04D1A8F0F30DBC078A2350A1F823CFD3, + 0x171565CE4FCD047B35EA6BCEE4EF6FDBFEC8CC73B7ACDB3A1EC97A776E13ACDFEFFC21ED6648E3F0EEC53DDB6C20FB61, ), ), None, @@ -63,8 +62,8 @@ pytest.param( FP2( ( - 3510328712861478240121438855244276237335901234329585006107499559909114695366216070652508985150831181717984778988906, # noqa: E501 - 2924545590598115509050131525615277284817672420174395176262156166974132393611647670391999011900253695923948997972401, # noqa: E501 + 3510328712861478240121438855244276237335901234329585006107499559909114695366216070652508985150831181717984778988906, + 2924545590598115509050131525615277284817672420174395176262156166974132393611647670391999011900253695923948997972401, ) ), Spec.INF_G2, diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py index 4fb826f5712..96e198e6316 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py @@ -1,6 +1,8 @@ """ -abstract: Tests BLS12_MAP_FP_TO_G1 precompile of [EIP-2537: Precompile for -BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). +abstract: Tests BLS12_MAP_FP_TO_G1 precompile. + Tests the BLS12_MAP_FP_TO_G1 precompile implementation from [EIP-2537: + Precompile for BLS12-381 curve operations] + (https://eips.ethereum.org/EIPS/eip-2537). """ import pytest @@ -21,8 +23,8 @@ ] G1_POINT_ZERO_FP = PointG1( - 0x11A9A0372B8F332D5C30DE9AD14E50372A73FA4C45D5F2FA5097F2D6FB93BCAC592F2E1711AC43DB0519870C7D0EA415, # noqa: E501 - 0x92C0F994164A0719F51C24BA3788DE240FF926B55F58C445116E8BC6A47CD63392FD4E8E22BDF9FEAA96EE773222133, # noqa: E501 + 0x11A9A0372B8F332D5C30DE9AD14E50372A73FA4C45D5F2FA5097F2D6FB93BCAC592F2E1711AC43DB0519870C7D0EA415, + 0x92C0F994164A0719F51C24BA3788DE240FF926B55F58C445116E8BC6A47CD63392FD4E8E22BDF9FEAA96EE773222133, ) @@ -40,15 +42,15 @@ pytest.param( FP(Spec.P - 1), PointG1( - 0x1073311196F8EF19477219CCEE3A48035FF432295AA9419EED45D186027D88B90832E14C4F0E2AA4D15F54D1C3ED0F93, # noqa: E501 - 0x16B3A3B2E3DDDF6A11459DDAF657FDE21C4F10282A56029D9B55AB3CE1F41E1CF39AD27E0EA35823C7D3250E81FF3D66, # noqa: E501 + 0x1073311196F8EF19477219CCEE3A48035FF432295AA9419EED45D186027D88B90832E14C4F0E2AA4D15F54D1C3ED0F93, + 0x16B3A3B2E3DDDF6A11459DDAF657FDE21C4F10282A56029D9B55AB3CE1F41E1CF39AD27E0EA35823C7D3250E81FF3D66, ), None, id="fp_p_minus_1", ), pytest.param( FP( - 799950832265136997107648781861994410980648980263584507133499364313075404851459407870655748616451882783569609925573 # noqa: E501 + 799950832265136997107648781861994410980648980263584507133499364313075404851459407870655748616451882783569609925573 ), Spec.INF_G1, None, diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py index bf22c7ed871..081d5d91f50 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py @@ -1,6 +1,8 @@ """ -abstract: Tests BLS12_PAIRING precompile of [EIP-2537: Precompile for BLS12-381 -curve operations](https://eips.ethereum.org/EIPS/eip-2537). +abstract: Tests BLS12_PAIRING precompile. + Tests the BLS12_PAIRING precompile implementation from [EIP-2537: + Precompile for BLS12-381 curve operations] + (https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py index 930101cc59c..79b884ba9dd 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py @@ -1,6 +1,8 @@ """ -abstract: Tests BLS12 precompiles of [EIP-2537: Precompile for BLS12-381 -curve operations](https://eips.ethereum.org/EIPS/eip-2537). +abstract: Tests BLS12 precompiles before fork activation + Tests the BLS12 precompiles behavior before fork activation from + [EIP-2537: Precompile for BLS12-381 curve operations] + (https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py index 24d86b5b8ca..e8dbf95fab9 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py @@ -1,7 +1,9 @@ """ -abstract: Tests minimum gas and input length for BLS12_G1MSM, BLS12_G2MSM, -BLS12_PAIRING precompiles of [EIP-2537: Precompile for BLS12-381 curve -operations](https://eips.ethereum.org/EIPS/eip-2537). +abstract: Tests minimum gas and input length for BLS12 precompiles + Tests minimum gas and input length requirements for BLS12_G1MSM, + BLS12_G2MSM, and BLS12_PAIRING precompiles from [EIP-2537: Precompile + for BLS12-381 curve operations] + (https://eips.ethereum.org/EIPS/eip-2537). """ from typing import Callable, List, SupportsBytes diff --git a/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py b/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py index fbdc1abe93a..bc59f731ba6 100644 --- a/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py +++ b/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-2935: Serve historical block hashes from -state](https://eips.ethereum.org/EIPS/eip-2935). +abstract: Tests [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935). """ from typing import Dict, List diff --git a/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py b/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py index 813f0dc7ab8..c18c83b700a 100644 --- a/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py +++ b/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-2935: Serve historical block hashes from -state](https://eips.ethereum.org/EIPS/eip-2935). +abstract: Tests [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935). """ from os.path import realpath diff --git a/tests/prague/eip6110_deposits/test_deposits.py b/tests/prague/eip6110_deposits/test_deposits.py index c9b8d20a68f..d2b767d5916 100644 --- a/tests/prague/eip6110_deposits/test_deposits.py +++ b/tests/prague/eip6110_deposits/test_deposits.py @@ -1,6 +1,8 @@ """ -abstract: Tests [EIP-6110: Supply validator deposits on -chain](https://eips.ethereum.org/EIPS/eip-6110). +abstract: Tests validator deposit functionality. + Tests the validator deposit functionality implementation from [EIP-6110: + Supply validator deposits on chain] + (https://eips.ethereum.org/EIPS/eip-6110). """ from typing import List diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py index ce0661c78f2..7122d233769 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable -withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). """ from os.path import realpath diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py index 035d0421ec5..88d2f556279 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable -withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). """ from typing import List diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py index 94502acfe29..b0fbd44736c 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable -withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). """ from typing import List diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py index cf7f60227b5..c7bfa48a93a 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable -withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). """ from os.path import realpath diff --git a/tests/prague/eip7251_consolidations/test_consolidations.py b/tests/prague/eip7251_consolidations/test_consolidations.py index 8622161174d..2cd022cb460 100644 --- a/tests/prague/eip7251_consolidations/test_consolidations.py +++ b/tests/prague/eip7251_consolidations/test_consolidations.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-7251: Increase the -MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). +abstract: Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). """ from typing import List diff --git a/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py b/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py index ef4cd67ea48..869f33fe227 100644 --- a/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py +++ b/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-7251: Increase the -MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). +abstract: Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). """ from os.path import realpath diff --git a/tests/prague/eip7251_consolidations/test_contract_deployment.py b/tests/prague/eip7251_consolidations/test_contract_deployment.py index 8ec30c26764..34e455ba785 100644 --- a/tests/prague/eip7251_consolidations/test_contract_deployment.py +++ b/tests/prague/eip7251_consolidations/test_contract_deployment.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-7251: Increase the -MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). +abstract: Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). """ from os.path import realpath diff --git a/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py b/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py index 7c747a4d6bd..dad177076ae 100644 --- a/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py +++ b/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-7251: Execution layer triggerable -consolidation](https://eips.ethereum.org/EIPS/eip-7251). +abstract: Tests [EIP-7251: Execution layer triggerable consolidation](https://eips.ethereum.org/EIPS/eip-7251). """ from typing import List diff --git a/tests/prague/eip7623_increase_calldata_cost/__init__.py b/tests/prague/eip7623_increase_calldata_cost/__init__.py index 951922c6f92..916ea9ceeb6 100644 --- a/tests/prague/eip7623_increase_calldata_cost/__init__.py +++ b/tests/prague/eip7623_increase_calldata_cost/__init__.py @@ -1,4 +1,4 @@ """ abstract: Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623) - Tests for [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). + Tests for [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). """ diff --git a/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py b/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py index 7f52884153d..96e2b5a7f29 100644 --- a/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py +++ b/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py @@ -1,6 +1,5 @@ """ -abstract: Test [EIP-7623: Increase calldata -cost](https://eips.ethereum.org/EIPS/eip-7623). +abstract: Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). """ from typing import List diff --git a/tests/prague/eip7623_increase_calldata_cost/test_refunds.py b/tests/prague/eip7623_increase_calldata_cost/test_refunds.py index a59a9cd2683..844b154f893 100644 --- a/tests/prague/eip7623_increase_calldata_cost/test_refunds.py +++ b/tests/prague/eip7623_increase_calldata_cost/test_refunds.py @@ -1,6 +1,5 @@ """ -abstract: Test [EIP-7623: Increase calldata -cost](https://eips.ethereum.org/EIPS/eip-7623). +abstract: Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). """ from enum import Enum, Flag, auto diff --git a/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py b/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py index 16dfebf8c2c..d09f8170d01 100644 --- a/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py +++ b/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py @@ -1,6 +1,5 @@ """ -abstract: Test [EIP-7623: Increase calldata -cost](https://eips.ethereum.org/EIPS/eip-7623). +abstract: Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). """ import pytest diff --git a/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py b/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py index 3988156634b..ff394294f89 100644 --- a/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py +++ b/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py @@ -1,9 +1,7 @@ """ -abstract: Tests [EIP-7685: General purpose execution layer -requests](https://eips.ethereum.org/EIPS/eip-7685) -Cross testing for withdrawal and deposit request for [EIP-7685: -General purpose execution layer -requests](https://eips.ethereum.org/EIPS/eip-7685). +abstract: Tests EIP-7685 General purpose execution layer requests + Cross testing for withdrawal and deposit request for + [EIP-7685: General purpose execution layer requests](https://eips.ethereum.org/EIPS/eip-7685). """ from itertools import permutations diff --git a/tests/prague/eip7702_set_code_tx/test_gas.py b/tests/prague/eip7702_set_code_tx/test_gas.py index 7629105b307..769db0239f7 100644 --- a/tests/prague/eip7702_set_code_tx/test_gas.py +++ b/tests/prague/eip7702_set_code_tx/test_gas.py @@ -1,6 +1,7 @@ """ -abstract: Tests related to gas of set-code transactions from [EIP-7702: Set EOA -account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). +abstract: Tests related to gas of set-code transactions from EIP-7702 + Tests related to gas of set-code transactions from + [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). """ from dataclasses import dataclass diff --git a/tests/prague/eip7702_set_code_tx/test_invalid_tx.py b/tests/prague/eip7702_set_code_tx/test_invalid_tx.py index 949bbed4a3d..7fc06589c08 100644 --- a/tests/prague/eip7702_set_code_tx/test_invalid_tx.py +++ b/tests/prague/eip7702_set_code_tx/test_invalid_tx.py @@ -1,6 +1,7 @@ """ -abstract: Tests invalid set-code transactions from [EIP-7702: Set EOA account -code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). +abstract: Tests invalid set-code transactions from EIP-7702. + Tests invalid set-code transactions from + [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). """ from enum import Enum, auto diff --git a/tests/prague/eip7702_set_code_tx/test_set_code_txs.py b/tests/prague/eip7702_set_code_tx/test_set_code_txs.py index b076db62df9..42c980d2e0f 100644 --- a/tests/prague/eip7702_set_code_tx/test_set_code_txs.py +++ b/tests/prague/eip7702_set_code_tx/test_set_code_txs.py @@ -1,6 +1,7 @@ """ -abstract: Tests use of set-code transactions from [EIP-7702: Set EOA account -code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). +abstract: Tests use of set-code transactions from EIP-7702. + Tests use of set-code transactions from + [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). """ from enum import StrEnum diff --git a/tests/shanghai/eip3651_warm_coinbase/__init__.py b/tests/shanghai/eip3651_warm_coinbase/__init__.py index f24c6b66a59..cd8d9647e05 100644 --- a/tests/shanghai/eip3651_warm_coinbase/__init__.py +++ b/tests/shanghai/eip3651_warm_coinbase/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-3651: Warm COINBASE](https://eips.ethereum.org/EIPS/eip-3651) - Tests for [EIP-3651: Warm COINBASE](https://eips.ethereum.org/EIPS/eip-3651). +abstract: Tests for [EIP-3651: Warm COINBASE](https://eips.ethereum.org/EIPS/eip-3651). """ diff --git a/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py b/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py index b49b8569fdf..3f811c605db 100644 --- a/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py +++ b/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py @@ -1,6 +1,6 @@ """ -abstract: Tests [EIP-3651: Warm COINBASE](https://eips.ethereum.org/EIPS/eip-3651) - Tests for [EIP-3651: Warm COINBASE](https://eips.ethereum.org/EIPS/eip-3651). +abstract: Tests [EIP-3651: Warm COINBASE](https://eips.ethereum.org/EIPS/eip-3651). + Tests for EIP-3651: Warm COINBASE. note: Tests ported from: - [ethereum/tests/pull/1082](https://github.com/ethereum/tests/pull/1082). diff --git a/tests/shanghai/eip3855_push0/test_push0.py b/tests/shanghai/eip3855_push0/test_push0.py index de3ec5064c9..850a5a3a9da 100644 --- a/tests/shanghai/eip3855_push0/test_push0.py +++ b/tests/shanghai/eip3855_push0/test_push0.py @@ -1,10 +1,9 @@ """ -abstract: Tests [EIP-3855: PUSH0 -Instruction](https://eips.ethereum.org/EIPS/eip-3855) Tests for [EIP-3855: -PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855). +abstract: Tests [EIP-3855: PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855) + Tests for [EIP-3855: PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855). note: Tests ported from: - -[ethereum/tests/pull/1033](https://github.com/ethereum/tests/pull/1033). + [ethereum/tests/pull/1033](https://github.com/ethereum/tests/pull/1033). """ import pytest diff --git a/tests/shanghai/eip3860_initcode/__init__.py b/tests/shanghai/eip3860_initcode/__init__.py index 62ee051a08a..501700995db 100644 --- a/tests/shanghai/eip3860_initcode/__init__.py +++ b/tests/shanghai/eip3860_initcode/__init__.py @@ -1,4 +1,4 @@ """ abstract: Test [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860) - Tests for [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860). + Tests for [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860). """ diff --git a/tests/shanghai/eip3860_initcode/test_initcode.py b/tests/shanghai/eip3860_initcode/test_initcode.py index 7eaf1c39a63..3f10fa02da1 100644 --- a/tests/shanghai/eip3860_initcode/test_initcode.py +++ b/tests/shanghai/eip3860_initcode/test_initcode.py @@ -1,11 +1,10 @@ """ -abstract: Test [EIP-3860: Limit and meter -initcode](https://eips.ethereum.org/EIPS/eip-3860) Tests for [EIP-3860: Limit -and meter initcode](https://eips.ethereum.org/EIPS/eip-3860). +abstract: Test [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860) + Tests for [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860). -note: Tests ported from: - -[ethereum/tests/pull/990](https://github.com/ethereum/tests/pull/990) - -[ethereum/tests/pull/1012](https://github.com/ethereum/tests/pull/990) +note: Tests ported from: + - [ethereum/tests/pull/990](https://github.com/ethereum/tests/pull/990) + - [ethereum/tests/pull/1012](https://github.com/ethereum/tests/pull/990) """ from typing import List diff --git a/tests/shanghai/eip4895_withdrawals/__init__.py b/tests/shanghai/eip4895_withdrawals/__init__.py index bb4a893dcb3..edd1dd22c5f 100644 --- a/tests/shanghai/eip4895_withdrawals/__init__.py +++ b/tests/shanghai/eip4895_withdrawals/__init__.py @@ -1,5 +1,4 @@ """ -abstract: Tests [EIP-4895: Beacon chain withdrawals](https://eips.ethereum.org/EIPS/eip-4895) - Test cases for [EIP-4895: Beacon chain push withdrawals as - operations](https://eips.ethereum.org/EIPS/eip-4895). +abstract: Tests [EIP-4895: Beacon chain withdrawals](https://eips.ethereum.org/EIPS/eip-4895). + Test cases for EIP-4895: Beacon chain push withdrawals as operations. """ diff --git a/tests/shanghai/eip4895_withdrawals/test_withdrawals.py b/tests/shanghai/eip4895_withdrawals/test_withdrawals.py index fbba806926f..86b07e51720 100644 --- a/tests/shanghai/eip4895_withdrawals/test_withdrawals.py +++ b/tests/shanghai/eip4895_withdrawals/test_withdrawals.py @@ -1,8 +1,6 @@ """ -abstract: Tests [EIP-4895: Beacon chain -withdrawals](https://eips.ethereum.org/EIPS/eip-4895) Test cases for [EIP-4895: -Beacon chain push withdrawals as -operations](https://eips.ethereum.org/EIPS/eip-4895). +abstract: Tests for [EIP-4895: Beacon chain withdrawals](https://eips.ethereum.org/EIPS/eip-4895). + Test cases for EIP-4895: Beacon chain push withdrawals as operations. """ from enum import Enum, unique diff --git a/tests/unscheduled/eip7692_eof_v1/__init__.py b/tests/unscheduled/eip7692_eof_v1/__init__.py index 39b893bb4af..21febf2d5b4 100644 --- a/tests/unscheduled/eip7692_eof_v1/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/__init__.py @@ -1,6 +1,6 @@ """ -abstract: Test cases for [EIP-7692: EVM Object Format (EOFv1) Meta](https://eips.ethereum.org/EIPS/eip-7692) - Test cases for the EIPs included in [EIP-7692 EOFv1 Meta](https://eips.ethereum.org/EIPS/eip-7692). +abstract: Test cases for [EIP-7692: EVM Object Format (EOFv1) Meta](https://eips.ethereum.org/EIPS/eip-7692). + Test cases for the EIPs included in EIP-7692 EOFv1 Meta. * [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663). * [EIP-3540: EOF - EVM Object Format v1](https://eips.ethereum.org/EIPS/eip-3540). @@ -16,7 +16,7 @@ ## Devnet Specifications -- [ethpandaops/eof-devnet-0](https://notes.ethereum.org/@ethpandaops/eof-devnet-0). -""" # noqa: E501 + - [ethpandaops/eof-devnet-0](https://notes.ethereum.org/@ethpandaops/eof-devnet-0). +""" EOF_FORK_NAME = "EOFv1" diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py index bcde29f9137..fac62387aff 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py @@ -1,6 +1,9 @@ """ -abstract: Test cases for [EIP-3540: EOF - EVM Object Format -v1](https://eips.ethereum.org/EIPS/eip-3540) EIP-3540 introduces a structured -format for EVM bytecode, with separate sections for code and data. Opcodes -introduced: None (defines a new bytecode structure but no new opcodes). +abstract: EOF - EVM Object Format v1 tests. + Test cases for + [EIP-3540: EOF - EVM Object Format v1](https://eips.ethereum.org/EIPS/eip-3540). + + EIP-3540 introduces a structured format for EVM bytecode, with separate + sections for code and data. Opcodes introduced: None (defines a new + bytecode structure but no new opcodes). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py index 2de612e3285..f8728ad036a 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py @@ -1,7 +1,6 @@ """ -abstract: Test cases for [EIP-4200: EOF - Static relative -jumps](https://eips.ethereum.org/EIPS/eip-4200). -EIP-4200 replaces dynamic jump instructions with relative jump offsets -for improved control flow predictability. -Opcodes introduced: `RJUMP` (`0xE0`), `RJUMPI` (`0xE1`), `RJUMPV` (`0xE2`). +abstract: Test cases for [EIP-4200: EOF - Static relative jumps](https://eips.ethereum.org/EIPS/eip-4200). + EIP-4200 replaces dynamic jump instructions with relative jump offsets for + improved control flow predictability. Opcodes introduced: `RJUMP` (`0xE0`), + `RJUMPI` (`0xE1`), `RJUMPV` (`0xE2`). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py index c7e591dd465..4498ad304fa 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py @@ -1,8 +1,6 @@ """ -abstract: Test cases for [EIP-4750: EOF - -Functions](https://eips.ethereum.org/EIPS/eip-4750). - -EIP-4750 formalizes functions in the EVM object format, introducing -callable units of code. -Opcodes introduced: `CALLF` (`0xE3`), `RETF` (`0xE4`). +abstract: Test cases for [EIP-4750: EOF - Functions](https://eips.ethereum.org/EIPS/eip-4750) + EIP-4750 formalizes functions in the EVM object format, introducing + callable units of code. Opcodes introduced: `CALLF` (`0xE3`), `RETF` + (`0xE4`). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py index 3e81fe6764b..831c0d3fbc0 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py @@ -1,8 +1,9 @@ """ -abstract: Test cases for [EIP-5450: EOF - Stack -Validation](https://eips.ethereum.org/EIPS/eip-5450). +abstract: EOF Stack Validation tests + Tests for + [EIP-5450: EOF - Stack Validation](https://eips.ethereum.org/EIPS/eip-5450). -EIP-5450 defines stack validation requirements to ensure consistent -behavior during execution. -Opcodes introduced: None (specifies validation rules for stack usage). + EIP-5450 defines stack validation requirements to ensure consistent + behavior during execution. Opcodes introduced: None (specifies validation + rules for stack usage). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py index f833734006b..46d8f72e4fa 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py @@ -1,6 +1,5 @@ """ -abstract: Test cases for [EIP-6206: EOF - JUMPF and non-returning -functions](https://eips.ethereum.org/EIPS/eip-6206) EIP-6206 adds a conditional -forward jump instruction and support for functions without return values. -Opcodes introduced: `JUMPF` (`0xE5`). +abstract: Test cases for [EIP-6206: EOF - JUMPF and non-returning functions](https://eips.ethereum.org/EIPS/eip-6206). + EIP-6206 adds a conditional forward jump instruction and support for + functions without return values. Opcodes introduced: `JUMPF` (`0xE5`). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py index 34f1124ed97..11d5b83e478 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py @@ -1,8 +1,9 @@ """ -abstract: Test cases for [EIP-663: SWAPN, DUPN and EXCHANGE -instructions](https://eips.ethereum.org/EIPS/eip-663) EIP-663 defines new stack -manipulation instructions that allow accessing the stack at higher depths. -Opcodes introduced: `DUPN` (`0xE6`), `SWAPN` (`0xE7`), `EXCHANGEN` (`0xE8`). +abstract: Test cases for EIP-663 SWAPN, DUPN and EXCHANGE instructions + [EIP-663](https://eips.ethereum.org/EIPS/eip-663) defines new stack + manipulation instructions that allow accessing the stack at higher depths. + Opcodes introduced: `DUPN` (`0xE6`), `SWAPN` (`0xE7`), `EXCHANGEN` + (`0xE8`). """ REFERENCE_SPEC_GIT_PATH = "EIPS/eip-663.md" diff --git a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py index 6f1966f9508..56e92d17965 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py +++ b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py @@ -1,6 +1,7 @@ """ -abstract: Tests [EIP-663: SWAPN, DUPN and EXCHANGE -instructions](https://eips.ethereum.org/EIPS/eip-663). +abstract: DUPN instruction tests + Tests for DUPN instruction in + [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663). """ import pytest diff --git a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py index 5b541a78a09..55a0bb945ef 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py +++ b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-663: SWAPN, DUPN and EXCHANGE -instructions](https://eips.ethereum.org/EIPS/eip-663). +abstract: Tests [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663). """ import pytest diff --git a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py index 387bf477ae7..b0d14af35de 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py +++ b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py @@ -1,7 +1,4 @@ -""" -abstract: Tests [EIP-663: SWAPN, DUPN and EXCHANGE -instructions](https://eips.ethereum.org/EIPS/eip-663). -""" +"""Tests [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663).""" import pytest diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py index f1976aeff22..bae0996845c 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py @@ -1,9 +1,10 @@ """ -abstract: Test cases for [EIP-7069: Revamped CALL -instructions](https://eips.ethereum.org/EIPS/eip-7069) EIP-7069 proposes -modifications to `CALL` instructions to align with the structured EOF format. -Opcodes introduced: `EXTCALL` (`0xF8`), `EXTDELEGATECALL` (`0xF9`), -`EXTSTATICCALL` (`0xFB`), `RETURNDATALOAD` (`0xF7`). +abstract: Test cases for EIP-7069 Revamped CALL instructions + [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069) + proposes modifications to `CALL` instructions to align with the + structured EOF format. Opcodes introduced: `EXTCALL` (`0xF8`), + `EXTDELEGATECALL` (`0xF9`), `EXTSTATICCALL` (`0xFB`), `RETURNDATALOAD` + (`0xF7`). """ REFERENCE_SPEC_GIT_PATH = "EIPS/eip-7069.md" diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py index 182057b8d52..7708aa5baf4 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-7069: Revamped CALL -instructions](https://eips.ethereum.org/EIPS/eip-7069) Tests for the -RETURNDATALOAD instruction. +abstract: Call data tests for EXT*CALL instructions + Tests for call data handling in + [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069). """ import pytest diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py index 00cd91b1d99..d111b4cc26c 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py @@ -1,6 +1,7 @@ """ -abstract: Tests [EIP-7069: Revamped CALL -instructions](https://eips.ethereum.org/EIPS/eip-7069) Tests gas consumption. +abstract: Gas consumption tests for EXT*CALL instructions + Tests for gas consumption in + [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069). """ import pytest diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py index 9f9eccbc46a..e06cf9f80c1 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py @@ -1,7 +1,7 @@ """ -abstract: Tests [EIP-7069: Revamped CALL -instructions](https://eips.ethereum.org/EIPS/eip-7069) Tests for the -RETURNDATALOAD instruction. +abstract: RETURNDATALOAD instruction tests + Tests for RETURNDATALOAD instruction in + [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069). """ from typing import cast diff --git a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py index b175120b31c..ca92477ccb2 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py @@ -1,7 +1,8 @@ """ -abstract: Test cases for [EIP-7480: EOF - Data section access -instructions](https://eips.ethereum.org/EIPS/eip-7480) EIP-7480 specifies -instructions for accessing data stored in the dedicated data section of the EOF -format. Opcodes introduced: `DATALOAD` (`0xD0`), `DATALOADN` (`0xD1`), -`DATASIZE` (`0xD2`), `DATACOPY` (`0xD3`). +abstract: Test cases for EOF Data section access instructions for EIP-7480. + EIP-7480 specifies instructions for accessing data stored in the dedicated + data section of the EOF format. Full specification: [EIP-7480: EOF - Data + section access instructions](https://eips.ethereum.org/EIPS/eip-7480). + Opcodes introduced: `DATALOAD` (`0xD0`), `DATALOADN` (`0xD1`), `DATASIZE` + (`0xD2`), `DATACOPY` (`0xD3`). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py index 0a6a65626e7..a5ec044750b 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py @@ -1,22 +1,22 @@ """ -abstract: Test cases for [EIP-7620: EOF Contract -Creation](https://eips.ethereum.org/EIPS/eip-7620) EIP-7620 replaces `CREATE` -and `CREATE2` with `EOFCREATE` for deploying contracts in the EOF format. -Opcodes introduced: `EOFCREATE` (`0xEC`), `RETURNCODE` (`0xEE`). +abstract: Test cases for EOF Contract Creation for EIP-7620. + EIP-7620 replaces `CREATE` and `CREATE2` with `EOFCREATE` for deploying + contracts in the EOF format. Full specification: + [EIP-7620: EOF Contract Creation](https://eips.ethereum.org/EIPS/eip-7620). + Opcodes introduced: `EOFCREATE` (`0xEC`), `RETURNCODE` (`0xEE`). + EOFCREATE, RETURNCODE, and container tests. -EOFCREATE, RETURNCODE, and container tests + evmone tests not ported: -evmone tests not ported - -- create_tx_with_eof_initcode: This calls it invalid, it is now the way to add -EOF contacts to state -- eofcreate_extcall_returncode: Per the new initcode -mode tests you cannot have RETURNCODE in a deployed contract -- eofcreate_dataloadn_referring_to_auxdata: covered by -tests.unscheduled.eip7480_data_section.test_data_opcodes. -test_data_section_succeed -- eofcreate_initcontainer_return: RETURN is banned in initcode containers -- eofcreate_initcontainer_stop: STOP is banned in initcode containers - All -TXCREATE tests. + - create_tx_with_eof_initcode: This calls it invalid, it is now the way to + add EOF contacts to state + - eofcreate_extcall_returncode: Per the new initcode + mode tests you cannot have RETURNCODE in a deployed contract + - eofcreate_dataloadn_referring_to_auxdata: covered by + tests.unscheduled.eip7480_data_section.test_data_opcodes. + test_data_section_succeed + - eofcreate_initcontainer_return: RETURN is banned in initcode containers + - eofcreate_initcontainer_stop: STOP is banned in initcode containers - All + TXCREATE tests. """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py index a7a83a36318..a0e886f11c4 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py @@ -1,5 +1,3 @@ """ -abstract: Test cases for -[EIP-7873: TXCREATE and -InitcodeTransaction](https://eips.ethereum.org/EIPS/eip-7873). +abstract: Test cases for [EIP-7873: TXCREATE and InitcodeTransaction](https://eips.ethereum.org/EIPS/eip-7873). """ diff --git a/tox.ini b/tox.ini index 43b46960077..c8fb2670d31 100644 --- a/tox.ini +++ b/tox.ini @@ -23,6 +23,9 @@ extras = lint commands = ruff check --no-fix --show-fixes {[testenv]python_source_dirs} ruff format --check {[testenv]python_source_dirs} + # The following ensures docstring and comment line length is checked to 79 characters + # see https://github.com/ethereum/execution-spec-tests/issues/2134 + ruff check --select W505 --config 'lint.pycodestyle.max-doc-length = 79' {[testenv]python_source_dirs} [testenv:typecheck] description = Run type checking (mypy) From c3f9d537c8b230b9e5b78bc51d166b3d172eab61 Mon Sep 17 00:00:00 2001 From: Felix H Date: Tue, 23 Sep 2025 09:03:15 +0000 Subject: [PATCH 03/16] fixes --- .vscode/settings.json | 2 +- src/cli/gen_index.py | 4 +- src/cli/gentest/request_manager.py | 2 +- src/config/docs.py | 3 +- src/ethereum_clis/clis/nethermind.py | 4 - src/ethereum_clis/transition_tool.py | 17 +- .../composite_types.py | 27 - src/ethereum_test_base_types/conversions.py | 16 +- src/ethereum_test_base_types/mixins.py | 36 +- src/ethereum_test_checklists/eip_checklist.py | 11 +- .../test_checklist_template_consistency.py | 6 +- .../exception_mapper.py | 20 +- src/ethereum_test_exceptions/exceptions.py | 117 - .../exceptions/block.py | 72 - .../exceptions/eof.py | 9 - .../exceptions/transaction.py | 42 - src/ethereum_test_fixtures/blockchain.py | 24 +- src/ethereum_test_fixtures/collector.py | 5 +- src/ethereum_test_fixtures/consume.py | 9 - .../pre_alloc_groups.py | 4 +- .../tests/test_blockchain.py | 5 +- .../tests/test_state.py | 5 +- src/ethereum_test_forks/base_fork.py | 24 +- src/ethereum_test_forks/forks/forks.py | 48 +- src/ethereum_test_forks/helpers.py | 9 +- src/ethereum_test_forks/tests/test_forks.py | 11 +- src/ethereum_test_specs/base_static.py | 79 +- src/ethereum_test_specs/blockchain.py | 102 +- src/ethereum_test_specs/eof.py | 63 - src/ethereum_test_specs/state.py | 14 +- .../static_state/common/common.py | 33 +- .../static_state/common/compile_yul.py | 16 +- .../static_state/common/tags.py | 16 +- .../tools_code/generators.py | 39 +- src/ethereum_test_tools/utility/generators.py | 88 +- src/ethereum_test_tools/utility/pytest.py | 117 +- .../utility/tests/test_pytest.py | 9 +- src/ethereum_test_tools/utility/versioning.py | 6 +- src/ethereum_test_types/blob_types.py | 8 +- src/ethereum_test_types/eof/constants.py | 4 - src/ethereum_test_types/eof/v1/__init__.py | 144 - src/ethereum_test_types/request_types.py | 18 - .../tests/test_blob_types.py | 6 +- src/ethereum_test_types/transaction_types.py | 5 +- src/ethereum_test_types/trie.py | 14 +- src/ethereum_test_vm/bytecode.py | 22 +- src/ethereum_test_vm/opcodes.py | 7810 +++++++++-------- src/pytest_plugins/consume/consume.py | 13 +- src/pytest_plugins/consume/releases.py | 11 +- .../consume/simulators/helpers/ruleset.py | 8 +- .../consume/simulators/rlp/conftest.py | 6 +- .../simulator_logic/test_via_sync.py | 9 +- .../custom_logging/plugin_logging.py | 24 +- .../execute/eth_config/eth_config.py | 4 +- .../execute/eth_config/execute_types.py | 9 +- src/pytest_plugins/execute/execute.py | 2 +- src/pytest_plugins/execute/pre_alloc.py | 11 +- src/pytest_plugins/filler/filler.py | 56 +- .../filler/gen_test_doc/gen_test_doc.py | 55 +- src/pytest_plugins/filler/ported_tests.py | 25 +- src/pytest_plugins/filler/pre_alloc.py | 7 +- .../filler/tests/test_benchmarking.py | 7 +- .../filler/tests/test_phase_manager.py | 20 +- .../tests/test_slow_marker_pre_alloc.py | 9 +- .../filler/tests/test_verify_sync_marker.py | 48 +- src/pytest_plugins/forks/forks.py | 137 +- .../tests/test_bad_command_line_options.py | 6 +- .../forks/tests/test_bad_validity_markers.py | 6 +- src/pytest_plugins/pytest_hive/pytest_hive.py | 26 +- src/pytest_plugins/shared/execute_fill.py | 6 - .../spec_version_checker.py | 29 +- .../test_p256verify.py | 62 +- 72 files changed, 4979 insertions(+), 4762 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2dbc599589b..a5f6cc1db9f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,7 +14,7 @@ "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[python]": { - "editor.rulers": [80, 100], + "editor.rulers": [79, 100], "editor.formatOnSave": true, "editor.defaultFormatter": "charliermarsh.ruff", "editor.codeActionsOnSave": { diff --git a/src/cli/gen_index.py b/src/cli/gen_index.py index dcd82741bdc..e1d8de1af2d 100644 --- a/src/cli/gen_index.py +++ b/src/cli/gen_index.py @@ -73,9 +73,7 @@ def count_json_files_exclude_index(start_path: Path) -> int: expose_value=True, help="Force re-generation of the index file, even if it already exists.", ) -def generate_fixtures_index_cli( - input_dir: str, quiet_mode: bool, force_flag: bool, disable_infer_format: bool -): +def generate_fixtures_index_cli(input_dir: str, quiet_mode: bool, force_flag: bool): """ CLI wrapper to an index of all the fixtures in the specified directory. """ diff --git a/src/cli/gentest/request_manager.py b/src/cli/gentest/request_manager.py index 62f375c45aa..ac517b7490d 100644 --- a/src/cli/gentest/request_manager.py +++ b/src/cli/gentest/request_manager.py @@ -1,5 +1,5 @@ """ -A request manager Ethereum RPC calls. +A request manager Ethereum RPC calls. The RequestManager handles transactions and block data retrieval from a remote Ethereum node, utilizing Pydantic models to define the structure of diff --git a/src/config/docs.py b/src/config/docs.py index 18454aee8f4..ac6c7e93cd6 100644 --- a/src/config/docs.py +++ b/src/config/docs.py @@ -1,7 +1,8 @@ """ A module for managing documentation-related configurations. -Classes: - DocsConfig: Holds configurations for documentation generation. +Classes: + DocsConfig: Holds configurations for documentation generation. """ from pydantic import BaseModel diff --git a/src/ethereum_clis/clis/nethermind.py b/src/ethereum_clis/clis/nethermind.py index 51432988a59..85d6ea44847 100644 --- a/src/ethereum_clis/clis/nethermind.py +++ b/src/ethereum_clis/clis/nethermind.py @@ -205,10 +205,6 @@ def consume_state_test( for test_result in file_results if test_result["name"].removesuffix(nethtest_suffix) == f"{fixture_name.split('/')[-1]}" - # TODO: the following was required for nethermind's - # feature/evm/eof branch nethtest version: - # 1.32.0-unstable+025871675bd2e0839f93d2b70416ebae9dbae012 == - # f"{fixture_name.split('.py::')[-1]}" ] assert len(test_result) < 2, f"Multiple test results for {fixture_name}" assert len(test_result) == 1, f"Test result for {fixture_name} missing" diff --git a/src/ethereum_clis/transition_tool.py b/src/ethereum_clis/transition_tool.py index 7d56eb80d5c..80e5ba3a85a 100644 --- a/src/ethereum_clis/transition_tool.py +++ b/src/ethereum_clis/transition_tool.py @@ -268,16 +268,16 @@ def _evaluate_filesystem( t8n_call = t8n_call.replace( os.path.dirname(file_path), os.path.join(debug_output_path, "input") ) - t8n_call = t8n_call.replace( # use a new output path for basedir - # and outputs + # use a new output path for basedir and outputs + t8n_call = t8n_call.replace( temp_dir.name, t8n_output_base_dir, ) t8n_script = textwrap.dedent( f"""\ #!/bin/bash - rm -rf {debug_output_path}/t8n.sh.out # hard-coded to avoid - # surprises + # hard-coded to avoid surprises + rm -rf {debug_output_path}/t8n.sh.out mkdir -p {debug_output_path}/t8n.sh.out/output {t8n_call} """ @@ -561,10 +561,11 @@ def dump_debug_stream( t8n_script = textwrap.dedent( f"""\ #!/bin/bash - rm -rf {debug_output_path}/t8n.sh.out # hard-coded to avoid - # surprises - mkdir {debug_output_path}/t8n.sh.out # unused if tracing is not - # enabled + # hard-coded to avoid surprises + rm -rf {debug_output_path}/t8n.sh.out + + # unused if tracing is not enabled + mkdir {debug_output_path}/t8n.sh.out {t8n_call} < {debug_output_path}/stdin.txt """ ) diff --git a/src/ethereum_test_base_types/composite_types.py b/src/ethereum_test_base_types/composite_types.py index 1cb76c006a4..63fbe534ff6 100644 --- a/src/ethereum_test_base_types/composite_types.py +++ b/src/ethereum_test_base_types/composite_types.py @@ -36,16 +36,7 @@ class Storage(EthereumTestRootModel[Dict[StorageKeyValueType, StorageKeyValueTyp str | int | bytes | SupportsBytes, str | int | bytes | SupportsBytes ] """ - - - - - - Dictionary type to be used when defining an input to initialize a storage. - - - """ @dataclass(kw_only=True) @@ -310,17 +301,8 @@ class Account(CamelModel): nonce: ZeroPaddedHexNumber = ZeroPaddedHexNumber(0) """ - - - - - - The scalar value equal to a) the number of transactions sent by an Externally Owned Account, b) the amount of contracts created by a contract. - - - """ balance: ZeroPaddedHexNumber = ZeroPaddedHexNumber(0) """The amount of Wei (10-18 Eth) the account has.""" @@ -331,17 +313,8 @@ class Account(CamelModel): NONEXISTENT: ClassVar[None] = None """ - - - - - - Sentinel object used to specify when an account should not exist in the state. - - - """ @dataclass(kw_only=True) diff --git a/src/ethereum_test_base_types/conversions.py b/src/ethereum_test_base_types/conversions.py index 330f46dde06..84fbb778959 100644 --- a/src/ethereum_test_base_types/conversions.py +++ b/src/ethereum_test_base_types/conversions.py @@ -60,12 +60,16 @@ def to_fixed_size_bytes( """ Convert multiple types into fixed-size bytes. - :param input_bytes: The input data to convert. :param size: The size of the - output bytes. :param left_padding: Whether to allow left-padding of the - input data bytes using zeros. If the input data is an integer, padding is - always performed. :param right_padding: Whether to allow right-padding of - the input data bytes using zeros. If the input data is an integer, padding - is always performed. + Args: + input_bytes: The input data to convert. + size: The size of the output bytes. + left_padding: Whether to allow left-padding of the input data bytes + using zeros. If the input data is an integer, padding is + always performed. + right_padding: Whether to allow right-padding of the input data bytes + using zeros. If the input data is an integer, padding + is always performed. + """ if isinstance(input_bytes, int): return int.to_bytes(input_bytes, length=size, byteorder="big", signed=input_bytes < 0) diff --git a/src/ethereum_test_base_types/mixins.py b/src/ethereum_test_base_types/mixins.py index 7b09bf5ccfe..d5c1d4cf5fa 100644 --- a/src/ethereum_test_base_types/mixins.py +++ b/src/ethereum_test_base_types/mixins.py @@ -23,12 +23,18 @@ def serialize( """ Serialize the model to the specified format with the given parameters. - :param mode: The mode of serialization. If mode is 'json', the output - will only contain JSON serializable types. If mode is 'python', the - output may contain non-JSON-serializable Python objects. :param - by_alias: Whether to use aliases for field names. :param exclude_none: - Whether to exclude fields with None values, default is True. :return: - The serialized representation of the model. + Args: + mode: The mode of serialization. If mode is 'json', the output + will only contain JSON serializable types. If mode is + 'python', the output may contain non-JSON-serializable + Python objects. + by_alias: Whether to use aliases for field names. + exclude_none: Whether to exclude fields with None values, + default is True. + + Returns: + dict[str, Any]: The serialized representation of the model. + """ if not hasattr(self, "model_dump"): raise NotImplementedError( @@ -50,12 +56,20 @@ def __repr_args__(self): representation, and is used by `gentest` module to generate the test cases. - See: - https://pydantic-docs.helpmanual.io/usage/models/#custom-repr - - https://github.com/ethereum/execution-spec-tests/pull/901# - issuecomment-24432968 35 + See: + https://pydantic-docs.helpmanual.io/usage/models/ + #custom-repr + + and + + https://github.com/ethereum/execution-spec-tests/pull/ + 901#issuecomment-24432968 35 + + Returns: + List[Tuple[str, Any]]: A list of tuples where each tuple + contains an attribute name and its + corresponding non-None value. - Returns: List[Tuple[str, Any]]: A list of tuples where each tuple - contains an attribute name and its corresponding non-None value. """ attrs_names = self.serialize(mode="python", by_alias=False).keys() attrs = ((s, getattr(self, s)) for s in attrs_names) diff --git a/src/ethereum_test_checklists/eip_checklist.py b/src/ethereum_test_checklists/eip_checklist.py index 347d52cc3c5..1361965eb72 100644 --- a/src/ethereum_test_checklists/eip_checklist.py +++ b/src/ethereum_test_checklists/eip_checklist.py @@ -102,10 +102,15 @@ class EIPChecklist: Note: If you modify this class structure, regenerate the type stub file using: uv run generate_checklist_stubs - Examples: @EIPChecklist.Opcode.Test.GasUsage.Normal() def - test_normal_gas(): pass + Examples: + @EIPChecklist.Opcode.Test.GasUsage.Normal() + def test_normal_gas(): + pass + + @EIPChecklist.Opcode.Test.StackOverflow + def test_stack_overflow(): + pass - @EIPChecklist.Opcode.Test.StackOverflow def test_stack_overflow(): pass """ class General(ChecklistItem): diff --git a/src/ethereum_test_checklists/tests/test_checklist_template_consistency.py b/src/ethereum_test_checklists/tests/test_checklist_template_consistency.py index 85a52123ef5..f8a190ae578 100644 --- a/src/ethereum_test_checklists/tests/test_checklist_template_consistency.py +++ b/src/ethereum_test_checklists/tests/test_checklist_template_consistency.py @@ -32,7 +32,7 @@ def extract_markdown_ids(markdown_content: str) -> Set[str]: return ids -def get_all_checklist_ids(obj, current_path="") -> Set[str]: +def get_all_checklist_ids(obj) -> Set[str]: """ Recursively extract all checklist IDs from EIPChecklist and its children. """ @@ -200,7 +200,7 @@ def test_eip_checklist_pytest_param_usage(): with pytest.raises((TypeError, AssertionError)): pytest.param( "test_value", - marks=EIPChecklist.Opcode.Test.StackOverflow, # Without () should - # fail + # Without () should fail + marks=EIPChecklist.Opcode.Test.StackOverflow, id="should_fail", ) diff --git a/src/ethereum_test_exceptions/exception_mapper.py b/src/ethereum_test_exceptions/exception_mapper.py index b750527097a..cf8e7b4e764 100644 --- a/src/ethereum_test_exceptions/exception_mapper.py +++ b/src/ethereum_test_exceptions/exception_mapper.py @@ -20,33 +20,24 @@ class ExceptionMapper(ABC): mapping_substring: ClassVar[Dict[ExceptionBase, str]] """ - - Mapping of exception to substring that should be present in the error message. Items in this mapping are used for substring matching (`substring in message`). - """ mapping_regex: ClassVar[Dict[ExceptionBase, str]] """ - - Mapping of exception to regex that should be present in the error message. Items in this mapping are compiled into regex patterns for faster matching, and then used for regex matching (`pattern.search(message)`). - """ reliable: ClassVar[bool] = True """ - - Whether the exceptions returned by the tool are reliable and can be accurately mapped to the exceptions in this class. - """ def __init__(self) -> None: @@ -122,15 +113,16 @@ def mapper_validator(v: str, info: ValidationInfo) -> Dict[str, Any] | Undefined ExceptionMapperValidator = BeforeValidator(mapper_validator) """ - - Validator that can be used to annotate a pydantic field in a model that is meant to be parsed from an external tool or client. The annotated type must be an union that can include `None`, -`UndefinedException` and a custom model as: ``` class -BlockExceptionWithMessage(ExceptionWithMessage[BlockException]): pass ``` where -`BlockException` can be any derivation of `ExceptionBase`. +`UndefinedException` and a custom model as: +``` +class BlockExceptionWithMessage(ExceptionWithMessage[BlockException]): + pass +``` +where `BlockException` can be any derivation of `ExceptionBase`. The `message` attribute is the verbatim message received from the external tool or client, and can be used to be printed for extra context information in case diff --git a/src/ethereum_test_exceptions/exceptions.py b/src/ethereum_test_exceptions/exceptions.py index c900668ec49..8de5ac505c3 100644 --- a/src/ethereum_test_exceptions/exceptions.py +++ b/src/ethereum_test_exceptions/exceptions.py @@ -141,19 +141,13 @@ class TransactionException(ExceptionBase): """Transaction nonce < sender.nonce.""" NONCE_TOO_BIG = auto() """ - - Transaction `nonce` is not allowed to be max_uint64 - 1 (this is probably TransactionTest). - """ NONCE_IS_MAX = auto() """ - - Transaction `nonce` is not allowed to be max_uint64 - 1 (this is StateTests). - """ NONCE_OVERFLOW = auto() """Transaction `nonce` is not allowed to be more than uint64.""" @@ -191,35 +185,23 @@ class TransactionException(ExceptionBase): """Error reading transaction priority fee field RLP.""" RLP_LEADING_ZEROS_DATA_SIZE = auto() """ - - Error reading transaction data field RLP, (rlp field length has leading zeros). - """ RLP_LEADING_ZEROS_NONCE_SIZE = auto() """ - - Error reading transaction nonce field RLP, (rlp field length has leading zeros). - """ RLP_TOO_FEW_ELEMENTS = auto() """ - - Error reading transaction RLP, structure has too few elements than expected. - """ RLP_TOO_MANY_ELEMENTS = auto() """ - - Error reading transaction RLP, structure has too many elements than expected. - """ RLP_ERROR_EOF = auto() """Error reading transaction RLP, rlp stream unexpectedly finished.""" @@ -253,42 +235,27 @@ class TransactionException(ExceptionBase): """Transaction has correct signature, but ec recovery failed.""" INSUFFICIENT_ACCOUNT_FUNDS = auto() """ - - Transaction's sender does not have enough funds to pay for the transaction. - """ INSUFFICIENT_MAX_FEE_PER_GAS = auto() """Transaction's max-fee-per-gas is lower than the block base-fee.""" PRIORITY_OVERFLOW = auto() """ - - Transaction's max-priority-fee-per-gas is exceeds 2^256-1 maximum value. - """ PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS = auto() """ - - Transaction's max-priority-fee-per-gas is greater than the max-fee-per-gas. - """ PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS_2 = auto() """ - - Transaction's max-priority-fee-per-gas is greater than the max-fee-per-gas (TransactionTests). - """ INSUFFICIENT_MAX_FEE_PER_BLOB_GAS = auto() """ - - Transaction's max-fee-per-blob-gas is lower than the block's blob-gas price. - """ INTRINSIC_GAS_TOO_LOW = auto() """Transaction's gas limit is too low.""" @@ -296,10 +263,7 @@ class TransactionException(ExceptionBase): """Transaction's gas limit is below the floor gas cost.""" INITCODE_SIZE_EXCEEDED = auto() """ - - Transaction's initcode for a contract-creating transaction is too large. - """ TYPE_3_TX_PRE_FORK = auto() """Transaction type 3 included before activation fork.""" @@ -319,10 +283,7 @@ class TransactionException(ExceptionBase): """Transaction causes block to go over blob gas limit.""" GAS_LIMIT_EXCEEDS_MAXIMUM = auto() """ - - Transaction gas limit exceeds the maximum allowed limit of 30 million. - """ TYPE_3_TX_ZERO_BLOBS = auto() """Transaction is type 3, but has no blobs.""" @@ -336,11 +297,8 @@ class TransactionException(ExceptionBase): """Transaction is a type 4 transaction and has an empty `to`.""" TYPE_4_INVALID_AUTHORIZATION_FORMAT = auto() """ - - Transaction is type 4, but contains an authorization that has an invalid format. - """ TYPE_4_TX_PRE_FORK = auto() """Transaction type 4 included before activation fork.""" @@ -369,26 +327,17 @@ class BlockException(ExceptionBase): """Block header's extra data >32 bytes.""" EXTRA_DATA_INVALID_DAO = auto() """ - - Block header's extra data after dao fork must be a fixed pre defined hash. - """ UNKNOWN_PARENT = auto() """ - - Block header's parent hash does not correspond to any of existing blocks on chain. - """ UNCLE_UNKNOWN_PARENT = auto() """ - - Uncle header's parent hash does not correspond to any of existing blocks on chain. - """ UNKNOWN_PARENT_ZERO = auto() """Block header's parent hash is zero hash.""" @@ -400,87 +349,57 @@ class BlockException(ExceptionBase): """Block header's timestamp <= parent header's timestamp.""" INVALID_DIFFICULTY = auto() """ - - Block header's difficulty does not match the difficulty formula calculated from previous block. - """ INVALID_LOG_BLOOM = auto() """ - - Block header's logs bloom hash does not match the actually computed log bloom. - """ INVALID_STATE_ROOT = auto() """ - - Block header's state root hash does not match the actually computed hash of the state. - """ INVALID_RECEIPTS_ROOT = auto() """ - - Block header's receipts root hash does not match the actually computed hash of receipts. - """ INVALID_TRANSACTIONS_ROOT = auto() """ - - Block header's transactions root hash does not match the actually computed hash of tx tree. - """ INVALID_UNCLES_HASH = auto() """ - - Block header's uncle hash does not match the actually computed hash of block's uncles. - """ GAS_USED_OVERFLOW = auto() """Block transactions consume more gas than block header allow.""" INVALID_GASLIMIT = auto() """ - - Block header's gas limit does not match the gas limit formula calculated from previous block. - """ INVALID_BASEFEE_PER_GAS = auto() """Block header's base_fee_per_gas field is calculated incorrect.""" INVALID_GAS_USED = auto() """ - - Block header's actual gas used does not match the provided header's value - """ INVALID_GAS_USED_ABOVE_LIMIT = auto() """Block header's gas used value is above the gas limit field's value.""" INVALID_WITHDRAWALS_ROOT = auto() """ - - Block header's withdrawals root does not match calculated withdrawals root. - """ INCORRECT_BLOCK_FORMAT = auto() """ - - Block's format is incorrect, contains invalid fields, is missing fields, or contains fields of a fork that is not active yet. - """ BLOB_GAS_USED_ABOVE_LIMIT = auto() """Block's blob gas used in header is above the limit.""" @@ -492,10 +411,7 @@ class BlockException(ExceptionBase): """Incorrect number of versioned hashes in a payload.""" RLP_STRUCTURES_ENCODING = auto() """ - - Block's rlp encoding is valid but ethereum structures in it are invalid. - """ RLP_WITHDRAWALS_NOT_READ = auto() """Block's rlp encoding is missing withdrawals.""" @@ -511,27 +427,18 @@ class BlockException(ExceptionBase): """Legacy block import is impossible in this chain configuration.""" IMPORT_IMPOSSIBLE_LEGACY_WRONG_PARENT = auto() """ - - Legacy block import is impossible, trying to import on top of a block that is not legacy. - """ IMPORT_IMPOSSIBLE_LONDON_WRONG_PARENT = auto() """ - - Trying to import london (basefee) block on top of block that is not 1559. - """ IMPORT_IMPOSSIBLE_PARIS_WRONG_POW = auto() """Trying to import paris(merge) block with PoW enabled.""" IMPORT_IMPOSSIBLE_PARIS_WRONG_POS = auto() """ - - Trying to import paris(merge) block with PoS enabled before TTD is reached. - """ IMPORT_IMPOSSIBLE_LONDON_OVER_PARIS = auto() """Trying to import london looking block over paris network (POS).""" @@ -541,43 +448,28 @@ class BlockException(ExceptionBase): """Shanghai block import is impossible in this chain configuration.""" IMPORT_IMPOSSIBLE_UNCLES_OVER_PARIS = auto() """ - - Trying to import a block after paris fork that has not empty uncles hash. - """ IMPORT_IMPOSSIBLE_DIFFICULTY_OVER_PARIS = auto() """Trying to import a block after paris fork that has difficulty != 0.""" SYSTEM_CONTRACT_EMPTY = auto() """ - - A system contract address contains no code at the end of fork activation block. - """ SYSTEM_CONTRACT_CALL_FAILED = auto() """ - - A system contract call at the end of block execution (from the system address) fails. - """ INVALID_BLOCK_HASH = auto() """ - - Block header's hash does not match the actually computed hash of the block. - """ INVALID_DEPOSIT_EVENT_LAYOUT = auto() """ - - Transaction emits a `DepositEvent` in the deposit contract (EIP-6110), but the layout of the event does not match the required layout. - """ @@ -660,27 +552,18 @@ class EOFException(ExceptionBase): """EOF container's specified max stack increase is above the limit.""" STACK_HIGHER_THAN_OUTPUTS = auto() """ - - EOF container section stack height is higher than the outputs. when returning - """ JUMPF_DESTINATION_INCOMPATIBLE_OUTPUTS = auto() """ - - EOF container section JUMPF's to a destination section with incompatible outputs. - """ INVALID_MAX_STACK_INCREASE = auto() """ - - EOF container section's specified max stack increase does not match the actual stack height. - """ INVALID_DATALOADN_INDEX = auto() """A DATALOADN instruction has out-of-bounds index for the data section.""" diff --git a/src/ethereum_test_exceptions/exceptions/block.py b/src/ethereum_test_exceptions/exceptions/block.py index cf9dc2fdb60..8e7eae0b24b 100644 --- a/src/ethereum_test_exceptions/exceptions/block.py +++ b/src/ethereum_test_exceptions/exceptions/block.py @@ -28,26 +28,17 @@ class BlockException(ExceptionBase): """Block header's extra data >32 bytes.""" EXTRA_DATA_INVALID_DAO = auto() """ - - Block header's extra data after dao fork must be a fixed pre defined hash. - """ UNKNOWN_PARENT = auto() """ - - Block header's parent hash does not correspond to any of existing blocks on chain. - """ UNCLE_UNKNOWN_PARENT = auto() """ - - Uncle header's parent hash does not correspond to any of existing blocks on chain. - """ UNKNOWN_PARENT_ZERO = auto() """Block header's parent hash is zero hash.""" @@ -59,87 +50,57 @@ class BlockException(ExceptionBase): """Block header's timestamp <= parent header's timestamp.""" INVALID_DIFFICULTY = auto() """ - - Block header's difficulty does not match the difficulty formula calculated from previous block. - """ INVALID_LOG_BLOOM = auto() """ - - Block header's logs bloom hash does not match the actually computed log bloom. - """ INVALID_STATE_ROOT = auto() """ - - Block header's state root hash does not match the actually computed hash of the state. - """ INVALID_RECEIPTS_ROOT = auto() """ - - Block header's receipts root hash does not match the actually computed hash of receipts. - """ INVALID_TRANSACTIONS_ROOT = auto() """ - - Block header's transactions root hash does not match the actually computed hash of tx tree. - """ INVALID_UNCLES_HASH = auto() """ - - Block header's uncle hash does not match the actually computed hash of block's uncles. - """ GAS_USED_OVERFLOW = auto() """Block transactions consume more gas than block header allow.""" INVALID_GASLIMIT = auto() """ - - Block header's gas limit does not match the gas limit formula calculated from previous block. - """ INVALID_BASEFEE_PER_GAS = auto() """Block header's base_fee_per_gas field is calculated incorrect.""" INVALID_GAS_USED = auto() """ - - Block header's actual gas used does not match the provided header's value - """ INVALID_GAS_USED_ABOVE_LIMIT = auto() """Block header's gas used value is above the gas limit field's value.""" INVALID_WITHDRAWALS_ROOT = auto() """ - - Block header's withdrawals root does not match calculated withdrawals root. - """ INCORRECT_BLOCK_FORMAT = auto() """ - - Block's format is incorrect, contains invalid fields, is missing fields, or contains fields of a fork that is not active yet. - """ BLOB_GAS_USED_ABOVE_LIMIT = auto() """Block's blob gas used in header is above the limit.""" @@ -151,10 +112,7 @@ class BlockException(ExceptionBase): """Incorrect number of versioned hashes in a payload.""" RLP_STRUCTURES_ENCODING = auto() """ - - Block's rlp encoding is valid but ethereum structures in it are invalid. - """ RLP_WITHDRAWALS_NOT_READ = auto() """Block's rlp encoding is missing withdrawals.""" @@ -170,27 +128,18 @@ class BlockException(ExceptionBase): """Legacy block import is impossible in this chain configuration.""" IMPORT_IMPOSSIBLE_LEGACY_WRONG_PARENT = auto() """ - - Legacy block import is impossible, trying to import on top of a block that is not legacy. - """ IMPORT_IMPOSSIBLE_LONDON_WRONG_PARENT = auto() """ - - Trying to import london (basefee) block on top of block that is not 1559. - """ IMPORT_IMPOSSIBLE_PARIS_WRONG_POW = auto() """Trying to import paris(merge) block with PoW enabled.""" IMPORT_IMPOSSIBLE_PARIS_WRONG_POS = auto() """ - - Trying to import paris(merge) block with PoS enabled before TTD is reached. - """ IMPORT_IMPOSSIBLE_LONDON_OVER_PARIS = auto() """Trying to import london looking block over paris network (POS).""" @@ -200,43 +149,28 @@ class BlockException(ExceptionBase): """Shanghai block import is impossible in this chain configuration.""" IMPORT_IMPOSSIBLE_UNCLES_OVER_PARIS = auto() """ - - Trying to import a block after paris fork that has not empty uncles hash. - """ IMPORT_IMPOSSIBLE_DIFFICULTY_OVER_PARIS = auto() """Trying to import a block after paris fork that has difficulty != 0.""" SYSTEM_CONTRACT_EMPTY = auto() """ - - A system contract address contains no code at the end of fork activation block. - """ SYSTEM_CONTRACT_CALL_FAILED = auto() """ - - A system contract call at the end of block execution (from the system address) fails. - """ INVALID_BLOCK_HASH = auto() """ - - Block header's hash does not match the actually computed hash of the block. - """ INVALID_DEPOSIT_EVENT_LAYOUT = auto() """ - - Transaction emits a `DepositEvent` in the deposit contract (EIP-6110), but the layout of the event does not match the required layout. - """ # --- Block-Level Access Lists (EIP-7928) --- # INVALID_BLOCK_ACCESS_LIST = auto() @@ -245,16 +179,10 @@ class BlockException(ExceptionBase): """Block header's BAL hash does not match the computed BAL hash.""" INVALID_BAL_EXTRA_ACCOUNT = auto() """ - - Block BAL contains an account change that is not present in the computed BAL. - """ INVALID_BAL_MISSING_ACCOUNT = auto() """ - - Block BAL is missing an account change that is present in the computed BAL. - """ diff --git a/src/ethereum_test_exceptions/exceptions/eof.py b/src/ethereum_test_exceptions/exceptions/eof.py index d17eb033ef3..0e9c0c5f6c6 100644 --- a/src/ethereum_test_exceptions/exceptions/eof.py +++ b/src/ethereum_test_exceptions/exceptions/eof.py @@ -84,27 +84,18 @@ class EOFException(ExceptionBase): """EOF container's specified max stack increase is above the limit.""" STACK_HIGHER_THAN_OUTPUTS = auto() """ - - EOF container section stack height is higher than the outputs. when returning - """ JUMPF_DESTINATION_INCOMPATIBLE_OUTPUTS = auto() """ - - EOF container section JUMPF's to a destination section with incompatible outputs. - """ INVALID_MAX_STACK_INCREASE = auto() """ - - EOF container section's specified max stack increase does not match the actual stack height. - """ INVALID_DATALOADN_INDEX = auto() """A DATALOADN instruction has out-of-bounds index for the data section.""" diff --git a/src/ethereum_test_exceptions/exceptions/transaction.py b/src/ethereum_test_exceptions/exceptions/transaction.py index 3adbb17fb95..ee67b0d55ef 100644 --- a/src/ethereum_test_exceptions/exceptions/transaction.py +++ b/src/ethereum_test_exceptions/exceptions/transaction.py @@ -29,19 +29,13 @@ class TransactionException(ExceptionBase): """Transaction nonce < sender.nonce.""" NONCE_TOO_BIG = auto() """ - - Transaction `nonce` is not allowed to be max_uint64 - 1 (this is probably TransactionTest). - """ NONCE_IS_MAX = auto() """ - - Transaction `nonce` is not allowed to be max_uint64 - 1 (this is StateTests). - """ NONCE_OVERFLOW = auto() """Transaction `nonce` is not allowed to be more than uint64.""" @@ -79,35 +73,23 @@ class TransactionException(ExceptionBase): """Error reading transaction priority fee field RLP.""" RLP_LEADING_ZEROS_DATA_SIZE = auto() """ - - Error reading transaction data field RLP, (rlp field length has leading zeros). - """ RLP_LEADING_ZEROS_NONCE_SIZE = auto() """ - - Error reading transaction nonce field RLP, (rlp field length has leading zeros). - """ RLP_TOO_FEW_ELEMENTS = auto() """ - - Error reading transaction RLP, structure has too few elements than expected. - """ RLP_TOO_MANY_ELEMENTS = auto() """ - - Error reading transaction RLP, structure has too many elements than expected. - """ RLP_ERROR_EOF = auto() """Error reading transaction RLP, rlp stream unexpectedly finished.""" @@ -141,42 +123,27 @@ class TransactionException(ExceptionBase): """Transaction has correct signature, but ec recovery failed.""" INSUFFICIENT_ACCOUNT_FUNDS = auto() """ - - Transaction's sender does not have enough funds to pay for the transaction. - """ INSUFFICIENT_MAX_FEE_PER_GAS = auto() """Transaction's max-fee-per-gas is lower than the block base-fee.""" PRIORITY_OVERFLOW = auto() """ - - Transaction's max-priority-fee-per-gas is exceeds 2^256-1 maximum value. - """ PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS = auto() """ - - Transaction's max-priority-fee-per-gas is greater than the max-fee-per-gas. - """ PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS_2 = auto() """ - - Transaction's max-priority-fee-per-gas is greater than the max-fee-per-gas (TransactionTests). - """ INSUFFICIENT_MAX_FEE_PER_BLOB_GAS = auto() """ - - Transaction's max-fee-per-blob-gas is lower than the block's blob-gas price. - """ INTRINSIC_GAS_TOO_LOW = auto() """Transaction's gas limit is too low.""" @@ -184,10 +151,7 @@ class TransactionException(ExceptionBase): """Transaction's gas limit is below the floor gas cost.""" INITCODE_SIZE_EXCEEDED = auto() """ - - Transaction's initcode for a contract-creating transaction is too large. - """ TYPE_3_TX_PRE_FORK = auto() """Transaction type 3 included before activation fork.""" @@ -207,10 +171,7 @@ class TransactionException(ExceptionBase): """Transaction causes block to go over blob gas limit.""" GAS_LIMIT_EXCEEDS_MAXIMUM = auto() """ - - Transaction gas limit exceeds the maximum allowed limit of 30 million. - """ TYPE_3_TX_ZERO_BLOBS = auto() """Transaction is type 3, but has no blobs.""" @@ -224,11 +185,8 @@ class TransactionException(ExceptionBase): """Transaction is a type 4 transaction and has an empty `to`.""" TYPE_4_INVALID_AUTHORIZATION_FORMAT = auto() """ - - Transaction is type 4, but contains an authorization that has an invalid format. - """ TYPE_4_TX_PRE_FORK = auto() """Transaction type 4 included before activation fork.""" diff --git a/src/ethereum_test_fixtures/blockchain.py b/src/ethereum_test_fixtures/blockchain.py index e2983cdb1a0..b5ef43cb400 100644 --- a/src/ethereum_test_fixtures/blockchain.py +++ b/src/ethereum_test_fixtures/blockchain.py @@ -476,8 +476,9 @@ def with_rlp(self, txs: List[Transaction]) -> "FixtureBlock": block = [ self.header.rlp_encode_list, [tx.serializable_list for tx in txs], - self.ommers, # TODO: This is incorrect, and we probably need to - # serialize the ommers + # TODO: This is incorrect, and we probably + # need to serialize the ommers + self.ommers, ] if self.withdrawals is not None: @@ -529,8 +530,8 @@ class BlockchainFixtureCommon(BaseFixture): pre: Alloc post_state: Alloc | None = Field(None) post_state_hash: Hash | None = Field(None) - last_block_hash: Hash = Field(..., alias="lastblockhash") # FIXME: - # lastBlockHash + # FIXME: lastBlockHash + last_block_hash: Hash = Field(..., alias="lastblockhash") config: FixtureConfig @model_validator(mode="before") @@ -577,8 +578,8 @@ class BlockchainEngineFixtureCommon(BaseFixture): fork: Fork = Field(..., alias="network") post_state_hash: Hash | None = Field(None) - last_block_hash: Hash = Field(..., alias="lastblockhash") # FIXME: - # lastBlockHash + # FIXME: lastBlockHash + last_block_hash: Hash = Field(..., alias="lastblockhash") config: FixtureConfig def get_fork(self) -> Fork | None: @@ -629,11 +630,8 @@ class BlockchainEngineXFixture(BlockchainEngineFixtureCommon): post_state_diff: Alloc | None = None """ - - State difference from genesis after test execution (efficiency optimization). - """ payloads: List[FixtureEngineNewPayload] = Field(..., alias="engineNewPayloads") @@ -644,10 +642,10 @@ class BlockchainEngineSyncFixture(BlockchainEngineFixture): """ Engine Sync specific test fixture information. - This fixture format is specifically designed for sync testing where: - The - client under test receives all payloads - A sync client attempts to sync - from the client under test - Both client types are parametrized from hive - client config + This fixture format is specifically designed for sync testing where: + - The client under test receives all payloads + - A sync client attempts to sync from the client under test + - Both client types are parametrized from hive client config """ format_name: ClassVar[str] = "blockchain_test_sync" diff --git a/src/ethereum_test_fixtures/collector.py b/src/ethereum_test_fixtures/collector.py index fcf5ae0b2f6..10606bfefc1 100644 --- a/src/ethereum_test_fixtures/collector.py +++ b/src/ethereum_test_fixtures/collector.py @@ -142,9 +142,8 @@ def add_fixture(self, info: TestInfo, fixture: BaseFixture) -> Path: / fixture.output_base_dir_name() / fixture_basename.with_suffix(fixture.output_file_extension) ) - if fixture_path not in self.all_fixtures.keys(): # relevant when we - # group by test - # function + # relevant when we group by test function + if fixture_path not in self.all_fixtures.keys(): self.all_fixtures[fixture_path] = Fixtures(root={}) self.json_path_to_test_item[fixture_path] = info diff --git a/src/ethereum_test_fixtures/consume.py b/src/ethereum_test_fixtures/consume.py index d850b5614f3..fa3e6c99dbf 100644 --- a/src/ethereum_test_fixtures/consume.py +++ b/src/ethereum_test_fixtures/consume.py @@ -71,20 +71,11 @@ class TestCaseIndexFile(TestCaseBase): # TODO: add pytest marks """ - - - - - - ConsumerTypes = Literal["all", "direct", "rlp", "engine"] @classmethod def _marks_default(cls): return {consumer_type: [] for consumer_type in get_args(ConsumerTypes)} marks: Mapping[ConsumerTypes, List[pytest.MarkDecorator]] = field( default_factory=lambda: TestCase._marks_default() ) - - - """ diff --git a/src/ethereum_test_fixtures/pre_alloc_groups.py b/src/ethereum_test_fixtures/pre_alloc_groups.py index 378f04e69f4..25173760d08 100644 --- a/src/ethereum_test_fixtures/pre_alloc_groups.py +++ b/src/ethereum_test_fixtures/pre_alloc_groups.py @@ -22,8 +22,8 @@ class PreAllocGroup(CamelModel): pre-allocation group optimization. """ - model_config = {"populate_by_name": True} # Allow both field names and - # aliases + # Allow both field names and aliases + model_config = {"populate_by_name": True} test_ids: List[str] = Field(default_factory=list) environment: Environment = Field(..., description="Grouping environment for this test group") diff --git a/src/ethereum_test_fixtures/tests/test_blockchain.py b/src/ethereum_test_fixtures/tests/test_blockchain.py index 5fcb8274dab..944f2ece29d 100644 --- a/src/ethereum_test_fixtures/tests/test_blockchain.py +++ b/src/ethereum_test_fixtures/tests/test_blockchain.py @@ -532,9 +532,8 @@ ), pytest.param( False, # Can not be deserialized: A single expect_exception str - # will not be - # deserialized as a list and therefore will not match the - # model_instance definition. + # will not be deserialized as a list and therefore will not + # match the model_instance definition. InvalidFixtureBlock( rlp="0x00", expect_exception=[TransactionException.INTRINSIC_GAS_TOO_LOW], diff --git a/src/ethereum_test_fixtures/tests/test_state.py b/src/ethereum_test_fixtures/tests/test_state.py index e7d5b299946..b1881065b20 100644 --- a/src/ethereum_test_fixtures/tests/test_state.py +++ b/src/ethereum_test_fixtures/tests/test_state.py @@ -51,9 +51,8 @@ ), pytest.param( False, # Can not be deserialized: A single expect_exception str - # will not be - # deserialized as a list and therefore will not match the - # model_instance definition. + # will not be deserialized as a list and therefore will not + # match the model_instance definition. FixtureForkPost( state_root=0, logs_hash=1, diff --git a/src/ethereum_test_forks/base_fork.py b/src/ethereum_test_forks/base_fork.py index 750a2c9d694..69af59800d5 100644 --- a/src/ethereum_test_forks/base_fork.py +++ b/src/ethereum_test_forks/base_fork.py @@ -114,16 +114,24 @@ def __call__( """ Return the intrinsic gas cost of a transaction given its properties. - Args: calldata: The data of the transaction. contract_creation: Whether - the transaction creates a contract. access_list: The list of access - lists for the transaction. authorization_list_or_count: The list of - authorizations or the count of authorizations for the transaction. - return_cost_deducted_prior_execution: If set to False, the returned - value is equal to the minimum gas required for the transaction to be - valid. If set to True, the returned value is equal to the cost that is - deducted from the gas limit before the transaction starts execution. + Args: + calldata: The data of the transaction. + contract_creation: Whether the transaction creates a contract. + access_list: The list of access lists for the transaction. + authorization_list_or_count: The list of authorizations or the count + of authorizations for the transaction. + return_cost_deducted_prior_execution: If set to False, the returned + value is equal to the minimum + gas required for the + transaction to be valid. If + set to True, the returned + value is equal to the cost + that is deducted from the gas + limit before the transaction + starts execution. Returns: Gas cost of a transaction + """ pass diff --git a/src/ethereum_test_forks/forks/forks.py b/src/ethereum_test_forks/forks/forks.py index 83ae639747a..3287a1ec1bd 100644 --- a/src/ethereum_test_forks/forks/forks.py +++ b/src/ethereum_test_forks/forks/forks.py @@ -477,12 +477,8 @@ def max_code_size(cls) -> int: """ At genesis, there is no upper bound for code size (bounded by block gas limit). - """ - """ - However, the default is set to the limit of EIP-170 (Spurious Dragon) - """ return 0x6000 @@ -1001,18 +997,26 @@ def base_fee_per_gas_calculator( EIP-1559 block validation pseudo code: - if INITIAL_FORK_BLOCK_NUMBER == block.number: expected_base_fee_per_gas - = INITIAL_BASE_FEE elif parent_gas_used == parent_gas_target: - expected_base_fee_per_gas = parent_base_fee_per_gas elif - parent_gas_used > parent_gas_target: gas_used_delta = parent_gas_used - - parent_gas_target base_fee_per_gas_delta = max( parent_base_fee_per_gas - * gas_used_delta // parent_gas_target // - BASE_FEE_MAX_CHANGE_DENOMINATOR, 1, ) expected_base_fee_per_gas = - parent_base_fee_per_gas + base_fee_per_gas_delta else: gas_used_delta = - parent_gas_target - parent_gas_used base_fee_per_gas_delta = ( - parent_base_fee_per_gas * gas_used_delta // parent_gas_target // - BASE_FEE_MAX_CHANGE_DENOMINATOR ) expected_base_fee_per_gas = - parent_base_fee_per_gas - base_fee_per_gas_delta + if INITIAL_FORK_BLOCK_NUMBER == block.number: + expected_base_fee_per_gas = INITIAL_BASE_FEE + elif parent_gas_used == parent_gas_target: + expected_base_fee_per_gas = parent_base_fee_per_gas + elif parent_gas_used > parent_gas_target: + gas_used_delta = parent_gas_used - parent_gas_target + base_fee_per_gas_delta = max( parent_base_fee_per_gas + * gas_used_delta // parent_gas_target // + BASE_FEE_MAX_CHANGE_DENOMINATOR, 1, ) + expected_base_fee_per_gas = parent_base_fee_per_gas + + base_fee_per_gas_delta + else: + gas_used_delta = parent_gas_target - parent_gas_used + base_fee_per_gas_delta = ( + parent_base_fee_per_gas * gas_used_delta // + parent_gas_target // + BASE_FEE_MAX_CHANGE_DENOMINATOR + ) + expected_base_fee_per_gas = parent_base_fee_per_gas - + base_fee_per_gas_delta """ base_fee_max_change_denominator = cls.base_fee_max_change_denominator( block_number, timestamp @@ -1257,8 +1261,8 @@ def fn( parent_excess_blobs: int | None = None, parent_blob_gas_used: int | None = None, parent_blob_count: int | None = None, - parent_base_fee_per_gas: int, # Required for Osaka as using this - # as base + # Required for Osaka as using this as base + parent_base_fee_per_gas: int, ) -> int: del parent_base_fee_per_gas @@ -1436,8 +1440,12 @@ def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address] """ At Prague, pre-compile for BLS operations are added. - BLS12_G1ADD = 0x0B BLS12_G1MSM = 0x0C BLS12_G2ADD = 0x0D BLS12_G2MSM = - 0x0E BLS12_PAIRING_CHECK = 0x0F BLS12_MAP_FP_TO_G1 = 0x10 + BLS12_G1ADD = 0x0B + BLS12_G1MSM = 0x0C + BLS12_G2ADD = 0x0D + BLS12_G2MSM = 0x0E + BLS12_PAIRING_CHECK = 0x0F + BLS12_MAP_FP_TO_G1 = 0x10 BLS12_MAP_FP2_TO_G2 = 0x11 """ return [ diff --git a/src/ethereum_test_forks/helpers.py b/src/ethereum_test_forks/helpers.py index 53890b7b5a3..3b138342800 100644 --- a/src/ethereum_test_forks/helpers.py +++ b/src/ethereum_test_forks/helpers.py @@ -327,9 +327,12 @@ def validate_fork_range_descriptor(cls, v: Any, handler: ValidatorFunctionWrapHa """ Validate the fork range descriptor from a string. - Examples: - ">=Osaka" validates to {greater_equal=Osaka, - less_than=None} - ">=Prague=Osaka" validates to {greater_equal=Osaka, less_than=None} + + - ">=PragueB, when filling, and given the from/until markers, we expect the following logic: - Marker Comparison A->B Included --------- ------------ --------------- - From A fork >= A True Until A fork <= A False From B fork >= - B True Until B fork <= B True + Marker Comparison A->B Included + --------- ------------ --------------- + From A fork >= A True + Until A fork <= A False + From B fork >= B True + Until B fork <= B True """ assert BerlinToLondonAt5 >= Berlin assert not BerlinToLondonAt5 <= Berlin diff --git a/src/ethereum_test_specs/base_static.py b/src/ethereum_test_specs/base_static.py index c4c6323d84d..9f64dc1c8ff 100644 --- a/src/ethereum_test_specs/base_static.py +++ b/src/ethereum_test_specs/base_static.py @@ -50,7 +50,7 @@ def _parse_into_subclass( @abstractmethod def fill_function(self) -> Callable: - ''' + """ Return the test function that can be used to fill the test. This method should be implemented by the subclasses. @@ -59,36 +59,73 @@ def fill_function(self) -> Callable: `@pytest.mark.parametrize` decorator to parametrize the test with the number of sub test cases. - Example: ``` @pytest.mark.parametrize("n", [1]) + Example: + ``` + @pytest.mark.parametrize("n", [1]) @pytest.mark.parametrize("m", [1, 2]) - @pytest.mark.valid_from("Homestead") def test_state_filler( state_test: - StateTestFiller, fork: Fork, pre: Alloc, n: int, m: int, ): """Generate - a test from a static state filler.""" assert n == 1 assert m in [1, 2] - env = Environment(**self.env.model_dump()) sender = pre.fund_eoa() tx = - Transaction( ty=0x0, nonce=0, to=Address(0x1000), gas_limit=500000, - protected=False if fork in [Frontier, Homestead] else True, data="", - sender=sender, ) state_test(env=env, pre=pre, post={}, tx=tx) - - return test_state_filler ``` + @pytest.mark.valid_from("Homestead") + def test_state_filler( + state_test: StateTestFiller, + fork: Fork, + pre: Alloc, + n: int, + m: int + ): + assert n == 1 assert m in [1, 2] + env = Environment(**self.env.model_dump()) + sender = pre.fund_eoa() + tx = Transaction( + ty=0x0, + nonce=0, + to=Address(0x1000), + gas_limit=500000, + protected=False if fork in [Frontier, Homestead] else True, + data="", + sender=sender, + ) + state_test(env=env, pre=pre, post={}, tx=tx) + ``` To aid the generation of the test, the function can be defined and then the decorator be applied after defining the function: - ``` def test_state_filler( state_test: StateTestFiller, fork: Fork, - pre: Alloc, n: int, m: int, ): ... test_state_filler = - pytest.mark.parametrize("n", [1])(test_state_filler) test_state_filler - = pytest.mark.parametrize("m", [1, 2])(test_state_filler) if - self.valid_from: test_state_filler = - pytest.mark.valid_from(self.valid_from)(test_state_filler) if - self.valid_until: test_state_filler = - pytest.mark.valid_until(self.valid_until)(test_state_filler) return - test_state_filler ``` + ``` + def test_state_filler( + state_test: StateTestFiller, + fork: Fork, + pre: Alloc, + n: int, + m: int, + ): + + ... + + test_state_filler = pytest.mark.parametrize("n", + [1])(test_state_filler + ) + test_state_filler = pytest.mark.parametrize("m", + [1, 2])(test_state_filler + ) + + if self.valid_from: + test_state_filler = pytest.mark.valid_from( + self.valid_from + )(test_state_filler) + + if self.valid_until: + test_state_filler = pytest.mark.valid_until( + self.valid_until + )(test_state_filler) + + return test_state_filler + ``` The function can contain the following parameters on top of the spec type parameter (`state_test` in the example above): - `fork`: The fork for which the test is currently being filled. - `pre`: The pre-state of the test. - ''' + + """ raise NotImplementedError @staticmethod diff --git a/src/ethereum_test_specs/blockchain.py b/src/ethereum_test_specs/blockchain.py index 29f662f6a60..6669ab2f274 100644 --- a/src/ethereum_test_specs/blockchain.py +++ b/src/ethereum_test_specs/blockchain.py @@ -126,25 +126,10 @@ class Header(CamelModel): REMOVE_FIELD: ClassVar[Removable] = Removable() """ - - - - - - Sentinel object used to specify that a header field should be removed. - - - """ EMPTY_FIELD: ClassVar[Removable] = Removable() """ - - - - - - Sentinel object used to specify that a header field must be empty during verification. @@ -154,9 +139,6 @@ class Header(CamelModel): ) block = Block( timestamp=TIMESTAMP, rlp_modifier=header_modifier, exception=BlockException.INCORRECT_BLOCK_FORMAT, engine_api_error_code=EngineAPIError.InvalidParams, ) ``` - - - """ model_config = ConfigDict( @@ -215,76 +197,29 @@ class Block(Header): """Block type used to describe block properties in test specs.""" header_verify: Header | None = None - """ - - - - - - - If set, the block header will be verified against the specified values. - - - - """ + # If set, the block header will be verified against the specified values. rlp_modifier: Header | None = None """ - - - - - - An RLP modifying header which values would be used to override the ones returned by the `ethereum_clis.TransitionTool`. - - - """ expected_block_access_list: BlockAccessListExpectation | None = None """ - - - - - - If set, the block access list will be verified and potentially corrupted for invalid tests. - - - """ exception: BLOCK_EXCEPTION_TYPE = None - """If set, the block is expected to be rejected by the client.""" + # If set, the block is expected to be rejected by the client. skip_exception_verification: bool = False """ - - - - - - Skip verifying that the exception is returned by the transition tool. This could be because the exception is inserted in the block after the transition tool evaluates it. - - - """ engine_api_error_code: EngineAPIError | None = None """ - - - - - - If set, the block is expected to produce an error response from the Engine API. - - - """ txs: List[Transaction] = Field(default_factory=list) """List of transactions included in the block.""" @@ -307,17 +242,8 @@ def set_environment(self, env: Environment) -> Environment: new_env_values: Dict[str, Any] = {} """ - - - - - - Values that need to be set in the environment and are `None` for this block need to be set to their defaults. - - - """ new_env_values["difficulty"] = self.difficulty new_env_values["prev_randao"] = self.prev_randao @@ -345,17 +271,8 @@ def set_environment(self, env: Environment) -> Environment: ): new_env_values["block_access_list"] = self.block_access_list """ - - - - - - These values are required, but they depend on the previous environment, so they can be calculated here. - - - """ if self.number is not None: new_env_values["number"] = self.number @@ -477,12 +394,6 @@ def verify_block_exception(self, transition_tool_exceptions_reliable: bool): "prev_randao": 0, } """ - - - - - - Default values for the genesis environment that are used to create all genesis headers. """ @@ -498,17 +409,8 @@ class BlockchainTest(BaseTest): chain_id: int = 1 exclude_full_post_state_in_output: bool = False """ - - - - - - Exclude the post state from the fixture output. In this case, the state verification is only performed based on the state root. - - - """ supported_fixture_formats: ClassVar[Sequence[FixtureFormat | LabeledFixtureFormat]] = [ diff --git a/src/ethereum_test_specs/eof.py b/src/ethereum_test_specs/eof.py index 44d3cd29f75..d64a98cde1d 100644 --- a/src/ethereum_test_specs/eof.py +++ b/src/ethereum_test_specs/eof.py @@ -183,12 +183,6 @@ class EOFTest(BaseTest): container: Container """ - - - - - - EOF container that will be tested for validity. The only supported type at the moment is @@ -197,18 +191,9 @@ class EOFTest(BaseTest): If an invalid container needs to be tested, and it cannot be generated using the Container class features, the `raw_bytes` field can be used to provide the raw container bytes. - - - """ expect_exception: EOFExceptionInstanceOrList | None = None """ - - - - - - Expected exception that the container should raise when parsed by an EOF parser. @@ -218,18 +203,9 @@ class EOFTest(BaseTest): The list of supported exceptions can be found in the `ethereum_test_exceptions.EOFException` class. - - - """ container_kind: ContainerKind = ContainerKind.RUNTIME """ - - - - - - Container kind type that the container should be treated as. The container kind can be one of the following: - `ContainerKind.INITCODE`: @@ -237,18 +213,9 @@ class EOFTest(BaseTest): container is a runtime container. The default value is `ContainerKind.RUNTIME`. - - - """ deployed_container: Container | None = None """ - - - - - - To be used when the container is an initcode container and the expected deployed container is known. @@ -274,57 +241,27 @@ class EOFTest(BaseTest): The deployed container is **not** executed at any point during the EOF validation test nor the generated State Test. For container runtime testing use the `EOFStateTest` class. - - - """ pre: Alloc | None = None """ - - - - - - Pre alloc object that is used during State Test generation. This field is automatically set by the test filler when generating a State Test from this EOF test and should otherwise be left unset. - - - """ post: Alloc | None = None """ - - - - - - Post alloc object that is used during State Test generation. This field is automatically set by the test filler when generating a State Test from this EOF test and is normally not set by the user. - - - """ sender: EOA | None = None """ - - - - - - Sender EOA object that is used during State Test generation. This field is automatically set by the `model_post_init` method and should otherwise be left unset. - - - """ supported_fixture_formats: ClassVar[Sequence[FixtureFormat | LabeledFixtureFormat]] = [ diff --git a/src/ethereum_test_specs/state.py b/src/ethereum_test_specs/state.py index 0d073347472..24b0cb08169 100644 --- a/src/ethereum_test_specs/state.py +++ b/src/ethereum_test_specs/state.py @@ -195,12 +195,14 @@ def _generate_blockchain_genesis_environment(self, *, fork: Fork) -> Environment "genesis timestamp cannot be negative, set state test env.timestamp to at least 1" ) # There's only a handful of values that we need to set in the genesis - # for the environment values at block 1 to make sense: - Number: Needs - # to be N minus 1 - Timestamp: Needs to be zero, because the subsequent - # block can come at any time. - Gas Limit: Changes from parent to - # child, needs to be set in genesis - Base Fee Per Gas: Block's base - # fee depends on the parent's value - Excess Blob Gas: Block's excess - # blob gas value depends on the parent's value + # for the environment values at block 1 to make sense: + # - Number: Needs to be N minus 1 + # - Timestamp: Needs to be zero, because the subsequent + # block can come at any time. + # - Gas Limit: Changes from parent to child, needs to be set in genesis + # - Base Fee Per Gas: Block's base fee depends on the parent's value + # - Excess Blob Gas: Block's excess blob gas value depends on + # the parent's value kwargs: Dict[str, Any] = { "number": self.env.number - 1, "timestamp": 0, diff --git a/src/ethereum_test_specs/static_state/common/common.py b/src/ethereum_test_specs/static_state/common/common.py index 3d706cf14e8..d10e6f254ed 100644 --- a/src/ethereum_test_specs/static_state/common/common.py +++ b/src/ethereum_test_specs/static_state/common/common.py @@ -194,13 +194,11 @@ def replace_tags(raw_code, keep_prefix: bool) -> str: [parameter_str], [ [ - int(t.lower(), 0) & ((1 << 256) - 1) # treat - # big - # ints as - # 256bits + # treat big ints as 256bits + int(t.lower(), 0) & ((1 << 256) - 1) if parameter_types[t_index] == "uint" - else int(t.lower(), 0) > 0 # treat positive - # values as True + # treat positive values as True + else int(t.lower(), 0) > 0 if parameter_types[t_index] == "bool" else False and ValueError("unhandled parameter_types") for t_index, t in enumerate(tokens[1:]) @@ -226,9 +224,16 @@ def replace_tags(raw_code, keep_prefix: bool) -> str: # - using docker: If the running machine does not have lllc # installed, we can use docker to run lllc, but we need to # start a container first, and the process is generally slower. - # from .docker import get_lllc_container_id result = - # subprocess.run( ["docker", "exec", get_lllc_container_id(), - # "lllc", tmp_path[5:]], capture_output=True, text=True, ) + # + # from .docker import get_lllc_container_id + # result = subprocess.run( ["docker", + # "exec", + # get_lllc_container_id(), + # "lllc", + # tmp_path[5:]], + # capture_output=True, + # text=True + # ) compiled_code = "".join(result.stdout.splitlines()) else: @@ -246,15 +251,17 @@ def tag_dependencies(self) -> Mapping[str, Tag]: class AddressTag: """ - Represents an address tag like: - . - - . - . + Represents an address tag like: + - . + - . + - . """ def __init__(self, tag_type: str, tag_name: str, original_string: str): """Initialize address tag.""" self.tag_type = tag_type # "eoa", "contract", or "coinbase" - self.tag_name = tag_name # e.g., "sender", "target", or address for - # 2-part tags + # e.g., "sender", "target", or address for 2-part tags + self.tag_name = tag_name self.original_string = original_string def __str__(self) -> str: diff --git a/src/ethereum_test_specs/static_state/common/compile_yul.py b/src/ethereum_test_specs/static_state/common/compile_yul.py index c4b6ec41854..632d0cd31ad 100644 --- a/src/ethereum_test_specs/static_state/common/compile_yul.py +++ b/src/ethereum_test_specs/static_state/common/compile_yul.py @@ -54,14 +54,18 @@ def compile_yul(source_file: str, evm_version: str | None = None, optimize: str Compiles a Yul source file using solc and returns the binary representation. - Parameters_: source_file (str): Path to the Yul source file. evm_version - (str, optional): The EVM version to use (e.g., 'istanbul'). Defaults to - None. optimize (any, optional): If provided (non-None), optimization flags - are not added. If None, additional optimization flags will be included. + Arguments: + source_file (str): Path to the Yul source file. + evm_version(str, optional): The EVM version to use (e.g., 'istanbul'). + Defaults to None. + optimize (any, optional): If provided (non-None), optimization flags + are not added. If None, additional + optimization flags will be included. - Returns_: str: The binary representation prefixed with "0x". + Returns: str: The binary representation prefixed with "0x". + + Raises: Exception: If the solc output contains an error message. - Raises_: Exception: If the solc output contains an error message. """ cmd = safe_solc_command(source_file, evm_version, optimize) diff --git a/src/ethereum_test_specs/static_state/common/tags.py b/src/ethereum_test_specs/static_state/common/tags.py index 9d7e11f9972..100ae06107c 100644 --- a/src/ethereum_test_specs/static_state/common/tags.py +++ b/src/ethereum_test_specs/static_state/common/tags.py @@ -20,8 +20,8 @@ class Tag(BaseModel, Generic[T]): name: str type: ClassVar[str] = "" regex_pattern: ClassVar[re.Pattern] = re.compile(r"<\w+:(\w+)(:[^>]+)?") - original_string: str | None = None # Store the original tag string for - # replacement + # Store the original tag string for replacement + original_string: str | None = None def __hash__(self) -> int: """Hash based on original string for use as dict key.""" @@ -65,14 +65,16 @@ class ContractTag(AddressTag): type: ClassVar[str] = "contract" regex_pattern: ClassVar[re.Pattern] = re.compile(r"]+)(?::(0x[a-fA-F0-9]+))?>") - debug_address: Address | None = None # Optional hard-coded address for - # debugging + # Optional hard-coded address for debugging + debug_address: Address | None = None @model_validator(mode="before") @classmethod def validate_from_string(cls, data: Any) -> Any: """ - Validate the contract tag from string: or + Validate the contract tag from string: + + or . """ if isinstance(data, str): @@ -152,8 +154,8 @@ class SenderTag(AddressTag): type: ClassVar[str] = "eoa" regex_pattern: ClassVar[re.Pattern] = re.compile(r"") - debug_address: Address | None = None # Optional hard-coded address for - # debugging + # Optional hard-coded address for debugging + debug_address: Address | None = None @model_validator(mode="before") @classmethod diff --git a/src/ethereum_test_tools/tools_code/generators.py b/src/ethereum_test_tools/tools_code/generators.py index 7b2baa03f81..350eb9b0f3b 100644 --- a/src/ethereum_test_tools/tools_code/generators.py +++ b/src/ethereum_test_tools/tools_code/generators.py @@ -304,11 +304,15 @@ class Switch(Bytecode): """ Helper class used to generate switch-case expressions in EVM bytecode. - Switch-case behavior: - If no condition is met in the list of BytecodeCases - conditions, the `default_action` bytecode is executed. - If multiple - conditions are met, the action from the first valid condition is the only - one executed. - There is no fall through; it is not possible to execute - multiple actions. + Switch-case behavior: + - If no condition is met in the list of BytecodeCases + conditions, the `default_action` bytecode is executed. + + - If multiple conditions are met, the action from the first valid + condition is the only one executed. + + - There is no fall through; it is not possible to execute + multiple actions. """ default_action: Bytecode | Op | None @@ -341,10 +345,12 @@ def __new__( switch-case behavior. """ # The length required to jump over subsequent actions to the final - # JUMPDEST at the end of the switch-case block: - add 6 per case for - # the length of the JUMPDEST and JUMP(ADD(PC, action_jump_length)) - # bytecode - add 3 to the total to account for this action's JUMP; the - # PC within the call requires a "correction" of 3. + # JUMPDEST at the end of the switch-case block: + # - add 6 per case for the length of the JUMPDEST and + # JUMP(ADD(PC, action_jump_length)) bytecode + # + # - add 3 to the total to account for this action's JUMP; + # the PC within the call requires a "correction" of 3. bytecode = Bytecode() @@ -372,14 +378,19 @@ def __new__( # outer-most onion layer. We build up layers around the default_action, # after 1 iteration of the loop, a simplified representation of the # bytecode is: - # JUMPI(case[n-1].condition) + default_action + JUMP() + JUMPDEST + - # case[n-1].action + JUMP() + # + # JUMPI(case[n-1].condition) + # + default_action + JUMP() + # + JUMPDEST + case[n-1].action + JUMP() + # # and after n=len(cases) iterations: - # JUMPI(case[0].condition) + JUMPI(case[1].condition) ... + - # JUMPI(case[n-1].condition) + default_action + JUMP() + JUMPDEST + + # + # JUMPI(case[0].condition) + # + JUMPI(case[1].condition) + # ... + # + JUMPI(case[n-1].condition) + default_action + JUMP() + JUMPDEST + # case[n-1].action + JUMP() + ... + JUMPDEST + case[1].action + JUMP() # + JUMPDEST + case[0].action + JUMP() - # for case in reversed(cases): action = case.action if evm_code_type == EVMCodeType.LEGACY: diff --git a/src/ethereum_test_tools/utility/generators.py b/src/ethereum_test_tools/utility/generators.py index 142898466bc..f155cb3ba41 100644 --- a/src/ethereum_test_tools/utility/generators.py +++ b/src/ethereum_test_tools/utility/generators.py @@ -67,17 +67,21 @@ def __call__( test_type: DeploymentTestType, ) -> Generator[Block, None, None]: """ - Args: fork (Fork): The fork to test. pre (Alloc): The pre state of the - blockchain. post (Alloc): The post state of the blockchain. test_type - (DeploymentTestType): The type of deployment test currently being - filled. - - Yields: Block: To add after the block where the contract was deployed - (e.g. can contain extra transactions to execute after the system - contract has been deployed, and/or a header object to verify that the - headers are correct). + Arguments: + fork (Fork): The fork to test. + pre (Alloc): The pre state of the blockchain. + post (Alloc): The post state of the blockchain. + test_type(DeploymentTestType): The type of deployment test + currently being filled. + + Yields: + Block: To add after the block where the contract was deployed + (e.g. can contain extra transactions to execute after + the system contract has been deployed, and/or a header + object to verify that the headers are correct). + """ - ... + pass def generate_system_contract_deploy_test( @@ -93,28 +97,45 @@ def generate_system_contract_deploy_test( Generates following test cases: - | before/after fork | fail on | invalid block | | | - empty block | | - --------------------------------------|-------------------|-------------|------ - ---------| `deploy_before_fork-nonzero_balance` | before | - False | False | `deploy_before_fork-zero_balance` | - before | True | False | - `deploy_on_fork_block-nonzero_balance`| on fork block | False | - False | `deploy_on_fork_block-zero_balance` | on fork block | - True | False | `deploy_after_fork-nonzero_balance` | after - | False | False | `deploy_after_fork-zero_balance` | - after | True | True | + | before/after fork | fail on | invalid block | + empty block | | + --------------------|-------------------|--------------|----------------| + `deploy_before_fork-| before | False | False | + nonzero_balance` + + `deploy_before_fork-| before | True | False | + zero_balance` + + `deploy_on_fork_ | on fork block | False | False | + block-nonzero_ + balance` + + `deploy_on_fork_ | on fork block | True | False | + block-zero_balance` + + `deploy_after_fork | after | False | False | + -nonzero_balance` + + `deploy_after_fork | after | True | True | + -zero_balance` + The `has balance` parametrization does not have an effect on the expectation of the test. - Args: fork (Fork): The fork to test. tx_json_path (Path): Path to the JSON - file with the transaction to deploy the system contract. Providing a JSON - file is useful to copy-paste the transaction from the EIP. - expected_deploy_address (Address): The expected address of the deployed - contract. fail_on_empty_code (bool): If True, the test is expected to fail - on empty code. expected_system_contract_storage (Dict | None): The expected - storage of the system contract. + Arguments: + fork (Fork): The fork to test. + tx_json_path (Path): Path to the JSON file with the transaction to + deploy the system contract. Providing a JSON + file is useful to copy-paste the transaction + from the EIP. + expected_deploy_address (Address): The expected address of the deployed + contract. + fail_on_empty_code (bool): If True, the test is expected to fail + on empty code. + expected_system_contract_storage (Dict | None): The expected storage of + the system contract. + """ with open(tx_json_path, mode="r") as f: tx_json = json.loads(f.read()) @@ -271,12 +292,13 @@ def generate_system_contract_error_test( Generate a test that verifies the correct behavior when a system contract fails execution. - Parametrizations required: - system_contract (Address): The address of the - system contract to deploy. - valid_from (Fork): The fork from which the - test is valid. + Parametrizations required: + - system_contract (Address): The address of the system contract to deploy. + - valid_from (Fork): The fork from which the test is valid. + + Arguments: + max_gas_limit (int): The maximum gas limit for the system transaction. - Args: max_gas_limit (int): The maximum gas limit for the system - transaction. """ def decorator(func: SystemContractDeployTestFunction): diff --git a/src/ethereum_test_tools/utility/pytest.py b/src/ethereum_test_tools/utility/pytest.py index 241ac40dc0f..ca93f55e09b 100644 --- a/src/ethereum_test_tools/utility/pytest.py +++ b/src/ethereum_test_tools/utility/pytest.py @@ -34,50 +34,95 @@ def extend_with_defaults( The function returns a dictionary that can be directly unpacked and passed to the `@pytest.mark.parametrize` decorator. - Args: defaults (Dict[str, Any]): A dictionary of default parameter names - and their values. These values will be added to each case unless the case - already defines a value for each parameter. cases (List[ParameterSet]): A - list of `pytest.param` objects representing different test cases. Its first - argument must be a dictionary defining parameter names and values. - parametrize_kwargs (Any): Additional keyword arguments to be passed to - `@pytest.mark.parametrize`. These arguments are not modified by this - function and are passed through unchanged. - - Returns: Dict[str, Any]: A dictionary with the following structure: - `argnames`: A list of parameter names. `argvalues`: A list of test cases - with modified parameter values. `parametrize_kwargs`: Additional keyword - arguments passed through unchanged. - - - - Example: ```python @pytest.mark.parametrize(**extend_with_defaults( - defaults=dict( min_value=0, # default minimum value is 0 max_value=100, # - default maximum value is 100 average=50, # default average value is 50 ), - cases=[ pytest.param( dict(), # use default values id='default_case', ), - pytest.param( dict(min_value=10), # override with min_value=10 - id='min_value_10', ), pytest.param( dict(max_value=200), # override with - max_value=200 id='max_value_200', ), pytest.param( dict(min_value=-10, - max_value=50), # override both min_value # and max_value - id='min_-10_max_50', ), pytest.param( dict(min_value=20, max_value=80, - average=50), # all defaults # are overridden id="min_20_max_80_avg_50", ), - pytest.param( dict(min_value=100, max_value=0), # invalid range - id='invalid_range', marks=pytest.mark.xfail(reason='invalid range'), ) ], - )) def test_range(min_value, max_value, average): assert min_value <= - max_value assert min_value <= average <= max_value ``` + Arguments: + defaults (Dict[str, Any]): A dictionary of default parameter names + and their values. These values will be added + to each case unless the case already defines + a value for each parameter. + cases (List[ParameterSet]): A list of `pytest.param` objects + representing different test cases. + Its first argument must be a dictionary + defining parameter names and values. + parametrize_kwargs (Any): Additional keyword arguments to be passed to + `@pytest.mark.parametrize`. These arguments are + not modified by this function and are passed + through unchanged. + + Returns: + Dict[str, Any]: A dictionary with the following structure: + `argnames`: A list of parameter names. + `argvalues`: A list of test cases with modified parameter values. + `parametrize_kwargs`: Additional keyword arguments passed + through unchanged. + + + Example: + ```python + @pytest.mark.parametrize(**extend_with_defaults( + defaults=dict( + min_value=0, # default minimum value is 0 + max_value=100, # default maximum value is 100 + average=50, # default average value is 50 + ), + + cases=[ + pytest.param( + dict(), # use default + values id='default_case', + ), + + pytest.param( + dict(min_value=10), # override with min_value=10 + id='min_value_10', + ), + + pytest.param( + dict(max_value=200), # override with max_value=200 + id='max_value_200', + ), + + pytest.param( + dict(min_value=-10, max_value=50), # override both min_value + # and max_value + id='min_-10_max_50', + ), + + pytest.param( + # all defaults are overridden + dict(min_value=20, max_value=80, average=50), + id="min_20_max_80_avg_50", + ), + + pytest.param( + dict(min_value=100, max_value=0), # invalid range + id='invalid_range', + marks=pytest.mark.xfail(reason='invalid range'), + ) + ], + )) + def test_range(min_value, max_value, average): + assert min_value <= max_value + assert min_value <= average <= max_value + ``` The above test will execute with the following sets of parameters: - ```python "default_case": {"min_value": 0, "max_value": 100, "average": 50} + ```python + "default_case": {"min_value": 0, "max_value": 100, "average": 50} "min_value_10": {"min_value": 10, "max_value": 100, "average": 50} "max_value_200": {"min_value": 0, "max_value": 200, "average": 50} "min_-10_max_50": {"min_value": -10, "max_value": 50, "average": 50} "min_20_max_80_avg_50": {"min_value": 20, "max_value": 80, "average": 50} - "invalid_range": {"min_value": 100, "max_value": 0, "average": 50} # - expected to fail ``` + # expected to fail + "invalid_range": {"min_value": 100, "max_value": 0, "average": 50} + ``` + + Notes: + - Each case in `cases` must contain exactly one value, which is a + dictionary of parameter values. + - The function performs an in-place update of the `cases` list, so + the original `cases` list is modified. - Notes: - Each case in `cases` must contain exactly one value, which is a - dictionary of parameter values. - The function performs an in-place update - of the `cases` list, so the original `cases` list is modified. """ for i, case in enumerate(cases): if not (len(case.values) == 1 and isinstance(case.values[0], dict)): diff --git a/src/ethereum_test_tools/utility/tests/test_pytest.py b/src/ethereum_test_tools/utility/tests/test_pytest.py index edc12d05f70..0db71cd0eac 100644 --- a/src/ethereum_test_tools/utility/tests/test_pytest.py +++ b/src/ethereum_test_tools/utility/tests/test_pytest.py @@ -29,14 +29,13 @@ id="max_value_200", ), pytest.param( - {"min_value": -10, "max_value": 50}, # override both min_value - # and max_value + # override both min_value and max_value + {"min_value": -10, "max_value": 50}, id="min_-10_max_50", ), pytest.param( - {"min_value": 20, "max_value": 80, "average": 50}, # all - # defaults - # are overridden + # all defaults are overridden + {"min_value": 20, "max_value": 80, "average": 50}, id="min_20_max_80_avg_50", ), pytest.param( diff --git a/src/ethereum_test_tools/utility/versioning.py b/src/ethereum_test_tools/utility/versioning.py index d98ac31c7ef..58b91bcd1fa 100644 --- a/src/ethereum_test_tools/utility/versioning.py +++ b/src/ethereum_test_tools/utility/versioning.py @@ -10,8 +10,10 @@ def get_current_commit_hash_or_tag(repo_path=".", shorten_hash=False): Get the latest commit tag or commit hash from the repository. If a tag points to the current commit, return the tag name. If no tag - exists: - If shorten_hash is True, return the first 8 characters of the - commit hash. - Otherwise, return the full commit hash. + exists: + - If shorten_hash is True, return the first 8 characters of the + commit hash. + - Otherwise, return the full commit hash. """ try: repo = Repo(repo_path) diff --git a/src/ethereum_test_types/blob_types.py b/src/ethereum_test_types/blob_types.py index a5c82c9944f..fa2cc59610a 100644 --- a/src/ethereum_test_types/blob_types.py +++ b/src/ethereum_test_types/blob_types.py @@ -50,8 +50,8 @@ class Blob(CamelModel): data: Bytes commitment: Bytes proof: List[Bytes] | Bytes # Bytes < Osaka, List[Bytes] >= Osaka - cells: List[Bytes] | None # None (in json: null) < Osaka, List[Bytes] >= - # Osaka + # None (in json: null) < Osaka, List[Bytes] >= Osaka + cells: List[Bytes] | None versioned_hash: Hash name: str @@ -288,8 +288,8 @@ def write_to_file(self): if output_location.exists(): logger.debug(f"Blob {output_location} already exists. It will be overwritten.") - with open(output_location, "w", encoding="utf-8") as f: # overwrite - # existing + # overwrite existing + with open(output_location, "w", encoding="utf-8") as f: f.write(json_str) def verify_cell_kzg_proof_batch(self, cell_indices: list) -> bool: diff --git a/src/ethereum_test_types/eof/constants.py b/src/ethereum_test_types/eof/constants.py index b4e61705d69..c047002fa29 100644 --- a/src/ethereum_test_types/eof/constants.py +++ b/src/ethereum_test_types/eof/constants.py @@ -2,8 +2,6 @@ EOF_MAGIC = b"\xef\x00" """ - - The second byte found on every EOF formatted contract, which was chosen to avoid clashes with three contracts which were deployed on Mainnet. """ @@ -16,8 +14,6 @@ MAX_RUNTIME_STACK_HEIGHT = 1024 """ - - Maximum height of the EVM runtime operand stack. Exceeding this value during execution will result in the stack overflow exception. This value applies to both legacy EVM and EOF. diff --git a/src/ethereum_test_types/eof/v1/__init__.py b/src/ethereum_test_types/eof/v1/__init__.py index a52f32656a5..1dddb0f71c2 100644 --- a/src/ethereum_test_types/eof/v1/__init__.py +++ b/src/ethereum_test_types/eof/v1/__init__.py @@ -110,75 +110,30 @@ class Section(CopyValidateModel): data: Bytes = Bytes(b"") """ - - - - - - Data to be contained by this section. Can be SupportsBytes, another EOF container or any other abstract data. - - - """ custom_size: int = 0 """ - - - - - - Custom size value to be used in the header. If unset, the header is built with length of the data. - - - """ kind: SectionKind | int """ - - - - - - Kind of section that is represented by this object. Can be any `int` outside of the values defined by `SectionKind` for testing purposes. - - - """ force_type_listing: bool = False """ - - - - - - Forces this section to appear in the TYPE section at the beginning of the container. - - - """ code_inputs: int = 0 """Data stack items consumed by this code section (function)""" code_outputs: int = NON_RETURNING_SECTION """ - - - - - - Data stack items produced by or expected at the end of this code section (function) - - - """ max_stack_increase: int | None = None """Maximum operand stack height increase above the code section inputs.""" @@ -186,31 +141,13 @@ class Section(CopyValidateModel): """Maximum height data stack reaches during execution of code section.""" auto_max_stack_height: bool = False """ - - - - - - Whether to automatically compute the best suggestion for the max_stack_height value for this code section. - - - """ auto_code_inputs_outputs: bool = False """ - - - - - - Whether to automatically compute the best suggestion for the code_inputs, code_outputs values for this code section. - - - """ skip_header_listing: bool = False """Skip section from listing in the header""" @@ -218,30 +155,12 @@ class Section(CopyValidateModel): """Skip section from listing in the body""" skip_types_body_listing: bool = False """ - - - - - - Skip section from listing in the types body (input, output, stack) bytes - - - """ skip_types_header_listing: bool = False """ - - - - - - Skip section from listing in the types header (not calculating input, output, stack size) - - - """ @cached_property @@ -390,79 +309,34 @@ class Container(CopyValidateModel): """List of sections in the container""" magic: Bytes = Bytes(EOF_MAGIC) """ - - - - - - Custom magic value used to override the mandatory EOF value for testing purposes. - - - """ version: Bytes = Bytes(VERSION_NUMBER_BYTES) """ - - - - - - Custom version value used to override the mandatory EOF V1 value for testing purposes. - - - """ header_terminator: Bytes = Bytes(EOF_HEADER_TERMINATOR) """Bytes used to terminate the header.""" extra: Bytes = Bytes(b"") """ - - - - - - Extra data to be appended at the end of the container, which will not be considered part of any of the sections, for testing purposes. - - - """ auto_type_section: AutoSection = AutoSection.AUTO """ - - - - - - Automatically generate a `TYPE` section based on the included `CODE` kind sections. - - - """ auto_data_section: bool = True """Automatically generate a `DATA` section.""" auto_sort_sections: AutoSection = AutoSection.AUTO """ - - - - - - Automatically sort sections for the header and body: Headers: type section first, all code sections, container sections, last data section(s) Body: type section first, all code sections, data section(s), last container sections - - - """ skip_join_concurrent_sections_in_header: bool = False """Skip joining concurrent sections in the header (code and container)""" @@ -472,32 +346,14 @@ class Container(CopyValidateModel): """Kind type of the container.""" raw_bytes: Optional[Bytes] = None """ - - - - - - Optional raw bytes that represent the container. Used to have a cohesive type among all test cases, even those that do not resemble a valid EOF V1 container. - - - """ expected_bytecode: Optional[Bytes] = None """ - - - - - - Optional raw bytes of the expected constructed bytecode. This allows confirming that raw EOF and Container() representations are identical. - - - """ @cached_property diff --git a/src/ethereum_test_types/request_types.py b/src/ethereum_test_types/request_types.py index 298055cddbc..d38fd62b5ee 100644 --- a/src/ethereum_test_types/request_types.py +++ b/src/ethereum_test_types/request_types.py @@ -37,11 +37,8 @@ class DepositRequest(RequestBase, CamelModel): """The amount in gwei of the deposit.""" signature: BLSSignature """ - - The signature of the deposit using the validator's private key that matches the `pubkey`. - """ index: HexNumber """The index of the deposit.""" @@ -64,19 +61,13 @@ class WithdrawalRequest(RequestBase, CamelModel): source_address: Address = Address(0) """ - - The address of the execution layer account that made the withdrawal request. - """ validator_pubkey: BLSPublicKey """ - - The current public key of the validator as it currently is in the beacon state. - """ amount: HexNumber """The amount in gwei to be withdrawn on the beacon chain.""" @@ -97,27 +88,18 @@ class ConsolidationRequest(RequestBase, CamelModel): source_address: Address = Address(0) """ - - The address of the execution layer account that made the consolidation request. - """ source_pubkey: BLSPublicKey """ - - The public key of the source validator as it currently is in the beacon state. - """ target_pubkey: BLSPublicKey """ - - The public key of the target validator as it currently is in the beacon state. - """ type: ClassVar[int] = 2 diff --git a/src/ethereum_test_types/tests/test_blob_types.py b/src/ethereum_test_types/tests/test_blob_types.py index 26448b80ecb..88cf1501f53 100644 --- a/src/ethereum_test_types/tests/test_blob_types.py +++ b/src/ethereum_test_types/tests/test_blob_types.py @@ -62,8 +62,6 @@ def wait_until_counter_reached(target: int, poll_interval: float = 0.1): try: current_value = int(file_path.read_text().strip()) if current_value == target: - # file_path.unlink() # get rid to effectively reset - # counter to 0 return current_value elif current_value > target: pytest.fail( @@ -158,8 +156,8 @@ def test_transition_fork_blobs( print(f"Original fork: {fork}, Timestamp: {timestamp}") pre_transition_fork = fork.transitions_from() - post_transition_fork_at_15k = fork.transitions_to() # only reached if - # timestamp >= 15000 + # only reached if timestamp >= 15000 + post_transition_fork_at_15k = fork.transitions_to() if not pre_transition_fork.supports_blobs() and timestamp < 15000: print( diff --git a/src/ethereum_test_types/transaction_types.py b/src/ethereum_test_types/transaction_types.py index 4d798801248..ce1117635e0 100644 --- a/src/ethereum_test_types/transaction_types.py +++ b/src/ethereum_test_types/transaction_types.py @@ -705,11 +705,10 @@ class NetworkWrappedTransaction(CamelModel, RLPSerializable): Network wrapped transaction as defined in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#networking). - < Osaka: rlp([tx_payload_body, blobs, commitments, - proofs]) + < Osaka: rlp([tx_payload_body, blobs, commitments, proofs]) >= Osaka: rlp([tx_payload_body, wrapper_version, blobs, commitments, - cell_proofs]) + cell_proofs]) """ tx: Transaction diff --git a/src/ethereum_test_types/trie.py b/src/ethereum_test_types/trie.py index 171f3daff38..261424d102c 100644 --- a/src/ethereum_test_types/trie.py +++ b/src/ethereum_test_types/trie.py @@ -240,16 +240,10 @@ def nibble_list_to_compact(x: Bytes, is_leaf: bool) -> Bytes: Highest nibble:: - +---+---+----------+--------+ | _ | _ | is_leaf | parity | - +---+---+----------+--------+ 3 2 1 0 - - - - - - - - + +---+---+----------+--------+ + | _ | _ | is_leaf | parity | + +---+---+----------+--------+ + 3 2 1 0 The lowest bit of the nibble encodes the parity of the length of the remaining nibbles -- `0` when even and `1` when odd. The second lowest bit diff --git a/src/ethereum_test_vm/bytecode.py b/src/ethereum_test_vm/bytecode.py index a0298f01df0..6e60c83b799 100644 --- a/src/ethereum_test_vm/bytecode.py +++ b/src/ethereum_test_vm/bytecode.py @@ -20,11 +20,13 @@ class Bytecode: between two bytecode objects. The stack height is not guaranteed to be correct, so the user must take this into consideration. - Parameters ---------- - popped_stack_items: number of items the bytecode - pops from the stack - pushed_stack_items: number of items the bytecode - pushes to the stack - min_stack_height: minimum stack height required by - the bytecode - max_stack_height: maximum stack height reached by the - bytecode + Parameters + ---------- + - popped_stack_items: number of items the bytecode pops from the stack + - pushed_stack_items: number of items the bytecode pushes to the stack + - min_stack_height: minimum stack height required by the bytecode + - max_stack_height: maximum stack height reached by the bytecode + """ _name_: str = "" @@ -110,8 +112,10 @@ def __eq__(self, other): """ Allow comparison between Bytecode instances and bytes objects. - Raises: - NotImplementedError: if the comparison is not between an - Bytecode or a bytes object. + Raises: + - NotImplementedError: if the comparison is not between an + Bytecode or a bytes object. + """ if isinstance(other, Bytecode): return ( @@ -162,8 +166,8 @@ def __add__(self, other: "Bytecode | bytes | int | None") -> "Bytecode": # instruction or bytecode to be popped off the stack before it starts # returning (pushing). - # Auxiliary variables representing "stages" of the execution of `c = a - # + b` bytecode: Assume starting point 0 as reference: + # Auxiliary variables representing "stages" of the execution of + # `c = a + b` bytecode: Assume starting point 0 as reference: a_start = 0 # A (potentially) pops some elements and reaches its "bottom", might be # negative: diff --git a/src/ethereum_test_vm/opcodes.py b/src/ethereum_test_vm/opcodes.py index 126344abc2e..aceeb6fd6ba 100644 --- a/src/ethereum_test_vm/opcodes.py +++ b/src/ethereum_test_vm/opcodes.py @@ -3,9 +3,9 @@ Acknowledgments: The individual opcode documentation below is due to the work by [smlXL](https://github.com/smlxl) on [evm.codes](https://www.evm.codes/), -available as open source -[github.com/smlxl/evm.codes](https://github.com/smlxl/evm.codes) - thank you! -And thanks to @ThreeHrSleep for integrating it in the docstrings. +available as open source [github.com/smlxl/ +evm.codes](https://github.com/smlxl/evm.codes) - thank you! And thanks +to @ThreeHrSleep for integrating it in the docstrings. """ from enum import Enum @@ -19,8 +19,8 @@ def _get_int_size(n: int) -> int: """Return size of an integer in bytes.""" if n < 0: - # Negative numbers in the EVM are represented as two's complement of 32 - # bytes + # Negative numbers in the EVM are represented as two's complement + # of 32 bytes return 32 byte_count = 0 while n: @@ -47,8 +47,8 @@ def _stack_argument_to_bytecode( if data_size > 32: raise ValueError("Opcode stack data must be less than 32 bytes") elif data_size == 0: - # Pushing 0 is done with the PUSH1 opcode for compatibility - # reasons. + # Pushing 0 is done with the PUSH1 opcode + # for compatibility reasons. data_size = 1 arg = arg.to_bytes( length=data_size, @@ -58,8 +58,8 @@ def _stack_argument_to_bytecode( else: arg = to_bytes(arg).lstrip(b"\0") # type: ignore if arg == b"": - # Pushing 0 is done with the PUSH1 opcode for compatibility - # reasons. + # Pushing 0 is done with the PUSH1 opcode for + # compatibility reasons. arg = b"\x00" data_size = len(arg) @@ -71,18 +71,24 @@ def _stack_argument_to_bytecode( class Opcode(Bytecode): """ - Represents a single Opcode instruction in the EVM, with extra metadata - useful to parametrize tests. + Represents a single Opcode instruction in the EVM, with extra + metadata useful to parametrize tests. + + Parameters + ---------- + - data_portion_length: number of bytes after the opcode in the bytecode + that represent data + - data_portion_formatter: function to format the data portion of the + opcode, if any + - stack_properties_modifier: function to modify the stack properties of + the opcode after the data portion has been processed + - kwargs: list of keyword arguments that can be passed to the opcode, + in the order they are meant to be placed in the stack + - kwargs_defaults: default values for the keyword arguments if any, + otherwise 0 + - unchecked_stack: whether the bytecode should ignore stack checks + when being called - Parameters ---------- - data_portion_length: number of bytes after the - opcode in the bytecode that represent data - data_portion_formatter: - function to format the data portion of the opcode, if any - - stack_properties_modifier: function to modify the stack properties of the - opcode after the data portion has been processed - kwargs: list of keyword - arguments that can be passed to the opcode, in the order they are meant to - be placed in the stack - kwargs_defaults: default values for the keyword - arguments if any, otherwise 0 - unchecked_stack: whether the bytecode - should ignore stack checks when being called """ data_portion_length: int @@ -112,8 +118,8 @@ def __new__( if kwargs_defaults is None: kwargs_defaults = {} if type(opcode_or_byte) is Opcode: - # Required because Enum class calls the base class with the - # instantiated object as parameter. + # Required because Enum class calls the base class + # with the instantiated object as parameter. return opcode_or_byte elif isinstance(opcode_or_byte, int) or isinstance(opcode_or_byte, bytes): obj_bytes = ( @@ -148,8 +154,8 @@ def __new__( def __getitem__(self, *args: "int | bytes | str | Iterable[int]") -> "Opcode": """ - Initialize a new instance of the opcode with the data portion set, and - also clear the data portion variables to avoid reusing them. + Initialize a new instance of the opcode with the data portion set, + and also clear the data portion variables to avoid reusing them. """ if self.data_portion_formatter is None and self.data_portion_length == 0: raise ValueError("Opcode does not have a data portion or has already been set") @@ -161,8 +167,8 @@ def __getitem__(self, *args: "int | bytes | str | Iterable[int]") -> "Opcode": else: data_portion = self.data_portion_formatter(*args) elif self.data_portion_length > 0: - # For opcodes with a data portion, the first argument is the data - # and the rest of the arguments form the stack. + # For opcodes with a data portion, the first argument is the + # data and the rest of the arguments form the stack. assert len(args) == 1, "Opcode with data portion requires exactly one argument" data = args[0] if isinstance(data, bytes) or isinstance(data, SupportsBytes) or isinstance(data, str): @@ -224,27 +230,30 @@ def __call__( ) -> Bytecode: """ Make all opcode instances callable to return formatted bytecode, which - constitutes a data portion, that is located after the opcode byte, and - pre-opcode bytecode, which is normally used to set up the stack. + constitutes a data portion, that is located after the opcode byte, + and pre-opcode bytecode, which is normally used to set up the stack. - This useful to automatically format, e.g., call opcodes and their stack - arguments as `Opcodes.CALL(Opcodes.GAS, 0x1234, 0x0, 0x0, 0x0, 0x0, - 0x0)`. + This useful to automatically format, e.g., call opcodes and their + stack arguments as + `Opcodes.CALL(Opcodes.GAS, 0x1234, 0x0, 0x0, 0x0, 0x0, 0x0)`. - Data sign is automatically detected but for this reason the range of - the input must be: `[-2^(data_portion_bits-1), 2^(data_portion_bits)]` - where: `data_portion_bits == data_portion_length * 8` + Data sign is automatically detected but for this reason the range + of the input must be: + `[-2^(data_portion_bits-1), 2^(data_portion_bits)]` + where: + `data_portion_bits == data_portion_length * 8` - For the stack, the arguments are set up in the opposite order they are - given, so the first argument is the last item pushed to the stack. + For the stack, the arguments are set up in the opposite order they + are given, so the first argument is the last item pushed to the stack. - The resulting stack arrangement does not take into account opcode stack - element consumption, so the stack height is not guaranteed to be - correct and the user must take this into consideration. + The resulting stack arrangement does not take into account + opcode stack element consumption, so the stack height is not + guaranteed to be correct and the user must take this into + consideration. - Integers can also be used as stack elements, in which case they are - automatically converted to PUSH operations, and negative numbers always - use a PUSH32 operation. + Integers can also be used as stack elements, in which case they + are automatically converted to PUSH operations, and negative numbers + always use a PUSH32 operation. Hex-strings will be automatically converted to bytes. """ @@ -320,8 +329,8 @@ def __new__( if macro_or_bytes is None: macro_or_bytes = Bytecode() if isinstance(macro_or_bytes, Macro): - # Required because Enum class calls the base class with the - # instantiated object as parameter. + # Required because Enum class calls the base class + # with the instantiated object as parameter. return macro_or_bytes else: instance = super().__new__(cls, macro_or_bytes) @@ -345,9 +354,10 @@ def __call__(self, *args_t: OpcodeCallArg, **kwargs) -> Bytecode: RJUMPV_BRANCH_OFFSET_BYTE_LENGTH = 2 -# TODO: Allowing Iterable here is a hacky way to support `range`, because -# Python 3.11+ will allow `Op.RJUMPV[*range(5)]`. This is a temporary solution -# until Python 3.11+ is the minimum required version. +# TODO: Allowing Iterable here is a hacky way to support `range`, +# because Python 3.11+ will allow `Op.RJUMPV[*range(5)]`. +# This is a temporary solution until Python 3.11+ is the minimum required +# version. def _rjumpv_encoder(*args: int | bytes | Iterable[int]) -> bytes: @@ -422,4257 +432,4735 @@ class Opcodes(Opcode, Enum): Contains deprecated and not yet implemented opcodes. - This enum is !! NOT !! meant to be iterated over by the tests. Instead, - create a list with cherry-picked opcodes from this Enum within the test if - iteration is needed. + This enum is !! NOT !! meant to be iterated over by the tests. + Instead, create a list with cherry-picked opcodes from this Enum + within the test if iteration is needed. Do !! NOT !! remove or modify existing opcodes from this list. """ STOP = Opcode(0x00, terminating=True) """ + STOP() + ---- + Description + ---- + Stop execution + Inputs + ---- + - None + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + 0 - STOP() ---- - - Description ---- Stop execution - - Inputs ---- - None + Source: [evm.codes/#00](https://www.evm.codes/#00) + """ - Outputs ---- - None + ADD = Opcode(0x01, popped_stack_items=2, pushed_stack_items=1) + """ + ADD(a, b) = c + ---- - Fork ---- Frontier + Description + ---- + Addition operation - Gas ---- 0 + Inputs + ---- + - a: first integer value to add + - b: second integer value to add - Source: [evm.codes/#00](https://www.evm.codes/#00) + Outputs + ---- + - c: integer result of the addition modulo 2**256 + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#01](https://www.evm.codes/#01) """ - ADD = Opcode(0x01, popped_stack_items=2, pushed_stack_items=1) + MUL = Opcode(0x02, popped_stack_items=2, pushed_stack_items=1) """ + MUL(a, b) = c + ---- + Description + ---- + Multiplication operation + Inputs + ---- + - a: first integer value to multiply + - b: second integer value to multiply + Outputs + ---- + - c: integer result of the multiplication modulo 2**256 + Fork + ---- + Frontier + Gas + ---- + 5 - ADD(a, b) = c ---- - - Description ---- Addition operation - - Inputs ---- - a: first integer value to add - b: second integer value to - add + Source: [evm.codes/#02](https://www.evm.codes/#02) + """ - Outputs ---- - c: integer result of the addition modulo 2**256 + SUB = Opcode(0x03, popped_stack_items=2, pushed_stack_items=1) + """ + SUB(a, b) = c + ---- - Fork ---- Frontier + Description + ---- + Subtraction operation - Gas ---- 3 + Inputs + ---- + - a: first integer value + - b: second integer value - Source: [evm.codes/#01](https://www.evm.codes/#01) + Outputs + ---- + - c: integer result of the subtraction modulo 2**256 + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#03](https://www.evm.codes/#03) """ - MUL = Opcode(0x02, popped_stack_items=2, pushed_stack_items=1) + DIV = Opcode(0x04, popped_stack_items=2, pushed_stack_items=1) """ + DIV(a, b) = c + ---- + Description + ---- + Division operation + Inputs + ---- + - a: numerator + - b: denominator (must be non-zero) + Outputs + ---- + - c: integer result of the division + Fork + ---- + Frontier + Gas + ---- + 5 - MUL(a, b) = c ---- - - Description ---- Multiplication operation - - Inputs ---- - a: first integer value to multiply - b: second integer value - to multiply + Source: [evm.codes/#04](https://www.evm.codes/#04) + """ - Outputs ---- - c: integer result of the multiplication modulo 2**256 + SDIV = Opcode(0x05, popped_stack_items=2, pushed_stack_items=1) + """ + SDIV(a, b) = c + ---- - Fork ---- Frontier + Description + ---- + Signed division operation - Gas ---- 5 + Inputs + ---- + - a: signed numerator + - b: signed denominator - Source: [evm.codes/#02](https://www.evm.codes/#02) + Outputs + ---- + - c: signed integer result of the division. If the denominator is 0, + the result will be 0 + ---- + Fork + ---- + Frontier + Gas + ---- + 5 + Source: [evm.codes/#05](https://www.evm.codes/#05) """ - SUB = Opcode(0x03, popped_stack_items=2, pushed_stack_items=1) + MOD = Opcode(0x06, popped_stack_items=2, pushed_stack_items=1) """ + MOD(a, b) = c + ---- + Description + ---- + Modulo operation + Inputs + ---- + - a: integer numerator + - b: integer denominator + Outputs + ---- + - a % b: integer result of the integer modulo. If the denominator is 0, + the result will be 0 + Fork + ---- + Frontier + Gas + ---- + 5 - SUB(a, b) = c ---- - - Description ---- Subtraction operation - - Inputs ---- - a: first integer value - b: second integer value + Source: [evm.codes/#06](https://www.evm.codes/#06) + """ - Outputs ---- - c: integer result of the subtraction modulo 2**256 + SMOD = Opcode(0x07, popped_stack_items=2, pushed_stack_items=1) + """ + SMOD(a, b) = c + ---- - Fork ---- Frontier + Description + ---- + Signed modulo remainder operation - Gas ---- 3 + Inputs + ---- + - a: integer numerator + - b: integer denominator - Source: [evm.codes/#03](https://www.evm.codes/#03) + Outputs + ---- + - a % b: integer result of the signed integer modulo. If the denominator + is 0, the result will be 0 + Fork + ---- + Frontier + Gas + ---- + 5 + Source: [evm.codes/#07](https://www.evm.codes/#07) """ - DIV = Opcode(0x04, popped_stack_items=2, pushed_stack_items=1) + ADDMOD = Opcode(0x08, popped_stack_items=3, pushed_stack_items=1) """ + ADDMOD(a, b, c) = d + ---- + Description + ---- + Modular addition operation with overflow check + Inputs + ---- + - a: first integer value + - b: second integer value + - c: integer denominator + Outputs + ---- + - (a + b) % N: integer result of the addition followed by a modulo. + If the denominator is 0, the result will be 0 + Fork + ---- + Frontier + Gas + ---- + 8 - DIV(a, b) = c ---- - - Description ---- Division operation - - Inputs ---- - a: numerator - b: denominator (must be non-zero) + Source: [evm.codes/#08](https://www.evm.codes/#08) + """ - Outputs ---- - c: integer result of the division + MULMOD = Opcode(0x09, popped_stack_items=3, pushed_stack_items=1) + """ + MULMOD(a, b, N) = d + ---- - Fork ---- Frontier + Description + ---- + Modulo multiplication operation - Gas ---- 5 + Inputs + ---- + - a: first integer value to multiply + - b: second integer value to multiply + - N: integer denominator - Source: [evm.codes/#04](https://www.evm.codes/#04) + Outputs + ---- + - (a * b) % N: integer result of the multiplication followed by a modulo. + If the denominator is 0, the result will be 0 + Fork + ---- + Frontier + Gas + ---- + 8 + Source: [evm.codes/#09](https://www.evm.codes/#09) """ - SDIV = Opcode(0x05, popped_stack_items=2, pushed_stack_items=1) + EXP = Opcode(0x0A, popped_stack_items=2, pushed_stack_items=1) """ + EXP(a, exponent) = a ** exponent + ---- + Description + ---- + Exponential operation + Inputs + ---- + - a: integer base + - exponent: integer exponent + Outputs + ---- + - a ** exponent: integer result of the exponential operation modulo 2**256 + Fork + ---- + Frontier + Gas + ---- + - static_gas = 10 + - dynamic_gas = 50 * exponent_byte_size - SDIV(a, b) = c ---- - - Description ---- Signed division operation - - Inputs ---- - a: signed numerator - b: signed denominator + Source: [evm.codes/#0A](https://www.evm.codes/#0A) + """ - Outputs ---- - c: signed integer result of the division. If the denominator - is 0, the result will be 0 ---- + SIGNEXTEND = Opcode(0x0B, popped_stack_items=2, pushed_stack_items=1) + """ + SIGNEXTEND(b, x) = y + ---- - Fork ---- Frontier + Description + ---- + Sign extension operation - Gas ---- 5 + Inputs + ---- + - b: size in byte - 1 of the integer to sign extend + - x: integer value to sign extend - Source: [evm.codes/#05](https://www.evm.codes/#05) + Outputs + ---- + - y: integer result of the sign extend + Fork + ---- + Frontier + Gas + ---- + 5 + Source: [evm.codes/#0B](https://www.evm.codes/#0B) """ - MOD = Opcode(0x06, popped_stack_items=2, pushed_stack_items=1) + LT = Opcode(0x10, popped_stack_items=2, pushed_stack_items=1) """ + LT(a, b) = a < b + ---- + Description + ---- + Less-than comparison + Inputs + ---- + - a: left side integer value + - b: right side integer value + Outputs + ---- + - a < b: 1 if the left side is smaller, 0 otherwise + Fork + ---- + Frontier + Gas + ---- + 3 - MOD(a, b) = c ---- - - Description ---- Modulo operation - - Inputs ---- - a: integer numerator - b: integer denominator + Source: [evm.codes/#10](https://www.evm.codes/#10) + """ - Outputs ---- - a % b: integer result of the integer modulo. If the - denominator is 0, the result will be 0 + GT = Opcode(0x11, popped_stack_items=2, pushed_stack_items=1) + """ + GT(a, b) = a > b + ---- - Fork ---- Frontier + Description + ---- + Greater-than comparison - Gas ---- 5 + Inputs + ---- + - a: left side integer + - b: right side integer - Source: [evm.codes/#06](https://www.evm.codes/#06) + Outputs + ---- + - a > b: 1 if the left side is bigger, 0 otherwise + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#11](https://www.evm.codes/#11) """ - SMOD = Opcode(0x07, popped_stack_items=2, pushed_stack_items=1) + SLT = Opcode(0x12, popped_stack_items=2, pushed_stack_items=1) """ + SLT(a, b) = a < b + ---- + Description + ---- + Signed less-than comparison + Inputs + ---- + - a: left side signed integer + - b: right side signed integer + Outputs + ---- + - a < b: 1 if the left side is smaller, 0 otherwise + Fork + ---- + Frontier + Gas + ---- + 3 - SMOD(a, b) = c ---- - - Description ---- Signed modulo remainder operation - - Inputs ---- - a: integer numerator - b: integer denominator + Source: [evm.codes/#12](https://www.evm.codes/#12) + """ - Outputs ---- - a % b: integer result of the signed integer modulo. If the - denominator is 0, the result will be 0 + SGT = Opcode(0x13, popped_stack_items=2, pushed_stack_items=1) + """ + SGT(a, b) = a > b + ---- - Fork ---- Frontier + Description + ---- + Signed greater-than comparison - Gas ---- 5 + Inputs + ---- + - a: left side signed integer + - b: right side signed integer - Source: [evm.codes/#07](https://www.evm.codes/#07) + Outputs + ---- + - a > b: 1 if the left side is bigger, 0 otherwise + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#13](https://www.evm.codes/#13) """ - ADDMOD = Opcode(0x08, popped_stack_items=3, pushed_stack_items=1) + EQ = Opcode(0x14, popped_stack_items=2, pushed_stack_items=1) """ + EQ(a, b) = a == b + ---- + Description + ---- + Equality comparison + Inputs + ---- + - a: left side integer + - b: right side integer + Outputs + ---- + - a == b: 1 if the left side is equal to the right side, 0 otherwise + Fork + ---- + Frontier + Gas + ---- + 3 - ADDMOD(a, b, c) = d ---- - - Description ---- Modular addition operation with overflow check - - Inputs ---- - a: first integer value - b: second integer value - c: integer - denominator + Source: [evm.codes/#14](https://www.evm.codes/#14) + """ - Outputs ---- - (a + b) % N: integer result of the addition followed by a - modulo. If the denominator is 0, the result will be 0 + ISZERO = Opcode(0x15, popped_stack_items=1, pushed_stack_items=1) + """ + ISZERO(a) = a == 0 + ---- - Fork ---- Frontier + Description + ---- + Is-zero comparison - Gas ---- 8 + Inputs + ---- + - a: integer - Source: [evm.codes/#08](https://www.evm.codes/#08) + Outputs + ---- + - a == 0: 1 if a is 0, 0 otherwise + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#15](https://www.evm.codes/#15) """ - MULMOD = Opcode(0x09, popped_stack_items=3, pushed_stack_items=1) + AND = Opcode(0x16, popped_stack_items=2, pushed_stack_items=1) """ + AND(a, b) = a & b + ---- + Description + ---- + Bitwise AND operation + Inputs + ---- + - a: first binary value + - b: second binary value + Outputs + ---- + - a & b: the bitwise AND result + Fork + ---- + Frontier + Gas + ---- + 3 - MULMOD(a, b, N) = d ---- - - Description ---- Modulo multiplication operation - - Inputs ---- - a: first integer value to multiply - b: second integer value - to multiply - N: integer denominator + Source: [evm.codes/#16](https://www.evm.codes/#16) + """ - Outputs ---- - (a * b) % N: integer result of the multiplication followed - by a modulo. If the denominator is 0, the result will be 0 + OR = Opcode(0x17, popped_stack_items=2, pushed_stack_items=1) + """ + OR(a, b) = a | b + ---- - Fork ---- Frontier + Description + ---- + Bitwise OR operation - Gas ---- 8 + Inputs + ---- + - a: first binary value + - b: second binary value - Source: [evm.codes/#09](https://www.evm.codes/#09) + Outputs + ---- + - a | b: the bitwise OR result + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#17](https://www.evm.codes/#17) """ - EXP = Opcode(0x0A, popped_stack_items=2, pushed_stack_items=1) + XOR = Opcode(0x18, popped_stack_items=2, pushed_stack_items=1) """ + XOR(a, b) = a ^ b + ---- + Description + ---- + Bitwise XOR operation + Inputs + ---- + - a: first binary value + - b: second binary value + Outputs + ---- + - a ^ b: the bitwise XOR result + Fork + ---- + Frontier + Gas + ---- + 3 - EXP(a, exponent) = a ** exponent ---- - - Description ---- Exponential operation - - Inputs ---- - a: integer base - exponent: integer exponent + Source: [evm.codes/#18](https://www.evm.codes/#18) + """ - Outputs ---- - a ** exponent: integer result of the exponential operation - modulo 2**256 + NOT = Opcode(0x19, popped_stack_items=1, pushed_stack_items=1) + """ + NOT(a) = ~a + ---- - Fork ---- Frontier + Description + ---- + Bitwise NOT operation - Gas ---- - static_gas = 10 - dynamic_gas = 50 * exponent_byte_size + Inputs + ---- + - a: binary value - Source: [evm.codes/#0A](https://www.evm.codes/#0A) + Outputs + ---- + - ~a: the bitwise NOT result + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#19](https://www.evm.codes/#19) """ - SIGNEXTEND = Opcode(0x0B, popped_stack_items=2, pushed_stack_items=1) + BYTE = Opcode(0x1A, popped_stack_items=2, pushed_stack_items=1) """ + BYTE(i, x) = y + ---- + Description + ---- + Extract a byte from the given position in the value + Inputs + ---- + - i: byte offset starting from the most significant byte + - x: 32-byte value + Outputs + ---- + - y: the indicated byte at the least significant position. + If the byte offset is out of range, the result is 0 + Fork + ---- + Frontier + Gas + ---- + 3 - SIGNEXTEND(b, x) = y ---- - - Description ---- Sign extension operation - - Inputs ---- - b: size in byte - 1 of the integer to sign extend - x: - integer value to sign extend + Source: [evm.codes/#1A](https://www.evm.codes/#1A) + """ - Outputs ---- - y: integer result of the sign extend + SHL = Opcode(0x1B, popped_stack_items=2, pushed_stack_items=1) + """ + SHL(shift, value) = value << shift + ---- - Fork ---- Frontier + Description + ---- + Shift left operation - Gas ---- 5 + Inputs + ---- + - shift: number of bits to shift to the left + - value: 32 bytes to shift - Source: [evm.codes/#0B](https://www.evm.codes/#0B) + Outputs + ---- + - value << shift: the shifted value. If shift is bigger than 255, returns 0 + Fork + ---- + Constantinople + Gas + ---- + 3 + Source: [evm.codes/#1B](https://www.evm.codes/#1B) """ - LT = Opcode(0x10, popped_stack_items=2, pushed_stack_items=1) + SHR = Opcode(0x1C, popped_stack_items=2, pushed_stack_items=1) """ + SHR(shift, value) = value >> shift + ---- + Description + ---- + Logical shift right operation + Inputs + ---- + - shift: number of bits to shift to the right. + - value: 32 bytes to shift + Outputs + ---- + - value >> shift: the shifted value. If shift is bigger than 255, returns 0 + Fork + ---- + Constantinople + Gas + ---- + 3 - LT(a, b) = a < b ---- - - Description ---- Less-than comparison - - Inputs ---- - a: left side integer value - b: right side integer value + Source: [evm.codes/#1C](https://www.evm.codes/#1C) + """ - Outputs ---- - a < b: 1 if the left side is smaller, 0 otherwise + SAR = Opcode(0x1D, popped_stack_items=2, pushed_stack_items=1) + """ + SAR(shift, value) = value >> shift + ---- - Fork ---- Frontier + Description + ---- + Arithmetic shift right operation - Gas ---- 3 + Inputs + ---- + - shift: number of bits to shift to the right + - value: integer to shift - Source: [evm.codes/#10](https://www.evm.codes/#10) + Outputs + ---- + - value >> shift: the shifted value + Fork + ---- + Constantinople + Gas + ---- + 3 + Source: [evm.codes/#1D](https://www.evm.codes/#1D) """ - GT = Opcode(0x11, popped_stack_items=2, pushed_stack_items=1) + CLZ = Opcode(0x1E, popped_stack_items=1, pushed_stack_items=1) """ + CLZ(value) = count_leading_zeros(value) + ---- + Description + ---- + Counts leading zeros (bitwise). + Inputs + ---- + - value: integer to count zeros on + Outputs + ---- + - zeros: leading zero bits + Fork + ---- + Osaka + Gas + ---- + 3 - GT(a, b) = a > b ---- - - Description ---- Greater-than comparison - - Inputs ---- - a: left side integer - b: right side integer + Source: [evm.codes/#1E](https://www.evm.codes/#1E) + """ - Outputs ---- - a > b: 1 if the left side is bigger, 0 otherwise + SHA3 = Opcode(0x20, popped_stack_items=2, pushed_stack_items=1, kwargs=["offset", "size"]) + """ + SHA3(offset, size) = hash + ---- - Fork ---- Frontier + Description + ---- + Compute Keccak-256 hash - Gas ---- 3 + Inputs + ---- + - offset: byte offset in the memory + - size: byte size to read in the memory - Source: [evm.codes/#11](https://www.evm.codes/#11) + Outputs + ---- + - hash: Keccak-256 hash of the given data in memory + Fork + ---- + Frontier + Gas + ---- + - minimum_word_size = (size + 31) / 32 + - static_gas = 30 + - dynamic_gas = 6 * minimum_word_size + memory_expansion_cost + Source: [evm.codes/#20](https://www.evm.codes/#20) """ - SLT = Opcode(0x12, popped_stack_items=2, pushed_stack_items=1) + ADDRESS = Opcode(0x30, pushed_stack_items=1) """ + ADDRESS() = address + ---- + Description + ---- + Get address of currently executing account + Inputs + ---- + - None + Outputs + ---- + - address: the 20-byte address of the current account + Fork + ---- + Frontier + Gas + ---- + 2 - SLT(a, b) = a < b ---- - - Description ---- Signed less-than comparison - - Inputs ---- - a: left side signed integer - b: right side signed integer + Source: [evm.codes/#30](https://www.evm.codes/#30) + """ - Outputs ---- - a < b: 1 if the left side is smaller, 0 otherwise + BALANCE = Opcode(0x31, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) + """ + BALANCE(address) = balance + ---- - Fork ---- Frontier + Description + ---- + Get the balance of the specified account - Gas ---- 3 + Inputs + ---- + - address: 20-byte address of the account to check - Source: [evm.codes/#12](https://www.evm.codes/#12) + Outputs + ---- + - balance: balance of the given account in wei. Returns 0 if the + account doesn't exist + Fork + ---- + Frontier + Gas + ---- + - static_gas = 0 + - dynamic_gas = 100 if warm_address, 2600 if cold_address + Source: [evm.codes/#31](https://www.evm.codes/#31) """ - SGT = Opcode(0x13, popped_stack_items=2, pushed_stack_items=1) + ORIGIN = Opcode(0x32, pushed_stack_items=1) """ + ORIGIN() = address + ---- + Description + ---- + Get execution origination address + Inputs + ---- + - None + Outputs + ---- + - address: the 20-byte address of the sender of the transaction. + It can only be an account without code + Fork + ---- + Frontier + Gas + ---- + 2 - SGT(a, b) = a > b ---- - - Description ---- Signed greater-than comparison - - Inputs ---- - a: left side signed integer - b: right side signed integer + Source: [evm.codes/#32](https://www.evm.codes/#32) + """ - Outputs ---- - a > b: 1 if the left side is bigger, 0 otherwise + CALLER = Opcode(0x33, pushed_stack_items=1) + """ + CALLER() = address + ---- - Fork ---- Frontier + Description + ---- + Get caller address - Gas ---- 3 + Inputs + ---- + - None - Source: [evm.codes/#13](https://www.evm.codes/#13) + Outputs + ---- + - address: the 20-byte address of the caller account. + This is the account that did the last + call (except delegate call) + Fork + ---- + Frontier + Gas + ---- + 2 + Source: [evm.codes/#33](https://www.evm.codes/#33) """ - EQ = Opcode(0x14, popped_stack_items=2, pushed_stack_items=1) + CALLVALUE = Opcode(0x34, pushed_stack_items=1) """ + CALLVALUE() = value + ---- + Description + ---- + Get deposited value by the instruction/transaction responsible + for this execution + Inputs + ---- + - None + Outputs + ---- + - value: the value of the current call in wei + Fork + ---- + Frontier + Gas + ---- + 2 - EQ(a, b) = a == b ---- - - Description ---- Equality comparison - - Inputs ---- - a: left side integer - b: right side integer + Source: [evm.codes/#34](https://www.evm.codes/#34) + """ - Outputs ---- - a == b: 1 if the left side is equal to the right side, 0 - otherwise + CALLDATALOAD = Opcode(0x35, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) + """ + CALLDATALOAD(offset) = data[offset] + ---- - Fork ---- Frontier + Description + ---- + Get input data of current environment - Gas ---- 3 + Inputs + ---- + - offset: byte offset in the calldata - Source: [evm.codes/#14](https://www.evm.codes/#14) + Outputs + ---- + - data[offset]: 32-byte value starting from the given offset of + the calldata. All bytes after the end of the calldata + are set to 0 + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#35](https://www.evm.codes/#35) """ - ISZERO = Opcode(0x15, popped_stack_items=1, pushed_stack_items=1) + CALLDATASIZE = Opcode(0x36, pushed_stack_items=1) """ + CALLDATASIZE() = size + ---- + Description + ---- + Get size of input data in current environment + Inputs + ---- + - None + Outputs + ---- + - size: byte size of the calldata + Fork + ---- + Frontier + Gas + ---- + 2 - ISZERO(a) = a == 0 ---- - - Description ---- Is-zero comparison - - Inputs ---- - a: integer + Source: [evm.codes/#36](https://www.evm.codes/#36) + """ - Outputs ---- - a == 0: 1 if a is 0, 0 otherwise + CALLDATACOPY = Opcode(0x37, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) + """ + CALLDATACOPY(dest_offset, offset, size) + ---- - Fork ---- Frontier + Description + ---- + Copy input data in current environment to memory - Gas ---- 3 + Inputs + ---- + - dest_offset: byte offset in the memory where the result will be copied + - offset: byte offset in the calldata to copy + - size: byte size to copy - Source: [evm.codes/#15](https://www.evm.codes/#15) + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + - minimum_word_size = (size + 31) / 32 + - static_gas = 3 + - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + Source: [evm.codes/#37](https://www.evm.codes/#37) """ - AND = Opcode(0x16, popped_stack_items=2, pushed_stack_items=1) + CODESIZE = Opcode(0x38, pushed_stack_items=1) """ + CODESIZE() = size + ---- + Description + ---- + Get size of code running in current environment + Inputs + ---- + - None + Outputs + ---- + - size: byte size of the code + Fork + ---- + Frontier + Gas + ---- + 2 - AND(a, b) = a & b ---- - - Description ---- Bitwise AND operation - - Inputs ---- - a: first binary value - b: second binary value - - Outputs ---- - a & b: the bitwise AND result + Source: [evm.codes/#38](https://www.evm.codes/#38) + """ - Fork ---- Frontier + CODECOPY = Opcode(0x39, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) + """ + CODECOPY(dest_offset, offset, size) + ---- - Gas ---- 3 + Description + ---- + Copy code running in current environment to memory - Source: [evm.codes/#16](https://www.evm.codes/#16) + Inputs + ---- + - dest_offset: byte offset in the memory where the result will be copied. + - offset: byte offset in the code to copy. + - size: byte size to copy + Fork + ---- + Frontier + Gas + ---- + - minimum_word_size = (size + 31) / 32 + - static_gas = 3 + - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + Source: [evm.codes/#39](https://www.evm.codes/#39) """ - OR = Opcode(0x17, popped_stack_items=2, pushed_stack_items=1) + GASPRICE = Opcode(0x3A, pushed_stack_items=1) """ + GASPRICE() = price + ---- + Description + ---- + Get price of gas in current environment + Outputs + ---- + - price: gas price in wei per gas + Fork + ---- + Frontier + Gas + ---- + 2 + Source: [evm.codes/#3A](https://www.evm.codes/#3A) + """ - OR(a, b) = a | b ---- + EXTCODESIZE = Opcode(0x3B, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) + """ + EXTCODESIZE(address) = size + ---- - Description ---- Bitwise OR operation + Description + ---- + Get size of an account's code - Inputs ---- - a: first binary value - b: second binary value + Inputs + ---- + - address: 20-byte address of the contract to query - Outputs ---- - a | b: the bitwise OR result + Outputs + ---- + - size: byte size of the code - Fork ---- Frontier + Fork + ---- + Frontier - Gas ---- 3 + Gas + ---- + - static_gas = 0 + - dynamic_gas = 100 if warm_address, 2600 if cold_address - Source: [evm.codes/#17](https://www.evm.codes/#17) + Source: [evm.codes/#3B](https://www.evm.codes/#3B) + """ + EXTCODECOPY = Opcode( + 0x3C, popped_stack_items=4, kwargs=["address", "dest_offset", "offset", "size"] + ) + """ + EXTCODECOPY(address, dest_offset, offset, size) + ---- + Description + ---- + Copy an account's code to memory - """ + Inputs + ---- + - address: 20-byte address of the contract to query + - dest_offset: byte offset in the memory where the result will be copied + - offset: byte offset in the code to copy + - size: byte size to copy - XOR = Opcode(0x18, popped_stack_items=2, pushed_stack_items=1) - """ + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + - minimum_word_size = (size + 31) / 32 + - static_gas = 0 + - dynamic_gas = 3 * minimum_word_size + + memory_expansion_cost + address_access_cost + Source: [evm.codes/#3C](https://www.evm.codes/#3C) + """ + RETURNDATASIZE = Opcode(0x3D, pushed_stack_items=1) + """ + RETURNDATASIZE() = size + ---- + Description + ---- + Get size of output data from the previous call from the current environment - XOR(a, b) = a ^ b ---- + Outputs + ---- + - size: byte size of the return data from the last executed sub context - Description ---- Bitwise XOR operation + Fork + ---- + Byzantium - Inputs ---- - a: first binary value - b: second binary value + Gas + ---- + 2 - Outputs ---- - a ^ b: the bitwise XOR result + Source: [evm.codes/#3D](https://www.evm.codes/#3D) + """ - Fork ---- Frontier + RETURNDATACOPY = Opcode(0x3E, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) + """ + RETURNDATACOPY(dest_offset, offset, size) + ---- - Gas ---- 3 + Description + ---- + Copy output data from the previous call to memory - Source: [evm.codes/#18](https://www.evm.codes/#18) + Inputs + ---- + - dest_offset: byte offset in the memory where the result will be copied + - offset: byte offset in the return data from the last + executed sub context to copy + - size: byte size to copy + Fork + ---- + Byzantium + Gas + ---- + - minimum_word_size = (size + 31) / 32 + - static_gas = 3 + - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + Source: [evm.codes/#3E](https://www.evm.codes/#3E) """ - NOT = Opcode(0x19, popped_stack_items=1, pushed_stack_items=1) + EXTCODEHASH = Opcode(0x3F, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) """ + EXTCODEHASH(address) = hash + ---- + Description + ---- + Get hash of an account's code + Inputs + ---- + - address: 20-byte address of the account + Outputs + ---- + - hash: hash of the chosen account's code, the empty hash (0xc5d24601...) + if the account has no code, or 0 if the account does not exist or + has been destroyed + Fork + ---- + Constantinople + Gas + ---- + - static_gas = 0 + - dynamic_gas = 100 if warm_address, 2600 if cold_address - NOT(a) = ~a ---- - - Description ---- Bitwise NOT operation - - Inputs ---- - a: binary value + Source: [evm.codes/#3F](https://www.evm.codes/#3F) + """ - Outputs ---- - ~a: the bitwise NOT result + BLOCKHASH = Opcode(0x40, popped_stack_items=1, pushed_stack_items=1, kwargs=["block_number"]) + """ + BLOCKHASH(block_number) = hash + ---- - Fork ---- Frontier + Description + ---- + Get the hash of one of the 256 most recent complete blocks - Gas ---- 3 + Inputs + ---- + - blockNumber: block number to get the hash from. Valid range is the + last 256 blocks (not including the current one). Current + block number can be queried with NUMBER - Source: [evm.codes/#19](https://www.evm.codes/#19) + Outputs + ---- + - hash: hash of the chosen block, or 0 if the block number is not + in the valid range + Fork + ---- + Frontier + Gas + ---- + 20 + Source: [evm.codes/#40](https://www.evm.codes/#40) """ - BYTE = Opcode(0x1A, popped_stack_items=2, pushed_stack_items=1) + COINBASE = Opcode(0x41, pushed_stack_items=1) """ + COINBASE() = address + ---- + Description + ---- + Get the block's beneficiary address + Inputs + ---- + - None + Outputs + ---- + - address: miner's 20-byte address + Fork + ---- + Frontier + Gas + ---- + 2 - BYTE(i, x) = y ---- - - Description ---- Extract a byte from the given position in the value - - Inputs ---- - i: byte offset starting from the most significant byte - x: - 32-byte value + Source: [evm.codes/#41](https://www.evm.codes/#41) + """ - Outputs ---- - y: the indicated byte at the least significant position. If - the byte offset is out of range, the result is 0 + TIMESTAMP = Opcode(0x42, pushed_stack_items=1) + """ + TIMESTAMP() = timestamp + ---- - Fork ---- Frontier + Description + ---- + Get the block's timestamp - Gas ---- 3 + Inputs + ---- + - None - Source: [evm.codes/#1A](https://www.evm.codes/#1A) + Outputs + ---- + - timestamp: unix timestamp of the current block + Fork + ---- + Frontier + Gas + ---- + 2 + Source: [evm.codes/#42](https://www.evm.codes/#42) """ - SHL = Opcode(0x1B, popped_stack_items=2, pushed_stack_items=1) + NUMBER = Opcode(0x43, pushed_stack_items=1) """ + NUMBER() = blockNumber + ---- + Description + ---- + Get the block's number + Inputs + ---- + - None + Outputs + ---- + - blockNumber: current block number + Fork + ---- + Frontier + Gas + ---- + 2 - SHL(shift, value) = value << shift ---- - - Description ---- Shift left operation - - Inputs ---- - shift: number of bits to shift to the left - value: 32 bytes - to shift + Source: [evm.codes/#43](https://www.evm.codes/#43) + """ - Outputs ---- - value << shift: the shifted value. If shift is bigger than - 255, returns 0 + PREVRANDAO = Opcode(0x44, pushed_stack_items=1) + """ + PREVRANDAO() = prevRandao + ---- - Fork ---- Constantinople + Description + ---- + Get the previous block's RANDAO mix - Gas ---- 3 + Inputs + ---- + - None - Source: [evm.codes/#1B](https://www.evm.codes/#1B) + Outputs + ---- + - prevRandao: previous block's RANDAO mix + Fork + ---- + Merge + Gas + ---- + 2 + Source: [evm.codes/#44](https://www.evm.codes/#44) """ - SHR = Opcode(0x1C, popped_stack_items=2, pushed_stack_items=1) + GASLIMIT = Opcode(0x45, pushed_stack_items=1) """ + GASLIMIT() = gasLimit + ---- + Description + ---- + Get the block's gas limit + Inputs + ---- + - None + Outputs + ---- + - gasLimit: gas limit + Fork + ---- + Frontier + Gas + ---- + 2 - SHR(shift, value) = value >> shift ---- - - Description ---- Logical shift right operation - - Inputs ---- - shift: number of bits to shift to the right. - value: 32 - bytes to shift + Source: [evm.codes/#45](https://www.evm.codes/#45) + """ - Outputs ---- - value >> shift: the shifted value. If shift is bigger than - 255, returns 0 + CHAINID = Opcode(0x46, pushed_stack_items=1) + """ + CHAINID() = chainId + ---- - Fork ---- Constantinople + Description + ---- + Get the chain ID - Gas ---- 3 + Inputs + ---- + - None - Source: [evm.codes/#1C](https://www.evm.codes/#1C) + Outputs + ---- + - chainId: chain id of the network + Fork + ---- + Istanbul + Gas + ---- + 2 + Source: [evm.codes/#46](https://www.evm.codes/#46) """ - SAR = Opcode(0x1D, popped_stack_items=2, pushed_stack_items=1) + SELFBALANCE = Opcode(0x47, pushed_stack_items=1) """ + SELFBALANCE() = balance + ---- + Description + ---- + Get balance of currently executing account + Inputs + ---- + - None + Outputs + ---- + - balance: balance of the current account in wei + Fork + ---- + Istanbul + Gas + ---- + 5 - SAR(shift, value) = value >> shift ---- - - Description ---- Arithmetic shift right operation - - Inputs ---- - shift: number of bits to shift to the right - value: integer - to shift - - Outputs ---- - value >> shift: the shifted value + Source: [evm.codes/#47](https://www.evm.codes/#47) + """ - Fork ---- Constantinople + BASEFEE = Opcode(0x48, pushed_stack_items=1) + """ + BASEFEE() = baseFee + ---- - Gas ---- 3 + Description + ---- + Get the base fee - Source: [evm.codes/#1D](https://www.evm.codes/#1D) + Outputs + ---- + - baseFee: base fee in wei + Fork + ---- + London + Gas + ---- + 2 + Source: [evm.codes/#48](https://www.evm.codes/#48) """ - CLZ = Opcode(0x1E, popped_stack_items=1, pushed_stack_items=1) + BLOBHASH = Opcode(0x49, popped_stack_items=1, pushed_stack_items=1, kwargs=["index"]) """ + BLOBHASH(index) = versionedHash + ---- + Description + ---- + Returns the versioned hash of a single blob contained in + the type-3 transaction + Inputs + ---- + - index: index of the blob + Outputs + ---- + - versionedHash: versioned hash of the blob + Fork + ---- + Cancun + Gas + ---- + 3 - CLZ(value) = count_leading_zeros(value) ---- - - Description ---- Counts leading zeros (bitwise). - - Inputs ---- - value: integer to count zeros on + Source: [eips.ethereum.org/EIPS/ + eip-4844](https://eips.ethereum.org/EIPS/eip-4844) + """ - Outputs ---- - zeros: leading zero bits + BLOBBASEFEE = Opcode(0x4A, popped_stack_items=0, pushed_stack_items=1) + """ + BLOBBASEFEE() = fee + ---- - Fork ---- Osaka + Description + ---- + Returns the value of the blob base fee of the block it is executing in - Gas ---- 3 + Inputs + ---- + - None - Source: [evm.codes/#1E](https://www.evm.codes/#1E) + Outputs + ---- + - baseFeePerBlobGas: base fee for the blob gas in wei + Fork + ---- + Cancun + Gas + ---- + 2 + Source: [eips.ethereum.org/EIPS/eip-7516](https://eips.ethereum.org/ + EIPS/eip-7516) """ - SHA3 = Opcode(0x20, popped_stack_items=2, pushed_stack_items=1, kwargs=["offset", "size"]) + POP = Opcode(0x50, popped_stack_items=1) """ + POP() + ---- + Description + ---- + Remove item from stack + Inputs + ---- + - None + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + 2 - SHA3(offset, size) = hash ---- - - Description ---- Compute Keccak-256 hash - - Inputs ---- - offset: byte offset in the memory - size: byte size to read - in the memory + Source: [evm.codes/#50](https://www.evm.codes/#50) + """ - Outputs ---- - hash: Keccak-256 hash of the given data in memory + MLOAD = Opcode(0x51, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) + """ + MLOAD(offset) = value + ---- - Fork ---- Frontier + Description + ---- + Load word from memory - Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 30 - - dynamic_gas = 6 * minimum_word_size + memory_expansion_cost + Inputs + ---- + - offset: offset in the memory in bytes - Source: [evm.codes/#20](https://www.evm.codes/#20) + Outputs + ---- + - value: the 32 bytes in memory starting at that offset. + If it goes beyond its current size (see MSIZE), writes 0s + Fork + ---- + Frontier + Gas + ---- + - static_gas = 3 + - dynamic_gas = memory_expansion_cost + Source: [evm.codes/#51](https://www.evm.codes/#51) """ - ADDRESS = Opcode(0x30, pushed_stack_items=1) + MSTORE = Opcode(0x52, popped_stack_items=2, kwargs=["offset", "value"]) """ + MSTORE(offset, value) + ---- + Description + ---- + Save word to memory + Inputs + ---- + - offset: offset in the memory in bytes + - value: 32-byte value to write in the memory + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + - static_gas = 3 + - dynamic_gas = memory_expansion_cost - ADDRESS() = address ---- - - Description ---- Get address of currently executing account - - Inputs ---- - None - - Outputs ---- - address: the 20-byte address of the current account + Source: [evm.codes/#52](https://www.evm.codes/#52) + """ - Fork ---- Frontier + MSTORE8 = Opcode(0x53, popped_stack_items=2, kwargs=["offset", "value"]) + """ + MSTORE8(offset, value) + ---- - Gas ---- 2 + Description + ---- + Save byte to memory - Source: [evm.codes/#30](https://www.evm.codes/#30) + Inputs + ---- + - offset: offset in the memory in bytes + - value: 1-byte value to write in the memory (the least significant + byte of the 32-byte stack value) + Fork + ---- + Frontier + Gas + ---- + - static_gas = 3 + - dynamic_gas = memory_expansion_cost + Source: [evm.codes/#53](https://www.evm.codes/#53) """ - BALANCE = Opcode(0x31, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) + SLOAD = Opcode(0x54, popped_stack_items=1, pushed_stack_items=1, kwargs=["key"]) """ + SLOAD(key) = value + ---- + Description + ---- + Load word from storage + Inputs + ---- + - key: 32-byte key in storage + Outputs + ---- + - value: 32-byte value corresponding to that key. 0 if that + key was never written before + Fork + ---- + Frontier + Gas + ---- + - static_gas = 0 + - dynamic_gas = 100 if warm_address, 2600 if cold_address - BALANCE(address) = balance ---- - - Description ---- Get the balance of the specified account - - Inputs ---- - address: 20-byte address of the account to check + Source: [evm.codes/#54](https://www.evm.codes/#54) + """ - Outputs ---- - balance: balance of the given account in wei. Returns 0 if - the account doesn't exist + SSTORE = Opcode(0x55, popped_stack_items=2, kwargs=["key", "value"]) + """ + SSTORE(key, value) + ---- - Fork ---- Frontier + Description + ---- + Save word to storage - Gas ---- - static_gas = 0 - dynamic_gas = 100 if warm_address, 2600 if - cold_address + Inputs + ---- + - key: 32-byte key in storage + - value: 32-byte value to store - Source: [evm.codes/#31](https://www.evm.codes/#31) + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + ``` + static_gas = 0 + + if value == current_value + if key is warm + base_dynamic_gas = 100 + else + base_dynamic_gas = 100 + else if current_value == original_value + if original_value == 0 + base_dynamic_gas = 20000 + else + base_dynamic_gas = 2900 + else + base_dynamic_gas = 100 + + if key is cold: + base_dynamic_gas += 2100 + ``` + Source: [evm.codes/#55](https://www.evm.codes/#55) """ - ORIGIN = Opcode(0x32, pushed_stack_items=1) + JUMP = Opcode(0x56, popped_stack_items=1, kwargs=["pc"]) """ + JUMP(pc) + ---- + Description + ---- + Alter the program counter + Inputs + ---- + - pc: byte offset in the deployed code where execution will continue from. + Must be a JUMPDEST instruction + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + 8 - ORIGIN() = address ---- - - Description ---- Get execution origination address - - Inputs ---- - None - - Outputs ---- - address: the 20-byte address of the sender of the - transaction. It can only be an account without code + Source: [evm.codes/#56](https://www.evm.codes/#56) + """ - Fork ---- Frontier + JUMPI = Opcode(0x57, popped_stack_items=2, kwargs=["pc", "condition"]) + """ + JUMPI(pc, condition) + ---- - Gas ---- 2 + Description + ---- + Conditionally alter the program counter - Source: [evm.codes/#32](https://www.evm.codes/#32) + Inputs + ---- + - pc: byte offset in the deployed code where execution will continue from. + Must be a JUMPDEST instruction + - condition: the program counter will be altered with the new value only + if this value is different from 0. Otherwise, the program + counter is simply incremented and the next instruction + will be executed + Fork + ---- + Frontier + Gas + ---- + 10 + Source: [evm.codes/#57](https://www.evm.codes/#57) """ - CALLER = Opcode(0x33, pushed_stack_items=1) + PC = Opcode(0x58, pushed_stack_items=1) """ + PC() = counter + ---- + Description + ---- + Get the value of the program counter prior to the increment corresponding + to this instruction + Inputs + ---- + - None + Outputs + ---- + - counter: PC of this instruction in the current program. + Fork + ---- + Frontier + Gas + ---- + 2 - CALLER() = address ---- - - Description ---- Get caller address - - Inputs ---- - None - - Outputs ---- - address: the 20-byte address of the caller account. This is - the account that did the last call (except delegate call) + Source: [evm.codes/#58](https://www.evm.codes/#58) + """ - Fork ---- Frontier + MSIZE = Opcode(0x59, pushed_stack_items=1) + """ + MSIZE() = size + ---- - Gas ---- 2 + Description + ---- + Get the size of active memory in bytes - Source: [evm.codes/#33](https://www.evm.codes/#33) + Outputs + ---- + - size: current memory size in bytes (higher offset accessed until now + 1) + Fork + ---- + Frontier + Gas + ---- + 2 + Source: [evm.codes/#59](https://www.evm.codes/#59) """ - CALLVALUE = Opcode(0x34, pushed_stack_items=1) + GAS = Opcode(0x5A, pushed_stack_items=1) """ + GAS() = gas_remaining + ---- + Description + ---- + Get the amount of available gas, including the corresponding reduction + for the cost of this instruction + Inputs + ---- + - None + Outputs + ---- + - gas: remaining gas (after this instruction) + Fork + ---- + Frontier + Gas + ---- + 2 - CALLVALUE() = value ---- - - Description ---- Get deposited value by the instruction/transaction - responsible for this execution - - Inputs ---- - None + Source: [evm.codes/#5A](https://www.evm.codes/#5A) + """ - Outputs ---- - value: the value of the current call in wei + JUMPDEST = Opcode(0x5B) + """ + JUMPDEST() + ---- - Fork ---- Frontier + Description + ---- + Mark a valid destination for jumps - Gas ---- 2 + Inputs + ---- + - None - Source: [evm.codes/#34](https://www.evm.codes/#34) + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + 1 + Source: [evm.codes/#5B](https://www.evm.codes/#5B) """ - CALLDATALOAD = Opcode(0x35, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) + NOOP = Opcode(0x5B) """ + NOOP() + ---- + Description + ---- + Synonym for JUMPDEST. Performs no operation. + Inputs + ---- + - None + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + 1 - CALLDATALOAD(offset) = data[offset] ---- - - Description ---- Get input data of current environment - - Inputs ---- - offset: byte offset in the calldata + Source: [evm.codes/#5B](https://www.evm.codes/#5B) + """ - Outputs ---- - data[offset]: 32-byte value starting from the given offset - of the calldata. All bytes after the end of the calldata are set to 0 + TLOAD = Opcode(0x5C, popped_stack_items=1, pushed_stack_items=1, kwargs=["key"]) + """ + TLOAD(key) = value + ---- - Fork ---- Frontier + Description + ---- + Load word from transient storage - Gas ---- 3 + Inputs + ---- + - key: 32-byte key in transient storage - Source: [evm.codes/#35](https://www.evm.codes/#35) + Outputs + ---- + - value: 32-byte value corresponding to that key. 0 if that key + was never written + Fork + ---- + Cancun + Gas + ---- + 100 + Source: [eips.ethereum.org/EIPS/eip-1153](https://eips.ethereum.org/EIPS/eip-1153) """ - CALLDATASIZE = Opcode(0x36, pushed_stack_items=1) + TSTORE = Opcode(0x5D, popped_stack_items=2, kwargs=["key", "value"]) """ + TSTORE(key, value) + ---- + Description + ---- + Save word to transient storage + Inputs + ---- + - key: 32-byte key in transient storage + - value: 32-byte value to store + Fork + ---- + Cancun + Gas + ---- + 100 + Source: [eips.ethereum.org/EIPS/eip-1153](https://eips.ethereum.org/EIPS/ + eip-1153) + """ - CALLDATASIZE() = size ---- - - Description ---- Get size of input data in current environment - - Inputs ---- - None - - Outputs ---- - size: byte size of the calldata + MCOPY = Opcode(0x5E, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) + """ + MCOPY(dest_offset, offset, size) + ---- - Fork ---- Frontier + Description + ---- + Copies areas in memory - Gas ---- 2 + Inputs + ---- + - dest_offset: byte offset in the memory where the result will be copied + - offset: byte offset in the calldata to copy + - size: byte size to copy - Source: [evm.codes/#36](https://www.evm.codes/#36) + Outputs + ---- + - None + Fork + ---- + Cancun + Gas + ---- + - minimum_word_size = (size + 31) / 32 + - static_gas = 3 + - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + Source: [eips.ethereum.org/EIPS/eip-5656](https://eips.ethereum.org/EIPS/ + eip-5656) """ - CALLDATACOPY = Opcode(0x37, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) + PUSH0 = Opcode(0x5F, pushed_stack_items=1) """ + PUSH0() = value + ---- + Description + ---- + Place value 0 on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, equal to 0 + Fork + ---- + Shanghai + Gas + ---- + 2 - CALLDATACOPY(dest_offset, offset, size) ---- - - Description ---- Copy input data in current environment to memory - - Inputs ---- - dest_offset: byte offset in the memory where the result will - be copied - offset: byte offset in the calldata to copy - size: byte size - to copy + Source: [evm.codes/#5F](https://www.evm.codes/#5F) + """ - Outputs ---- - None + PUSH1 = Opcode(0x60, pushed_stack_items=1, data_portion_length=1) + """ + PUSH1() = value + ---- - Fork ---- Frontier + Description + ---- + Place 1 byte item on stack - Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 3 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + Inputs + ---- + - None - Source: [evm.codes/#37](https://www.evm.codes/#37) + Outputs + ---- + - value: pushed value, aligned to the right (put in the + lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#60](https://www.evm.codes/#60) """ - CODESIZE = Opcode(0x38, pushed_stack_items=1) + PUSH2 = Opcode(0x61, pushed_stack_items=1, data_portion_length=2) """ + PUSH2() = value + ---- + Description + ---- + Place 2 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in the lowest + significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - CODESIZE() = size ---- - - Description ---- Get size of code running in current environment - - Inputs ---- - None + Source: [evm.codes/#61](https://www.evm.codes/#61) + """ - Outputs ---- - size: byte size of the code + PUSH3 = Opcode(0x62, pushed_stack_items=1, data_portion_length=3) + """ + PUSH3() = value + ---- - Fork ---- Frontier + Description + ---- + Place 3 byte item on stack - Gas ---- 2 + Inputs + ---- + - None - Source: [evm.codes/#38](https://www.evm.codes/#38) + Outputs + ---- + - value: pushed value, aligned to the right (put in the + lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#62](https://www.evm.codes/#62) """ - CODECOPY = Opcode(0x39, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) + PUSH4 = Opcode(0x63, pushed_stack_items=1, data_portion_length=4) """ + PUSH4() = value + ---- + Description + ---- + Place 4 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in the lowest + significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - CODECOPY(dest_offset, offset, size) ---- - - Description ---- Copy code running in current environment to memory + Source: [evm.codes/#63](https://www.evm.codes/#63) + """ - Inputs ---- - dest_offset: byte offset in the memory where the result will - be copied. - offset: byte offset in the code to copy. - size: byte size to - copy + PUSH5 = Opcode(0x64, pushed_stack_items=1, data_portion_length=5) + """ + PUSH5() = value + ---- - Fork ---- Frontier + Description + ---- + Place 5 byte item on stack - Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 3 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + Inputs + ---- + - None - Source: [evm.codes/#39](https://www.evm.codes/#39) + Outputs + ---- + - value: pushed value, aligned to the right (put in the lowest + significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#64](https://www.evm.codes/#64) """ - GASPRICE = Opcode(0x3A, pushed_stack_items=1) + PUSH6 = Opcode(0x65, pushed_stack_items=1, data_portion_length=6) """ + PUSH6() = value + ---- + Description + ---- + Place 6 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in the + lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - GASPRICE() = price ---- - - Description ---- Get price of gas in current environment + Source: [evm.codes/#65](https://www.evm.codes/#65) + """ - Outputs ---- - price: gas price in wei per gas + PUSH7 = Opcode(0x66, pushed_stack_items=1, data_portion_length=7) + """ + PUSH7() = value + ---- - Fork ---- Frontier + Description + ---- + Place 7 byte item on stack - Gas ---- 2 + Inputs + ---- + - None - Source: [evm.codes/#3A](https://www.evm.codes/#3A) + Outputs + ---- + - value: pushed value, aligned to the right (put in the + lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#66](https://www.evm.codes/#66) """ - EXTCODESIZE = Opcode(0x3B, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) + PUSH8 = Opcode(0x67, pushed_stack_items=1, data_portion_length=8) """ + PUSH8() = value + ---- + Description + ---- + Place 8 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in the + lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - EXTCODESIZE(address) = size ---- - - Description ---- Get size of an account's code - - Inputs ---- - address: 20-byte address of the contract to query + Source: [evm.codes/#67](https://www.evm.codes/#67) + """ - Outputs ---- - size: byte size of the code + PUSH9 = Opcode(0x68, pushed_stack_items=1, data_portion_length=9) + """ + PUSH9() = value + ---- - Fork ---- Frontier + Description + ---- + Place 9 byte item on stack - Gas ---- - static_gas = 0 - dynamic_gas = 100 if warm_address, 2600 if - cold_address + Inputs + ---- + - None - Source: [evm.codes/#3B](https://www.evm.codes/#3B) + Outputs + ---- + - value: pushed value, aligned to the right (put in the + lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#68](https://www.evm.codes/#68) """ - EXTCODECOPY = Opcode( - 0x3C, popped_stack_items=4, kwargs=["address", "dest_offset", "offset", "size"] - ) + PUSH10 = Opcode(0x69, pushed_stack_items=1, data_portion_length=10) """ + PUSH10() = value + ---- + Description + ---- + Place 10 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - EXTCODECOPY(address, dest_offset, offset, size) ---- - - Description ---- Copy an account's code to memory - - Inputs ---- - address: 20-byte address of the contract to query - - dest_offset: byte offset in the memory where the result will be copied - - offset: byte offset in the code to copy - size: byte size to copy + Source: [evm.codes/#69](https://www.evm.codes/#69) + """ - Outputs ---- - None + PUSH11 = Opcode(0x6A, pushed_stack_items=1, data_portion_length=11) + """ + PUSH11() = value + ---- - Fork ---- Frontier + Description + ---- + Place 11 byte item on stack - Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 0 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + - address_access_cost + Inputs + ---- + - None - Source: [evm.codes/#3C](https://www.evm.codes/#3C) + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#6A](https://www.evm.codes/#6A) """ - RETURNDATASIZE = Opcode(0x3D, pushed_stack_items=1) + PUSH12 = Opcode(0x6B, pushed_stack_items=1, data_portion_length=12) """ + PUSH12() = value + ---- + Description + ---- + Place 12 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in the + lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - RETURNDATASIZE() = size ---- - - Description ---- Get size of output data from the previous call from the - current environment + Source: [evm.codes/#6B](https://www.evm.codes/#6B) + """ - Outputs ---- - size: byte size of the return data from the last executed - sub context + PUSH13 = Opcode(0x6C, pushed_stack_items=1, data_portion_length=13) + """ + PUSH13() = value + ---- - Fork ---- Byzantium + Description + ---- + Place 13 byte item on stack - Gas ---- 2 + Inputs + ---- + - None - Source: [evm.codes/#3D](https://www.evm.codes/#3D) + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#6C](https://www.evm.codes/#6C) """ - RETURNDATACOPY = Opcode(0x3E, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) + PUSH14 = Opcode(0x6D, pushed_stack_items=1, data_portion_length=14) """ + PUSH14() = value + ---- + Description + ---- + Place 14 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier - RETURNDATACOPY(dest_offset, offset, size) ---- + Gas + ---- + 3 - Description ---- Copy output data from the previous call to memory + Source: [evm.codes/#6D](https://www.evm.codes/#6D) + """ - Inputs ---- - dest_offset: byte offset in the memory where the result will - be copied - offset: byte offset in the return data from the last executed - sub context to copy - size: byte size to copy + PUSH15 = Opcode(0x6E, pushed_stack_items=1, data_portion_length=15) + """ + PUSH15() = value + ---- - Fork ---- Byzantium + Description + ---- + Place 15 byte item on stack - Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 3 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + Inputs + ---- + - None - Source: [evm.codes/#3E](https://www.evm.codes/#3E) + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#6E](https://www.evm.codes/#6E) """ - EXTCODEHASH = Opcode(0x3F, popped_stack_items=1, pushed_stack_items=1, kwargs=["address"]) + PUSH16 = Opcode(0x6F, pushed_stack_items=1, data_portion_length=16) """ + PUSH16() = value + ---- + Description + ---- + Place 16 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - EXTCODEHASH(address) = hash ---- - - Description ---- Get hash of an account's code - - Inputs ---- - address: 20-byte address of the account + Source: [evm.codes/#6F](https://www.evm.codes/#6F) + """ - Outputs ---- - hash: hash of the chosen account's code, the empty hash - (0xc5d24601...) if the account has no code, or 0 if the account does not - exist or has been destroyed + PUSH17 = Opcode(0x70, pushed_stack_items=1, data_portion_length=17) + """ + PUSH17() = value + ---- - Fork ---- Constantinople + Description + ---- + Place 17 byte item on stack - Gas ---- - static_gas = 0 - dynamic_gas = 100 if warm_address, 2600 if - cold_address + Inputs + ---- + - None - Source: [evm.codes/#3F](https://www.evm.codes/#3F) + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#70](https://www.evm.codes/#70) """ - BLOCKHASH = Opcode(0x40, popped_stack_items=1, pushed_stack_items=1, kwargs=["block_number"]) + PUSH18 = Opcode(0x71, pushed_stack_items=1, data_portion_length=18) """ + PUSH18() = value + ---- + Description + ---- + Place 18 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - BLOCKHASH(block_number) = hash ---- - - Description ---- Get the hash of one of the 256 most recent complete blocks - - Inputs ---- - blockNumber: block number to get the hash from. Valid range - is the last 256 blocks (not including the current one). Current block - number can be queried with NUMBER + Source: [evm.codes/#71](https://www.evm.codes/#71) + """ - Outputs ---- - hash: hash of the chosen block, or 0 if the block number is - not in the valid range + PUSH19 = Opcode(0x72, pushed_stack_items=1, data_portion_length=19) + """ + PUSH19() = value + ---- - Fork ---- Frontier + Description + ---- + Place 19 byte item on stack - Gas ---- 20 + Inputs + ---- + - None - Source: [evm.codes/#40](https://www.evm.codes/#40) + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#72](https://www.evm.codes/#72) """ - COINBASE = Opcode(0x41, pushed_stack_items=1) + PUSH20 = Opcode(0x73, pushed_stack_items=1, data_portion_length=20) """ + PUSH20() = value + ---- + Description + ---- + Place 20 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - COINBASE() = address ---- - - Description ---- Get the block's beneficiary address - - Inputs ---- - None + Source: [evm.codes/#73](https://www.evm.codes/#73) + """ - Outputs ---- - address: miner's 20-byte address + PUSH21 = Opcode(0x74, pushed_stack_items=1, data_portion_length=21) + """ + PUSH21() = value + ---- - Fork ---- Frontier + Description + ---- + Place 21 byte item on stack - Gas ---- 2 + Inputs + ---- + - None - Source: [evm.codes/#41](https://www.evm.codes/#41) + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#74](https://www.evm.codes/#74) """ - TIMESTAMP = Opcode(0x42, pushed_stack_items=1) + PUSH22 = Opcode(0x75, pushed_stack_items=1, data_portion_length=22) """ + PUSH22() = value + ---- + Description + ---- + Place 22 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - TIMESTAMP() = timestamp ---- - - Description ---- Get the block's timestamp - - Inputs ---- - None + Source: [evm.codes/#75](https://www.evm.codes/#75) + """ - Outputs ---- - timestamp: unix timestamp of the current block + PUSH23 = Opcode(0x76, pushed_stack_items=1, data_portion_length=23) + """ + PUSH23() = value + ---- - Fork ---- Frontier + Description + ---- + Place 23 byte item on stack - Gas ---- 2 + Inputs + ---- + - None - Source: [evm.codes/#42](https://www.evm.codes/#42) + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#76](https://www.evm.codes/#76) """ - NUMBER = Opcode(0x43, pushed_stack_items=1) + PUSH24 = Opcode(0x77, pushed_stack_items=1, data_portion_length=24) """ + PUSH24() = value + ---- + Description + ---- + Place 24 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - NUMBER() = blockNumber ---- - - Description ---- Get the block's number - - Inputs ---- - None + Source: [evm.codes/#77](https://www.evm.codes/#77) + """ - Outputs ---- - blockNumber: current block number + PUSH25 = Opcode(0x78, pushed_stack_items=1, data_portion_length=25) + """ + PUSH25() = value + ---- - Fork ---- Frontier + Description + ---- + Place 25 byte item on stack - Gas ---- 2 + Inputs + ---- + - None - Source: [evm.codes/#43](https://www.evm.codes/#43) + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#78](https://www.evm.codes/#78) """ - PREVRANDAO = Opcode(0x44, pushed_stack_items=1) + PUSH26 = Opcode(0x79, pushed_stack_items=1, data_portion_length=26) """ + PUSH26() = value + ---- + Description + ---- + Place 26 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - PREVRANDAO() = prevRandao ---- - - Description ---- Get the previous block's RANDAO mix - - Inputs ---- - None + Source: [evm.codes/#79](https://www.evm.codes/#79) + """ - Outputs ---- - prevRandao: previous block's RANDAO mix + PUSH27 = Opcode(0x7A, pushed_stack_items=1, data_portion_length=27) + """ + PUSH27() = value + ---- - Fork ---- Merge + Description + ---- + Place 27 byte item on stack - Gas ---- 2 + Inputs + ---- + - None - Source: [evm.codes/#44](https://www.evm.codes/#44) + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#7A](https://www.evm.codes/#7A) """ - GASLIMIT = Opcode(0x45, pushed_stack_items=1) + PUSH28 = Opcode(0x7B, pushed_stack_items=1, data_portion_length=28) """ + PUSH28() = value + ---- + Description + ---- + Place 28 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - GASLIMIT() = gasLimit ---- - - Description ---- Get the block's gas limit - - Inputs ---- - None + Source: [evm.codes/#7B](https://www.evm.codes/#7B) + """ - Outputs ---- - gasLimit: gas limit + PUSH29 = Opcode(0x7C, pushed_stack_items=1, data_portion_length=29) + """ + PUSH29() = value + ---- - Fork ---- Frontier + Description + ---- + Place 29 byte item on stack - Gas ---- 2 + Inputs + ---- + - None - Source: [evm.codes/#45](https://www.evm.codes/#45) + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#7C](https://www.evm.codes/#7C) """ - CHAINID = Opcode(0x46, pushed_stack_items=1) + PUSH30 = Opcode(0x7D, pushed_stack_items=1, data_portion_length=30) """ + PUSH30() = value + ---- + Description + ---- + Place 30 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - CHAINID() = chainId ---- + Source: [evm.codes/#7D](https://www.evm.codes/#7D) + """ - Description ---- Get the chain ID + PUSH31 = Opcode(0x7E, pushed_stack_items=1, data_portion_length=31) + """ + PUSH31() = value + ---- - Inputs ---- - None + Description + ---- + Place 31 byte item on stack - Outputs ---- - chainId: chain id of the network + Inputs + ---- + - None - Fork ---- Istanbul - - Gas ---- 2 - - Source: [evm.codes/#46](https://www.evm.codes/#46) + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#7E](https://www.evm.codes/#7E) """ - SELFBALANCE = Opcode(0x47, pushed_stack_items=1) + PUSH32 = Opcode(0x7F, pushed_stack_items=1, data_portion_length=32) """ + PUSH32() = value + ---- + Description + ---- + Place 32 byte item on stack + Inputs + ---- + - None + Outputs + ---- + - value: pushed value, aligned to the right (put in + the lowest significant bytes) + Fork + ---- + Frontier + Gas + ---- + 3 - SELFBALANCE() = balance ---- - - Description ---- Get balance of currently executing account - - Inputs ---- - None - - Outputs ---- - balance: balance of the current account in wei - - Fork ---- Istanbul - - Gas ---- 5 - - Source: [evm.codes/#47](https://www.evm.codes/#47) - - - + Source: [evm.codes/#7F](https://www.evm.codes/#7F) """ - BASEFEE = Opcode(0x48, pushed_stack_items=1) + DUP1 = Opcode(0x80, pushed_stack_items=1, min_stack_height=1) """ + DUP1(value) = value, value + ---- + Description + ---- + Duplicate 1st stack item + Inputs + ---- + - value: value to duplicate + Outputs + ---- + - value: duplicated value + - value: original value + Fork + ---- + Frontier + Gas + ---- + 3 - BASEFEE() = baseFee ---- - - Description ---- Get the base fee + Source: [evm.codes/#80](https://www.evm.codes/#80) + """ - Outputs ---- - baseFee: base fee in wei + DUP2 = Opcode(0x81, pushed_stack_items=1, min_stack_height=2) + """ + DUP2(v1, v2) = v2, v1, v2 + ---- - Fork ---- London + Description + ---- + Duplicate 2nd stack item - Gas ---- 2 + Inputs + ---- + - v1: ignored value + - v2: value to duplicate - Source: [evm.codes/#48](https://www.evm.codes/#48) + Outputs + ---- + - v2: duplicated value + - v1: ignored value + - v2: original value + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#81](https://www.evm.codes/#81) """ - BLOBHASH = Opcode(0x49, popped_stack_items=1, pushed_stack_items=1, kwargs=["index"]) + DUP3 = Opcode(0x82, pushed_stack_items=1, min_stack_height=3) """ + DUP3(v1, v2, v3) = v3, v1, v2, v3 + ---- + Description + ---- + Duplicate 3rd stack item + Inputs + ---- + - v1: ignored value + - v2: ignored value + - v3: value to duplicate + Outputs + ---- + - v3: duplicated value + - v1: ignored value + - v2: ignored value + - v3: original value + Fork + ---- + Frontier + Gas + ---- + 3 - BLOBHASH(index) = versionedHash ---- - - Description ---- Returns the versioned hash of a single blob contained in - the type-3 transaction - - Inputs ---- - index: index of the blob + Source: [evm.codes/#82](https://www.evm.codes/#82) + """ - Outputs ---- - versionedHash: versioned hash of the blob + DUP4 = Opcode(0x83, pushed_stack_items=1, min_stack_height=4) + """ + DUP4(v1, v2, v3, v4) = v4, v1, v2, v3, v4 + ---- - Fork ---- Cancun + Description + ---- + Duplicate 4th stack item - Gas ---- 3 + Inputs + ---- + - v1: ignored value + - v2: ignored value + - v3: ignored value + - v4: value to duplicate - Source: - [eips.ethereum.org/EIPS/eip-4844](https://eips.ethereum.org/EIPS/eip-4844) + Outputs + ---- + - v4: duplicated value + - v1: ignored value + - v2: ignored value + - v3: ignored value + - v4: original value + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#83](https://www.evm.codes/#83) """ - BLOBBASEFEE = Opcode(0x4A, popped_stack_items=0, pushed_stack_items=1) + DUP5 = Opcode(0x84, pushed_stack_items=1, min_stack_height=5) """ + DUP5(v1, v2, v3, v4, v5) = v5, v1, v2, v3, v4, v5 + ---- + + Description + ---- + Duplicate 5th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - v3: ignored value + - v4: ignored value + - v5: value to duplicate + + Outputs + ---- + - v5: duplicated value + - v1: ignored value + - v2: ignored value + - v3: ignored value + - v4: ignored value + - v5: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#84](https://www.evm.codes/#84) + """ + DUP6 = Opcode(0x85, pushed_stack_items=1, min_stack_height=6) + """ + DUP6(v1, v2, ..., v5, v6) = v6, v1, v2, ..., v5, v6 + ---- + + Description + ---- + Duplicate 6th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - ... + - v5: ignored value + - v6: value to duplicate + + Outputs + ---- + - v6: duplicated value + - v1: ignored value + - v2: ignored value + - ... + - v5: ignored value + - v6: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#85](https://www.evm.codes/#85) + """ + DUP7 = Opcode(0x86, pushed_stack_items=1, min_stack_height=7) + """ + DUP7(v1, v2, ..., v6, v7) = v7, v1, v2, ..., v6, v7 + ---- + + Description + ---- + Duplicate 7th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - ... + - v6: ignored value + - v7: value to duplicate + + Outputs + ---- + - v7: duplicated value + - v1: ignored value + - v2: ignored value + - ... + - v6: ignored value + - v7: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#86](https://www.evm.codes/#86) + """ - BLOBBASEFEE() = fee ---- - - Description ---- Returns the value of the blob base fee of the block it is - executing in - - Inputs ---- - None + DUP8 = Opcode(0x87, pushed_stack_items=1, min_stack_height=8) + """ + DUP8(v1, v2, ..., v7, v8) = v8, v1, v2, ..., v7, v8 + ---- + + Description + ---- + Duplicate 8th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - ... + - v7: ignored value + - v8: value to duplicate + + Outputs + ---- + - v8: duplicated value + - v1: ignored value + - v2: ignored value + - ... + - v7: ignored value + - v8: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 - Outputs ---- - baseFeePerBlobGas: base fee for the blob gas in wei + Source: [evm.codes/#87](https://www.evm.codes/#87) + """ - Fork ---- Cancun + DUP9 = Opcode(0x88, pushed_stack_items=1, min_stack_height=9) + """ + DUP9(v1, v2, ..., v8, v9) = v9, v1, v2, ..., v8, v9 + ---- + + Description + ---- + Duplicate 9th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - ... + - v8: ignored value + - v9: value to duplicate + + Outputs + ---- + - v9: duplicated value + - v1: ignored value + - v2: ignored value + - ... + - v8: ignored value + - v9: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 - Gas ---- 2 + Source: [evm.codes/#88](https://www.evm.codes/#88) + """ + DUP10 = Opcode(0x89, pushed_stack_items=1, min_stack_height=10) + """ + DUP10(v1, v2, ..., v9, v10) = v10, v1, v2, ..., v9, v10 + ---- + + Description + ---- + Duplicate 10th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - ... + - v9: ignored value + - v10: value to duplicate + + Outputs + ---- + - v10: duplicated value + - v1: ignored value + - v2: ignored value + - ... + - v9: ignored value + - v10: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 - Source: - [eips.ethereum.org/EIPS/eip-7516](https://eips.ethereum.org/EIPS/eip-7516) + Source: [evm.codes/#89](https://www.evm.codes/#89) + """ + DUP11 = Opcode(0x8A, pushed_stack_items=1, min_stack_height=11) + """ + DUP11(v1, v2, ..., v10, v11) = v11, v1, v2, ..., v10, v11 + ---- + + Description + ---- + Duplicate 11th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - ... + - v10: ignored value + - v11: value to duplicate + + Outputs + ---- + - v11: duplicated value + - v1: ignored value + - v2: ignored value + - ... + - v10: ignored value + - v11: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#8A](https://www.evm.codes/#8A) + """ + DUP12 = Opcode(0x8B, pushed_stack_items=1, min_stack_height=12) """ + DUP12(v1, v2, ..., v11, v12) = v12, v1, v2, ..., v11, v12 + ---- + + Description + ---- + Duplicate 12th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - ... + - v11: ignored value + - v12: value to duplicate + + Outputs + ---- + - v12: duplicated value + - v1: ignored value + - v2: ignored value + - ... + - v11: ignored value + - v12: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 - POP = Opcode(0x50, popped_stack_items=1) + Source: [evm.codes/#8B](https://www.evm.codes/#8B) """ + DUP13 = Opcode(0x8C, pushed_stack_items=1, min_stack_height=13) + """ + DUP13(v1, v2, ..., v12, v13) = v13, v1, v2, ..., v12, v13 + ---- + + Description + ---- + Duplicate 13th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - ... + - v12: ignored value + - v13: value to duplicate + + Outputs + ---- + - v13: duplicated value + - v1: ignored value + - v2: ignored value + - ... + - v12: ignored value + - v13: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#8C](https://www.evm.codes/#8C) + """ + DUP14 = Opcode(0x8D, pushed_stack_items=1, min_stack_height=14) + """ + DUP14(v1, v2, ..., v13, v14) = v14, v1, v2, ..., v13, v14 + ---- + + Description + ---- + Duplicate 14th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - ... + - v13: ignored value + - v14: value to duplicate + + Outputs + ---- + - v14: duplicated value + - v1: ignored value + - v2: ignored value + - ... + - v13: ignored value + - v14: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#8D](https://www.evm.codes/#8D) + """ + DUP15 = Opcode(0x8E, pushed_stack_items=1, min_stack_height=15) + """ + DUP15(v1, v2, ..., v14, v15) = v15, v1, v2, ..., v14, v15 + ---- + + Description + ---- + Duplicate 15th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - ... + - v14: ignored value + - v15: value to duplicate + + Outputs + ---- + - v15: duplicated value + - v1: ignored value + - v2: ignored value + - ... + - v14: ignored value + - v15: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 - POP() ---- + Source: [evm.codes/#8E](https://www.evm.codes/#8E) + """ - Description ---- Remove item from stack + DUP16 = Opcode(0x8F, pushed_stack_items=1, min_stack_height=16) + """ + DUP16(v1, v2, ..., v15, v16) = v16, v1, v2, ..., v15, v16 + ---- + + Description + ---- + Duplicate 16th stack item + + Inputs + ---- + - v1: ignored value + - v2: ignored value + - ... + - v15: ignored value + - v16: value to duplicate + + Outputs + ---- + - v16: duplicated value + - v1: ignored value + - v2: ignored value + - ... + - v15: ignored value + - v16: original value + + Fork + ---- + Frontier + + Gas + ---- + 3 - Inputs ---- - None + Source: [evm.codes/#8F](https://www.evm.codes/#8F) + """ - Outputs ---- - None + SWAP1 = Opcode(0x90, min_stack_height=2) + """ + SWAP1(v1, v2) = v2, v1 + ---- - Fork ---- Frontier + Description + ---- + Exchange the top stack item with the second stack item. - Gas ---- 2 + Inputs + ---- + - v1: value to swap + - v2: value to swap - Source: [evm.codes/#50](https://www.evm.codes/#50) + Outputs + ---- + - v1: swapped value + - v2: swapped value + Fork + ---- + Frontier + Gas + ---- + 3 + Source: [evm.codes/#90](https://www.evm.codes/#90) """ - MLOAD = Opcode(0x51, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) + SWAP2 = Opcode(0x91, min_stack_height=3) """ + SWAP2(v1, v2, v3) = v3, v2, v1 + ---- + Description + ---- + Exchange 1st and 3rd stack items + Inputs + ---- + - v1: value to swap + - v2: ignored value + - v3: value to swap + Outputs + ---- + - v3: swapped value + - v2: ignored value + - v1: swapped value + Fork + ---- + Frontier + Gas + ---- + 3 - MLOAD(offset) = value ---- + Source: [evm.codes/#91](https://www.evm.codes/#91) + """ - Description ---- Load word from memory + SWAP3 = Opcode(0x92, min_stack_height=4) + """ + SWAP3(v1, v2, v3, v4) = v4, v2, v3, v1 + ---- - Inputs ---- - offset: offset in the memory in bytes + Description + ---- + Exchange 1st and 4th stack items - Outputs ---- - value: the 32 bytes in memory starting at that offset. If it - goes beyond its current size (see MSIZE), writes 0s + Inputs + ---- + - v1: value to swap + - v2: ignored value + - v3: ignored value + - v4: value to swap - Fork ---- Frontier + Outputs + ---- + - v4: swapped value + - v2: ignored value + - v3: ignored value + - v1: swapped value - Gas ---- - static_gas = 3 - dynamic_gas = memory_expansion_cost + Fork + ---- + Frontier - Source: [evm.codes/#51](https://www.evm.codes/#51) + Gas + ---- + 3 + Source: [evm.codes/#92](https://www.evm.codes/#92) + """ + SWAP4 = Opcode(0x93, min_stack_height=5) + """ + SWAP4(v1, v2, ..., v4, v5) = v5, v2, ..., v4, v1 + ---- + + Description + ---- + Exchange 1st and 5th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v4: ignored value + - v5: value to swap + + Outputs + ---- + - v5: swapped value + - v2: ignored value + - ... + - v4: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#93](https://www.evm.codes/#93) """ - MSTORE = Opcode(0x52, popped_stack_items=2, kwargs=["offset", "value"]) + SWAP5 = Opcode(0x94, min_stack_height=6) """ + SWAP5(v1, v2, ..., v5, v6) = v6, v2, ..., v5, v1 + ---- + + Description + ---- + Exchange 1st and 6th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v5: ignored value + - v6: value to swap + + Outputs + ---- + - v6: swapped value + - v2: ignored value + - ... + - v5: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#94](https://www.evm.codes/#94) + """ + SWAP6 = Opcode(0x95, min_stack_height=7) + """ + SWAP6(v1, v2, ..., v6, v7) = v7, v2, ..., v6, v1 + ---- + + Description + ---- + Exchange 1st and 7th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v6: ignored value + - v7: value to swap + + Outputs + ---- + - v7: swapped value + - v2: ignored value + - ... + - v6: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#95](https://www.evm.codes/#95) + """ + SWAP7 = Opcode(0x96, min_stack_height=8) + """ + SWAP7(v1, v2, ..., v7, v8) = v8, v2, ..., v7, v1 + ---- + + Description + ---- + Exchange 1st and 8th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v7: ignored value + - v8: value to swap + + Outputs + ---- + - v8: swapped value + - v2: ignored value + - ... + - v7: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#96](https://www.evm.codes/#96) + """ - MSTORE(offset, value) ---- + SWAP8 = Opcode(0x97, min_stack_height=9) + """ + SWAP8(v1, v2, ..., v8, v9) = v9, v2, ..., v8, v1 + ---- + + Description + ---- + Exchange 1st and 9th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v8: ignored value + - v9: value to swap + + Outputs + ---- + - v9: swapped value + - v2: ignored value + - ... + - v8: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 - Description ---- Save word to memory + Source: [evm.codes/#97](https://www.evm.codes/#97) + """ - Inputs ---- - offset: offset in the memory in bytes - value: 32-byte value - to write in the memory + SWAP9 = Opcode(0x98, min_stack_height=10) + """ + SWAP9(v1, v2, ..., v9, v10) = v10, v2, ..., v9, v1 + ---- + + Description + ---- + Exchange 1st and 10th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v9: ignored value + - v10: value to swap + + Outputs + ---- + - v10: swapped value + - v2: ignored value + - ... + - v9: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 - Outputs ---- - None + Source: [evm.codes/#98](https://www.evm.codes/#98) + """ - Fork ---- Frontier + SWAP10 = Opcode(0x99, min_stack_height=11) + """ + SWAP10(v1, v2, ..., v10, v11) = v11, v2, ..., v10, v1 + ---- + + Description + ---- + Exchange 1st and 11th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v10: ignored value + - v11: value to swap + + Outputs + ---- + - v11: swapped value + - v2: ignored value + - ... + - v10: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 - Gas ---- - static_gas = 3 - dynamic_gas = memory_expansion_cost + Source: [evm.codes/#99](https://www.evm.codes/#99) + """ - Source: [evm.codes/#52](https://www.evm.codes/#52) + SWAP11 = Opcode(0x9A, min_stack_height=12) + """ + SWAP11(v1, v2, ..., v11, v12) = v12, v2, ..., v11, v1 + ---- + + Description + ---- + Exchange 1st and 12th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v11: ignored value + - v12: value to swap + + Outputs + ---- + - v12: swapped value + - v2: ignored value + - ... + - v11: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#9A](https://www.evm.codes/#9A) + """ + SWAP12 = Opcode(0x9B, min_stack_height=13) + """ + SWAP12(v1, v2, ..., v12, v13) = v13, v2, ..., v12, v1 + ---- + + Description + ---- + Exchange 1st and 13th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v12: ignored value + - v13: value to swap + + Outputs + ---- + - v13: swapped value + - v2: ignored value + - ... + - v12: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#9B](https://www.evm.codes/#9B) """ - MSTORE8 = Opcode(0x53, popped_stack_items=2, kwargs=["offset", "value"]) + SWAP13 = Opcode(0x9C, min_stack_height=14) """ + SWAP13(v1, v2, ..., v13, v14) = v14, v2, ..., v13, v1 + ---- + + Description + ---- + Exchange 1st and 14th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v13: ignored value + - v14: value to swap + + Outputs + ---- + - v14: swapped value + - v2: ignored value + - ... + - v13: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#9C](https://www.evm.codes/#9C) + """ + SWAP14 = Opcode(0x9D, min_stack_height=15) + """ + SWAP14(v1, v2, ..., v14, v15) = v15, v2, ..., v14, v1 + ---- + + Description + ---- + Exchange 1st and 15th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v14: ignored value + - v15: value to swap + + Outputs + ---- + - v15: swapped value + - v2: ignored value + - ... + - v14: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#9D](https://www.evm.codes/#9D) + """ + SWAP15 = Opcode(0x9E, min_stack_height=16) + """ + SWAP15(v1, v2, ..., v15, v16) = v16, v2, ..., v15, v1 + ---- + + Description + ---- + Exchange 1st and 16th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v15: ignored value + - v16: value to swap + + Outputs + ---- + - v16: swapped value + - v2: ignored value + - ... + - v15: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 + Source: [evm.codes/#9E](https://www.evm.codes/#9E) + """ - MSTORE8(offset, value) ---- + SWAP16 = Opcode(0x9F, min_stack_height=17) + """ + SWAP16(v1, v2, ..., v16, v17) = v17, v2, ..., v16, v1 + ---- + + Description + ---- + Exchange 1st and 17th stack items + + Inputs + ---- + - v1: value to swap + - v2: ignored value + - ... + - v16: ignored value + - v17: value to swap + + Outputs + ---- + - v17: swapped value + - v2: ignored value + - ... + - v16: ignored value + - v1: swapped value + + Fork + ---- + Frontier + + Gas + ---- + 3 - Description ---- Save byte to memory + Source: [evm.codes/#9F](https://www.evm.codes/#9F) + """ - Inputs ---- - offset: offset in the memory in bytes - value: 1-byte value - to write in the memory (the least significant byte of the 32-byte stack - value) + LOG0 = Opcode(0xA0, popped_stack_items=2, kwargs=["offset", "size"]) + """ + LOG0(offset, size) + ---- - Fork ---- Frontier + Description + ---- + Append log record with no topics - Gas ---- - static_gas = 3 - dynamic_gas = memory_expansion_cost + Inputs + ---- + - offset: byte offset in the memory in bytes + - size: byte size to copy - Source: [evm.codes/#53](https://www.evm.codes/#53) + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + - static_gas = 375 + - dynamic_gas = 375 * topic_count + 8 * size + memory_expansion_cost + Source: [evm.codes/#A0](https://www.evm.codes/#A0) """ - SLOAD = Opcode(0x54, popped_stack_items=1, pushed_stack_items=1, kwargs=["key"]) + LOG1 = Opcode(0xA1, popped_stack_items=3, kwargs=["offset", "size", "topic_1"]) """ + LOG1(offset, size, topic_1) + ---- + Description + ---- + Append log record with one topic + Inputs + ---- + - offset: byte offset in the memory in bytes + - size: byte size to copy + - topic_1: 32-byte value + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + - static_gas = 375 + - dynamic_gas = 375 * topic_count + 8 * size + memory_expansion_cost - SLOAD(key) = value ---- - - Description ---- Load word from storage - - Inputs ---- - key: 32-byte key in storage + Source: [evm.codes/#A1](https://www.evm.codes/#A1) + """ - Outputs ---- - value: 32-byte value corresponding to that key. 0 if that - key was never written before + LOG2 = Opcode(0xA2, popped_stack_items=4, kwargs=["offset", "size", "topic_1", "topic_2"]) + """ + LOG2(offset, size, topic_1, topic_2) + ---- - Fork ---- Frontier + Description + ---- + Append log record with two topics - Gas ---- - static_gas = 0 - dynamic_gas = 100 if warm_address, 2600 if - cold_address + Inputs + ---- + - offset: byte offset in the memory in bytes + - size: byte size to copy + - topic_1: 32-byte value + - topic_2: 32-byte value - Source: [evm.codes/#54](https://www.evm.codes/#54) + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + - static_gas = 375 + - dynamic_gas = 375 * topic_count + 8 * size + memory_expansion_cost + Source: [evm.codes/#A2](https://www.evm.codes/#A2) """ - SSTORE = Opcode(0x55, popped_stack_items=2, kwargs=["key", "value"]) + LOG3 = Opcode( + 0xA3, popped_stack_items=5, kwargs=["offset", "size", "topic_1", "topic_2", "topic_3"] + ) """ + LOG3(offset, size, topic_1, topic_2, topic_3) + ---- + Description + ---- + Append log record with three topics + Inputs + ---- + - offset: byte offset in the memory in bytes + - size: byte size to copy + - topic_1: 32-byte value + - topic_2: 32-byte value + - topic_3: 32-byte value + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + - static_gas = 375 + - dynamic_gas = 375 * topic_count + 8 * size + memory_expansion_cost - SSTORE(key, value) ---- - - Description ---- Save word to storage - - Inputs ---- - key: 32-byte key in storage - value: 32-byte value to store - - Outputs ---- - None - - Fork ---- Frontier + Source: [evm.codes/#A3](https://www.evm.codes/#A3) + """ - Gas ---- ``` static_gas = 0 + LOG4 = Opcode( + 0xA4, + popped_stack_items=6, + kwargs=["offset", "size", "topic_1", "topic_2", "topic_3", "topic_4"], + ) + """ + LOG4(offset, size, topic_1, topic_2, topic_3, topic_4) + ---- - if value == current_value if key is warm base_dynamic_gas = 100 else - base_dynamic_gas = 100 else if current_value == original_value if - original_value == 0 base_dynamic_gas = 20000 else base_dynamic_gas = 2900 - else base_dynamic_gas = 100 + Description + ---- + Append log record with four topics - if key is cold: base_dynamic_gas += 2100 ``` + Inputs + ---- + - offset: byte offset in the memory in bytes + - size: byte size to copy + - topic_1: 32-byte value + - topic_2: 32-byte value + - topic_3: 32-byte value + - topic_4: 32-byte value - Source: [evm.codes/#55](https://www.evm.codes/#55) + Outputs + ---- + - None + Fork + ---- + Frontier + Gas + ---- + - static_gas = 375 + - dynamic_gas = 375 * topic_count + 8 * size + memory_expansion_cost + Source: [evm.codes/#A4](https://www.evm.codes/#A4) """ - JUMP = Opcode(0x56, popped_stack_items=1, kwargs=["pc"]) + RJUMP = Opcode(0xE0, data_portion_length=2) """ + !!! Note: This opcode is under development + RJUMP() + ---- + Description + ---- + Inputs + ---- + Outputs + ---- + Fork + ---- + EOF Fork - JUMP(pc) ---- + Gas + ---- - Description ---- Alter the program counter + Source: [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/ + eip-4200) + """ - Inputs ---- - pc: byte offset in the deployed code where execution will - continue from. Must be a JUMPDEST instruction + DATALOAD = Opcode(0xD0, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) + """ + !!! Note: This opcode is under development - Outputs ---- - None + DATALOAD(offset) + ---- - Fork ---- Frontier + Description + ---- + Reads 32 bytes of data at offset onto the stack - Gas ---- 8 + Inputs + ---- + - offset: offset within the data section to start copying - Source: [evm.codes/#56](https://www.evm.codes/#56) + Outputs + ---- + none + Fork + ---- + EOF Fork + Gas + ---- + 4 + Source: [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/ + eip-7480) """ - JUMPI = Opcode(0x57, popped_stack_items=2, kwargs=["pc", "condition"]) + DATALOADN = Opcode(0xD1, pushed_stack_items=1, data_portion_length=2) """ + !!! Note: This opcode is under development + DATALOADN() + ---- + Description + ---- + Reads 32 bytes of data at offset onto the stack + Immediates + ---- + 2 bytes forming a UInt16, which is the offset into the data section. + Inputs + ---- + none + Outputs + ---- + none - JUMPI(pc, condition) ---- - - Description ---- Conditionally alter the program counter - - Inputs ---- - pc: byte offset in the deployed code where execution will - continue from. Must be a JUMPDEST instruction - condition: the program - counter will be altered with the new value only if this value is different - from 0. Otherwise, the program counter is simply incremented and the next - instruction will be executed - - Fork ---- Frontier - - Gas ---- 10 - - Source: [evm.codes/#57](https://www.evm.codes/#57) - + Fork + ---- + EOF Fork + Gas + ---- + 3 + Source: [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/ + eip-7480) """ - PC = Opcode(0x58, pushed_stack_items=1) + DATASIZE = Opcode(0xD2, pushed_stack_items=1) """ + !!! Note: This opcode is under development + DATASIZE() + ---- + Description + ---- + Returns the size of the data section + Inputs + ---- + Outputs + ---- + The size of the data section. If there is no data section, returns 0. + Fork + ---- + EOF Fork - PC() = counter ---- + Gas + ---- + 2 - Description ---- Get the value of the program counter prior to the - increment corresponding to this instruction + Source: [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/ + eip-7480) + """ - Inputs ---- - None + DATACOPY = Opcode(0xD3, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) + """ + !!! Note: This opcode is under development - Outputs ---- - counter: PC of this instruction in the current program. + DATACOPY(dest_offset, offset, size) + ---- - Fork ---- Frontier + Description + ---- + Copies data from the data section into call frame memory - Gas ---- 2 + Inputs + ---- + - dest_offset: The offset within the memory section to start copying to + - offset: The offset within the data section to start copying from + - size: The number of bytes to copy - Source: [evm.codes/#58](https://www.evm.codes/#58) + Outputs + ---- + none + Fork + ---- + EOF Fork + Gas + ---- + - minimum_word_size = (size + 31) / 32 + - static_gas = 3 + - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost + Source: [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/ + eip-7480) """ - MSIZE = Opcode(0x59, pushed_stack_items=1) + RJUMPI = Opcode(0xE1, popped_stack_items=1, data_portion_length=2) """ + !!! Note: This opcode is under development + RJUMPI() + ---- + Description + ---- + Inputs + ---- + Outputs + ---- + Fork + ---- + EOF Fork - MSIZE() = size ---- - - Description ---- Get the size of active memory in bytes - - Outputs ---- - size: current memory size in bytes (higher offset accessed - until now + 1) - - Fork ---- Frontier - - Gas ---- 2 - - Source: [evm.codes/#59](https://www.evm.codes/#59) - - + Gas + ---- + Source: [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/ + eip-4200) """ - GAS = Opcode(0x5A, pushed_stack_items=1) + RJUMPV = Opcode( + 0xE2, + popped_stack_items=1, + data_portion_formatter=_rjumpv_encoder, + ) """ + !!! Note: This opcode is under development + RJUMPV() + ---- + Description + ---- + Relative jump with variable offset. + When calling this opcode to generate bytecode, the first argument is + used to format the data portion of the opcode, and it can be either + of two types: + - A bytes type, and in this instance the bytes are used verbatim + as the data portion. + - An integer iterable, list or tuple or any other iterable, where + each element is a jump offset. + Inputs + ---- + Outputs + ---- - GAS() = gas_remaining ---- - - Description ---- Get the amount of available gas, including the - corresponding reduction for the cost of this instruction - - Inputs ---- - None - - Outputs ---- - gas: remaining gas (after this instruction) - - Fork ---- Frontier - - Gas ---- 2 - - Source: [evm.codes/#5A](https://www.evm.codes/#5A) - + Fork + ---- + EOF Fork + Gas + ---- + Source: [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/ + eip-4200) """ - JUMPDEST = Opcode(0x5B) + CALLF = Opcode(0xE3, data_portion_length=2, unchecked_stack=True) """ + !!! Note: This opcode is under development + CALLF() + ---- + Description + ---- + - deduct 5 gas + - read uint16 operand idx + - if 1024 < len(stack) + types[idx].max_stack_height - types[idx].inputs, + execution results in an exceptional halt + - if 1024 <= len(return_stack), execution results in an exceptional halt + - push new element to return_stack (current_code_idx, pc+3) + - update current_code_idx to idx and set pc to 0 + Inputs + ---- + Any: The inputs are not checked because we cannot know how many inputs + the callee function/section requires + Outputs + ---- + Any: The outputs are variable because we cannot know how many outputs the + callee function/section produces - JUMPDEST() ---- - - Description ---- Mark a valid destination for jumps - - Inputs ---- - None - - Outputs ---- - None - - Fork ---- Frontier - - Gas ---- 1 - - Source: [evm.codes/#5B](https://www.evm.codes/#5B) - + Fork + ---- + EOF Fork + Gas + ---- + 5 + Source: + [ipsilon/eof/blob/main/spec/eof.md](https://github.com/ipsilon/eof/blob/ + main/spec/eof.md) """ - NOOP = Opcode(0x5B) + RETF = Opcode(0xE4, terminating=True) """ + !!! Note: This opcode is under development + RETF() + ---- + Description + ---- + Inputs + ---- + Outputs + ---- + Fork + ---- + EOF Fork - NOOP() ---- - - Description ---- Synonym for JUMPDEST. Performs no operation. + Gas + ---- + 3 + """ - Inputs ---- - None + JUMPF = Opcode(0xE5, data_portion_length=2, terminating=True, unchecked_stack=True) + """ + !!! Note: This opcode is under development - Outputs ---- - None + JUMPF() + ---- - Fork ---- Frontier - - Gas ---- 1 - - Source: [evm.codes/#5B](https://www.evm.codes/#5B) - - - - """ - - TLOAD = Opcode(0x5C, popped_stack_items=1, pushed_stack_items=1, kwargs=["key"]) - """ - - - - - - - TLOAD(key) = value ---- - - Description ---- Load word from transient storage - - Inputs ---- - key: 32-byte key in transient storage - - Outputs ---- - value: 32-byte value corresponding to that key. 0 if that - key was never written - - Fork ---- Cancun - - Gas ---- 100 - - Source: - [eips.ethereum.org/EIPS/eip-1153](https://eips.ethereum.org/EIPS/eip-1153) - - - - """ - - TSTORE = Opcode(0x5D, popped_stack_items=2, kwargs=["key", "value"]) - """ - - - - - - - TSTORE(key, value) ---- - - Description ---- Save word to transient storage - - Inputs ---- - key: 32-byte key in transient storage - value: 32-byte value - to store - - Fork ---- Cancun - - Gas ---- 100 - - Source: - [eips.ethereum.org/EIPS/eip-1153](https://eips.ethereum.org/EIPS/eip-1153) - - - - """ - - MCOPY = Opcode(0x5E, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) - """ - - - - - - - MCOPY(dest_offset, offset, size) ---- - - Description ---- Copies areas in memory - - Inputs ---- - dest_offset: byte offset in the memory where the result will - be copied - offset: byte offset in the calldata to copy - size: byte size - to copy - - Outputs ---- - None - - Fork ---- Cancun - - Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 3 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost - - Source: - [eips.ethereum.org/EIPS/eip-5656](https://eips.ethereum.org/EIPS/eip-5656) - - - - """ - - PUSH0 = Opcode(0x5F, pushed_stack_items=1) - """ - - - - - - - PUSH0() = value ---- - - Description ---- Place value 0 on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, equal to 0 - - Fork ---- Shanghai - - Gas ---- 2 - - Source: [evm.codes/#5F](https://www.evm.codes/#5F) - - - - """ - - PUSH1 = Opcode(0x60, pushed_stack_items=1, data_portion_length=1) - """ - - - - - - - PUSH1() = value ---- - - Description ---- Place 1 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#60](https://www.evm.codes/#60) - - - - """ - - PUSH2 = Opcode(0x61, pushed_stack_items=1, data_portion_length=2) - """ - - - - - - - PUSH2() = value ---- - - Description ---- Place 2 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#61](https://www.evm.codes/#61) - - - - """ - - PUSH3 = Opcode(0x62, pushed_stack_items=1, data_portion_length=3) - """ - - - - - - - PUSH3() = value ---- - - Description ---- Place 3 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#62](https://www.evm.codes/#62) - - - - """ - - PUSH4 = Opcode(0x63, pushed_stack_items=1, data_portion_length=4) - """ - - - - - - - PUSH4() = value ---- - - Description ---- Place 4 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#63](https://www.evm.codes/#63) - - - - """ - - PUSH5 = Opcode(0x64, pushed_stack_items=1, data_portion_length=5) - """ - - - - - - - PUSH5() = value ---- - - Description ---- Place 5 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#64](https://www.evm.codes/#64) - - - - """ - - PUSH6 = Opcode(0x65, pushed_stack_items=1, data_portion_length=6) - """ - - - - - - - PUSH6() = value ---- - - Description ---- Place 6 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#65](https://www.evm.codes/#65) - - - - """ - - PUSH7 = Opcode(0x66, pushed_stack_items=1, data_portion_length=7) - """ - - - - - - - PUSH7() = value ---- - - Description ---- Place 7 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#66](https://www.evm.codes/#66) - - - - """ - - PUSH8 = Opcode(0x67, pushed_stack_items=1, data_portion_length=8) - """ - - - - - - - PUSH8() = value ---- - - Description ---- Place 8 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#67](https://www.evm.codes/#67) - - - - """ - - PUSH9 = Opcode(0x68, pushed_stack_items=1, data_portion_length=9) - """ - - - - - - - PUSH9() = value ---- - - Description ---- Place 9 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#68](https://www.evm.codes/#68) - - - - """ - - PUSH10 = Opcode(0x69, pushed_stack_items=1, data_portion_length=10) - """ - - - - - - - PUSH10() = value ---- - - Description ---- Place 10 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#69](https://www.evm.codes/#69) - - - - """ - - PUSH11 = Opcode(0x6A, pushed_stack_items=1, data_portion_length=11) - """ - - - - - - - PUSH11() = value ---- - - Description ---- Place 11 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#6A](https://www.evm.codes/#6A) - - - - """ - - PUSH12 = Opcode(0x6B, pushed_stack_items=1, data_portion_length=12) - """ - - - - - - - PUSH12() = value ---- - - Description ---- Place 12 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#6B](https://www.evm.codes/#6B) - - - - """ - - PUSH13 = Opcode(0x6C, pushed_stack_items=1, data_portion_length=13) - """ - - - - - - - PUSH13() = value ---- - - Description ---- Place 13 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#6C](https://www.evm.codes/#6C) - - - - """ - - PUSH14 = Opcode(0x6D, pushed_stack_items=1, data_portion_length=14) - """ - - - - - - - PUSH14() = value ---- - - Description ---- Place 14 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - - - - - Gas ---- 3 - - Source: [evm.codes/#6D](https://www.evm.codes/#6D) - - - - """ - - PUSH15 = Opcode(0x6E, pushed_stack_items=1, data_portion_length=15) - """ - - - - - - - PUSH15() = value ---- - - Description ---- Place 15 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#6E](https://www.evm.codes/#6E) - - - - """ - - PUSH16 = Opcode(0x6F, pushed_stack_items=1, data_portion_length=16) - """ - - - - - - - PUSH16() = value ---- - - Description ---- Place 16 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#6F](https://www.evm.codes/#6F) - - - - """ - - PUSH17 = Opcode(0x70, pushed_stack_items=1, data_portion_length=17) - """ - - - - - - - PUSH17() = value ---- - - Description ---- Place 17 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#70](https://www.evm.codes/#70) - - - - """ - - PUSH18 = Opcode(0x71, pushed_stack_items=1, data_portion_length=18) - """ - - - - - - - PUSH18() = value ---- - - Description ---- Place 18 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#71](https://www.evm.codes/#71) - - - - """ - - PUSH19 = Opcode(0x72, pushed_stack_items=1, data_portion_length=19) - """ - - - - - - - PUSH19() = value ---- - - Description ---- Place 19 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#72](https://www.evm.codes/#72) - - - - """ - - PUSH20 = Opcode(0x73, pushed_stack_items=1, data_portion_length=20) - """ - - - - - - - PUSH20() = value ---- - - Description ---- Place 20 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#73](https://www.evm.codes/#73) - - - - """ - - PUSH21 = Opcode(0x74, pushed_stack_items=1, data_portion_length=21) - """ - - - - - - - PUSH21() = value ---- - - Description ---- Place 21 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#74](https://www.evm.codes/#74) - - - - """ - - PUSH22 = Opcode(0x75, pushed_stack_items=1, data_portion_length=22) - """ - - - - - - - PUSH22() = value ---- - - Description ---- Place 22 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#75](https://www.evm.codes/#75) - - - - """ - - PUSH23 = Opcode(0x76, pushed_stack_items=1, data_portion_length=23) - """ - - - - - - - PUSH23() = value ---- - - Description ---- Place 23 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#76](https://www.evm.codes/#76) - - - - """ - - PUSH24 = Opcode(0x77, pushed_stack_items=1, data_portion_length=24) - """ - - - - - - - PUSH24() = value ---- - - Description ---- Place 24 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#77](https://www.evm.codes/#77) - - - - """ - - PUSH25 = Opcode(0x78, pushed_stack_items=1, data_portion_length=25) - """ - - - - - - - PUSH25() = value ---- - - Description ---- Place 25 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#78](https://www.evm.codes/#78) - - - - """ - - PUSH26 = Opcode(0x79, pushed_stack_items=1, data_portion_length=26) - """ - - - - - - - PUSH26() = value ---- - - Description ---- Place 26 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#79](https://www.evm.codes/#79) - - - - """ - - PUSH27 = Opcode(0x7A, pushed_stack_items=1, data_portion_length=27) - """ - - - - - - - PUSH27() = value ---- - - Description ---- Place 27 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#7A](https://www.evm.codes/#7A) - - - - """ - - PUSH28 = Opcode(0x7B, pushed_stack_items=1, data_portion_length=28) - """ - - - - - - - PUSH28() = value ---- - - Description ---- Place 28 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#7B](https://www.evm.codes/#7B) - - - - """ - - PUSH29 = Opcode(0x7C, pushed_stack_items=1, data_portion_length=29) - """ - - - - - - - PUSH29() = value ---- - - Description ---- Place 29 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#7C](https://www.evm.codes/#7C) - - - - """ - - PUSH30 = Opcode(0x7D, pushed_stack_items=1, data_portion_length=30) - """ - - - - - - - PUSH30() = value ---- - - Description ---- Place 30 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#7D](https://www.evm.codes/#7D) - - - - """ - - PUSH31 = Opcode(0x7E, pushed_stack_items=1, data_portion_length=31) - """ - - - - - - - PUSH31() = value ---- - - Description ---- Place 31 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#7E](https://www.evm.codes/#7E) - - - - """ - - PUSH32 = Opcode(0x7F, pushed_stack_items=1, data_portion_length=32) - """ - - - - - - - PUSH32() = value ---- - - Description ---- Place 32 byte item on stack - - Inputs ---- - None - - Outputs ---- - value: pushed value, aligned to the right (put in the lowest - significant bytes) - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#7F](https://www.evm.codes/#7F) - - - - """ - - DUP1 = Opcode(0x80, pushed_stack_items=1, min_stack_height=1) - """ - - - - - - - DUP1(value) = value, value ---- - - Description ---- Duplicate 1st stack item - - Inputs ---- - value: value to duplicate - - Outputs ---- - value: duplicated value - value: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#80](https://www.evm.codes/#80) - - - - """ - - DUP2 = Opcode(0x81, pushed_stack_items=1, min_stack_height=2) - """ - - - - - - - DUP2(v1, v2) = v2, v1, v2 ---- - - Description ---- Duplicate 2nd stack item - - Inputs ---- - v1: ignored value - v2: value to duplicate - - Outputs ---- - v2: duplicated value - v1: ignored value - v2: original - value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#81](https://www.evm.codes/#81) - - - - """ - - DUP3 = Opcode(0x82, pushed_stack_items=1, min_stack_height=3) - """ - - - - - - - DUP3(v1, v2, v3) = v3, v1, v2, v3 ---- - - Description ---- Duplicate 3rd stack item - - Inputs ---- - v1: ignored value - v2: ignored value - v3: value to - duplicate - - Outputs ---- - v3: duplicated value - v1: ignored value - v2: ignored value - - v3: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#82](https://www.evm.codes/#82) - - - - """ - - DUP4 = Opcode(0x83, pushed_stack_items=1, min_stack_height=4) - """ - - - - - - - DUP4(v1, v2, v3, v4) = v4, v1, v2, v3, v4 ---- - - Description ---- Duplicate 4th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - v3: ignored value - - v4: value to duplicate - - Outputs ---- - v4: duplicated value - v1: ignored value - v2: ignored value - - v3: ignored value - v4: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#83](https://www.evm.codes/#83) - - - - """ - - DUP5 = Opcode(0x84, pushed_stack_items=1, min_stack_height=5) - """ - - - - - - - DUP5(v1, v2, v3, v4, v5) = v5, v1, v2, v3, v4, v5 ---- - - Description ---- Duplicate 5th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - v3: ignored value - - v4: ignored value - v5: value to duplicate - - Outputs ---- - v5: duplicated value - v1: ignored value - v2: ignored value - - v3: ignored value - v4: ignored value - v5: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#84](https://www.evm.codes/#84) - - - - """ - - DUP6 = Opcode(0x85, pushed_stack_items=1, min_stack_height=6) - """ - - - - - - - DUP6(v1, v2, ..., v5, v6) = v6, v1, v2, ..., v5, v6 ---- - - Description ---- Duplicate 6th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - ... - v5: ignored - value - v6: value to duplicate - - Outputs ---- - v6: duplicated value - v1: ignored value - v2: ignored value - - ... - v5: ignored value - v6: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#85](https://www.evm.codes/#85) - - - - """ - - DUP7 = Opcode(0x86, pushed_stack_items=1, min_stack_height=7) - """ - - - - - - - DUP7(v1, v2, ..., v6, v7) = v7, v1, v2, ..., v6, v7 ---- - - Description ---- Duplicate 7th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - ... - v6: ignored - value - v7: value to duplicate - - Outputs ---- - v7: duplicated value - v1: ignored value - v2: ignored value - - ... - v6: ignored value - v7: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#86](https://www.evm.codes/#86) - - - - """ - - DUP8 = Opcode(0x87, pushed_stack_items=1, min_stack_height=8) - """ - - - - - - - DUP8(v1, v2, ..., v7, v8) = v8, v1, v2, ..., v7, v8 ---- - - Description ---- Duplicate 8th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - ... - v7: ignored - value - v8: value to duplicate - - Outputs ---- - v8: duplicated value - v1: ignored value - v2: ignored value - - ... - v7: ignored value - v8: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#87](https://www.evm.codes/#87) - - - - """ - - DUP9 = Opcode(0x88, pushed_stack_items=1, min_stack_height=9) - """ - - - - - - - DUP9(v1, v2, ..., v8, v9) = v9, v1, v2, ..., v8, v9 ---- - - Description ---- Duplicate 9th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - ... - v8: ignored - value - v9: value to duplicate - - Outputs ---- - v9: duplicated value - v1: ignored value - v2: ignored value - - ... - v8: ignored value - v9: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#88](https://www.evm.codes/#88) - - - - """ - DUP10 = Opcode(0x89, pushed_stack_items=1, min_stack_height=10) - """ - - - - - - - DUP10(v1, v2, ..., v9, v10) = v10, v1, v2, ..., v9, v10 ---- - - Description ---- Duplicate 10th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - ... - v9: ignored - value - v10: value to duplicate - - Outputs ---- - v10: duplicated value - v1: ignored value - v2: ignored - value - ... - v9: ignored value - v10: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#89](https://www.evm.codes/#89) - - - - """ - - DUP11 = Opcode(0x8A, pushed_stack_items=1, min_stack_height=11) - """ - - - - - - - DUP11(v1, v2, ..., v10, v11) = v11, v1, v2, ..., v10, v11 ---- - - Description ---- Duplicate 11th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - ... - v10: ignored - value - v11: value to duplicate - - Outputs ---- - v11: duplicated value - v1: ignored value - v2: ignored - value - ... - v10: ignored value - v11: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#8A](https://www.evm.codes/#8A) - - - - """ - - DUP12 = Opcode(0x8B, pushed_stack_items=1, min_stack_height=12) - """ - - - - - - - DUP12(v1, v2, ..., v11, v12) = v12, v1, v2, ..., v11, v12 ---- - - Description ---- Duplicate 12th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - ... - v11: ignored - value - v12: value to duplicate - - Outputs ---- - v12: duplicated value - v1: ignored value - v2: ignored - value - ... - v11: ignored value - v12: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#8B](https://www.evm.codes/#8B) - - - - """ - - DUP13 = Opcode(0x8C, pushed_stack_items=1, min_stack_height=13) - """ - - - - - - - DUP13(v1, v2, ..., v12, v13) = v13, v1, v2, ..., v12, v13 ---- - - Description ---- Duplicate 13th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - ... - v12: ignored - value - v13: value to duplicate - - Outputs ---- - v13: duplicated value - v1: ignored value - v2: ignored - value - ... - v12: ignored value - v13: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#8C](https://www.evm.codes/#8C) - - - - """ - - DUP14 = Opcode(0x8D, pushed_stack_items=1, min_stack_height=14) - """ - - - - - - - DUP14(v1, v2, ..., v13, v14) = v14, v1, v2, ..., v13, v14 ---- - - Description ---- Duplicate 14th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - ... - v13: ignored - value - v14: value to duplicate - - Outputs ---- - v14: duplicated value - v1: ignored value - v2: ignored - value - ... - v13: ignored value - v14: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#8D](https://www.evm.codes/#8D) - - - - """ - - DUP15 = Opcode(0x8E, pushed_stack_items=1, min_stack_height=15) - """ - - - - - - - DUP15(v1, v2, ..., v14, v15) = v15, v1, v2, ..., v14, v15 ---- - - Description ---- Duplicate 15th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - ... - v14: ignored - value - v15: value to duplicate - - Outputs ---- - v15: duplicated value - v1: ignored value - v2: ignored - value - ... - v14: ignored value - v15: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#8E](https://www.evm.codes/#8E) - - - - """ - - DUP16 = Opcode(0x8F, pushed_stack_items=1, min_stack_height=16) - """ - - - - - - - DUP16(v1, v2, ..., v15, v16) = v16, v1, v2, ..., v15, v16 ---- - - Description ---- Duplicate 16th stack item - - Inputs ---- - v1: ignored value - v2: ignored value - ... - v15: ignored - value - v16: value to duplicate - - Outputs ---- - v16: duplicated value - v1: ignored value - v2: ignored - value - ... - v15: ignored value - v16: original value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#8F](https://www.evm.codes/#8F) - - - - """ - - SWAP1 = Opcode(0x90, min_stack_height=2) - """ - - - - - - - SWAP1(v1, v2) = v2, v1 ---- - - Description ---- Exchange the top stack item with the second stack item. - - Inputs ---- - v1: value to swap - v2: value to swap - - Outputs ---- - v1: swapped value - v2: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#90](https://www.evm.codes/#90) - - - - """ - - SWAP2 = Opcode(0x91, min_stack_height=3) - """ - - - - - - - SWAP2(v1, v2, v3) = v3, v2, v1 ---- - - Description ---- Exchange 1st and 3rd stack items - - Inputs ---- - v1: value to swap - v2: ignored value - v3: value to swap - - Outputs ---- - v3: swapped value - v2: ignored value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#91](https://www.evm.codes/#91) - - - - """ - - SWAP3 = Opcode(0x92, min_stack_height=4) - """ - - - - - - - SWAP3(v1, v2, v3, v4) = v4, v2, v3, v1 ---- - - Description ---- Exchange 1st and 4th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - v3: ignored value - - v4: value to swap - - Outputs ---- - v4: swapped value - v2: ignored value - v3: ignored value - - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#92](https://www.evm.codes/#92) - - - - """ - - SWAP4 = Opcode(0x93, min_stack_height=5) - """ - - - - - - - SWAP4(v1, v2, ..., v4, v5) = v5, v2, ..., v4, v1 ---- - - Description ---- Exchange 1st and 5th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v4: ignored - value - v5: value to swap - - Outputs ---- - v5: swapped value - v2: ignored value - ... - v4: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#93](https://www.evm.codes/#93) - - - - """ - - SWAP5 = Opcode(0x94, min_stack_height=6) - """ - - - - - - - SWAP5(v1, v2, ..., v5, v6) = v6, v2, ..., v5, v1 ---- - - Description ---- Exchange 1st and 6th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v5: ignored - value - v6: value to swap - - Outputs ---- - v6: swapped value - v2: ignored value - ... - v5: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#94](https://www.evm.codes/#94) - - - - """ - - SWAP6 = Opcode(0x95, min_stack_height=7) - """ - - - - - - - SWAP6(v1, v2, ..., v6, v7) = v7, v2, ..., v6, v1 ---- - - Description ---- Exchange 1st and 7th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v6: ignored - value - v7: value to swap - - Outputs ---- - v7: swapped value - v2: ignored value - ... - v6: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#95](https://www.evm.codes/#95) - - - - """ - - SWAP7 = Opcode(0x96, min_stack_height=8) - """ - - - - - - - SWAP7(v1, v2, ..., v7, v8) = v8, v2, ..., v7, v1 ---- - - Description ---- Exchange 1st and 8th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v7: ignored - value - v8: value to swap - - Outputs ---- - v8: swapped value - v2: ignored value - ... - v7: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#96](https://www.evm.codes/#96) - - - - """ - - SWAP8 = Opcode(0x97, min_stack_height=9) - """ - - - - - - - SWAP8(v1, v2, ..., v8, v9) = v9, v2, ..., v8, v1 ---- - - Description ---- Exchange 1st and 9th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v8: ignored - value - v9: value to swap - - Outputs ---- - v9: swapped value - v2: ignored value - ... - v8: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#97](https://www.evm.codes/#97) - - - - """ - - SWAP9 = Opcode(0x98, min_stack_height=10) - """ - - - - - - - SWAP9(v1, v2, ..., v9, v10) = v10, v2, ..., v9, v1 ---- - - Description ---- Exchange 1st and 10th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v9: ignored - value - v10: value to swap - - Outputs ---- - v10: swapped value - v2: ignored value - ... - v9: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#98](https://www.evm.codes/#98) - - - - """ - - SWAP10 = Opcode(0x99, min_stack_height=11) - """ - - - - - - - SWAP10(v1, v2, ..., v10, v11) = v11, v2, ..., v10, v1 ---- - - Description ---- Exchange 1st and 11th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v10: ignored - value - v11: value to swap - - Outputs ---- - v11: swapped value - v2: ignored value - ... - v10: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#99](https://www.evm.codes/#99) - - - - """ - - SWAP11 = Opcode(0x9A, min_stack_height=12) - """ - - - - - - - SWAP11(v1, v2, ..., v11, v12) = v12, v2, ..., v11, v1 ---- - - Description ---- Exchange 1st and 12th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v11: ignored - value - v12: value to swap - - Outputs ---- - v12: swapped value - v2: ignored value - ... - v11: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#9A](https://www.evm.codes/#9A) - - - - """ - - SWAP12 = Opcode(0x9B, min_stack_height=13) - """ - - - - - - - SWAP12(v1, v2, ..., v12, v13) = v13, v2, ..., v12, v1 ---- - - Description ---- Exchange 1st and 13th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v12: ignored - value - v13: value to swap - - Outputs ---- - v13: swapped value - v2: ignored value - ... - v12: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#9B](https://www.evm.codes/#9B) - - - - """ - - SWAP13 = Opcode(0x9C, min_stack_height=14) - """ - - - - - - - SWAP13(v1, v2, ..., v13, v14) = v14, v2, ..., v13, v1 ---- - - Description ---- Exchange 1st and 14th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v13: ignored - value - v14: value to swap - - Outputs ---- - v14: swapped value - v2: ignored value - ... - v13: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#9C](https://www.evm.codes/#9C) - - - - """ - - SWAP14 = Opcode(0x9D, min_stack_height=15) - """ - - - - - - - SWAP14(v1, v2, ..., v14, v15) = v15, v2, ..., v14, v1 ---- - - Description ---- Exchange 1st and 15th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v14: ignored - value - v15: value to swap - - Outputs ---- - v15: swapped value - v2: ignored value - ... - v14: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#9D](https://www.evm.codes/#9D) - - - - """ - - SWAP15 = Opcode(0x9E, min_stack_height=16) - """ - - - - - - - SWAP15(v1, v2, ..., v15, v16) = v16, v2, ..., v15, v1 ---- - - Description ---- Exchange 1st and 16th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v15: ignored - value - v16: value to swap - - Outputs ---- - v16: swapped value - v2: ignored value - ... - v15: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#9E](https://www.evm.codes/#9E) - - - - """ - - SWAP16 = Opcode(0x9F, min_stack_height=17) - """ - - - - - - - SWAP16(v1, v2, ..., v16, v17) = v17, v2, ..., v16, v1 ---- - - Description ---- Exchange 1st and 17th stack items - - Inputs ---- - v1: value to swap - v2: ignored value - ... - v16: ignored - value - v17: value to swap - - Outputs ---- - v17: swapped value - v2: ignored value - ... - v16: ignored - value - v1: swapped value - - Fork ---- Frontier - - Gas ---- 3 - - Source: [evm.codes/#9F](https://www.evm.codes/#9F) - - - - """ - - LOG0 = Opcode(0xA0, popped_stack_items=2, kwargs=["offset", "size"]) - """ - - - - - - - LOG0(offset, size) ---- - - Description ---- Append log record with no topics - - Inputs ---- - offset: byte offset in the memory in bytes - size: byte size - to copy - - Outputs ---- - None - - Fork ---- Frontier - - Gas ---- - static_gas = 375 - dynamic_gas = 375 * topic_count + 8 * size + - memory_expansion_cost - - Source: [evm.codes/#A0](https://www.evm.codes/#A0) - - - - """ - - LOG1 = Opcode(0xA1, popped_stack_items=3, kwargs=["offset", "size", "topic_1"]) - """ - - - - - - - LOG1(offset, size, topic_1) ---- - - Description ---- Append log record with one topic - - Inputs ---- - offset: byte offset in the memory in bytes - size: byte size - to copy - topic_1: 32-byte value - - Outputs ---- - None - - Fork ---- Frontier - - Gas ---- - static_gas = 375 - dynamic_gas = 375 * topic_count + 8 * size + - memory_expansion_cost - - Source: [evm.codes/#A1](https://www.evm.codes/#A1) - - - - """ - - LOG2 = Opcode(0xA2, popped_stack_items=4, kwargs=["offset", "size", "topic_1", "topic_2"]) - """ - - - - - - - LOG2(offset, size, topic_1, topic_2) ---- - - Description ---- Append log record with two topics - - Inputs ---- - offset: byte offset in the memory in bytes - size: byte size - to copy - topic_1: 32-byte value - topic_2: 32-byte value - - Outputs ---- - None - - Fork ---- Frontier - - Gas ---- - static_gas = 375 - dynamic_gas = 375 * topic_count + 8 * size + - memory_expansion_cost - - Source: [evm.codes/#A2](https://www.evm.codes/#A2) - - - - """ - - LOG3 = Opcode( - 0xA3, popped_stack_items=5, kwargs=["offset", "size", "topic_1", "topic_2", "topic_3"] - ) - """ - - - - - - - LOG3(offset, size, topic_1, topic_2, topic_3) ---- - - Description ---- Append log record with three topics - - Inputs ---- - offset: byte offset in the memory in bytes - size: byte size - to copy - topic_1: 32-byte value - topic_2: 32-byte value - topic_3: - 32-byte value - - Outputs ---- - None - - Fork ---- Frontier - - Gas ---- - static_gas = 375 - dynamic_gas = 375 * topic_count + 8 * size + - memory_expansion_cost - - Source: [evm.codes/#A3](https://www.evm.codes/#A3) - - - - """ - - LOG4 = Opcode( - 0xA4, - popped_stack_items=6, - kwargs=["offset", "size", "topic_1", "topic_2", "topic_3", "topic_4"], - ) - """ - - - - - - - LOG4(offset, size, topic_1, topic_2, topic_3, topic_4) ---- - - Description ---- Append log record with four topics - - Inputs ---- - offset: byte offset in the memory in bytes - size: byte size - to copy - topic_1: 32-byte value - topic_2: 32-byte value - topic_3: - 32-byte value - topic_4: 32-byte value - - Outputs ---- - None - - Fork ---- Frontier - - Gas ---- - static_gas = 375 - dynamic_gas = 375 * topic_count + 8 * size + - memory_expansion_cost - - Source: [evm.codes/#A4](https://www.evm.codes/#A4) - - - - """ - - RJUMP = Opcode(0xE0, data_portion_length=2) - """ - - - - - - - !!! Note: This opcode is under development - - RJUMP() ---- - - Description ---- - - Inputs ---- - - Outputs ---- - - Fork ---- EOF Fork - - Gas ---- - - Source: - [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/eip-4200) - - - - """ - - DATALOAD = Opcode(0xD0, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) - """ - - - - - - - !!! Note: This opcode is under development - - DATALOAD(offset) ---- - - Description ---- Reads 32 bytes of data at offset onto the stack - - Inputs ---- - offset: offset within the data section to start copying - - Outputs ---- none - - Fork ---- EOF Fork - - Gas ---- 4 - - Source: - [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) - - - - """ - - DATALOADN = Opcode(0xD1, pushed_stack_items=1, data_portion_length=2) - """ - - - - - - - !!! Note: This opcode is under development - - DATALOADN() ---- - - Description ---- Reads 32 bytes of data at offset onto the stack - - Immediates ---- 2 bytes forming a UInt16, which is the offset into the data - section. - - Inputs ---- none - - Outputs ---- none - - Fork ---- EOF Fork - - Gas ---- 3 - - Source: - [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) - - - - """ - - DATASIZE = Opcode(0xD2, pushed_stack_items=1) - """ - - - - - - - !!! Note: This opcode is under development - - DATASIZE() ---- - - Description ---- Returns the size of the data section - - Inputs ---- - - Outputs ---- The size of the data section. If there is no data section, - returns 0. - - Fork ---- EOF Fork - - Gas ---- 2 - - Source: - [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) - - - - """ - - DATACOPY = Opcode(0xD3, popped_stack_items=3, kwargs=["dest_offset", "offset", "size"]) - """ - - - - - - - !!! Note: This opcode is under development - - DATACOPY(dest_offset, offset, size) ---- - - Description ---- Copies data from the data section into call frame memory - - Inputs ---- - dest_offset: The offset within the memory section to start - copying to - offset: The offset within the data section to start copying - from - size: The number of bytes to copy - - Outputs ---- none - - Fork ---- EOF Fork - - Gas ---- - minimum_word_size = (size + 31) / 32 - static_gas = 3 - - dynamic_gas = 3 * minimum_word_size + memory_expansion_cost - - Source: - [eips.ethereum.org/EIPS/eip-7480](https://eips.ethereum.org/EIPS/eip-7480) - - - - """ - - RJUMPI = Opcode(0xE1, popped_stack_items=1, data_portion_length=2) - """ - - - - - - - !!! Note: This opcode is under development - - RJUMPI() ---- - - Description ---- - - Inputs ---- - - Outputs ---- - - Fork ---- EOF Fork - - Gas ---- - - Source: - [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/eip-4200) - - - - """ - - RJUMPV = Opcode( - 0xE2, - popped_stack_items=1, - data_portion_formatter=_rjumpv_encoder, - ) - """ - - - - - - - !!! Note: This opcode is under development - - RJUMPV() ---- - - Description ---- Relative jump with variable offset. - - When calling this opcode to generate bytecode, the first argument is used - to format the data portion of the opcode, and it can be either of two - types: - A bytes type, and in this instance the bytes are used verbatim as - the data portion. - An integer iterable, list or tuple or any other - iterable, where each element is a jump offset. - - Inputs ---- - - Outputs ---- - - Fork ---- EOF Fork - - Gas ---- - - Source: - [eips.ethereum.org/EIPS/eip-4200](https://eips.ethereum.org/EIPS/eip-4200) - - - - """ - - CALLF = Opcode(0xE3, data_portion_length=2, unchecked_stack=True) - """ - - - - - - - !!! Note: This opcode is under development - - CALLF() ---- - - Description ---- - - - deduct 5 gas - read uint16 operand idx - if 1024 < len(stack) + - types[idx].max_stack_height - types[idx].inputs, execution results in an - exceptional halt - if 1024 <= len(return_stack), execution results in an - exceptional halt - push new element to return_stack (current_code_idx, - pc+3) - update current_code_idx to idx and set pc to 0 - - Inputs ---- Any: The inputs are not checked because we cannot know how many - inputs the callee function/section requires - - Outputs ---- Any: The outputs are variable because we cannot know how many - outputs the callee function/section produces - - Fork ---- EOF Fork - - Gas ---- 5 - - Source: - [ipsilon/eof/blob/main/spec/eof.md](https://github.com/ipsilon/eof/blob/main/sp - ec/eof.md) - - - - """ - - RETF = Opcode(0xE4, terminating=True) - """ - - - - - - - !!! Note: This opcode is under development - - RETF() ---- - - Description ---- - - Inputs ---- - - Outputs ---- - - Fork ---- EOF Fork - - Gas ---- 3 - - - - """ - - JUMPF = Opcode(0xE5, data_portion_length=2, terminating=True, unchecked_stack=True) - """ - - - - - - - !!! Note: This opcode is under development - - JUMPF() ---- - - Description ---- - - - deduct 5 gas - read uint16 operand idx - if 1024 < len(stack) + - types[idx].max_stack_height - types[idx].inputs, execution results in an - exceptional halt - set current_code_idx to idx - set pc = 0 - - - - - - Inputs ---- - - Outputs ---- - - Fork ---- EOF Fork - - Gas ---- 5 - - - - - - - - """ - - DUPN = Opcode( - 0xE6, - pushed_stack_items=1, - data_portion_length=1, - stack_properties_modifier=_dupn_stack_properties_modifier, - ) - """ - - - - - - - !!! Note: This opcode is under development - - DUPN() ---- - - Description ---- - - - deduct 3 gas - read uint8 operand imm - n = imm + 1 - n‘th (1-based) - stack item is duplicated at the top of the stack - Stack validation: - stack_height >= n - - - - - - Inputs ---- - - Outputs ---- - - Fork ---- EOF Fork - - Gas ---- - - - - - - - - """ - - SWAPN = Opcode( - 0xE7, data_portion_length=1, stack_properties_modifier=_swapn_stack_properties_modifier - ) - """ + Description + ---- + - deduct 5 gas + - read uint16 operand idx + - if 1024 < len(stack) + types[idx].max_stack_height - types[idx].inputs, + execution results in an exceptional halt + - set current_code_idx to idx + - set pc = 0 + Inputs + ---- + Outputs + ---- + Fork + ---- + EOF Fork + Gas + ---- + 5 + + """ + + DUPN = Opcode( + 0xE6, + pushed_stack_items=1, + data_portion_length=1, + stack_properties_modifier=_dupn_stack_properties_modifier, + ) + """ !!! Note: This opcode is under development - SWAPN() ---- + DUPN() + ---- - Description ---- + Description + ---- - - deduct 3 gas - read uint8 operand imm - n = imm + 1 - n + 1th stack item - is swapped with the top stack item (1-based). - Stack validation: - stack_height >= n + 1 + - deduct 3 gas + - read uint8 operand imm + - n = imm + 1 + - n‘th (1-based) stack item is duplicated at the top of the stack + - Stack validation: stack_height >= n + Inputs + ---- + Outputs + ---- + Fork + ---- + EOF Fork - Inputs ---- + Gas + ---- + + """ - Outputs ---- + SWAPN = Opcode( + 0xE7, data_portion_length=1, stack_properties_modifier=_swapn_stack_properties_modifier + ) + """ + !!! Note: This opcode is under development - Fork ---- EOF Fork + SWAPN() + ---- - Gas ---- + Description + ---- + - deduct 3 gas + - read uint8 operand imm + - n = imm + 1 + - n + 1th stack item is swapped with the top stack item (1-based). + - Stack validation: stack_height >= n + 1 + Inputs + ---- + Outputs + ---- + Fork + ---- + EOF Fork + Gas + ---- """ @@ -4683,39 +5171,37 @@ class Opcodes(Opcode, Enum): stack_properties_modifier=_exchange_stack_properties_modifier, ) """ - - - - - - !!! Note: This opcode is under development - EXCHANGE[x, y] ---- - - Description ---- Exchanges two stack positions. Two nybbles, n is high 4 - bits + 1, then m is 4 low bits + 1. Exchanges the n+1'th item with the n + - m + 1 item. - - Inputs x and y when the opcode is used as `EXCHANGE[x, y]`, are equal to: - - x = n + 1 - y = n + m + 1 Which each equals to 1-based stack positions - swapped. - - Inputs ---- n + m + 1, or ((imm >> 4) + (imm &0x0F) + 3) from the raw - immediate, - - Outputs ---- n + m + 1, or ((imm >> 4) + (imm &0x0F) + 3) from the raw - immediate, - - Fork ---- EOF_FORK - - Gas ---- 3 + EXCHANGE[x, y] + ---- + Description + ---- + Exchanges two stack positions. Two nybbles, n is high 4 bits + 1, + then m is 4 low bits + 1. + Exchanges the n+1'th item with the n + m + 1 item. + Inputs x and y when the opcode is used as `EXCHANGE[x, y]`, are equal to: + - x = n + 1 + - y = n + m + 1 + Which each equals to 1-based stack positions swapped. + Inputs + ---- + n + m + 1, or ((imm >> 4) + (imm &0x0F) + 3) from the raw immediate, + Outputs + ---- + n + m + 1, or ((imm >> 4) + (imm &0x0F) + 3) from the raw immediate, + Fork + ---- + EOF_FORK + Gas + ---- + 3 """ @@ -4727,31 +5213,25 @@ class Opcodes(Opcode, Enum): kwargs=["salt", "input_offset", "input_size", "value"], ) """ - - - - - - !!! Note: This opcode is under development - EOFCREATE[initcontainer_index] (salt, input_offset, input_size, value) ---- - - Description ---- - - Inputs ---- - - Outputs ---- - - Fork ---- - - Gas ---- - + EOFCREATE[initcontainer_index] (salt, input_offset, input_size, value) + ---- + Description + ---- + Inputs + ---- + Outputs + ---- + Fork + ---- + Gas + ---- """ @@ -4762,31 +5242,25 @@ class Opcodes(Opcode, Enum): kwargs=["tx_initcode_hash", "salt", "input_offset", "input_size", "value"], ) """ - - - - - - !!! Note: This opcode is under development - TXCREATE (tx_initcode_hash, salt, input_offset, input_size, value) ---- - - Description ---- - - Inputs ---- - - Outputs ---- - - Fork ---- - - Gas ---- - + TXCREATE (tx_initcode_hash, salt, input_offset, input_size, value) + ---- + Description + ---- + Inputs + ---- + Outputs + ---- + Fork + ---- + Gas + ---- """ @@ -4798,31 +5272,25 @@ class Opcodes(Opcode, Enum): kwargs=["auxdata_offset", "auxdata_size"], ) """ - - - - - - !!! Note: This opcode is under development - RETURNCODE() ---- - - Description ---- - - Inputs ---- - - Outputs ---- - - Fork ---- - - Gas ---- - + RETURNCODE() + ---- + Description + ---- + Inputs + ---- + Outputs + ---- + Fork + ---- + Gas + ---- """ @@ -4830,35 +5298,42 @@ class Opcodes(Opcode, Enum): 0xF0, popped_stack_items=3, pushed_stack_items=1, kwargs=["value", "offset", "size"] ) """ + CREATE(value, offset, size) = address + ---- + Description + ---- + Create a new contract with the given code - - - - - CREATE(value, offset, size) = address ---- - - Description ---- Create a new contract with the given code - - Inputs ---- - value: value in wei to send to the new account - offset: byte - offset in the memory in bytes, the initialization code for the new account + Inputs + ---- + - value: value in wei to send to the new account + - offset: byte offset in the memory in bytes, the initialization code + for the new account - size: byte size to copy (size of the initialization code) - Outputs ---- - address: the address of the deployed contract, 0 if the - deployment failed - - Fork ---- Frontier + Outputs + ---- + - address: the address of the deployed contract, 0 if the deployment failed - Gas ---- ``` minimum_word_size = (size + 31) / 32 init_code_cost = 2 * - minimum_word_size code_deposit_cost = 200 * deployed_code_size + Fork + ---- + Frontier - static_gas = 32000 dynamic_gas = init_code_cost + memory_expansion_cost + - deployment_code_execution_cost + code_deposit_cost ``` + Gas + ---- + ``` + minimum_word_size = (size + 31) / 32 + init_code_cost = 2 * minimum_word_size + code_deposit_cost = 200 * deployed_code_size + + static_gas = 32000 + dynamic_gas = init_code_cost + memory_expansion_cost + + deployment_code_execution_cost + + code_deposit_cost + ``` Source: [evm.codes/#F0](https://www.evm.codes/#F0) - - - """ CALL = Opcode( @@ -4869,38 +5344,45 @@ class Opcodes(Opcode, Enum): kwargs_defaults={"gas": GAS}, ) """ - - - - - - - CALL(gas, address, value, args_offset, args_size, ret_offset, ret_size) = - success ---- - - Description ---- Message-call into an account - - Inputs ---- - gas: amount of gas to send to the sub context to execute. The - gas that is not used by the sub context is returned to this one - address: - the account which context to execute - value: value in wei to send to the - account - args_offset: byte offset in the memory in bytes, the calldata of - the sub context - args_size: byte size to copy (size of the calldata) - - ret_offset: byte offset in the memory in bytes, where to store the return - data of the sub context - ret_size: byte size to copy (size of the return - data) - - Outputs ---- - success: return 0 if the sub context reverted, 1 otherwise - - Fork ---- Frontier - - Gas ---- ``` static_gas = 0 dynamic_gas = memory_expansion_cost + - code_execution_cost + address_access_cost + positive_value_cost + - value_to_empty_account_cost ``` + CALL(gas, address, value, args_offset, args_size, ret_offset, ret_size) + = success + ---- + + Description + ---- + Message-call into an account + + Inputs + ---- + - gas: amount of gas to send to the sub context to execute. The gas that + is not used by the sub context is returned to this one + - address: the account which context to execute + - value: value in wei to send to the account + - args_offset: byte offset in the memory in bytes, the calldata of + the sub context + - args_size: byte size to copy (size of the calldata) + - ret_offset: byte offset in the memory in bytes, where to store the + return data of the sub context + - ret_size: byte size to copy (size of the return data) + + Outputs + ---- + - success: return 0 if the sub context reverted, 1 otherwise + + Fork + ---- + Frontier + + Gas + ---- + ``` + static_gas = 0 + dynamic_gas = memory_expansion_cost + code_execution_cost + + address_access_cost + positive_value_cost + + value_to_empty_account_cost + ``` Source: [evm.codes/#F1](https://www.evm.codes/#F1) - - - """ CALLCODE = Opcode( @@ -4911,67 +5393,76 @@ class Opcodes(Opcode, Enum): kwargs_defaults={"gas": GAS}, ) """ - - - - - - CALLCODE(gas, address, value, args_offset, args_size, ret_offset, ret_size) - = success ---- - - Description ---- Message-call into this account with an alternative - account's code. Executes code starting at the address to which the call is - made. - - Inputs ---- - gas: amount of gas to send to the sub context to execute. The - gas that is not used by the sub context is returned to this one - address: - the account which code to execute - value: value in wei to send to the - account - args_offset: byte offset in the memory in bytes, the calldata of - the sub context - args_size: byte size to copy (size of the calldata) - - ret_offset: byte offset in the memory in bytes, where to store the return - data of the sub context - ret_size: byte size to copy (size of the return - data) - - Outputs ---- - success: return 0 if the sub context reverted, 1 otherwise - - Fork ---- Frontier - - Gas ---- ``` static_gas = 0 dynamic_gas = memory_expansion_cost + - code_execution_cost + address_access_cost + positive_value_cost ``` + = success + ---- + + Description + ---- + Message-call into this account with an alternative account's code. + Executes code starting at the address to which the call is made. + + Inputs + ---- + - gas: amount of gas to send to the sub context to execute. The gas that + is not used by the sub context is returned to this one + - address: the account which code to execute + - value: value in wei to send to the account + - args_offset: byte offset in the memory in bytes, the calldata of + the sub context + - args_size: byte size to copy (size of the calldata) + - ret_offset: byte offset in the memory in bytes, where to store the + return data of the sub context + - ret_size: byte size to copy (size of the return data) + + Outputs + ---- + - success: return 0 if the sub context reverted, 1 otherwise + + Fork + ---- + Frontier + + Gas + ---- + ``` + static_gas = 0 + dynamic_gas = memory_expansion_cost + code_execution_cost + + address_access_cost + positive_value_cost + ``` Source: [evm.codes/#F2](https://www.evm.codes/#F2) - - - """ RETURN = Opcode(0xF3, popped_stack_items=2, kwargs=["offset", "size"], terminating=True) """ + RETURN(offset, size) + ---- + Description + ---- + Halt execution returning output data + Inputs + ---- + - offset: byte offset in the memory in bytes, to copy what will be + the return data of this context + - size: byte size to copy (size of the return data) + Outputs + ---- + - None + Fork + ---- + Frontier - - RETURN(offset, size) ---- - - Description ---- Halt execution returning output data - - Inputs ---- - offset: byte offset in the memory in bytes, to copy what will - be the return data of this context - size: byte size to copy (size of the - return data) - - Outputs ---- - None - - Fork ---- Frontier - - Gas ---- - static_gas = 0 - dynamic_gas = memory_expansion_cost + Gas + ---- + - static_gas = 0 + - dynamic_gas = memory_expansion_cost Source: [evm.codes/#F3](https://www.evm.codes/#F3) - - - """ DELEGATECALL = Opcode( @@ -4982,37 +5473,42 @@ class Opcodes(Opcode, Enum): kwargs_defaults={"gas": GAS}, ) """ - - - - - - - DELEGATECALL(gas, address, args_offset, args_size, ret_offset, ret_size) = - success ---- - - Description ---- Message-call into this account with an alternative - account's code, but persisting the current values for sender and value - - Inputs ---- - gas: amount of gas to send to the sub context to execute. The - gas that is not used by the sub context is returned to this one - address: - the account which code to execute - args_offset: byte offset in the memory - in bytes, the calldata of the sub context - args_size: byte size to copy - (size of the calldata) - ret_offset: byte offset in the memory in bytes, - where to store the return data of the sub context - ret_size: byte size to - copy (size of the return data) - - Outputs ---- - success: return 0 if the sub context reverted, 1 otherwise - - Fork ---- Byzantium - - Gas ---- - static_gas = 0 - dynamic_gas = memory_expansion_cost + - code_execution_cost + address_access_cost + DELEGATECALL(gas, address, args_offset, args_size, ret_offset, ret_size) + = success + ---- + + Description + ---- + Message-call into this account with an alternative account's code, but + persisting the current values for sender and value + + Inputs + ---- + - gas: amount of gas to send to the sub context to execute. The gas that + is not used by the sub context is returned to this one + - address: the account which code to execute + - args_offset: byte offset in the memory in bytes, the calldata of + the sub context + - args_size: byte size to copy (size of the calldata) + - ret_offset: byte offset in the memory in bytes, where to store + the return data of the sub context + - ret_size: byte size to copy (size of the return data) + + Outputs + ---- + - success: return 0 if the sub context reverted, 1 otherwise + + Fork + ---- + Byzantium + + Gas + ---- + - static_gas = 0 + - dynamic_gas = memory_expansion_cost + code_execution_cost + + address_access_cost Source: [evm.codes/#F4](https://www.evm.codes/#F4) - - - """ CREATE2 = Opcode( @@ -5022,38 +5518,44 @@ class Opcodes(Opcode, Enum): kwargs=["value", "offset", "size", "salt"], ) """ + CREATE2(value, offset, size, salt) = address + ---- + Description + ---- + Creates a new contract + Inputs + ---- + - value: value in wei to send to the new account + - offset: byte offset in the memory in bytes, the initialization code + of the new account + - size: byte size to copy (size of the initialization code) + - salt: 32-byte value used to create the new account at a + deterministic address + Outputs + ---- + - address: the address of the deployed contract, 0 if the deployment failed + Fork + ---- + Constantinople - - CREATE2(value, offset, size, salt) = address ---- - - Description ---- Creates a new contract - - Inputs ---- - value: value in wei to send to the new account - offset: byte - offset in the memory in bytes, the initialization code of the new account - - size: byte size to copy (size of the initialization code) - salt: 32-byte - value used to create the new account at a deterministic address - - Outputs ---- - address: the address of the deployed contract, 0 if the - deployment failed - - Fork ---- Constantinople - - Gas ---- ``` minimum_word_size = (size + 31) / 32 init_code_cost = 2 * - minimum_word_size hash_cost = 6 * minimum_word_size code_deposit_cost = 200 - * deployed_code_size - - static_gas = 32000 dynamic_gas = init_code_cost + hash_cost + - memory_expansion_cost + deployment_code_execution_cost + code_deposit_cost + Gas + ---- + ``` + minimum_word_size = (size + 31) / 32 + init_code_cost = 2 * minimum_word_size + hash_cost = 6 * minimum_word_size + code_deposit_cost = 200 * deployed_code_size + + static_gas = 32000 + dynamic_gas = init_code_cost + hash_cost + memory_expansion_cost + + deployment_code_execution_cost + code_deposit_cost ``` Source: [evm.codes/#F5](https://www.evm.codes/#F5) - - - """ EXTCALL = Opcode( @@ -5063,35 +5565,43 @@ class Opcodes(Opcode, Enum): kwargs=["address", "args_offset", "args_size", "value"], ) """ - - - - - - - EXTCALL(address, args_offset, args_size, value) = address ---- - - Description ---- Message-call into an account - - Inputs ---- - address: the account which context to execute - args_offset: - byte offset in the memory in bytes, the calldata of the sub context - - args_size: byte size to copy (size of the calldata) - value: value in wei - to send to the account - - Outputs ---- - success: - `0` if the call was successful. - `1` if the call - has reverted (also can be pushed earlier in a light failure scenario). - - `2` if the call has failed. - - Fork ---- Prague - - Gas ---- ``` static_gas = 0 dynamic_gas = memory_expansion_cost + - code_execution_cost + address_access_cost + positive_value_cost + - value_to_empty_account_cost ``` + EXTCALL(address, args_offset, args_size, value) = address + ---- + + Description + ---- + Message-call into an account + + Inputs + ---- + - address: the account which context to execute + - args_offset: byte offset in the memory in bytes, the calldata of + the sub context + - args_size: byte size to copy (size of the calldata) + - value: value in wei to send to the account + + Outputs + ---- + - success: + - `0` if the call was successful. + - `1` if the call has reverted (also can be pushed earlier in a + light failure scenario). + - `2` if the call has failed. + + Fork + ---- + Prague + + Gas + ---- + ``` + static_gas = 0 + dynamic_gas = memory_expansion_cost + code_execution_cost + + address_access_cost + positive_value_cost + + value_to_empty_account_cost + ``` Source: [EIP-7069](https://eips.ethereum.org/EIPS/eip-7069) - - - """ EXTDELEGATECALL = Opcode( @@ -5101,34 +5611,40 @@ class Opcodes(Opcode, Enum): kwargs=["address", "args_offset", "args_size"], ) """ - - - - - - - EXTDELEGATECALL(address, args_offset, args_size) = address ---- - - Description ---- Message-call into this account with an alternative - account's code, but persisting the current values for sender and value - - Inputs ---- - address: the account which context to execute - args_offset: - byte offset in the memory in bytes, the calldata of the sub context - - args_size: byte size to copy (size of the calldata) - - Outputs ---- - success: - `0` if the call was successful. - `1` if the call - has reverted (also can be pushed earlier in a light failure scenario). - - `2` if the call has failed. - - Fork ---- Prague - - Gas ---- - static_gas = 0 - dynamic_gas = memory_expansion_cost + - code_execution_cost + address_access_cost + EXTDELEGATECALL(address, args_offset, args_size) = address + ---- + + Description + ---- + Message-call into this account with an alternative account's code, + but persisting the current values for sender and value + + Inputs + ---- + - address: the account which context to execute + - args_offset: byte offset in the memory in bytes, the calldata of + the sub context + - args_size: byte size to copy (size of the calldata) + + Outputs + ---- + - success: + - `0` if the call was successful. + - `1` if the call has reverted (also can be pushed earlier in a + light failure scenario). + - `2` if the call has failed. + + Fork + ---- + Prague + + Gas + ---- + - static_gas = 0 + - dynamic_gas = memory_expansion_cost + code_execution_cost + + address_access_cost Source: [EIP-7069](https://eips.ethereum.org/EIPS/eip-7069) - - - """ STATICCALL = Opcode( @@ -5139,36 +5655,41 @@ class Opcodes(Opcode, Enum): kwargs_defaults={"gas": GAS}, ) """ - - - - - - - STATICCALL(gas, address, args_offset, args_size, ret_offset, ret_size) = - success ---- - - Description ---- Static message-call into an account - - Inputs ---- - gas: amount of gas to send to the sub context to execute. The - gas that is not used by the sub context is returned to this one - address: - the account which context to execute - args_offset: byte offset in the - memory in bytes, the calldata of the sub context - args_size: byte size to - copy (size of the calldata) - ret_offset: byte offset in the memory in - bytes, where to store the return data of the sub context - ret_size: byte - size to copy (size of the return data) - - Outputs ---- - success: return 0 if the sub context reverted, 1 otherwise - - Fork ---- Byzantium - - Gas ---- - static_gas = 0 - dynamic_gas = memory_expansion_cost + - code_execution_cost + address_access_cost + STATICCALL(gas, address, args_offset, args_size, ret_offset, ret_size) + = success + ---- + + Description + ---- + Static message-call into an account + + Inputs + ---- + - gas: amount of gas to send to the sub context to execute. The gas + that is not used by the sub context is returned to this one + - address: the account which context to execute + - args_offset: byte offset in the memory in bytes, the calldata of the + sub context + - args_size: byte size to copy (size of the calldata) + - ret_offset: byte offset in the memory in bytes, where to store the + return data of the sub context + - ret_size: byte size to copy (size of the return data) + + Outputs + ---- + - success: return 0 if the sub context reverted, 1 otherwise + + Fork + ---- + Byzantium + + Gas + ---- + - static_gas = 0 + - dynamic_gas = memory_expansion_cost + code_execution_cost + + address_access_cost Source: [evm.codes/#FA](https://www.evm.codes/#FA) - - - """ EXTSTATICCALL = Opcode( @@ -5178,132 +5699,141 @@ class Opcodes(Opcode, Enum): kwargs=["address", "args_offset", "args_size"], ) """ - - - - - - - EXTSTATICCALL(address, args_offset, args_size) = address ---- - - Description ---- Static message-call into an account - - Inputs ---- - address: the account which context to execute - args_offset: - byte offset in the memory in bytes, the calldata of the sub context - - args_size: byte size to copy (size of the calldata) - - Outputs ---- - success: - `0` if the call was successful. - `1` if the call - has reverted (also can be pushed earlier in a light failure scenario). - - `2` if the call has failed. - - Fork ---- Prague - - Gas ---- - static_gas = 0 - dynamic_gas = memory_expansion_cost + - code_execution_cost + address_access_cost + EXTSTATICCALL(address, args_offset, args_size) = address + ---- + + Description + ---- + Static message-call into an account + + Inputs + ---- + - address: the account which context to execute + - args_offset: byte offset in the memory in bytes, the calldata + of the sub context + - args_size: byte size to copy (size of the calldata) + + Outputs + ---- + - success: + - `0` if the call was successful. + - `1` if the call has reverted (also can be pushed earlier in a + light failure scenario). + - `2` if the call has failed. + + Fork + ---- + Prague + + Gas + ---- + - static_gas = 0 + - dynamic_gas = memory_expansion_cost + code_execution_cost + + address_access_cost Source: [EIP-7069](https://eips.ethereum.org/EIPS/eip-7069) - - - """ RETURNDATALOAD = Opcode(0xF7, popped_stack_items=1, pushed_stack_items=1, kwargs=["offset"]) """ + RETURNDATALOAD(offset) + ---- + Description + ---- + Copy 32 bytes from returndata at offset onto the stack + Inputs + ---- + - offset: byte offset in the return data from the last executed + sub context to copy + Fork + ---- + EOF - - - RETURNDATALOAD(offset) ---- - - Description ---- Copy 32 bytes from returndata at offset onto the stack - - Inputs ---- - offset: byte offset in the return data from the last executed - sub context to copy - - Fork ---- EOF - - Gas ---- 3 - - - + Gas + ---- + 3 """ REVERT = Opcode(0xFD, popped_stack_items=2, kwargs=["offset", "size"], terminating=True) """ + REVERT(offset, size) + ---- + Description + ---- + Halt execution reverting state changes but returning data and remaining gas + Inputs + ---- + - offset: byte offset in the memory in bytes. The return data of + the calling context + - size: byte size to copy (size of the return data) + Fork + ---- + Byzantium - - - REVERT(offset, size) ---- - - Description ---- Halt execution reverting state changes but returning data - and remaining gas - - Inputs ---- - offset: byte offset in the memory in bytes. The return data - of the calling context - size: byte size to copy (size of the return data) - - Fork ---- Byzantium - - Gas ---- static_gas = 0 dynamic_gas = memory_expansion_cost + Gas + ---- + static_gas = 0 + dynamic_gas = memory_expansion_cost Source: [evm.codes/#FD](https://www.evm.codes/#FD) - - - """ INVALID = Opcode(0xFE, terminating=True) """ + INVALID() + ---- + Description + ---- + Designated invalid instruction + Inputs + ---- + None + Outputs + ---- + None + Fork + ---- + Frontier - - INVALID() ---- - - Description ---- Designated invalid instruction - - Inputs ---- None - - Outputs ---- None - - Fork ---- Frontier - - Gas ---- All the remaining gas in this context is consumed + Gas + ---- + All the remaining gas in this context is consumed Source: [evm.codes/#FE](https://www.evm.codes/#FE) - - - """ SELFDESTRUCT = Opcode(0xFF, popped_stack_items=1, kwargs=["address"]) """ + SELFDESTRUCT(address) + ---- + Description + ---- + Halt execution and register the account for later deletion + Inputs + ---- + - address: account to send the current balance to + Fork + ---- + Frontier - - - SELFDESTRUCT(address) ---- - - Description ---- Halt execution and register the account for later deletion - - Inputs ---- - address: account to send the current balance to - - Fork ---- Frontier - - Gas ---- 5000 + Gas + ---- + 5000 Source: [evm.codes/#FF](https://www.evm.codes/#FF) - - - """ @@ -5345,7 +5875,8 @@ class Opcodes(Opcode, Enum): def _mstore_operation(data: OpcodeCallArg = b"", offset: OpcodeCallArg = 0) -> Bytecode: """ - Generate the bytecode that stores an arbitrary amount of data in memory. + Generate the bytecode that stores an arbitrary + amount of data in memory. """ assert isinstance(offset, int) if isinstance(data, int): @@ -5357,11 +5888,11 @@ def _mstore_operation(data: OpcodeCallArg = b"", offset: OpcodeCallArg = 0) -> B if len(chunk) == 32: bytecode += Opcodes.MSTORE(offset, chunk) else: - # We need to MLOAD the existing data at the offset and then do a - # bitwise OR with the new data to store it in memory. + # We need to MLOAD the existing data at the offset and then + # do a bitwise OR with the new data to store it in memory. bytecode += Opcodes.MLOAD(offset) - # Create a mask to zero out the leftmost bytes of the existing - # data. + # Create a mask to zero out the leftmost bytes of + # the existing data. mask_size = 32 - len(chunk) bytecode += _push_opcodes_byte_list[mask_size - 1][-1] bytecode += Opcodes.AND @@ -5378,54 +5909,53 @@ class Macros(Macro, Enum): OOG = Macro(Opcodes.SHA3(0, 100000000000)) """ - - - - - - - OOG() ---- + OOG() + ---- Halt execution by consuming all available gas. - Inputs ---- - None. Any input arguments are ignored. + Inputs + ---- + - None. Any input arguments are ignored. - Outputs ---- - None + Outputs + ---- + - None - Fork ---- Frontier - - Gas ---- `SHA3(0, 100000000000)` results in 19073514453125027 gas used and - an OOG exception. - - Note: If a value > `100000000000` is used as second argument, the resulting - geth trace reports gas `30` and an OOG exception. `SHA3(0, SUB(0, 1))` - causes a gas > u64 exception and an OOG exception. - - Bytecode ---- SHA3(0, 100000000000) + Fork + ---- + Frontier + Gas + ---- + `SHA3(0, 100000000000)` results in 19073514453125027 gas used and an OOG + exception. + Note: + If a value > `100000000000` is used as second argument, the resulting geth + trace reports gas `30` and an OOG exception. + `SHA3(0, SUB(0, 1))` causes a gas > u64 exception and an OOG exception. + Bytecode + ---- + SHA3(0, 100000000000) """ MSTORE = Macro(lambda_operation=_mstore_operation) """ - - - - - - - MSTORE(data, offset) ---- + MSTORE(data, offset) + ---- Place data of arbitrary length into memory at a given offset. - Inputs ---- - data: The data to store in memory. Can be an integer or - bytes. - offset: The offset in memory to store the data. - - Outputs ---- - None - - + Inputs + ---- + - data: The data to store in memory. Can be an integer or bytes. + - offset: The offset in memory to store the data. + Outputs + ---- + - None """ diff --git a/src/pytest_plugins/consume/consume.py b/src/pytest_plugins/consume/consume.py index fb04421aa4e..4313615b19c 100644 --- a/src/pytest_plugins/consume/consume.py +++ b/src/pytest_plugins/consume/consume.py @@ -266,11 +266,14 @@ def from_string(cls, pattern: str) -> "SimLimitBehavior": Parse the `--sim.limit` argument and return a `SimLimitBehavior` instance. - If `pattern`: - Is "collectonly", enable collection mode without - filtering. - Starts with "collectonly:", enable collection mode and use - the rest as a regex pattern. - Starts with "id:", treat the rest as a - literal test ID and escape special regex chars. - Starts with - "collectonly:id:", enable collection mode with a literal test ID. + If `pattern`: + - Is "collectonly", enable collection mode without filtering. + - Starts with "collectonly:", enable collection mode and use the + rest as a regex pattern. + - Starts with "id:", treat the rest as a literal test ID and escape + special regex chars. + - Starts with "collectonly:id:", enable collection mode with a + literal test ID. """ if pattern == "collectonly": return cls(pattern=".*", collectonly=True) diff --git a/src/pytest_plugins/consume/releases.py b/src/pytest_plugins/consume/releases.py index 082b1ca98dc..26ecc67b17f 100644 --- a/src/pytest_plugins/consume/releases.py +++ b/src/pytest_plugins/consume/releases.py @@ -224,11 +224,12 @@ def get_release_page_url(release_string: str) -> str: """ Return the GitHub Release page URL for a specific release descriptor. - This function can handle: - A standard release string (e.g., - "eip7692@latest") - from execution-spec-tests only. - A direct asset - download link (e.g., - "https://github.com/ethereum/execution-spec-tests/releases/download/v4.0.0/fixt - ures_eip7692.tar.gz"). + This function can handle: + - A standard release string (e.g., "eip7692@latest") from + execution-spec-tests only. + - A direct asset download link (e.g., + "https://github.com/ethereum/execution-spec-tests/releases/ + download/v4.0.0/fixtures_eip7692.tar.gz"). """ release_information = get_release_information() diff --git a/src/pytest_plugins/consume/simulators/helpers/ruleset.py b/src/pytest_plugins/consume/simulators/helpers/ruleset.py index 751f6c02846..2098dc6c938 100644 --- a/src/pytest_plugins/consume/simulators/helpers/ruleset.py +++ b/src/pytest_plugins/consume/simulators/helpers/ruleset.py @@ -44,9 +44,11 @@ def get_blob_schedule_entries(fork: Fork) -> Dict[str, int]: Generate blob schedule entries for each fork (and respective parent forks). Adds the following entries to the ruleset for the given fork (and parent - forks): HIVE_{FORK}_BLOB_TARGET: target_blobs_per_block() - HIVE_{FORK}_BLOB_MAX: max_blobs_per_block() - HIVE_{FORK}_BLOB_BASE_FEE_UPDATE_FRACTION: blob_base_fee_update_fraction() + forks): + HIVE_{FORK}_BLOB_TARGET: target_blobs_per_block() + HIVE_{FORK}_BLOB_MAX: max_blobs_per_block() + HIVE_{FORK}_BLOB_BASE_FEE_UPDATE_FRACTION: blob_base_fee_update_ + fraction() """ entries: Dict = {} forks_with_blobs: List[Fork] = [] diff --git a/src/pytest_plugins/consume/simulators/rlp/conftest.py b/src/pytest_plugins/consume/simulators/rlp/conftest.py index 92a2c97fb52..66ad7dd62a7 100644 --- a/src/pytest_plugins/consume/simulators/rlp/conftest.py +++ b/src/pytest_plugins/consume/simulators/rlp/conftest.py @@ -65,9 +65,9 @@ def client_files( """ Define the files that hive will start the client with. - The files are specified as a dictionary whose: - Keys are the target file - paths in the client's docker container, and, - Values are in-memory - buffered file objects. + The files are specified as a dictionary whose: + - Keys are the target file paths in the client's docker container, and, + - Values are in-memory buffered file objects. """ files = {f"/blocks/{i + 1:04d}.rlp": rlp for i, rlp in enumerate(buffered_blocks_rlp)} files["/genesis.json"] = buffered_genesis diff --git a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py index bfec67792da..2781b7540f9 100644 --- a/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py +++ b/src/pytest_plugins/consume/simulators/simulator_logic/test_via_sync.py @@ -340,8 +340,8 @@ def test_blockchain_via_sync( except Exception as e: raise LoggedError(f"admin_addPeer failed: {e}") from e - time.sleep(1) # quick sleep to allow for connection - TODO: is this - # necessary? + # quick sleep to allow for connection - TODO: is this necessary? + time.sleep(1) try: sync_peer_count = sync_net_rpc.peer_count() @@ -378,9 +378,8 @@ def test_blockchain_via_sync( ) try: - version = last_valid_payload.new_payload_version # log version - # used for - # debugging + # log version used for debugging + version = last_valid_payload.new_payload_version logger.info(f"Sending target payload via engine_newPayloadV{version}") # send the payload to sync client diff --git a/src/pytest_plugins/custom_logging/plugin_logging.py b/src/pytest_plugins/custom_logging/plugin_logging.py index 2580f9f7af5..3387992c8a9 100644 --- a/src/pytest_plugins/custom_logging/plugin_logging.py +++ b/src/pytest_plugins/custom_logging/plugin_logging.py @@ -9,9 +9,10 @@ use case, timestamps are essential to verify timing issues against the clients log. -This module provides both: 1. A standalone logging configuration system that -can be used in any Python project 2. A pytest plugin that automatically -configures logging for pytest sessions +This module provides both: +1. A standalone logging configuration system that can be used in any + Python project +2. A pytest plugin that automatically configures logging for pytest sessions """ import functools @@ -100,8 +101,8 @@ class UTCFormatter(logging.Formatter): suffix. """ - def formatTime(self, record, datefmt=None): # noqa: D102,N802 # camelcase - # required + def formatTime(self, record, datefmt=None): # noqa: D102,N802 + # camelcase required dt = datetime.fromtimestamp(record.created, tz=timezone.utc) return dt.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3] + "+00:00" @@ -176,12 +177,15 @@ def configure_logging( This function can be used in any Python project to set up logging with the same settings as the pytest plugin. - Args: log_level: The logging level to use (name or numeric value) log_file: - Path to the log file (if None, no file logging is set up) log_to_stdout: - Whether to log to stdout log_format: The log format string use_color: - Whether to use colors in stdout output (auto-detected if None) + Args: + log_level: The logging level to use (name or numeric value) + log_file: Path to the log file (if None, no file logging is set up) + log_to_stdout: Whether to log to stdout + log_format: The log format string + use_color: Whether to use colors in stdout output (auto-detected if None) Returns: The file handler if log_file is provided, otherwise None + """ # Initialize root logger root_logger = logging.getLogger() @@ -317,7 +321,7 @@ def pytest_report_header(config: pytest.Config) -> list[str]: return [] -def pytest_terminal_summary(terminalreporter: TerminalReporter, exitstatus: int) -> None: +def pytest_terminal_summary(terminalreporter: TerminalReporter) -> None: """ Display the log file path in the terminal summary like the HTML report does. diff --git a/src/pytest_plugins/execute/eth_config/eth_config.py b/src/pytest_plugins/execute/eth_config/eth_config.py index 2f6a08c6f5e..c373083eb90 100644 --- a/src/pytest_plugins/execute/eth_config/eth_config.py +++ b/src/pytest_plugins/execute/eth_config/eth_config.py @@ -195,8 +195,8 @@ def all_rpc_endpoints(config) -> Dict[str, List[EthRPC]]: Derive a mapping of exec clients to the RPC URLs they are reachable at. """ rpc_endpoint = config.getoption("rpc_endpoint") - el_clients: List[str] = config.getoption("majority_clients") # besu, - # erigon, .. + # besu, erigon, .. + el_clients: List[str] = config.getoption("majority_clients") if len(el_clients) == 0: endpoint_name = rpc_endpoint try: diff --git a/src/pytest_plugins/execute/eth_config/execute_types.py b/src/pytest_plugins/execute/eth_config/execute_types.py index aea17d14fb6..393d5c251ca 100644 --- a/src/pytest_plugins/execute/eth_config/execute_types.py +++ b/src/pytest_plugins/execute/eth_config/execute_types.py @@ -284,8 +284,13 @@ def preprocess_fork_times_blocks(cls, data: Any): Fork times and block numbers have the following format in the root of the object: - ``` "berlinBlock": 0, "londonBlock": 0, ... "pragueTime": 0, - "osakaTime": 1753379304, ``` + ``` + "berlinBlock": 0, + "londonBlock": 0, + ... + "pragueTime": 0, + "osakaTime": 1753379304, + ``` This function strips the "*Block" and "*Time" part and moves the values. diff --git a/src/pytest_plugins/execute/execute.py b/src/pytest_plugins/execute/execute.py index 5e6353b70a9..42676a62113 100644 --- a/src/pytest_plugins/execute/execute.py +++ b/src/pytest_plugins/execute/execute.py @@ -405,7 +405,7 @@ def pytest_generate_tests(metafunc: pytest.Metafunc): ) -def pytest_collection_modifyitems(config: pytest.Config, items: List[pytest.Item]): +def pytest_collection_modifyitems(items: List[pytest.Item]): """ Remove transition tests and add the appropriate execute markers to the test. diff --git a/src/pytest_plugins/execute/pre_alloc.py b/src/pytest_plugins/execute/pre_alloc.py index 9fcb524fb87..4ec7c4e4ae7 100644 --- a/src/pytest_plugins/execute/pre_alloc.py +++ b/src/pytest_plugins/execute/pre_alloc.py @@ -414,8 +414,8 @@ def fund_eoa( authorization_list=[ AuthorizationTuple( chain_id=self._chain_id, - address=0, # Reset delegation to an address - # without code + # Reset delegation to an address without code + address=0, nonce=eoa.nonce, signer=eoa, ), @@ -487,8 +487,11 @@ def empty_account(self) -> Address: Add a previously unused account guaranteed to be empty to the pre-alloc. - This ensures the account has: - Zero balance - Zero nonce - No code - - No storage + This ensures the account has: + - Zero balance + - Zero nonce + - No code + - No storage This is different from precompiles or system contracts. The function does not send any transactions, ensuring that the account remains diff --git a/src/pytest_plugins/filler/filler.py b/src/pytest_plugins/filler/filler.py index e22c3334719..7e4f1998ffe 100644 --- a/src/pytest_plugins/filler/filler.py +++ b/src/pytest_plugins/filler/filler.py @@ -1,8 +1,9 @@ """ -Top-level pytest configuration file providing: - Command-line options, - -Test-fixtures that can be used by all test cases, and that modifies pytest -hooks in order to fill test specs for all tests and writes the generated -fixtures to file. +Top-level pytest configuration file providing: +- Command-line options, +- Test-fixtures that can be used by all test cases, +and that modifies pytest hooks in order to fill test specs for all tests +and writes the generated fixtures to file. """ import configparser @@ -60,8 +61,11 @@ class PhaseManager: Manages the execution phase for fixture generation. The filler plugin supports two-phase execution for pre-allocation group - generation: - Phase 1: Generate pre-allocation groups (pytest run with - --generate-pre-alloc-groups). - Phase 2: Fill fixtures using pre-allocation + generation: + - Phase 1: Generate pre-allocation groups (pytest run with + --generate-pre-alloc-groups). + + - Phase 2: Fill fixtures using pre-allocation groups (pytest run with --use-pre-alloc-groups). Note: These are separate pytest runs orchestrated by the CLI wrapper. Each @@ -76,9 +80,11 @@ def from_config(cls, config: pytest.Config) -> "Self": """ Create a PhaseManager from pytest configuration. - Flag logic: - use_pre_alloc_groups: We're in phase 2 (FILL) after phase - 1 (PRE_ALLOC_GENERATION). - generate_pre_alloc_groups or - generate_all_formats: We're in phase 1 (PRE_ALLOC_GENERATION). - + Flag logic: + - use_pre_alloc_groups: We're in phase 2 (FILL) after phase + 1 (PRE_ALLOC_GENERATION). + - generate_pre_alloc_groups or generate_all_formats: + We're in phase 1 (PRE_ALLOC_GENERATION). - Otherwise: Normal single-phase filling (FILL). Note: generate_all_formats triggers PRE_ALLOC_GENERATION because the @@ -331,15 +337,17 @@ def calculate_post_state_diff(post_state: Alloc, genesis_state: Alloc) -> Alloc: storing only the accounts that changed during test execution, rather than the full post-state which may contain thousands of unchanged accounts. - Returns an Alloc containing only the accounts that: - Changed between - genesis and post state (balance, nonce, storage, code) - Were created - during test execution (new accounts) - Were deleted during test execution - (represented as None) + Returns an Alloc containing only the accounts that: + - Changed between genesis and post state (balance, nonce, storage, code) + - Were created during test execution (new accounts) + - Were deleted during test execution (represented as None) - Args: post_state: Final state after test execution genesis_state: Genesis - pre-allocation state + Args: + post_state: Final state after test execution + genesis_state: Genesis pre-allocation state Returns: Alloc containing only the state differences for efficient storage + """ diff: Dict[Address, Account | None] = {} @@ -722,7 +730,10 @@ def pytest_report_teststatus(report, config: pytest.Config): 1. To disable test session progress report if we're writing the JSON fixtures to stdout to be read by a consume command on stdin. I.e., don't - write this type of output to the console: ```text ...x... ``` + write this type of output to the console: + ```text + ...x... + ``` """ if config.fixture_output.is_stdout: # type: ignore[attr-defined] return report.outcome, "", report.outcome.upper() @@ -860,10 +871,8 @@ def pytest_runtest_makereport(item, call): ]: report.user_properties.append(("evm_dump_dir", item.config.evm_dump_dir)) else: - report.user_properties.append(("evm_dump_dir", "N/A")) # not - # yet - # for - # EOF + # not yet for EOF + report.user_properties.append(("evm_dump_dir", "N/A")) def pytest_html_report_title(report): @@ -1444,9 +1453,10 @@ def pytest_sessionfinish(session: pytest.Session, exitstatus: int): """ Perform session finish tasks. - - Save pre-allocation groups (phase 1) - Remove any lock files that may - have been created. - Generate index file for all produced fixtures. - - Create tarball of the output directory if the output is a tarball. + - Save pre-allocation groups (phase 1) + - Remove any lock files that may have been created. + - Generate index file for all produced fixtures. + - Create tarball of the output directory if the output is a tarball. """ del exitstatus diff --git a/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py b/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py index dcf2f9c7949..aae46ab5feb 100644 --- a/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py +++ b/src/pytest_plugins/filler/gen_test_doc/gen_test_doc.py @@ -3,14 +3,17 @@ It generates the top-level "Test Case Reference" section in EEST's mkdocs site. -Note: ---- - No output directory is specified for the generated output; file IO +Note: +---- +- No output directory is specified for the generated output; file IO occurs via the `mkdocs-gen-files` plugin. `mkdocs serve` writes intermediate files to our local `docs/` directory and then copies it to the site directory. We modify `docs/navigation.md` and write all other output underneath `docs/tests`. If mkdocs is interrupted, these intermediate artifacts are left in `docs/`. -Usage: ------ +Usage: +------ !!! note "Ensuring a clean build" @@ -33,6 +36,7 @@ ```console uv run mkdocs serve ``` + """ import glob @@ -145,10 +149,12 @@ def get_import_path(path: Path) -> str: """ Get the import path for a given path. - - For modules, strip the file extension. - For directories (i.e., packages - such as `tests.berlin`), `with_suffix()` is ignored. + - For modules, strip the file extension. + - For directories (i.e., packages such as `tests.berlin`), + `with_suffix()` is ignored. - To do: ------ + To do: + ------ - This should be combined with `get_test_function_import_path`. """ @@ -313,7 +319,8 @@ def get_doc_site_base_url(self) -> str: deploys a version of the site underneath a sub-directory named after the version, e.g.: - - https://eest.ethereum.org/main/ - https://eest.ethereum.org/v4.1.0/ + - https://eest.ethereum.org/main/ + - https://eest.ethereum.org/v4.1.0/ We need to be able to include the javascript available at: @@ -358,8 +365,8 @@ def create_function_page_props(self, test_functions: Dict["str", List[Item]]) -> ] for function_id, function_items in test_functions.items(): assert all(isinstance(item, pytest.Function) for item in function_items) - items = cast(List[pytest.Function], function_items) # help mypy - # infer type + # help mypy infer type + items = cast(List[pytest.Function], function_items) # extract parametrized test cases for each test function test_cases = [] @@ -516,8 +523,8 @@ def add_directory_page_props(self) -> None: # development fork Currently breaks for # `tests/unscheduled/eip7692_eof_v1/index.md` target_or_valid_fork=fork.capitalize() if fork else "Unknown", - package_name=get_import_path(directory), # init.py will be - # used for docstrings + # init.py will be used for docstrings + package_name=get_import_path(directory), is_benchmark=is_benchmark, ) @@ -566,8 +573,8 @@ def add_markdown_page_props(self) -> None: title=md_path.stem, path=md_path, source_code_url=generate_github_url(md_path, branch_or_commit_or_tag=self.ref), - pytest_node_id=str(md_path), # abuse: not a test, but used in - # source code link + # abuse: not a test, but used in source code link + pytest_node_id=str(md_path), target_or_valid_fork="", package_name="", ) @@ -586,27 +593,29 @@ def sort_by_fork_deployment_and_path(x: PageProps) -> Tuple[Any, ...]: Nav entries / output files contain special cases such as: - - ("Test Case Reference",) -> tests/index.md - ("Test Case - Reference", "Berlin") -> tests/berlin/index.md - ("Test Case - Reference", "EIP-7692 EOF V1", tracker.md") - tests/unscheduled/eip7692_eof_v1/tracker.md - ("Test Case - Reference", "Shanghai", "EIP-3855 PUSH0", "Spec") -> + - ("Test Case Reference",) -> tests/index.md + - ("Test Case Reference", "Berlin") -> tests/berlin/index.md + - ("Test Case Reference", "EIP-7692 EOF V1", tracker.md") + tests/unscheduled/eip7692_eof_v1/tracker.md + - ("Test Case Reference", "Shanghai", "EIP-3855 PUSH0", "Spec") -> tests/shanghai/eip3855_push0/spec.py This function provides and ordering to sort nav men entries as follows: 1. Forks are listed in the chronological order that they were - deployed. 2. Special files listed first (before test pages): "*.md" - and `Spec.py`, 3. The page's corresponding file path under + deployed. + 2. Special files listed first (before test pages): "*.md" + and `Spec.py`, + 3. The page's corresponding file path under `./tests/`. """ length = len(x.path.parts) if length > 1: - fork = str(x.path.parts[1]).lower() # the fork folder from the - # relative path - if fork not in fork_order: # unscheduled features added to the - # end + # the fork folder from the relative path + fork = str(x.path.parts[1]).lower() + # unscheduled features added to the end + if fork not in fork_order: return (999, str(x.path)) if length == 1: return (0,) diff --git a/src/pytest_plugins/filler/ported_tests.py b/src/pytest_plugins/filler/ported_tests.py index b470e8e4e97..0d7f5475bbb 100644 --- a/src/pytest_plugins/filler/ported_tests.py +++ b/src/pytest_plugins/filler/ported_tests.py @@ -4,10 +4,13 @@ This plugin extracts and displays information from @pytest.mark.ported_from markers, showing either the static filler file paths or associated PR URLs. -Usage: ------ # Show static filler file paths uv run fill --show-ported-from -tests/ +Usage: +------ +# Show static filler file paths: +# uv run fill --show-ported-from tests/ -# Show PR URLs instead uv run fill --show-ported-from=prs tests/ +# Show PR URLs instead: +# uv run fill --show-ported-from=prs tests/ The plugin will: 1. Collect all test items with @pytest.mark.ported_from markers @@ -17,11 +20,17 @@ 4. Skip test execution (collection only) 5. Exclude tests with coverage_missed_reason from output -Marker Format: -------------- @pytest.mark.ported_from( -["path/to/static_filler1.json", "path/to/static_filler2.json"], pr=[ -"https://github.com/ethereum/execution-spec-tests/pull/1234", -"https://github.com/ethereum/execution-spec-tests/pull/5678", ], -coverage_missed_reason="Optional reason for accepted coverage miss", ) +Marker Format: +-------------- +@pytest.mark.ported_from( + ["path/to/static_filler1.json", + "path/to/static_filler2.json"], + pr=[ + "https://github.com/ethereum/execution-spec-tests/pull/1234", + "https://github.com/ethereum/execution-spec-tests/pull/5678", + ], + coverage_missed_reason="Optional reason for accepted coverage miss", +) """ import re diff --git a/src/pytest_plugins/filler/pre_alloc.py b/src/pytest_plugins/filler/pre_alloc.py index 8330a3f0761..ef6c6509765 100644 --- a/src/pytest_plugins/filler/pre_alloc.py +++ b/src/pytest_plugins/filler/pre_alloc.py @@ -263,8 +263,11 @@ def empty_account(self) -> Address: Add a previously unused account guaranteed to be empty to the pre-alloc. - This ensures the account has: - Zero balance - Zero nonce - No code - - No storage + This ensures the account has: + - Zero balance + - Zero nonce + - No code + - No storage This is different from precompiles or system contracts. The function does not send any transactions, ensuring that the account remains diff --git a/src/pytest_plugins/filler/tests/test_benchmarking.py b/src/pytest_plugins/filler/tests/test_benchmarking.py index fe7fd976c6c..42c8f80874e 100644 --- a/src/pytest_plugins/filler/tests/test_benchmarking.py +++ b/src/pytest_plugins/filler/tests/test_benchmarking.py @@ -36,10 +36,13 @@ def setup_test_directory_structure( """ Set up the common test directory structure used across multiple tests. - Args: pytester: The pytest Pytester fixture test_content: The content to - write to the test file test_filename: The name of the test file to create + Args: + pytester: The pytest Pytester fixture + test_content: The content to write to the test file + test_filename: The name of the test file to create Returns: The path to the created test module file + """ tests_dir = pytester.mkdir("tests") istanbul_tests_dir = tests_dir / "istanbul" diff --git a/src/pytest_plugins/filler/tests/test_phase_manager.py b/src/pytest_plugins/filler/tests/test_phase_manager.py index 4463788c743..6aa6e5fa7b4 100644 --- a/src/pytest_plugins/filler/tests/test_phase_manager.py +++ b/src/pytest_plugins/filler/tests/test_phase_manager.py @@ -111,24 +111,20 @@ def test_all_flag_combinations(self): test_cases = [ # (generate_pre_alloc, use_pre_alloc, generate_all) -> # (current_phase, has_previous) - (False, False, False, FixtureFillingPhase.FILL, False), # Normal - # fill + # Normal fill + (False, False, False, FixtureFillingPhase.FILL, False), # Generate all triggers phase 1 (False, False, True, FixtureFillingPhase.PRE_ALLOC_GENERATION, False), (False, True, False, FixtureFillingPhase.FILL, True), # Phase 2 - (False, True, True, FixtureFillingPhase.FILL, True), # Phase 2 - # with - # generate - # all + # Phase 2 with generate all + (False, True, True, FixtureFillingPhase.FILL, True), (True, False, False, FixtureFillingPhase.PRE_ALLOC_GENERATION, False), # Phase 1 # Phase 1 with generate all (True, False, True, FixtureFillingPhase.PRE_ALLOC_GENERATION, False), - (True, True, False, FixtureFillingPhase.FILL, True), # Invalid but - # use_pre_alloc - # wins - (True, True, True, FixtureFillingPhase.FILL, True), # Invalid but - # use_pre_alloc - # wins + # Invalid but use_pre_alloc wins + (True, True, False, FixtureFillingPhase.FILL, True), + # Invalid but use_pre_alloc wins + (True, True, True, FixtureFillingPhase.FILL, True), ] for gen_pre, use_pre, gen_all, expected_phase, has_previous in test_cases: diff --git a/src/pytest_plugins/filler/tests/test_slow_marker_pre_alloc.py b/src/pytest_plugins/filler/tests/test_slow_marker_pre_alloc.py index 1258211ce98..67b0d43c5f1 100644 --- a/src/pytest_plugins/filler/tests/test_slow_marker_pre_alloc.py +++ b/src/pytest_plugins/filler/tests/test_slow_marker_pre_alloc.py @@ -231,9 +231,12 @@ def test_slow_for_integration(state_test: StateTestFiller, pre: Alloc): ] # The test generates 3 formats (state_test, blockchain_test, - # blockchain_test_engine) But it also runs on multiple forks (Cancun and - # Prague), so expect more tests This is fine - the important thing is that - # they all pass + # blockchain_test_engine). + + # But it also runs on multiple forks (Cancun and + # Prague), so expect more tests. + + # This is fine - the important thing is that they all pass. result = pytester.runpytest(*args) # Verify that tests passed (don't care about exact count due to fork diff --git a/src/pytest_plugins/filler/tests/test_verify_sync_marker.py b/src/pytest_plugins/filler/tests/test_verify_sync_marker.py index 381fe0f31b9..ce76da9c608 100644 --- a/src/pytest_plugins/filler/tests/test_verify_sync_marker.py +++ b/src/pytest_plugins/filler/tests/test_verify_sync_marker.py @@ -71,26 +71,34 @@ def test_verify_sync_marker( """ Test blockchain sync fixture generation with verify_sync marker. - The test module has 3 test functions (4 test cases with parametrization): - - test_verify_sync_default: generates all formats except sync (no verify_sync - marker) - test_verify_sync_with_marker: generates all formats including - sync (has verify_sync marker) - test_verify_sync_with_param_marks: tests - parametrized marks with verify_sync (2 cases) - - Each test generates fixture formats: - BlockchainFixture (always) - - BlockchainEngineFixture (always) - BlockchainEngineSyncFixture (only when - marked with verify_sync marker) - - Expected outcomes: - 4 test cases total - Each generates BlockchainFixture - (4) and BlockchainEngineFixture (4) = 8 fixtures - Sync fixtures: - - test_verify_sync_with_marker: 1 sync fixture ✓ - - test_verify_sync_with_param_marks[no_exception]: 1 sync fixture ✓ - Total - sync fixtures: 2 - Not generated (due to exception_test marker): - - test_verify_sync_with_param_marks[with_exception]: sync fixture not - generated - - Final counts: - Passed: 8 (base fixtures) + 2 (sync fixtures) = 10 passed - - Skipped: 0 skipped - Failed: 0 failed + The test module has 3 test functions (4 test cases with parametrization): + - test_verify_sync_default: generates all formats except sync + (no verify_sync marker) + - test_verify_sync_with_marker: generates all formats including sync + (has verify_sync marker) + - test_verify_sync_with_param_marks: tests parametrized marks with + verify_sync (2 cases) + + Each test generates fixture formats: + - BlockchainFixture (always) + - BlockchainEngineFixture (always) + - BlockchainEngineSyncFixture (only when marked with verify_sync marker) + + Expected outcomes: + - 4 test cases total + - Each generates BlockchainFixture (4) and BlockchainEngineFixture (4) = + 8 fixtures + + - Sync fixtures: + - test_verify_sync_with_marker: 1 sync fixture ✓ + - test_verify_sync_with_param_marks[no_exception]: 1 sync fixture ✓ + - Total sync fixtures: 2 - Not generated (due to exception_test marker): + - test_verify_sync_with_param_marks[with_exception]: sync fixture + not generated + + Final counts: + - Passed: 8 (base fixtures) + 2 (sync fixtures) = 10 passed + - Skipped: 0 skipped - Failed: 0 failed """ # Create proper directory structure for tests tests_dir = pytester.mkdir("tests") diff --git a/src/pytest_plugins/forks/forks.py b/src/pytest_plugins/forks/forks.py index 7121c8dd411..994a590d795 100644 --- a/src/pytest_plugins/forks/forks.py +++ b/src/pytest_plugins/forks/forks.py @@ -86,10 +86,14 @@ def __init__( """ Initialize a new fork parametrizer object for a given fork. - Args: fork: The fork for which the test cases will be parametrized. - marks: A list of pytest marks to apply to all the test cases - parametrized by the fork. fork_covariant_parameters: A list of fork - covariant parameters for the test case, for unit testing purposes only. + Args: + fork: The fork for which the test cases will be parametrized. + marks: A list of pytest marks to apply to all the test cases + parametrized by the fork. + fork_covariant_parameters: A list of fork covariant parameters + for the test case, for unit testing + purposes only. + """ if marks is None: marks = [] @@ -173,11 +177,15 @@ def __init__( """ Initialize a new covariant descriptor. - Args: argnames: The names of the parameters that are covariant with the - fork. fn: A function that takes the fork as the single parameter and - returns the values for the parameter for each fork. selector: A - function that filters the values for the parameter. marks: A list of - pytest marks to apply to the test cases parametrized by the parameter. + Args: + argnames: The names of the parameters that are covariant with the + fork. + fn: A function that takes the fork as the single parameter and + returns the values for the parameter for each fork. + selector: A function that filters the values for the parameter. + marks: A list of pytest marks to apply to the test cases + parametrized by the parameter. + """ self.argnames = ( [argname.strip() for argname in argnames.split(",")] @@ -254,11 +262,16 @@ class CovariantDecorator(CovariantDescriptor): The decorator must be subclassed with the appropriate class variables before initialization. - Attributes: marker_name: Name of the marker. description: Description of - the marker. fork_attribute_name: Name of the method to call on the fork to - get the values. marker_parameter_names: Names of the parameters to be - parametrized in the test function. indirect: Whether the parameters should - be passed through fixtures (indirect parametrization). + Attributes: + marker_name: Name of the marker. + description: Description of the marker. + fork_attribute_name: Name of the method to call on the fork to + get the values. + marker_parameter_names: Names of the parameters to be parametrized + in the test function. + indirect: Whether the parameters should be passed through fixtures + (indirect parametrization). + """ marker_name: ClassVar[str] @@ -402,9 +415,8 @@ def pytest_configure(config: pytest.Config): Register the plugin's custom markers and process command-line options. Custom marker registration: - https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html# registering- - # custom - -markers + https://docs.pytest.org/en/7.1.x/how-to/ + writing_plugins.html# registering-custom-markers """ config.addinivalue_line( "markers", @@ -586,11 +598,12 @@ class ValidityMarker(ABC): Instantiation must be done per test function, and the `process` method must be called to process the fork arguments. - When subclassing, the following optional parameters can be set: - - marker_name: Name of the marker, if not set, the class name is converted to - underscore. - mutually_exclusive: List of other marker types incompatible - with this one. - flag: Whether the marker is a flag and should always be - included. + When subclassing, the following optional parameters can be set: + - marker_name: Name of the marker, if not set, the class name is + converted to underscore. + - mutually_exclusive: List of other marker types incompatible + with this one. + - flag: Whether the marker is a flag and should always be included. """ marker_name: ClassVar[str] @@ -734,13 +747,18 @@ class ValidFrom(ValidityMarker): Marker used to specify the fork from which the test is valid. The test will not be filled for forks before the specified fork. - ```python import pytest + ```python + import pytest from ethereum_test_tools import Alloc, StateTestFiller - @pytest.mark.valid_from("London") def - test_something_only_valid_after_london( state_test: StateTestFiller, pre: - Alloc ): pass ``` + @pytest.mark.valid_from("London") + def test_something_only_valid_after_london( + state_test: StateTestFiller, + pre: Alloc + ): + pass + ``` In this example, the test will only be filled for the London fork and after, e.g. London, Paris, Shanghai, Cancun, etc. @@ -760,13 +778,18 @@ class ValidUntil(ValidityMarker): Marker to specify the fork until which the test is valid. The test will not be filled for forks after the specified fork. - ```python import pytest + ```python + import pytest from ethereum_test_tools import Alloc, StateTestFiller - @pytest.mark.valid_until("London") def - test_something_only_valid_until_london( state_test: StateTestFiller, pre: - Alloc ): pass ``` + @pytest.mark.valid_until("London") + def test_something_only_valid_until_london( + state_test: StateTestFiller, + pre: Alloc + ): + pass + ``` In this example, the test will only be filled for the London fork and before, e.g. London, Berlin, Istanbul, etc. @@ -785,13 +808,18 @@ class ValidAt(ValidityMarker): """ Marker to specify each fork individually for which the test is valid. - ```python import pytest + ```python + import pytest from ethereum_test_tools import Alloc, StateTestFiller - @pytest.mark.valid_at("London", "Cancun") def - test_something_only_valid_at_london_and_cancun( state_test: - StateTestFiller, pre: Alloc ): pass ``` + @pytest.mark.valid_at("London", "Cancun") + def test_something_only_valid_at_london_and_cancun( + state_test: StateTestFiller, + pre: Alloc + ): + pass + ``` In this example, the test will only be filled for the London and Cancun forks. @@ -811,13 +839,18 @@ class ValidAtTransitionTo(ValidityMarker, mutually_exclusive=[ValidAt, ValidFrom and at block 5 (for pre-merge forks) or at timestamp 15,000 (for post-merge forks) the fork transition occurs. - ```python import pytest + ```python + import pytest from ethereum_test_tools import Alloc, BlockchainTestFiller - @pytest.mark.valid_at_transition_to("London") def - test_something_that_happens_during_the_fork_transition_to_london( - blockchain_test: BlockchainTestFiller, pre: Alloc ): pass ``` + @pytest.mark.valid_at_transition_to("London") + def test_something_that_happens_during_the_fork_transition_to_london( + blockchain_test: BlockchainTestFiller, + pre: Alloc + ): + pass + ``` In this example, the test will only be filled for the fork that transitions to London at block number 5, `BerlinToLondonAt5`, and no other forks. @@ -833,17 +866,23 @@ class ValidAtTransitionTo(ValidityMarker, mutually_exclusive=[ValidAt, ValidFrom This marker also accepts the following keyword arguments: - `subsequent_transitions`: Force the test to also fill for subsequent fork - transitions. - `until`: Implies `subsequent_transitions` and puts a limit + transitions. + - `until`: Implies `subsequent_transitions` and puts a limit on which transition fork will the test filling will be limited to. - For example: ```python @pytest.mark.valid_at_transition_to("Cancun", - subsequent_transitions=True) ``` + For example: + ```python + @pytest.mark.valid_at_transition_to("Cancun", subsequent_transitions=True) + ``` produces tests on `ShanghaiToCancunAtTime15k` and `CancunToPragueAtTime15k`, and any transition fork after that. - And: ```python @pytest.mark.valid_at_transition_to("Cancun", - subsequent_transitions=True, until="Prague") ``` + And: + ```python + @pytest.mark.valid_at_transition_to("Cancun", + subsequent_transitions=True, until="Prague") + ``` produces tests on `ShanghaiToCancunAtTime15k` and `CancunToPragueAtTime15k`, but no forks after Prague. @@ -881,12 +920,18 @@ class ValidForBPOForks(ValidityMarker, marker_name="valid_for_bpo_forks", flag=T """ Marker to specify that a test is valid for BPO forks. - ```python import pytest + ```python + import pytest from ethereum_test_tools import Alloc, BlockchainTestFiller - @pytest.mark.valid_for_bpo_forks() def test_something_in_a_bpo_fork( - blockchain_test: BlockchainTestFiller, pre: Alloc ): pass ``` + @pytest.mark.valid_for_bpo_forks() + def test_something_in_a_bpo_fork( + blockchain_test: BlockchainTestFiller, + pre: Alloc + ): + pass + ``` """ def _process_with_marker_args(self) -> Set[Fork]: diff --git a/src/pytest_plugins/forks/tests/test_bad_command_line_options.py b/src/pytest_plugins/forks/tests/test_bad_command_line_options.py index 448e7432164..8059bbb1c3e 100644 --- a/src/pytest_plugins/forks/tests/test_bad_command_line_options.py +++ b/src/pytest_plugins/forks/tests/test_bad_command_line_options.py @@ -58,9 +58,9 @@ ) def test_bad_options(pytester, options, error_string): """ - Test that a test with an invalid command-line options: - Creates an outcome - with exactly one error. - Triggers the expected error string in pytest's - console output. + Test that a test with an invalid command-line options: + - Creates an outcome with exactly one error. + - Triggers the expected error string in pytest's console output. Each invalid marker/marker combination is tested with one test in its own test session. diff --git a/src/pytest_plugins/forks/tests/test_bad_validity_markers.py b/src/pytest_plugins/forks/tests/test_bad_validity_markers.py index ea8156408c2..a3ff787973f 100644 --- a/src/pytest_plugins/forks/tests/test_bad_validity_markers.py +++ b/src/pytest_plugins/forks/tests/test_bad_validity_markers.py @@ -216,9 +216,9 @@ def test_case(state_test): ) def test_invalid_validity_markers(pytester, error_string, test_function): """ - Test that a test with an invalid marker cases: - Creates an outcome with - exactly one error. - Triggers the expected error string in pytest's console - output. + Test that a test with an invalid marker cases: + - Creates an outcome with exactly one error. + - Triggers the expected error string in pytest's console output. Each invalid marker/marker combination is tested with one test in its own test session. diff --git a/src/pytest_plugins/pytest_hive/pytest_hive.py b/src/pytest_plugins/pytest_hive/pytest_hive.py index d6effbb4d21..b19ffbeb610 100644 --- a/src/pytest_plugins/pytest_hive/pytest_hive.py +++ b/src/pytest_plugins/pytest_hive/pytest_hive.py @@ -8,9 +8,11 @@ These fixtures are used when creating the hive test suite. -Log Capture Architecture: ------------------------- This module implements a -log capture approach that ensures all logs, including those generated during -fixture teardown, are properly captured and included in the test results. +Log Capture Architecture: +------------------------- +This module implements a log capture approach that ensures all logs, +including those generated during fixture teardown, are properly +captured and included in the test results. The key insight is that we need to ensure that test finalization happens *before* the test suite is finalized, but *after* all fixtures have been torn @@ -19,9 +21,12 @@ 1. Since the `hive_test` fixture depends on the `test_suite` fixture, pytest guarantees that the teardown of `hive_test` runs before the teardown of -`test_suite` 2. All logs are processed and the test is finalized in the -teardown phase of the `hive_test` fixture using the pytest test report data 3. -This sequencing ensures that all logs are captured and the test is properly +`test_suite` + +2. All logs are processed and the test is finalized in the +teardown phase of the `hive_test` fixture using the pytest test report data + +3. This sequencing ensures that all logs are captured and the test is properly finalized before its parent test suite is finalized This approach relies on the pytest fixture dependency graph and teardown @@ -138,8 +143,13 @@ def pytest_runtest_makereport(item, call): This is used to get the test result and pass it to the hive test suite. - Available as: - result_setup - setup result - result_call - test result - - result_teardown - teardown result + Available as: + - result_setup + - setup result + - result_call + - test result + - result_teardown + - teardown result """ del call diff --git a/src/pytest_plugins/shared/execute_fill.py b/src/pytest_plugins/shared/execute_fill.py index c47e217ea74..0df88c2ef38 100644 --- a/src/pytest_plugins/shared/execute_fill.py +++ b/src/pytest_plugins/shared/execute_fill.py @@ -20,12 +20,6 @@ "env", } """ - - - - - - List of test parameters that have a default fixture value which can be retrieved and used for the test instance if it was not explicitly specified when calling from the test function. diff --git a/src/pytest_plugins/spec_version_checker/spec_version_checker.py b/src/pytest_plugins/spec_version_checker/spec_version_checker.py index 5fd965139ae..1ddd8d96854 100644 --- a/src/pytest_plugins/spec_version_checker/spec_version_checker.py +++ b/src/pytest_plugins/spec_version_checker/spec_version_checker.py @@ -70,8 +70,9 @@ def get_ref_spec_from_module( """ Return the reference spec object defined in a module. - Args: module: The module to extract reference spec from github_token: - Optional GitHub token for API authentication + Args: + module: The module to extract reference spec from + github_token: Optional GitHub token for API authentication Raises: Exception: If the module path contains "eip" and the module does not define a reference spec. @@ -79,6 +80,7 @@ def get_ref_spec_from_module( Returns: spec_obj: Return None if the module path does not contain "eip", i.e., the module is not required to define a reference spec, otherwise, return the ReferenceSpec object as defined by the module. + """ if not is_test_for_an_eip(str(module.__file__)): return None @@ -114,8 +116,10 @@ def test_eip_spec_version(module: ModuleType, github_token: Optional[str] = None Test that the ReferenceSpec object as defined in the test module is not outdated when compared to the remote hash from ethereum/EIPs. - Args: module: Module to test github_token: Optional GitHub token for API - authentication + Args: + module: Module to test + github_token: Optional GitHub token for API authentication + """ ref_spec = get_ref_spec_from_module(module, github_token=github_token) assert ref_spec, "No reference spec object defined" @@ -149,8 +153,11 @@ def __init__(self, name: str, parent: Node, **kwargs: Any): """ Initialize the test item. - Args: name: Name of the test parent: Parent node **kwargs: Additional - keyword arguments + Args: + name: Name of the test + parent: Parent node + **kwargs: Additional keyword arguments + """ super().__init__(name, parent) self.module = None # type: ignore @@ -163,8 +170,10 @@ def from_parent(cls, parent: Node, **kw: Any) -> "EIPSpecTestItem": https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.fr om_parent. - Args: parent: The parent Node kw: Additional keyword arguments (module, - github_token) + Args: + parent: The parent Node + kw: Additional keyword arguments (module, github_token) + """ module = kw.pop("module", None) github_token = kw.pop("github_token", None) @@ -189,9 +198,7 @@ def reportinfo(self) -> tuple[str, int, str]: return "spec_version_checker", 0, f"{self.name}" -def pytest_collection_modifyitems( - session: pytest.Session, config: pytest.Config, items: List[Item] -): +def pytest_collection_modifyitems(config: pytest.Config, items: List[Item]): """ Insert a new test EIPSpecTestItem for every test module with 'eip' in its path. diff --git a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py index 089f8bbb9cc..eb7bb154e9f 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py +++ b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py @@ -52,15 +52,20 @@ def test_wycheproof_valid(state_test: StateTestFiller, pre: Alloc, post: dict, t "input_data,expected_output,vector_gas_value", vectors_from_file("secp256r1_special_case_r_s.json") + vectors_from_file("secp256r1_modified_r_s.json"), - # Test vectors generated from Wycheproof's ECDSA secp256r1 SHA-256 test suite, invalid cases - # Source: https://github.com/C2SP/wycheproof/blob/main/testvectors/ecdsa_secp256r1_sha256_test.json + # Test vectors generated from Wycheproof's ECDSA secp256r1 SHA-256 + # test suite, invalid cases + # Source: https://github.com/C2SP/wycheproof/blob/main/ + # testvectors/ecdsa_secp256r1_sha256_test.json ) @pytest.mark.parametrize("precompile_address", [Spec.P256VERIFY], ids=[""]) @EIPChecklist.Precompile.Test.CallContexts.Normal() @EIPChecklist.Precompile.Test.Inputs.Invalid() @EIPChecklist.Precompile.Test.Inputs.MaxValues() def test_wycheproof_invalid(state_test: StateTestFiller, pre: Alloc, post: dict, tx: Transaction): - """Test P256Verify precompile with Wycheproof test suite (invalid cases).""" + """ + Test P256Verify precompile with Wycheproof test suite + (invalid cases). + """ state_test(env=Environment(), pre=pre, post=post, tx=tx) @@ -68,15 +73,19 @@ def test_wycheproof_invalid(state_test: StateTestFiller, pre: Alloc, post: dict, "input_data,expected_output,vector_gas_value", vectors_from_file("secp256r1_small_large_r_s.json") + vectors_from_file("secp256r1_special_points.json"), - # Test vectors generated from Wycheproof's ECDSA secp256r1 SHA-256 test suite, - # valid/invalid cases - # Source: https://github.com/C2SP/wycheproof/blob/main/testvectors/ecdsa_secp256r1_sha256_test.json + # Test vectors generated from Wycheproof's ECDSA secp256r1 SHA-256 + # test suite, valid/invalid cases + # Source: https://github.com/C2SP/wycheproof/blob/main/ + # testvectors/ecdsa_secp256r1_sha256_test.json ) @pytest.mark.parametrize("precompile_address", [Spec.P256VERIFY], ids=[""]) @EIPChecklist.Precompile.Test.CallContexts.Normal() @EIPChecklist.Precompile.Test.Inputs.MaxValues() def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, tx: Transaction): - """Test P256Verify precompile with Wycheproof test suite (mixed valid/invalid cases).""" + """ + Test P256Verify precompile with Wycheproof test suite + (mixed valid/invalid cases). + """ state_test(env=Environment(), pre=pre, post=post, tx=tx) @@ -231,7 +240,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t pytest.param( # Invalid curve attack: Composite order curve with b = -Spec.B # Random point which satisfies y² = x³ - 3x - Spec.B (mod p) - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0xC223E1538C4D7B5BBD3EF932736826FD64F4E8B5C80250D9E07A728689D13C38) + R(0x0C7CB59EF6BE7539397CC979AD9A87A3B73A0DD268BBA4990A3378C6391512D5) + S(0xF8C943685BCFE7864C0F8485CACD732D3A9F167531CAF26B67A3CB10B641F92C) @@ -242,7 +252,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t pytest.param( # Invalid curve attack: Composite order curve with b = -Spec.B # Random point which satisfies y² = x³ - 3x - Spec.B (mod p) - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0x982D25BF8E0E81FF41AC3C8033604C78ED5EF17C6EDDA977072EAB6821A7AD0A) + R(0x7C1996FA0EC911E4739AE7340B5345823272F494DFA32034A4FE5642C3DB91F2) + S(0x1E4D6CCF1AFB675D18BD27274770C8B84028D272D1D2641E70B30E1DF17AF3DC) @@ -252,7 +263,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: random point bytes. - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0) + R(0xD21697149F598FEAE9A750DCA86AE6D5EFA654680BA748D2DF7053115101C129) + S(0xEF3FD943AD1F126B3EBA1A5900D79886755DB6DAFCB6B0117D86364340CE36CC) @@ -262,7 +274,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: random point bytes. - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0) + R(0x52E47C5D6AAB66AB6A18A694359EB86FDD40F10E79EF5493C5469EC88BA03334) + S(0x7584C5BF3CA2869C7E383B1603A935EEB79D990B7F7152E055EC562E87FD715E) @@ -272,7 +285,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: random point bytes. - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0) + R(0x81333B13B13F362253BD536D17563A72EB575F1993F55ED40E633E503F60B864) + S(0xE2208C4045F5241ECCF08F825399224C4B78595A10433EC33799DCAD7B0E1F4A) @@ -282,7 +296,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: random point bytes. - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0) + R(0x3C593B5857D1D0EB83923D73E76A7A53EF191BB210267D8C0BE17A4E34AB2E73) + S(0xD022359310067882F713AFBECECE71CB80E4857368F46AB0346362DB033ED298) @@ -292,7 +307,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: random point bytes. - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0) + R(0x425CFFCA652791CABFC81B1E4B7712DBA196599FABCE16978E06E6AF486B1FEC) + S(0x58B864B5A41CD17524E4773EC353C9590D792F601DA075AD9B3F40E8E7070E8A) @@ -302,7 +318,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: random point bytes. - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0x2DA0A74BE3122AEAEF5704D0EB27881FBFB918B4A5252B660935263D0569BA92) + R(0x5543729CBCFD99EE6C3B422D7F245903E7177B3A6A4E3C20C0DC5F5E109795AE) + S(0x96403D5BB253EBD7DEF44BCBC062FCD4EA5E358B19B67C13E625EFDF6B977597) @@ -312,7 +329,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: random point bytes. - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0x1F9D9B26DB42380C85F075174DDAF158F9DE4CD10C3104190D7AF96938DD8ECD) + R(0x159946DBC4F1DE68CD4096862A5B10E5986ACB32229D6E68884DC83DAB70A307) + S(0x63D80724A4074421F7DD255630794E3AEBE635B756D72B24652AAC07D01B289C) @@ -322,7 +340,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: random point bytes. - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0xD380DA9251F1FB809ED48C70DC8F81E91C471F0E81BC95E7611C653278A5B6B4) + R(0xFF197EB72A9E531B17B872525247E6564B786CC014ED28B6849CE7D8C976BDF2) + S(0x7B0B2EFF9BB5409052B35FD3FF81DCE77D95A1F75C46989817045120DA5C3C9C) @@ -332,7 +351,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: random point bytes. - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0x4B082B60497ED87FFE570612D521E73A2CD6C832744EF8E4E2E329E30D3D5879) + R(0x6665A88CB3FF30D339A1975FD46CF5EF480A68A093AB778550073D3528C3B609) + S(0xAEAADDB235E4AC6097356DB96161E27849EA8EDF1E971F74EB51E19A1CC950A1) @@ -342,7 +362,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: random point bytes. - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0x6CC2B605CFBDB22B9E7B55EFE8C1DA0F1C5A0EC1AA8D82EEDFB5EA70E9846E88) + R(0x3C593B5857D1D0EB83923D73E76A7A53EF191BB210267D8C0BE17A4E34AB2E73) + S(0xD022359310067882F713AFBECECE71CB80E4857368F46AB0346362DB033ED298) @@ -352,7 +373,8 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: random point bytes. - # Without the curve check in the implementation, the signature checks out. + # Without the curve check in the implementation, + # the signature checks out. H(0x810C1D53EA96A700C93F6AF1C183197B040EA6FEAE10564877A1C78EC6074FF1) + R(0x34D0F0C8E14D39002B5DEA00808957963E849503DDFD626323433047D696C7C4) + S(0x6A7FE39C046304317F799FB900877073F2AE3C798DD4414795551A833ABCBA85) From cc0c2a6f4e8710d951efbe94662cd22072a8885d Mon Sep 17 00:00:00 2001 From: danceratopz Date: Tue, 23 Sep 2025 12:02:11 +0200 Subject: [PATCH 04/16] chore: remove abstract and other admonitions from test module docstrings --- .../test_block_access_lists_invalid.py | 5 +- tests/benchmark/__init__.py | 13 +++-- tests/benchmark/test_worst_blocks.py | 2 +- tests/benchmark/test_worst_bytecode.py | 2 +- tests/benchmark/test_worst_compute.py | 4 +- tests/benchmark/test_worst_memory.py | 2 +- tests/benchmark/test_worst_opcode.py | 3 +- .../benchmark/test_worst_stateful_opcodes.py | 2 +- .../eip2929_gas_cost_increases/__init__.py | 2 +- .../test_precompile_warming.py | 6 +- tests/berlin/eip2930_access_list/__init__.py | 2 +- .../test_tx_intrinsic_gas.py | 7 ++- .../eip198_modexp_precompile/helpers.py | 4 +- .../eip198_modexp_precompile/test_modexp.py | 7 ++- tests/cancun/eip1153_tstore/__init__.py | 4 +- .../cancun/eip1153_tstore/test_tload_calls.py | 4 +- .../eip1153_tstore/test_tload_reentrancy.py | 4 +- tests/cancun/eip1153_tstore/test_tstorage.py | 8 +-- .../test_tstorage_clear_after_tx.py | 2 +- .../test_tstorage_create_contexts.py | 4 +- .../test_tstorage_execution_contexts.py | 4 +- .../test_tstorage_reentrancy_contexts.py | 6 +- .../test_tstorage_selfdestruct.py | 8 +-- .../eip1153_tstore/test_tstore_reentrancy.py | 2 +- .../test_beacon_root_contract.py | 23 ++++---- tests/cancun/eip4844_blobs/test_blob_txs.py | 17 +++--- .../eip4844_blobs/test_blobhash_opcode.py | 25 ++++---- .../test_blobhash_opcode_contexts.py | 2 +- .../eip4844_blobs/test_excess_blob_gas.py | 47 +++++++-------- .../test_excess_blob_gas_fork_transition.py | 5 +- .../test_point_evaluation_precompile.py | 51 +++++++++-------- .../test_point_evaluation_precompile_gas.py | 7 ++- tests/cancun/eip5656_mcopy/test_mcopy.py | 2 +- .../eip5656_mcopy/test_mcopy_contexts.py | 5 +- .../test_mcopy_memory_expansion.py | 7 ++- .../eip6780_selfdestruct/test_selfdestruct.py | 5 +- .../test_blobgasfee_opcode.py | 5 +- .../eip1014_create2/__init__.py | 2 +- .../eip145_bitwise_shift/__init__.py | 3 +- .../identity_precompile/test_identity.py | 2 +- .../test_identity_returndatasize.py | 2 +- .../test_call_and_callcode_gas_calculation.py | 57 ++++++++++--------- tests/frontier/opcodes/test_dup.py | 2 +- tests/frontier/opcodes/test_push.py | 1 + .../precompiles/test_precompile_absence.py | 2 +- tests/istanbul/eip1344_chainid/__init__.py | 2 +- .../istanbul/eip1344_chainid/test_chainid.py | 3 +- tests/istanbul/eip152_blake2/__init__.py | 3 +- tests/istanbul/eip152_blake2/test_blake2.py | 3 +- .../eip152_blake2/test_blake2_delegatecall.py | 2 +- tests/osaka/eip7594_peerdas/test_get_blobs.py | 7 ++- .../eip7594_peerdas/test_max_blob_per_tx.py | 7 ++- .../eip7823_modexp_upper_bounds/__init__.py | 5 +- .../test_modexp_upper_bounds.py | 3 +- .../__init__.py | 3 +- .../test_tx_gas_limit.py | 7 ++- .../test_tx_gas_limit_transition_fork.py | 7 ++- .../eip7883_modexp_gas_increase/__init__.py | 2 +- .../test_modexp_thresholds.py | 7 ++- .../test_modexp_thresholds_transition.py | 3 +- .../test_blob_base_fee.py | 6 +- .../test_blob_reserve_price_with_bpo.py | 2 +- .../osaka/eip7934_block_rlp_limit/__init__.py | 2 +- .../test_max_block_rlp_size.py | 2 +- .../eip7939_count_leading_zeros/__init__.py | 3 +- .../test_count_leading_zeros.py | 4 +- .../__init__.py | 3 +- .../test_p256verify.py | 2 +- .../test_p256verify_before_fork.py | 6 +- .../security/test_selfdestruct_balance_bug.py | 8 ++- .../__init__.py | 2 +- .../test_bls12_g1add.py | 9 +-- .../test_bls12_g1msm.py | 7 ++- .../test_bls12_g1mul.py | 9 +-- .../test_bls12_g2add.py | 9 +-- .../test_bls12_g2msm.py | 7 ++- .../test_bls12_g2mul.py | 7 ++- .../test_bls12_map_fp2_to_g2.py | 7 ++- .../test_bls12_map_fp_to_g1.py | 8 +-- .../test_bls12_pairing.py | 8 +-- .../test_bls12_precompiles_before_fork.py | 9 +-- ...t_bls12_variable_length_input_contracts.py | 11 ++-- .../test_block_hashes.py | 2 +- .../test_contract_deployment.py | 2 +- .../prague/eip6110_deposits/test_deposits.py | 8 +-- .../test_contract_deployment.py | 2 +- .../test_modified_withdrawal_contract.py | 2 +- .../test_withdrawal_requests.py | 2 +- .../test_withdrawal_requests_during_fork.py | 2 +- .../test_consolidations.py | 2 +- .../test_consolidations_during_fork.py | 2 +- .../test_contract_deployment.py | 2 +- .../test_modified_consolidation_contract.py | 2 +- .../__init__.py | 3 +- .../test_execution_gas.py | 2 +- .../test_refunds.py | 2 +- .../test_transaction_validity.py | 2 +- .../test_multi_type_requests.py | 7 ++- tests/prague/eip7702_set_code_tx/test_gas.py | 7 ++- .../eip7702_set_code_tx/test_invalid_tx.py | 7 ++- .../eip7702_set_code_tx/test_set_code_txs.py | 7 ++- .../test_set_code_txs_2.py | 4 +- .../eip3651_warm_coinbase/__init__.py | 2 +- .../test_warm_coinbase.py | 7 +-- tests/shanghai/eip3855_push0/__init__.py | 3 +- tests/shanghai/eip3855_push0/test_push0.py | 7 +-- tests/shanghai/eip3860_initcode/__init__.py | 2 +- .../eip3860_initcode/test_initcode.py | 9 ++- .../shanghai/eip4895_withdrawals/__init__.py | 3 +- .../eip4895_withdrawals/test_withdrawals.py | 3 +- tests/unscheduled/eip7692_eof_v1/__init__.py | 2 +- .../eip7692_eof_v1/eip3540_eof_v1/__init__.py | 2 +- .../eip4200_relative_jumps/__init__.py | 2 +- .../eip4750_functions/__init__.py | 2 +- .../eip7692_eof_v1/eip5450_stack/__init__.py | 2 +- .../eip7692_eof_v1/eip6206_jumpf/__init__.py | 2 +- .../eip663_dupn_swapn_exchange/__init__.py | 2 +- .../eip663_dupn_swapn_exchange/test_dupn.py | 2 +- .../test_exchange.py | 2 +- .../eip7069_extcall/__init__.py | 2 +- .../eip7069_extcall/test_calldata.py | 2 +- .../eip7069_extcall/test_gas.py | 2 +- .../eip7069_extcall/test_returndataload.py | 2 +- .../eip7480_data_section/__init__.py | 2 +- .../eip7620_eof_create/__init__.py | 2 +- .../eip7873_tx_create/__init__.py | 2 +- 126 files changed, 365 insertions(+), 346 deletions(-) diff --git a/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py b/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py index 5bb5a3d2f37..34ae52f9036 100644 --- a/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py +++ b/tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_invalid.py @@ -1,6 +1,7 @@ """ -abstract: Test cases for invalid Block Access Lists. - These tests verify that clients properly reject blocks with corrupted BALs. +Test cases for invalid Block Access Lists. + +These tests verify that clients properly reject blocks with corrupted BALs. """ import pytest diff --git a/tests/benchmark/__init__.py b/tests/benchmark/__init__.py index ee4b35674ba..ce3a8eda042 100644 --- a/tests/benchmark/__init__.py +++ b/tests/benchmark/__init__.py @@ -1,8 +1,9 @@ """ -abstract: Benchmark tests for EVMs. - Benchmark tests aim to maximize the usage of a specific opcode, precompile, - or operation within a transaction or block. These can be executed against - EVM implementations to ensure they handle pathological cases efficiently - and correctly, allowing Ethereum to safely - [Scale the L1](https://protocol.ethereum.foundation/). +Benchmark tests for EVMs. + +Benchmark tests aim to maximize the usage of a specific opcode, precompile, +or operation within a transaction or block. These can be executed against +EVM implementations to ensure they handle pathological cases efficiently +and correctly, allowing Ethereum to safely +[Scale the L1](https://protocol.ethereum.foundation/). """ diff --git a/tests/benchmark/test_worst_blocks.py b/tests/benchmark/test_worst_blocks.py index 1b1735f8b89..c5f625aa1b8 100644 --- a/tests/benchmark/test_worst_blocks.py +++ b/tests/benchmark/test_worst_blocks.py @@ -1,5 +1,5 @@ """ -abstract: Tests that benchmark EVMs in worst-case block scenarios. +Tests that benchmark EVMs in worst-case block scenarios. """ import random diff --git a/tests/benchmark/test_worst_bytecode.py b/tests/benchmark/test_worst_bytecode.py index ac981f890a4..818522066b9 100644 --- a/tests/benchmark/test_worst_bytecode.py +++ b/tests/benchmark/test_worst_bytecode.py @@ -1,5 +1,5 @@ """ -abstract: Tests that benchmark EVMs in worst-case opcode scenarios. +Tests that benchmark EVMs in worst-case opcode scenarios. """ import math diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index be121ebf886..a07e0332552 100644 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -1,7 +1,5 @@ """ -abstract: Tests that benchmark EVMs in worst-case compute scenarios. - Tests that benchmark EVMs when running worst-case compute opcodes and - precompile scenarios. +Tests that benchmark EVMs in worst-case compute scenarios. """ import math diff --git a/tests/benchmark/test_worst_memory.py b/tests/benchmark/test_worst_memory.py index 7a0fde24d22..4ec6b96df20 100644 --- a/tests/benchmark/test_worst_memory.py +++ b/tests/benchmark/test_worst_memory.py @@ -1,5 +1,5 @@ """ -abstract: Tests that benchmark EVMs in the worst-case memory opcodes. +Tests that benchmark EVMs in the worst-case memory opcodes. """ import pytest diff --git a/tests/benchmark/test_worst_opcode.py b/tests/benchmark/test_worst_opcode.py index a640e5cbcdb..9ee805a628b 100644 --- a/tests/benchmark/test_worst_opcode.py +++ b/tests/benchmark/test_worst_opcode.py @@ -1,6 +1,5 @@ """ -abstract: Tests benchmark worst-case opcode scenarios. - Tests running worst-case opcodes scenarios for benchmarking purposes. +Tests benchmark worst-case opcode scenarios. """ import pytest diff --git a/tests/benchmark/test_worst_stateful_opcodes.py b/tests/benchmark/test_worst_stateful_opcodes.py index b2d462659cf..f5cd6c0289f 100644 --- a/tests/benchmark/test_worst_stateful_opcodes.py +++ b/tests/benchmark/test_worst_stateful_opcodes.py @@ -1,5 +1,5 @@ """ -abstract: Tests that benchmark EVMs for worst-case stateful opcodes. +Tests that benchmark EVMs for worst-case stateful opcodes. """ import math diff --git a/tests/berlin/eip2929_gas_cost_increases/__init__.py b/tests/berlin/eip2929_gas_cost_increases/__init__.py index 1516ab785f2..baedc1cb649 100644 --- a/tests/berlin/eip2929_gas_cost_increases/__init__.py +++ b/tests/berlin/eip2929_gas_cost_increases/__init__.py @@ -1,3 +1,3 @@ """ -abstract: Tests for [EIP-2929: Gas cost increases for state access opcodes](https://eips.ethereum.org/EIPS/eip-2929). +Tests for [EIP-2929: Gas cost increases for state access opcodes](https://eips.ethereum.org/EIPS/eip-2929). """ diff --git a/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py b/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py index 216d07c878e..e0a6131aa52 100644 --- a/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py +++ b/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py @@ -1,8 +1,8 @@ """ -abstract: Tests precompile warming behavior. +Tests EIP-2929 precompile warming behavior. - Tests precompile warming behavior across fork transitions from - [EIP-2929: Gas cost increases for state access opcodes] +Tests precompile warming behavior across fork transitions from +[EIP-2929: Gas cost increases for state access opcodes] (https://eips.ethereum.org/EIPS/eip-2929). """ diff --git a/tests/berlin/eip2930_access_list/__init__.py b/tests/berlin/eip2930_access_list/__init__.py index 6ac96b8cde0..25187646f76 100644 --- a/tests/berlin/eip2930_access_list/__init__.py +++ b/tests/berlin/eip2930_access_list/__init__.py @@ -1,3 +1,3 @@ """ -abstract: Tests for [EIP-2930: Optional access lists](https://eips.ethereum.org/EIPS/eip-2930). +Tests for [EIP-2930: Optional access lists](https://eips.ethereum.org/EIPS/eip-2930). """ diff --git a/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py b/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py index 86abea16253..cb5fe94b96c 100644 --- a/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py +++ b/tests/berlin/eip2930_access_list/test_tx_intrinsic_gas.py @@ -1,7 +1,8 @@ """ -abstract: Tests [EIP-2930: Access list transaction](https://eips.ethereum.org/EIPS/eip-2930). - Original test by Ori: - https://github.com/ethereum/tests/blob/v15.0/src/GeneralStateTestsFiller/stEIP1559/intrinsicGen.js. +Tests [EIP-2930: Access list transaction](https://eips.ethereum.org/EIPS/eip-2930). + +Original test by Ori: +https://github.com/ethereum/tests/blob/v15.0/src/GeneralStateTestsFiller/stEIP1559/intrinsicGen.js. """ from typing import List diff --git a/tests/byzantium/eip198_modexp_precompile/helpers.py b/tests/byzantium/eip198_modexp_precompile/helpers.py index 0bc073c2183..0360f9ddc90 100644 --- a/tests/byzantium/eip198_modexp_precompile/helpers.py +++ b/tests/byzantium/eip198_modexp_precompile/helpers.py @@ -1,4 +1,6 @@ -"""Helper functions for the EIP-198 ModExp precompile tests.""" +""" +Helper functions for the EIP-198 ModExp precompile tests. +""" from typing import Tuple diff --git a/tests/byzantium/eip198_modexp_precompile/test_modexp.py b/tests/byzantium/eip198_modexp_precompile/test_modexp.py index 079bf972db2..978963ec6d5 100644 --- a/tests/byzantium/eip198_modexp_precompile/test_modexp.py +++ b/tests/byzantium/eip198_modexp_precompile/test_modexp.py @@ -1,7 +1,8 @@ """ -abstract: Test [EIP-198: MODEXP Precompile](https://eips.ethereum.org/EIPS/eip-198). - Tests the MODEXP precompile, located at address 0x0000..0005. Test cases - from the EIP are labelled with `EIP-198-caseX` in the test id. +Test [EIP-198: MODEXP Precompile](https://eips.ethereum.org/EIPS/eip-198). + +Tests the MODEXP precompile, located at address 0x0000..0005. Test cases +from the EIP are labelled with `EIP-198-caseX` in the test id. """ import pytest diff --git a/tests/cancun/eip1153_tstore/__init__.py b/tests/cancun/eip1153_tstore/__init__.py index 23d17ac5e19..96885cdf5c5 100644 --- a/tests/cancun/eip1153_tstore/__init__.py +++ b/tests/cancun/eip1153_tstore/__init__.py @@ -1,4 +1,6 @@ -"""EIP-1153 Tests.""" +""" +[EIP-1153](https://eips.ethereum.org/EIPS/eip-1153) Tests. +""" from enum import Enum, unique from pprint import pprint diff --git a/tests/cancun/eip1153_tstore/test_tload_calls.py b/tests/cancun/eip1153_tstore/test_tload_calls.py index 8fa7880904d..120f2060d65 100644 --- a/tests/cancun/eip1153_tstore/test_tload_calls.py +++ b/tests/cancun/eip1153_tstore/test_tload_calls.py @@ -1,4 +1,6 @@ -"""Ethereum Transient Storage EIP Tests https://eips.ethereum.org/EIPS/eip-1153.""" +""" +[EIP-1153](https://eips.ethereum.org/EIPS/eip-1153) Transient Storage tests. +""" import pytest diff --git a/tests/cancun/eip1153_tstore/test_tload_reentrancy.py b/tests/cancun/eip1153_tstore/test_tload_reentrancy.py index 708a2a7ddef..e0d7cc99095 100644 --- a/tests/cancun/eip1153_tstore/test_tload_reentrancy.py +++ b/tests/cancun/eip1153_tstore/test_tload_reentrancy.py @@ -1,4 +1,6 @@ -"""Ethereum Transient Storage EIP Tests https://eips.ethereum.org/EIPS/eip-1153.""" +""" +[EIP-1153](https://eips.ethereum.org/EIPS/eip-1153) Transient Storage tests. +""" from enum import Enum diff --git a/tests/cancun/eip1153_tstore/test_tstorage.py b/tests/cancun/eip1153_tstore/test_tstorage.py index 939d515327e..95b576bd0fd 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage.py +++ b/tests/cancun/eip1153_tstore/test_tstorage.py @@ -1,10 +1,8 @@ """ -abstract: Transient storage opcodes tests. - Tests for [EIP-1153: Transient Storage - Opcodes](https://eips.ethereum.org/EIPS/eip-1153). +EIP-1153 Transient Storage opcode tests. - Ports and extends some tests from - [ethereum/tests/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage). +Ports and extends some tests from +[ethereum/tests/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage/](https://github.com/ethereum/tests/blob/9b00b68593f5869eb51a6659e1cc983e875e616b/src/EIPTestsFiller/StateTests/stEIP1153-transientStorage). """ from enum import unique diff --git a/tests/cancun/eip1153_tstore/test_tstorage_clear_after_tx.py b/tests/cancun/eip1153_tstore/test_tstorage_clear_after_tx.py index a1d71560696..fc7e75fd486 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_clear_after_tx.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_clear_after_tx.py @@ -1,4 +1,4 @@ -"""Ethereum Transient Storage EIP Tests https://eips.ethereum.org/EIPS/eip-1153.""" +"""EIP-1153 Transient Storage tests.""" from typing import Optional diff --git a/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py index d5bcc0857a0..353a5b1b631 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py @@ -1,7 +1,5 @@ """ -abstract: Transient storage in contract creation contexts tests - Tests for transient storage behavior in contract creation contexts from - [EIP-1153: Transient Storage](https://eips.ethereum.org/EIPS/eip-1153). +Test transient storage in contract creation contexts. """ from enum import unique diff --git a/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py index 5c2a49fa690..ce59935b639 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py @@ -1,7 +1,5 @@ """ -abstract: EIP-1153 Transient Storage execution contexts tests - Tests for transient storage behavior in execution contexts from - [EIP-1153: Transient Storage](https://eips.ethereum.org/EIPS/eip-1153). +Test EIP-1153 Transient Storage in execution contexts. """ from enum import EnumMeta, unique diff --git a/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py index 7b479262c26..05044ef8ac8 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_reentrancy_contexts.py @@ -1,9 +1,5 @@ """ -abstract: Tests transient storage in reentrancy contexts. - - Tests transient storage behavior in various reentrancy contexts from - [EIP-1153: Transient Storage] - (https://eips.ethereum.org/EIPS/eip-1153). +Tests transient storage in reentrancy contexts. """ from enum import EnumMeta, unique diff --git a/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py b/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py index d8f5a1a136f..6237c830990 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_selfdestruct.py @@ -1,10 +1,8 @@ """ -abstract: EIP-1153 Transient Storage with selfdestruct tests. - Tests for transient storage behavior with selfdestruct from [EIP-1153: - Storage](https://eips.ethereum.org/EIPS/eip-1153). +EIP-1153 Transient Storage with selfdestruct tests. - Test cases for `TSTORE` and `TLOAD` opcode calls in reentrancy after - self-destruct, taking into account the changes in EIP-6780. +Test cases for `TSTORE` and `TLOAD` opcode calls in reentrancy after +self-destruct, taking into account the changes in EIP-6780. """ from enum import unique diff --git a/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py b/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py index 516ea9ded7f..e7e3bdf7af0 100644 --- a/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py +++ b/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py @@ -1,4 +1,4 @@ -"""Ethereum Transient Storage EIP Tests https://eips.ethereum.org/EIPS/eip-1153.""" +"""EIP-1153 Transient Storage tests.""" from enum import Enum diff --git a/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py b/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py index bae31eff72e..fdfa1d36108 100644 --- a/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py +++ b/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py @@ -1,18 +1,19 @@ """ -abstract: Tests beacon block root for [EIP-4788: Beacon block root in the EVM](https://eips.ethereum.org/EIPS/eip-4788) - Note: To add a new test, add a function that is named `test_`. +Tests beacon block root for [EIP-4788: Beacon block root in the EVM](https://eips.ethereum.org/EIPS/eip-4788). - It must take at least the following arguments: +Note: To add a new test, add a function that is named `test_`. - - `state_test` - - `env` - - `pre` - - `tx` - - `post` - - `valid_call` +It must take at least the following arguments: - All other `pytest.fixtures` can be parametrized to generate new - combinations and test cases. +- `state_test` +- `env` +- `pre` +- `tx` +- `post` +- `valid_call` + +All other `pytest.fixtures` can be parametrized to generate new +combinations and test cases. """ from itertools import count diff --git a/tests/cancun/eip4844_blobs/test_blob_txs.py b/tests/cancun/eip4844_blobs/test_blob_txs.py index f4bb577c3e0..162ae8c3a6b 100644 --- a/tests/cancun/eip4844_blobs/test_blob_txs.py +++ b/tests/cancun/eip4844_blobs/test_blob_txs.py @@ -1,16 +1,17 @@ """ Tests blob type transactions for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). - Note: To add a new test, add a function that is named `test_`. - It must at least use the following arguments: +Note: To add a new test, add a function that is named `test_`. - - `blockchain_test` or `state_test` - - `pre` - - `env` - - `block` or `txs`. +It must at least use the following arguments: - All other `pytest.fixture` fixtures can be parametrized to generate new - combinations and test cases. +- `blockchain_test` or `state_test` +- `pre` +- `env` +- `block` or `txs`. + +All other `pytest.fixture` fixtures can be parametrized to generate new +combinations and test cases. """ from typing import List, Optional, Tuple diff --git a/tests/cancun/eip4844_blobs/test_blobhash_opcode.py b/tests/cancun/eip4844_blobs/test_blobhash_opcode.py index 30218e0887c..471095b6533 100644 --- a/tests/cancun/eip4844_blobs/test_blobhash_opcode.py +++ b/tests/cancun/eip4844_blobs/test_blobhash_opcode.py @@ -1,19 +1,20 @@ """ -abstract: Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) - Note: Adding a new test Add a function that is named `test_` and - takes at least the following arguments. +Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). - Required arguments: - - `blockchain_test` - - `pre` - - `tx` - - `post` +Note: Adding a new test Add a function that is named `test_` and +takes at least the following arguments. - Additional custom `pytest.fixture` fixtures can be added and parametrized - for - new test cases. +Required arguments: +- `blockchain_test` +- `pre` +- `tx` +- `post` - There is no specific structure to follow within this test module. +Additional custom `pytest.fixture` fixtures can be added and parametrized +for +new test cases. + +There is no specific structure to follow within this test module. """ from typing import List diff --git a/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py b/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py index a56a6979074..4366ef45023 100644 --- a/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py +++ b/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py @@ -1,5 +1,5 @@ """ -abstract: Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). +Tests `BLOBHASH` opcode in [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). """ from enum import Enum diff --git a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py index 7cbdcf78cc6..b7ea3ca29c2 100644 --- a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py +++ b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py @@ -1,27 +1,28 @@ """ -abstract: Tests `excessBlobGas` and `blobGasUsed` block fields for EIP-4844. - Tests `excessBlobGas` and `blobGasUsed` block fields for - [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) - Note: Adding a new test Add a function that is named `test_` and - takes at least the following arguments. - - Required arguments: - - `blockchain_test` - - `env` - - `pre` - - `blocks` - - `post` - - `correct_excess_blob_gas` - - The following arguments can be parametrized to generate new combinations - and - test cases: - - - new_blobs: Number of blobs in the block (automatically split across - transactions as needed) - - All other `pytest.fixture` fixtures can be parametrized to generate new - combinations and test cases. +Tests `excessBlobGas` and `blobGasUsed` block fields for EIP-4844. + +Tests `excessBlobGas` and `blobGasUsed` block fields for +[EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844) +Note: Adding a new test Add a function that is named `test_` and +takes at least the following arguments. + +Required arguments: +- `blockchain_test` +- `env` +- `pre` +- `blocks` +- `post` +- `correct_excess_blob_gas` + +The following arguments can be parametrized to generate new combinations +and +test cases: + +- new_blobs: Number of blobs in the block (automatically split across +transactions as needed) + +All other `pytest.fixture` fixtures can be parametrized to generate new +combinations and test cases. """ import itertools diff --git a/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py b/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py index 5c5c579077b..115a0569e01 100644 --- a/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py +++ b/tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py @@ -1,6 +1,7 @@ """ -abstract: Test `excessBlobGas` & `blobGasUsed` block fields at fork transition - Tests for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). +Test `excessBlobGas` & `blobGasUsed` block fields at fork transition. + +Tests for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). """ from typing import List, Mapping diff --git a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py index 9250a04bcd6..a2da764ae43 100644 --- a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py +++ b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py @@ -1,29 +1,30 @@ """ -abstract: Tests point evaluation precompile for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). - Note: Adding a new test Add a function that is named `test_` and - takes at least the following arguments. - - Required arguments: - - `blockchain_test` or `state_test` - - `pre` - - `tx` - - `post` - - The following arguments *need* to be parametrized or the test will not be - generated: - - - `versioned_hash` - - `kzg_commitment` - - `z` - - `y` - - `kzg_proof` - - `result` - - These values correspond to a single call of the precompile, and `result` - refers to whether the call should succeed or fail. - - All other `pytest.fixture` fixtures can be parametrized to generate new - combinations and test cases. +Tests point evaluation precompile for [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). + +Note: Adding a new test Add a function that is named `test_` and +takes at least the following arguments. + +Required arguments: +- `blockchain_test` or `state_test` +- `pre` +- `tx` +- `post` + +The following arguments *need* to be parametrized or the test will not be +generated: + +- `versioned_hash` +- `kzg_commitment` +- `z` +- `y` +- `kzg_proof` +- `result` + +These values correspond to a single call of the precompile, and `result` +refers to whether the call should succeed or fail. + +All other `pytest.fixture` fixtures can be parametrized to generate new +combinations and test cases. """ import glob diff --git a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py index a16d3bdfd09..f8eb3d96f29 100644 --- a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py +++ b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py @@ -1,7 +1,8 @@ """ -abstract: Tests gas usage on point evaluation precompile for EIP-4844. - Tests gas usage on point evaluation precompile for - [EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). +Tests gas usage on point evaluation precompile for EIP-4844. + +Tests gas usage on point evaluation precompile for +[EIP-4844: Shard Blob Transactions](https://eips.ethereum.org/EIPS/eip-4844). """ from typing import Dict, Literal diff --git a/tests/cancun/eip5656_mcopy/test_mcopy.py b/tests/cancun/eip5656_mcopy/test_mcopy.py index 0895b1e27fb..83db999fd15 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656). +Tests [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656). """ from typing import Mapping diff --git a/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py b/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py index c9bd455f672..4c606d49e78 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py @@ -1,6 +1,7 @@ """ -abstract: Test memory copy under different call contexts. - Tests for [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656). +Test memory copy under different call contexts. + +Tests for [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656). """ from itertools import cycle, islice diff --git a/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py b/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py index 945fd994370..6a9801d0098 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py @@ -1,8 +1,9 @@ """ -abstract: Test MCOPY with memory expansion and potential OOG errors - Test copy operations of [EIP-5656: MCOPY - Memory copying +Test MCOPY with memory expansion and potential OOG errors. + +Test copy operations of [EIP-5656: MCOPY - Memory copying instruction](https://eips.ethereum.org/EIPS/eip-5656) that produce - a memory expansion, and potentially an out-of-gas error. +a memory expansion, and potentially an out-of-gas error. """ import itertools diff --git a/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py b/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py index deccb85bc1d..95729a73eb9 100644 --- a/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py +++ b/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py @@ -1,6 +1,7 @@ """ -abstract: SELFDESTRUCT only in same transaction tests - Tests for [EIP-6780: SELFDESTRUCT only in same transaction](https://eips.ethereum.org/EIPS/eip-6780). +SELFDESTRUCT only in same transaction tests. + +Tests for [EIP-6780: SELFDESTRUCT only in same transaction](https://eips.ethereum.org/EIPS/eip-6780). """ from itertools import cycle diff --git a/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py b/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py index 970920236e4..8fc048309b6 100644 --- a/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py +++ b/tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py @@ -1,6 +1,7 @@ """ -abstract: BLOBBASEFEE opcode tests - Tests for [EIP-7516: BLOBBASEFEE opcode](https://eips.ethereum.org/EIPS/eip-7516). +BLOBBASEFEE opcode tests. + +Tests for [EIP-7516: BLOBBASEFEE opcode](https://eips.ethereum.org/EIPS/eip-7516). """ from itertools import count diff --git a/tests/constantinople/eip1014_create2/__init__.py b/tests/constantinople/eip1014_create2/__init__.py index 658cd0bbdfa..724704b1812 100644 --- a/tests/constantinople/eip1014_create2/__init__.py +++ b/tests/constantinople/eip1014_create2/__init__.py @@ -1,3 +1,3 @@ """ -abstract: Tests for [EIP-1014: Skinny CREATE2](https://eips.ethereum.org/EIPS/eip-1014). +Tests for [EIP-1014: Skinny CREATE2](https://eips.ethereum.org/EIPS/eip-1014). """ diff --git a/tests/constantinople/eip145_bitwise_shift/__init__.py b/tests/constantinople/eip145_bitwise_shift/__init__.py index eef4aab5831..bdca58cbe60 100644 --- a/tests/constantinople/eip145_bitwise_shift/__init__.py +++ b/tests/constantinople/eip145_bitwise_shift/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Test [EIP-145: Bitwise shifting instructions in EVM](https://eips.ethereum.org/EIPS/eip-145). - Tests for [EIP-145: Bitwise shifting instructions in EVM](https://eips.ethereum.org/EIPS/eip-145). +Test [EIP-145: Bitwise shifting instructions in EVM](https://eips.ethereum.org/EIPS/eip-145). """ diff --git a/tests/frontier/identity_precompile/test_identity.py b/tests/frontier/identity_precompile/test_identity.py index 67ff1ad1219..653c763564c 100644 --- a/tests/frontier/identity_precompile/test_identity.py +++ b/tests/frontier/identity_precompile/test_identity.py @@ -1,4 +1,4 @@ -"""abstract: Test identity precompile output size.""" +"""Test identity precompile output size.""" from typing import Tuple diff --git a/tests/frontier/identity_precompile/test_identity_returndatasize.py b/tests/frontier/identity_precompile/test_identity_returndatasize.py index 4b07ff2acf0..6e352664dc2 100644 --- a/tests/frontier/identity_precompile/test_identity_returndatasize.py +++ b/tests/frontier/identity_precompile/test_identity_returndatasize.py @@ -1,4 +1,4 @@ -"""abstract: Test identity precompile output size.""" +"""Test identity precompile output size.""" import pytest diff --git a/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py b/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py index e05433c38bc..223b9501236 100644 --- a/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py +++ b/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py @@ -1,32 +1,33 @@ """ -abstract: Tests nested CALL/CALLCODE gas usage with positive value transfer - This test investigates an issue identified in EthereumJS, as reported in: - https://github.com/ethereumjs/ethereumjs-monorepo/issues/3194. - - The issue pertains to the incorrect gas calculation for CALL/CALLCODE - operations with a positive value transfer, due to the pre-addition of the - gas stipend (2300) to the currently available gas instead of adding it to - the new call frame. This bug was specific to the case where insufficient - gas was provided for the CALL/CALLCODE operation. Due to the pre-addition - of the stipend to the currently available gas, the case for insufficient - gas was not properly failing with an out-of-gas error. - - Test setup: - - Given two smart contract accounts, 0x0A (caller) and 0x0B (callee): - 1. An arbitrary transaction calls into the contract 0x0A. - 2. Contract 0x0A executes a CALL to contract 0x0B with a specific gas limit - (X). - 3. Contract 0x0B then attempts a CALL/CALLCODE to a non-existent contract - 0x0C, with a positive value transfer (activating the gas stipend). - 4. If the gas X provided by contract 0x0A to 0x0B is sufficient, contract - 0x0B will push 0x01 onto the stack after returning to the call frame in - 0x0A. Otherwise, it should push 0x00, indicating the insufficiency of - gas X (for the bug in EthereumJS, the CALL/CALLCODE operation would - return 0x01 due to the pre-addition of the gas stipend). - 5. The resulting stack value is saved into contract 0x0A's storage, - allowing us to verify whether the provided gas was sufficient or - insufficient. +Tests nested CALL/CALLCODE gas usage with positive value transfer. + +This test investigates an issue identified in EthereumJS, as reported in: +https://github.com/ethereumjs/ethereumjs-monorepo/issues/3194. + +The issue pertains to the incorrect gas calculation for CALL/CALLCODE +operations with a positive value transfer, due to the pre-addition of the +gas stipend (2300) to the currently available gas instead of adding it to +the new call frame. This bug was specific to the case where insufficient +gas was provided for the CALL/CALLCODE operation. Due to the pre-addition +of the stipend to the currently available gas, the case for insufficient +gas was not properly failing with an out-of-gas error. + +Test setup: + +Given two smart contract accounts, 0x0A (caller) and 0x0B (callee): +1. An arbitrary transaction calls into the contract 0x0A. +2. Contract 0x0A executes a CALL to contract 0x0B with a specific gas limit +(X). +3. Contract 0x0B then attempts a CALL/CALLCODE to a non-existent contract +0x0C, with a positive value transfer (activating the gas stipend). +4. If the gas X provided by contract 0x0A to 0x0B is sufficient, contract +0x0B will push 0x01 onto the stack after returning to the call frame in +0x0A. Otherwise, it should push 0x00, indicating the insufficiency of +gas X (for the bug in EthereumJS, the CALL/CALLCODE operation would +return 0x01 due to the pre-addition of the gas stipend). +5. The resulting stack value is saved into contract 0x0A's storage, +allowing us to verify whether the provided gas was sufficient or +insufficient. """ from typing import Dict diff --git a/tests/frontier/opcodes/test_dup.py b/tests/frontier/opcodes/test_dup.py index 6e1679184b7..ee8cbd3c141 100644 --- a/tests/frontier/opcodes/test_dup.py +++ b/tests/frontier/opcodes/test_dup.py @@ -1,4 +1,4 @@ -"""abstract: Test DUP Test the DUP opcodes.""" +"""Test DUP Test the DUP opcodes.""" import pytest diff --git a/tests/frontier/opcodes/test_push.py b/tests/frontier/opcodes/test_push.py index 400a658e2c1..f3a6794a84d 100644 --- a/tests/frontier/opcodes/test_push.py +++ b/tests/frontier/opcodes/test_push.py @@ -1,5 +1,6 @@ """ A State test for the set of `PUSH*` opcodes. + Ported from: https://github.com/ethereum/tests/blob/ 4f65a0a7cbecf4442415c226c65e089acaaf6a8b/src/ diff --git a/tests/frontier/precompiles/test_precompile_absence.py b/tests/frontier/precompiles/test_precompile_absence.py index eeb0f65ca77..46b9dd44ece 100644 --- a/tests/frontier/precompiles/test_precompile_absence.py +++ b/tests/frontier/precompiles/test_precompile_absence.py @@ -1,4 +1,4 @@ -"""abstract: Test Calling Precompile Range (close to zero).""" +"""Test Calling Precompile Range (close to zero).""" import pytest diff --git a/tests/istanbul/eip1344_chainid/__init__.py b/tests/istanbul/eip1344_chainid/__init__.py index db7dbcd6e73..3669063cbee 100644 --- a/tests/istanbul/eip1344_chainid/__init__.py +++ b/tests/istanbul/eip1344_chainid/__init__.py @@ -1,3 +1,3 @@ """ -abstract: Tests for [EIP-1344: ChainID Opcode](https://eips.ethereum.org/EIPS/eip-1344). +Tests for [EIP-1344: ChainID Opcode](https://eips.ethereum.org/EIPS/eip-1344). """ diff --git a/tests/istanbul/eip1344_chainid/test_chainid.py b/tests/istanbul/eip1344_chainid/test_chainid.py index 7f3070d9a90..da878691b23 100644 --- a/tests/istanbul/eip1344_chainid/test_chainid.py +++ b/tests/istanbul/eip1344_chainid/test_chainid.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-1344: CHAINID opcode](https://eips.ethereum.org/EIPS/eip-1344). - Test cases for EIP-1344: CHAINID opcode. +Tests [EIP-1344: CHAINID opcode](https://eips.ethereum.org/EIPS/eip-1344). """ import pytest diff --git a/tests/istanbul/eip152_blake2/__init__.py b/tests/istanbul/eip152_blake2/__init__.py index 1c9a85f63bb..040419e930f 100644 --- a/tests/istanbul/eip152_blake2/__init__.py +++ b/tests/istanbul/eip152_blake2/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-152: BLAKE2 compression precompile](https://eips.ethereum.org/EIPS/eip-152). - Test cases for EIP-152: BLAKE2 compression precompile. +Tests [EIP-152: BLAKE2 compression precompile](https://eips.ethereum.org/EIPS/eip-152). """ diff --git a/tests/istanbul/eip152_blake2/test_blake2.py b/tests/istanbul/eip152_blake2/test_blake2.py index dab5c9e6ba3..6e575947c83 100644 --- a/tests/istanbul/eip152_blake2/test_blake2.py +++ b/tests/istanbul/eip152_blake2/test_blake2.py @@ -1,6 +1,5 @@ """ -abstract: Tests [EIP-152: BLAKE2b compression precompile](https://eips.ethereum.org/EIPS/eip-152) - Test cases for [EIP-152: BLAKE2b compression precompile](https://eips.ethereum.org/EIPS/eip-152). +Tests [EIP-152: BLAKE2b compression precompile](https://eips.ethereum.org/EIPS/eip-152). """ from typing import List diff --git a/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py b/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py index 9a78779e2ea..79ecfb664bd 100644 --- a/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py +++ b/tests/istanbul/eip152_blake2/test_blake2_delegatecall.py @@ -1,5 +1,5 @@ """ -abstract: Test delegatecall to Blake2B Precompile before and after added. +Test delegatecall to Blake2B Precompile before and after added. """ import pytest diff --git a/tests/osaka/eip7594_peerdas/test_get_blobs.py b/tests/osaka/eip7594_peerdas/test_get_blobs.py index c0745000162..a38fcf36c51 100644 --- a/tests/osaka/eip7594_peerdas/test_get_blobs.py +++ b/tests/osaka/eip7594_peerdas/test_get_blobs.py @@ -1,7 +1,8 @@ """ -abstract: Get blobs engine endpoint tests - Tests for get blobs engine endpoint in [EIP-7594: PeerDAS - Peer Data - Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). +Get blobs engine endpoint tests. + +Tests for get blobs engine endpoint in [EIP-7594: PeerDAS - Peer Data +Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). """ from hashlib import sha256 diff --git a/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py b/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py index f83ebb23028..4dcf4ce2050 100644 --- a/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py +++ b/tests/osaka/eip7594_peerdas/test_max_blob_per_tx.py @@ -1,7 +1,8 @@ """ -abstract: MAX_BLOBS_PER_TX limit tests - Tests for `MAX_BLOBS_PER_TX` limit in [EIP-7594: PeerDAS - Peer Data - Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). +MAX_BLOBS_PER_TX limit tests. + +Tests for `MAX_BLOBS_PER_TX` limit in [EIP-7594: PeerDAS - Peer Data +Availability Sampling](https://eips.ethereum.org/EIPS/eip-7594). """ import pytest diff --git a/tests/osaka/eip7823_modexp_upper_bounds/__init__.py b/tests/osaka/eip7823_modexp_upper_bounds/__init__.py index 3c635edb962..b41a84cc6c0 100644 --- a/tests/osaka/eip7823_modexp_upper_bounds/__init__.py +++ b/tests/osaka/eip7823_modexp_upper_bounds/__init__.py @@ -1,4 +1,5 @@ """ -abstract: Tests [EIP-7823: Set upper bounds for MODEXP](https://eips.ethereum.org/EIPS/eip-7823). - Test cases for EIP-7823: Set upper bounds for MODEXP. +Tests [EIP-7823: Set upper bounds for MODEXP](https://eips.ethereum.org/EIPS/eip-7823). + +Test cases for EIP-7823: Set upper bounds for MODEXP. """ diff --git a/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py b/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py index 2863bdff43d..d91c4d3c711 100644 --- a/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py +++ b/tests/osaka/eip7823_modexp_upper_bounds/test_modexp_upper_bounds.py @@ -1,6 +1,5 @@ """ -abstract: Test [EIP-7823: Set upper bounds for MODEXP](https://eips.ethereum.org/EIPS/eip-7823) - Tests upper bounds of the MODEXP precompile. +Test [EIP-7823: Set upper bounds for MODEXP](https://eips.ethereum.org/EIPS/eip-7823). """ from typing import Dict diff --git a/tests/osaka/eip7825_transaction_gas_limit_cap/__init__.py b/tests/osaka/eip7825_transaction_gas_limit_cap/__init__.py index 24f15f932eb..6ad1209d939 100644 --- a/tests/osaka/eip7825_transaction_gas_limit_cap/__init__.py +++ b/tests/osaka/eip7825_transaction_gas_limit_cap/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-7825: Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825). - Test cases for EIP-7825: Transaction Gas Limit Cap. +Tests [EIP-7825: Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825). """ diff --git a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py index c1921b694b0..5eca0d23e58 100644 --- a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py +++ b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py @@ -1,7 +1,8 @@ """ -abstract: Transaction gas limit cap tests - Tests for transaction gas limit cap in [EIP-7825: Transaction Gas Limit - Cap](https://eips.ethereum.org/EIPS/eip-7825). +Transaction gas limit cap tests. + +Tests for transaction gas limit cap in [EIP-7825: Transaction Gas Limit +Cap](https://eips.ethereum.org/EIPS/eip-7825). """ from typing import List diff --git a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py index baf57654f97..c28cd62dbcf 100644 --- a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py +++ b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit_transition_fork.py @@ -1,7 +1,8 @@ """ -abstract: Transaction gas limit cap fork transition tests - Tests for fork transition behavior in [EIP-7825: Transaction Gas Limit - Cap](https://eips.ethereum.org/EIPS/eip-7825). +Transaction gas limit cap fork transition tests. + +Tests for fork transition behavior in [EIP-7825: Transaction Gas Limit +Cap](https://eips.ethereum.org/EIPS/eip-7825). """ import pytest diff --git a/tests/osaka/eip7883_modexp_gas_increase/__init__.py b/tests/osaka/eip7883_modexp_gas_increase/__init__.py index 133f473b9ae..7987a367c26 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/__init__.py +++ b/tests/osaka/eip7883_modexp_gas_increase/__init__.py @@ -1,3 +1,3 @@ """ -abstract: Tests for [EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883). +Tests for [EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883). """ diff --git a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py index da6b018f890..504781473fb 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py +++ b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py @@ -1,7 +1,8 @@ """ -abstract: EIP-7883 ModExp gas cost increase tests - Tests for ModExp gas cost increase in - [EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883). +EIP-7883 ModExp gas cost increase tests. + +Tests for ModExp gas cost increase in +[EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883). """ from typing import Dict diff --git a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds_transition.py b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds_transition.py index d6ff90b68de..5d779ae627c 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds_transition.py +++ b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds_transition.py @@ -1,6 +1,5 @@ """ -Test ModExp gas cost transition from EIP-7883 before and after the Osaka hard -fork. +Test ModExp gas cost transition from EIP-7883 before & after the Osaka fork. """ import pytest diff --git a/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py b/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py index 09a8e67ed65..820f19b54a4 100644 --- a/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py +++ b/tests/osaka/eip7918_blob_reserve_price/test_blob_base_fee.py @@ -1,6 +1,8 @@ """ -abstract: [EIP-7918: Blob base fee bounded by execution -cost](https://eips.ethereum.org/EIPS/eip-7918). + [EIP-7918: Blob base fee bounded by execution cost](https://eips.ethereum.org/EIPS/eip-7918). + +Test the blob base fee reserve price mechanism for +[EIP-7918: Blob base fee bounded by execution cost](https://eips.ethereum.org/EIPS/eip-7918). """ from typing import Dict, List diff --git a/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo.py b/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo.py index 2ee655bcaf7..b52dce2943b 100644 --- a/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo.py +++ b/tests/osaka/eip7918_blob_reserve_price/test_blob_reserve_price_with_bpo.py @@ -1,5 +1,5 @@ """ -abstract: [EIP-7918: Blob base fee bounded by execution + [EIP-7918: Blob base fee bounded by execution cost](https://eips.ethereum.org/EIPS/eip-7918). """ diff --git a/tests/osaka/eip7934_block_rlp_limit/__init__.py b/tests/osaka/eip7934_block_rlp_limit/__init__.py index 562bf665681..f2bdbe02266 100644 --- a/tests/osaka/eip7934_block_rlp_limit/__init__.py +++ b/tests/osaka/eip7934_block_rlp_limit/__init__.py @@ -1,3 +1,3 @@ """ -abstract: Tests for [EIP-7934: RLP Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934). +Tests for [EIP-7934: RLP Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934). """ diff --git a/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py b/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py index df4eb79d688..50bccb4fd85 100644 --- a/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py +++ b/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py @@ -1,5 +1,5 @@ """ -abstract: Tests for [EIP-7934: RLP Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934). +Tests for [EIP-7934: RLP Execution Block Size Limit](https://eips.ethereum.org/EIPS/eip-7934). """ from functools import lru_cache diff --git a/tests/osaka/eip7939_count_leading_zeros/__init__.py b/tests/osaka/eip7939_count_leading_zeros/__init__.py index 23769774cfe..1e9f1a4156c 100644 --- a/tests/osaka/eip7939_count_leading_zeros/__init__.py +++ b/tests/osaka/eip7939_count_leading_zeros/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-7939: Count leading zeros (CLZ) opcode](https://eips.ethereum.org/EIPS/eip-7939) - Test cases for [EIP-7939: Count leading zeros (CLZ) opcode](https://eips.ethereum.org/EIPS/eip-7939). +Tests [EIP-7939: Count leading zeros (CLZ) opcode](https://eips.ethereum.org/EIPS/eip-7939). """ diff --git a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py index 40541a1f853..2ca49d0779e 100644 --- a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py +++ b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py @@ -1,7 +1,5 @@ """ -abstract: Tests [EIP-7939: Count leading zeros (CLZ)](https://eips.ethereum.org/EIPS/eip-7939) - Test cases for - [EIP-7939: Count leading zeros (CLZ) opcode](https://eips.ethereum.org/EIPS/eip-7939). +Tests [EIP-7939: Count leading zeros (CLZ)](https://eips.ethereum.org/EIPS/eip-7939). """ import pytest diff --git a/tests/osaka/eip7951_p256verify_precompiles/__init__.py b/tests/osaka/eip7951_p256verify_precompiles/__init__.py index 3e17ffea1e5..a5fa2c7cfc6 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/__init__.py +++ b/tests/osaka/eip7951_p256verify_precompiles/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951). - Test cases for EIP-7951: Precompile for secp256r1 Curve Support. +Tests [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951). """ diff --git a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py index eb7bb154e9f..e954a85cbe7 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py +++ b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py @@ -1,5 +1,5 @@ """ -abstract: Tests for [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951). +Tests for [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951). """ import pytest diff --git a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify_before_fork.py b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify_before_fork.py index 5c8bafe5ae6..9f8f692ad30 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify_before_fork.py +++ b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify_before_fork.py @@ -1,6 +1,8 @@ """ -abstract: Tests P256VERIFY precompiles of [EIP-7951: Precompile for secp256r1 -Curve Support](https://eips.ethereum.org/EIPS/eip-7951) Tests P256VERIFY +Tests P256VERIFY precompiles of [EIP-7951: Precompile for secp256r1 +Curve Support](https://eips.ethereum.org/EIPS/eip-7951). + +Tests P256VERIFY precompiles of [EIP-7951: Precompile for secp256r1 Curve Support](https://eips.ethereum.org/EIPS/eip-7951) before the Osaka hard fork is active. diff --git a/tests/paris/security/test_selfdestruct_balance_bug.py b/tests/paris/security/test_selfdestruct_balance_bug.py index 529d8f3565e..da14a74eaf1 100644 --- a/tests/paris/security/test_selfdestruct_balance_bug.py +++ b/tests/paris/security/test_selfdestruct_balance_bug.py @@ -1,13 +1,15 @@ """ -bug: Tests the Consensus Flaw During Block Processing related to SELFDESTRUCT +Tests the Consensus Flaw During Block Processing related to SELFDESTRUCT. + Tests the consensus-vulnerability reported in [go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4](https://github.com/ethere um/go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4). To reproduce the issue with this test case: -1. Fill the test with the most recent geth evm version. 2. Run the fixture -output within a vulnerable geth version: v1.9.20 > geth >= v1.9.4. +1. Fill the test with the most recent geth evm version. +2. Run the fixture + output within a vulnerable geth version: v1.9.20 > geth >= v1.9.4. """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/__init__.py b/tests/prague/eip2537_bls_12_381_precompiles/__init__.py index 660915e8076..bc90dfa9752 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/__init__.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/__init__.py @@ -1,3 +1,3 @@ """ -abstract: Tests [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). +Tests [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). """ diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py index 08e6a5059b1..6d6effdde05 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1add.py @@ -1,8 +1,9 @@ """ -abstract: Tests BLS12_G1ADD precompile - Tests the BLS12_G1ADD precompile implementation from [EIP-2537: - Precompile for BLS12-381 curve operations] - (https://eips.ethereum.org/EIPS/eip-2537). +Tests BLS12_G1ADD precompile. + +Tests the BLS12_G1ADD precompile implementation from [EIP-2537: +Precompile for BLS12-381 curve operations] +(https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py index f72da72428f..560a39009bb 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py @@ -1,7 +1,8 @@ """ -abstract: Test the BLS12_G1MSM precompile - Test the BLS12_G1MSM precompile introduced in - [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). +Test the BLS12_G1MSM precompile. + +Test the BLS12_G1MSM precompile introduced in +[EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py index f18a51fc52a..d03e29b9481 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py @@ -1,8 +1,9 @@ """ -abstract: Tests BLS12_G1MUL precompile - Tests the BLS12_G1MUL precompile implementation from [EIP-2537: - Precompile for BLS12-381 curve operations] - (https://eips.ethereum.org/EIPS/eip-2537). +Tests BLS12_G1MUL precompile. + +Tests the BLS12_G1MUL precompile implementation from [EIP-2537: +Precompile for BLS12-381 curve operations] +(https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py index 19807f81164..71e71ed7ebc 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2add.py @@ -1,8 +1,9 @@ """ -abstract: Tests BLS12_G2ADD precompile - Tests the BLS12_G2ADD precompile implementation from [EIP-2537: - Precompile for BLS12-381 curve operations] - (https://eips.ethereum.org/EIPS/eip-2537). +Tests BLS12_G2ADD precompile. + +Tests the BLS12_G2ADD precompile implementation from [EIP-2537: +Precompile for BLS12-381 curve operations] +(https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py index ef1eebde9c7..518dd6d1dba 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py @@ -1,7 +1,8 @@ """ -abstract: Test the BLS12_G2MSM precompile - Test the BLS12_G2MSM precompile introduced in - [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). +Test the BLS12_G2MSM precompile. + +Test the BLS12_G2MSM precompile introduced in +[EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py index defc47c0994..4256de3afc2 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2mul.py @@ -1,7 +1,8 @@ """ -abstract: Test the BLS12_G2MUL precompile - Test the BLS12_G2MUL precompile introduced in - [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). +Test the BLS12_G2MUL precompile. + +Test the BLS12_G2MUL precompile introduced in +[EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py index 9a75b31c35b..095df9e8884 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp2_to_g2.py @@ -1,7 +1,8 @@ """ -abstract: Test the BLS12_MAP_FP2_TO_G2 precompile - Test the BLS12_MAP_FP2_TO_G2 precompile introduced in - [EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). +Test the BLS12_MAP_FP2_TO_G2 precompile. + +Test the BLS12_MAP_FP2_TO_G2 precompile introduced in +[EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py index 96e198e6316..d8c0d73a2cd 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_map_fp_to_g1.py @@ -1,8 +1,8 @@ """ -abstract: Tests BLS12_MAP_FP_TO_G1 precompile. - Tests the BLS12_MAP_FP_TO_G1 precompile implementation from [EIP-2537: - Precompile for BLS12-381 curve operations] - (https://eips.ethereum.org/EIPS/eip-2537). +Tests BLS12_MAP_FP_TO_G1 precompile. + +Tests the BLS12_MAP_FP_TO_G1 precompile implementation from +[EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py index 081d5d91f50..d8798201a40 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_pairing.py @@ -1,8 +1,8 @@ """ -abstract: Tests BLS12_PAIRING precompile. - Tests the BLS12_PAIRING precompile implementation from [EIP-2537: - Precompile for BLS12-381 curve operations] - (https://eips.ethereum.org/EIPS/eip-2537). +Tests BLS12_PAIRING precompile. + +Tests the BLS12_PAIRING precompile implementation from +[EIP-2537: Precompile for BLS12-381 curve operations](https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py index 79b884ba9dd..9c56ff39ac0 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_precompiles_before_fork.py @@ -1,8 +1,9 @@ """ -abstract: Tests BLS12 precompiles before fork activation - Tests the BLS12 precompiles behavior before fork activation from - [EIP-2537: Precompile for BLS12-381 curve operations] - (https://eips.ethereum.org/EIPS/eip-2537). +Tests BLS12 precompiles before fork activation. + +Tests the BLS12 precompiles behavior before fork activation from +[EIP-2537: Precompile for BLS12-381 curve operations] +(https://eips.ethereum.org/EIPS/eip-2537). """ import pytest diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py index e8dbf95fab9..4be5d751171 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py @@ -1,9 +1,10 @@ """ -abstract: Tests minimum gas and input length for BLS12 precompiles - Tests minimum gas and input length requirements for BLS12_G1MSM, - BLS12_G2MSM, and BLS12_PAIRING precompiles from [EIP-2537: Precompile - for BLS12-381 curve operations] - (https://eips.ethereum.org/EIPS/eip-2537). +Tests minimum gas and input length for BLS12 precompiles. + +Tests minimum gas and input length requirements for BLS12_G1MSM, +BLS12_G2MSM, and BLS12_PAIRING precompiles from [EIP-2537: Precompile +for BLS12-381 curve operations] +(https://eips.ethereum.org/EIPS/eip-2537). """ from typing import Callable, List, SupportsBytes diff --git a/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py b/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py index bc59f731ba6..35128bbefdb 100644 --- a/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py +++ b/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935). +Tests [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935). """ from typing import Dict, List diff --git a/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py b/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py index c18c83b700a..6593bd45275 100644 --- a/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py +++ b/tests/prague/eip2935_historical_block_hashes_from_state/test_contract_deployment.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935). +Tests [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935). """ from os.path import realpath diff --git a/tests/prague/eip6110_deposits/test_deposits.py b/tests/prague/eip6110_deposits/test_deposits.py index d2b767d5916..edf36f75107 100644 --- a/tests/prague/eip6110_deposits/test_deposits.py +++ b/tests/prague/eip6110_deposits/test_deposits.py @@ -1,8 +1,8 @@ """ -abstract: Tests validator deposit functionality. - Tests the validator deposit functionality implementation from [EIP-6110: - Supply validator deposits on chain] - (https://eips.ethereum.org/EIPS/eip-6110). +Tests validator deposit functionality. + +Tests the validator deposit functionality implementation from +[EIP-6110: Supply validator deposits on chain](https://eips.ethereum.org/EIPS/eip-6110). """ from typing import List diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py index 7122d233769..0d1aa8b5178 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_contract_deployment.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). """ from os.path import realpath diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py index 88d2f556279..e47a564ede4 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). """ from typing import List diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py index b0fbd44736c..0613eae2367 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). """ from typing import List diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py index c7bfa48a93a..6f9948c0385 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/test_withdrawal_requests_during_fork.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). +Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002). """ from os.path import realpath diff --git a/tests/prague/eip7251_consolidations/test_consolidations.py b/tests/prague/eip7251_consolidations/test_consolidations.py index 2cd022cb460..929ba8ba09b 100644 --- a/tests/prague/eip7251_consolidations/test_consolidations.py +++ b/tests/prague/eip7251_consolidations/test_consolidations.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). +Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). """ from typing import List diff --git a/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py b/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py index 869f33fe227..36f948c1029 100644 --- a/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py +++ b/tests/prague/eip7251_consolidations/test_consolidations_during_fork.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). +Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). """ from os.path import realpath diff --git a/tests/prague/eip7251_consolidations/test_contract_deployment.py b/tests/prague/eip7251_consolidations/test_contract_deployment.py index 34e455ba785..0d195306ac1 100644 --- a/tests/prague/eip7251_consolidations/test_contract_deployment.py +++ b/tests/prague/eip7251_consolidations/test_contract_deployment.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). +Tests [EIP-7251: Increase the MAX_EFFECTIVE_BALANCE](https://eips.ethereum.org/EIPS/eip-7251). """ from os.path import realpath diff --git a/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py b/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py index dad177076ae..a3f33ac2ec2 100644 --- a/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py +++ b/tests/prague/eip7251_consolidations/test_modified_consolidation_contract.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-7251: Execution layer triggerable consolidation](https://eips.ethereum.org/EIPS/eip-7251). +Tests [EIP-7251: Execution layer triggerable consolidation](https://eips.ethereum.org/EIPS/eip-7251). """ from typing import List diff --git a/tests/prague/eip7623_increase_calldata_cost/__init__.py b/tests/prague/eip7623_increase_calldata_cost/__init__.py index 916ea9ceeb6..ef3f7c8099e 100644 --- a/tests/prague/eip7623_increase_calldata_cost/__init__.py +++ b/tests/prague/eip7623_increase_calldata_cost/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623) - Tests for [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). +Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). """ diff --git a/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py b/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py index 96e2b5a7f29..53eb2957b5c 100644 --- a/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py +++ b/tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py @@ -1,5 +1,5 @@ """ -abstract: Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). +Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). """ from typing import List diff --git a/tests/prague/eip7623_increase_calldata_cost/test_refunds.py b/tests/prague/eip7623_increase_calldata_cost/test_refunds.py index 844b154f893..2fa3d80eed5 100644 --- a/tests/prague/eip7623_increase_calldata_cost/test_refunds.py +++ b/tests/prague/eip7623_increase_calldata_cost/test_refunds.py @@ -1,5 +1,5 @@ """ -abstract: Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). +Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). """ from enum import Enum, Flag, auto diff --git a/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py b/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py index d09f8170d01..dba9565f94b 100644 --- a/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py +++ b/tests/prague/eip7623_increase_calldata_cost/test_transaction_validity.py @@ -1,5 +1,5 @@ """ -abstract: Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). +Test [EIP-7623: Increase calldata cost](https://eips.ethereum.org/EIPS/eip-7623). """ import pytest diff --git a/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py b/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py index ff394294f89..382b1cb404c 100644 --- a/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py +++ b/tests/prague/eip7685_general_purpose_el_requests/test_multi_type_requests.py @@ -1,7 +1,8 @@ """ -abstract: Tests EIP-7685 General purpose execution layer requests - Cross testing for withdrawal and deposit request for - [EIP-7685: General purpose execution layer requests](https://eips.ethereum.org/EIPS/eip-7685). +Tests EIP-7685 General purpose execution layer requests. + +Cross testing for withdrawal and deposit request for +[EIP-7685: General purpose execution layer requests](https://eips.ethereum.org/EIPS/eip-7685). """ from itertools import permutations diff --git a/tests/prague/eip7702_set_code_tx/test_gas.py b/tests/prague/eip7702_set_code_tx/test_gas.py index 769db0239f7..1ff2140f019 100644 --- a/tests/prague/eip7702_set_code_tx/test_gas.py +++ b/tests/prague/eip7702_set_code_tx/test_gas.py @@ -1,7 +1,8 @@ """ -abstract: Tests related to gas of set-code transactions from EIP-7702 - Tests related to gas of set-code transactions from - [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). +Tests related to gas of set-code transactions from EIP-7702. + +Tests related to gas of set-code transactions from +[EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). """ from dataclasses import dataclass diff --git a/tests/prague/eip7702_set_code_tx/test_invalid_tx.py b/tests/prague/eip7702_set_code_tx/test_invalid_tx.py index 7fc06589c08..4855a738238 100644 --- a/tests/prague/eip7702_set_code_tx/test_invalid_tx.py +++ b/tests/prague/eip7702_set_code_tx/test_invalid_tx.py @@ -1,7 +1,8 @@ """ -abstract: Tests invalid set-code transactions from EIP-7702. - Tests invalid set-code transactions from - [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). +Tests invalid set-code transactions from EIP-7702. + +Tests invalid set-code transactions from +[EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). """ from enum import Enum, auto diff --git a/tests/prague/eip7702_set_code_tx/test_set_code_txs.py b/tests/prague/eip7702_set_code_tx/test_set_code_txs.py index 42c980d2e0f..d9ee6efcb34 100644 --- a/tests/prague/eip7702_set_code_tx/test_set_code_txs.py +++ b/tests/prague/eip7702_set_code_tx/test_set_code_txs.py @@ -1,7 +1,8 @@ """ -abstract: Tests use of set-code transactions from EIP-7702. - Tests use of set-code transactions from - [EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). +Tests use of set-code transactions from EIP-7702. + +Tests use of set-code transactions from +[EIP-7702: Set EOA account code for one transaction](https://eips.ethereum.org/EIPS/eip-7702). """ from enum import StrEnum diff --git a/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py b/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py index ba34205e9d1..e362e98f9ee 100644 --- a/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py +++ b/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py @@ -1,4 +1,6 @@ -"""A state test for [EIP-7702 SetCodeTX](https://eips.ethereum.org/EIPS/eip-7702).""" +""" +A state test for [EIP-7702 SetCodeTX](https://eips.ethereum.org/EIPS/eip-7702). +""" from enum import Enum, IntEnum diff --git a/tests/shanghai/eip3651_warm_coinbase/__init__.py b/tests/shanghai/eip3651_warm_coinbase/__init__.py index cd8d9647e05..66363cc4b39 100644 --- a/tests/shanghai/eip3651_warm_coinbase/__init__.py +++ b/tests/shanghai/eip3651_warm_coinbase/__init__.py @@ -1,3 +1,3 @@ """ -abstract: Tests for [EIP-3651: Warm COINBASE](https://eips.ethereum.org/EIPS/eip-3651). +Tests for [EIP-3651: Warm COINBASE](https://eips.ethereum.org/EIPS/eip-3651). """ diff --git a/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py b/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py index 3f811c605db..7f535043bae 100644 --- a/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py +++ b/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py @@ -1,9 +1,8 @@ """ -abstract: Tests [EIP-3651: Warm COINBASE](https://eips.ethereum.org/EIPS/eip-3651). - Tests for EIP-3651: Warm COINBASE. +Tests [EIP-3651: Warm COINBASE](https://eips.ethereum.org/EIPS/eip-3651). -note: Tests ported from: - - [ethereum/tests/pull/1082](https://github.com/ethereum/tests/pull/1082). +Tests ported from: +[ethereum/tests/pull/1082](https://github.com/ethereum/tests/pull/1082). """ import pytest diff --git a/tests/shanghai/eip3855_push0/__init__.py b/tests/shanghai/eip3855_push0/__init__.py index a8372e6ccfc..986e36b5494 100644 --- a/tests/shanghai/eip3855_push0/__init__.py +++ b/tests/shanghai/eip3855_push0/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-3855: PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855) - Tests for [EIP-3855: PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855). +Tests [EIP-3855: PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855). """ diff --git a/tests/shanghai/eip3855_push0/test_push0.py b/tests/shanghai/eip3855_push0/test_push0.py index 850a5a3a9da..068ef083cc3 100644 --- a/tests/shanghai/eip3855_push0/test_push0.py +++ b/tests/shanghai/eip3855_push0/test_push0.py @@ -1,9 +1,8 @@ """ -abstract: Tests [EIP-3855: PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855) - Tests for [EIP-3855: PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855). +Tests [EIP-3855: PUSH0 Instruction](https://eips.ethereum.org/EIPS/eip-3855). -note: Tests ported from: - - [ethereum/tests/pull/1033](https://github.com/ethereum/tests/pull/1033). +Tests ported from: +[ethereum/tests/pull/1033](https://github.com/ethereum/tests/pull/1033). """ import pytest diff --git a/tests/shanghai/eip3860_initcode/__init__.py b/tests/shanghai/eip3860_initcode/__init__.py index 501700995db..a6c7d4a01f2 100644 --- a/tests/shanghai/eip3860_initcode/__init__.py +++ b/tests/shanghai/eip3860_initcode/__init__.py @@ -1,4 +1,4 @@ """ -abstract: Test [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860) +Test [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860) Tests for [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860). """ diff --git a/tests/shanghai/eip3860_initcode/test_initcode.py b/tests/shanghai/eip3860_initcode/test_initcode.py index 3f10fa02da1..218eec6e258 100644 --- a/tests/shanghai/eip3860_initcode/test_initcode.py +++ b/tests/shanghai/eip3860_initcode/test_initcode.py @@ -1,10 +1,9 @@ """ -abstract: Test [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860) - Tests for [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860). +Test [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860). -note: Tests ported from: - - [ethereum/tests/pull/990](https://github.com/ethereum/tests/pull/990) - - [ethereum/tests/pull/1012](https://github.com/ethereum/tests/pull/990) +Tests ported from: +- [ethereum/tests/pull/990](https://github.com/ethereum/tests/pull/990) +- [ethereum/tests/pull/1012](https://github.com/ethereum/tests/pull/990) """ from typing import List diff --git a/tests/shanghai/eip4895_withdrawals/__init__.py b/tests/shanghai/eip4895_withdrawals/__init__.py index edd1dd22c5f..c10cd7154bd 100644 --- a/tests/shanghai/eip4895_withdrawals/__init__.py +++ b/tests/shanghai/eip4895_withdrawals/__init__.py @@ -1,4 +1,3 @@ """ -abstract: Tests [EIP-4895: Beacon chain withdrawals](https://eips.ethereum.org/EIPS/eip-4895). - Test cases for EIP-4895: Beacon chain push withdrawals as operations. +Tests [EIP-4895: Beacon chain withdrawals](https://eips.ethereum.org/EIPS/eip-4895). """ diff --git a/tests/shanghai/eip4895_withdrawals/test_withdrawals.py b/tests/shanghai/eip4895_withdrawals/test_withdrawals.py index 86b07e51720..e47d85d3e57 100644 --- a/tests/shanghai/eip4895_withdrawals/test_withdrawals.py +++ b/tests/shanghai/eip4895_withdrawals/test_withdrawals.py @@ -1,6 +1,5 @@ """ -abstract: Tests for [EIP-4895: Beacon chain withdrawals](https://eips.ethereum.org/EIPS/eip-4895). - Test cases for EIP-4895: Beacon chain push withdrawals as operations. +Tests for [EIP-4895: Beacon chain withdrawals](https://eips.ethereum.org/EIPS/eip-4895). """ from enum import Enum, unique diff --git a/tests/unscheduled/eip7692_eof_v1/__init__.py b/tests/unscheduled/eip7692_eof_v1/__init__.py index 21febf2d5b4..47bb9a0684c 100644 --- a/tests/unscheduled/eip7692_eof_v1/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/__init__.py @@ -1,5 +1,5 @@ """ -abstract: Test cases for [EIP-7692: EVM Object Format (EOFv1) Meta](https://eips.ethereum.org/EIPS/eip-7692). +Test cases for [EIP-7692: EVM Object Format (EOFv1) Meta](https://eips.ethereum.org/EIPS/eip-7692). Test cases for the EIPs included in EIP-7692 EOFv1 Meta. * [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663). diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py index fac62387aff..e47fa8864fa 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py @@ -1,5 +1,5 @@ """ -abstract: EOF - EVM Object Format v1 tests. +EOF - EVM Object Format v1 tests. Test cases for [EIP-3540: EOF - EVM Object Format v1](https://eips.ethereum.org/EIPS/eip-3540). diff --git a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py index f8728ad036a..c01c8ade58e 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py @@ -1,5 +1,5 @@ """ -abstract: Test cases for [EIP-4200: EOF - Static relative jumps](https://eips.ethereum.org/EIPS/eip-4200). +Test cases for [EIP-4200: EOF - Static relative jumps](https://eips.ethereum.org/EIPS/eip-4200). EIP-4200 replaces dynamic jump instructions with relative jump offsets for improved control flow predictability. Opcodes introduced: `RJUMP` (`0xE0`), `RJUMPI` (`0xE1`), `RJUMPV` (`0xE2`). diff --git a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py index 4498ad304fa..ba7a019fdd9 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py @@ -1,5 +1,5 @@ """ -abstract: Test cases for [EIP-4750: EOF - Functions](https://eips.ethereum.org/EIPS/eip-4750) +Test cases for [EIP-4750: EOF - Functions](https://eips.ethereum.org/EIPS/eip-4750) EIP-4750 formalizes functions in the EVM object format, introducing callable units of code. Opcodes introduced: `CALLF` (`0xE3`), `RETF` (`0xE4`). diff --git a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py index 831c0d3fbc0..c09e062349f 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py @@ -1,5 +1,5 @@ """ -abstract: EOF Stack Validation tests +EOF Stack Validation tests Tests for [EIP-5450: EOF - Stack Validation](https://eips.ethereum.org/EIPS/eip-5450). diff --git a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py index 46d8f72e4fa..d9c5e46fb10 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py @@ -1,5 +1,5 @@ """ -abstract: Test cases for [EIP-6206: EOF - JUMPF and non-returning functions](https://eips.ethereum.org/EIPS/eip-6206). +Test cases for [EIP-6206: EOF - JUMPF and non-returning functions](https://eips.ethereum.org/EIPS/eip-6206). EIP-6206 adds a conditional forward jump instruction and support for functions without return values. Opcodes introduced: `JUMPF` (`0xE5`). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py index 11d5b83e478..01a78b47340 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/__init__.py @@ -1,5 +1,5 @@ """ -abstract: Test cases for EIP-663 SWAPN, DUPN and EXCHANGE instructions +Test cases for EIP-663 SWAPN, DUPN and EXCHANGE instructions [EIP-663](https://eips.ethereum.org/EIPS/eip-663) defines new stack manipulation instructions that allow accessing the stack at higher depths. Opcodes introduced: `DUPN` (`0xE6`), `SWAPN` (`0xE7`), `EXCHANGEN` diff --git a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py index 56e92d17965..a68cae56817 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py +++ b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_dupn.py @@ -1,5 +1,5 @@ """ -abstract: DUPN instruction tests +DUPN instruction tests Tests for DUPN instruction in [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py index 55a0bb945ef..583c10d89bc 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py +++ b/tests/unscheduled/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_exchange.py @@ -1,5 +1,5 @@ """ -abstract: Tests [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663). +Tests [EIP-663: SWAPN, DUPN and EXCHANGE instructions](https://eips.ethereum.org/EIPS/eip-663). """ import pytest diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py index bae0996845c..672c24a7406 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/__init__.py @@ -1,5 +1,5 @@ """ -abstract: Test cases for EIP-7069 Revamped CALL instructions +Test cases for EIP-7069 Revamped CALL instructions [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069) proposes modifications to `CALL` instructions to align with the structured EOF format. Opcodes introduced: `EXTCALL` (`0xF8`), diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py index 7708aa5baf4..99faf722834 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calldata.py @@ -1,5 +1,5 @@ """ -abstract: Call data tests for EXT*CALL instructions +Call data tests for EXT*CALL instructions Tests for call data handling in [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py index d111b4cc26c..638adc05c5b 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_gas.py @@ -1,5 +1,5 @@ """ -abstract: Gas consumption tests for EXT*CALL instructions +Gas consumption tests for EXT*CALL instructions Tests for gas consumption in [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py index e06cf9f80c1..8c75d1af340 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_returndataload.py @@ -1,5 +1,5 @@ """ -abstract: RETURNDATALOAD instruction tests +RETURNDATALOAD instruction tests Tests for RETURNDATALOAD instruction in [EIP-7069: Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py index ca92477ccb2..5d726f12940 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py @@ -1,5 +1,5 @@ """ -abstract: Test cases for EOF Data section access instructions for EIP-7480. +Test cases for EOF Data section access instructions for EIP-7480. EIP-7480 specifies instructions for accessing data stored in the dedicated data section of the EOF format. Full specification: [EIP-7480: EOF - Data section access instructions](https://eips.ethereum.org/EIPS/eip-7480). diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py index a5ec044750b..2ef0a8613de 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py @@ -1,5 +1,5 @@ """ -abstract: Test cases for EOF Contract Creation for EIP-7620. +Test cases for EOF Contract Creation for EIP-7620. EIP-7620 replaces `CREATE` and `CREATE2` with `EOFCREATE` for deploying contracts in the EOF format. Full specification: [EIP-7620: EOF Contract Creation](https://eips.ethereum.org/EIPS/eip-7620). diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py index a0e886f11c4..ddd44267933 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/__init__.py @@ -1,3 +1,3 @@ """ -abstract: Test cases for [EIP-7873: TXCREATE and InitcodeTransaction](https://eips.ethereum.org/EIPS/eip-7873). +Test cases for [EIP-7873: TXCREATE and InitcodeTransaction](https://eips.ethereum.org/EIPS/eip-7873). """ From c74adc1c476751355c6f1edf6e8d8855b78f1ba5 Mon Sep 17 00:00:00 2001 From: Felix H Date: Tue, 23 Sep 2025 15:42:12 +0000 Subject: [PATCH 05/16] fixes --- .../account_absent_values.py | 32 ++++++++++--------- .../block_access_list/expectations.py | 21 ++++++++---- .../block_access_list/t8n.py | 6 ++-- .../tests/test_block_access_lists.py | 13 ++++++-- 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/ethereum_test_types/block_access_list/account_absent_values.py b/src/ethereum_test_types/block_access_list/account_absent_values.py index 7bf3fd2213e..c0fea606a97 100644 --- a/src/ethereum_test_types/block_access_list/account_absent_values.py +++ b/src/ethereum_test_types/block_access_list/account_absent_values.py @@ -1,10 +1,11 @@ """ BalAccountAbsentValues class for BAL testing. -This module provides a unified class for specifying explicit absent values in Block Access Lists. -This class uses the same change classes as BalAccountChanges to specify specific values that -should NOT exist in the BAL. For checking complete absence, use BalAccountExpectation -with empty lists instead. +This module provides a unified class for specifying explicit absent values +in Block Access Lists. This class uses the same change classes as +BalAccountChanges to specify specific values that should NOT exist in the BAL. +For checking complete absence, use BalAccountExpectation with empty lists +instead. """ from typing import List @@ -31,18 +32,19 @@ class BalAccountAbsentValues(CamelModel): """ - Represents explicit absent value expectations for a specific account in a block. + Represents explicit absent value expectations for a specific account + in a block. - This class specifies specific changes that should NOT exist in the BAL for a - given account. + This class specifies specific changes that should NOT exist in the BAL + for a given account. - IMPORTANT: This class is for checking that specific values are absent, NOT for - checking that entire categories are empty. For complete absence checks - (e.g., "no nonce changes at all"), use BalAccountExpectation with empty lists - instead. + IMPORTANT: This class is for checking that specific values are absent, + NOT for checking that entire categories are empty. For complete + absence checks (e.g., "no nonce changes at all"), use + BalAccountExpectation with empty lists instead. - The validation works by checking that none of the specified explicit changes - exist in the actual BAL. + The validation works by checking that none of the specified + explicit changes exist in the actual BAL. Example: # Forbid specific nonce change at tx 1 with post_nonce=5, and specific @@ -156,8 +158,8 @@ def _validate_forbidden_changes( def validate_against(self, account: BalAccountChange) -> None: """ - Validate that the account does not contain the forbidden changes specified in - this object. + Validate that the account does not contain the forbidden changes + specified in this object. Args: account: The BalAccountChange to validate against diff --git a/src/ethereum_test_types/block_access_list/expectations.py b/src/ethereum_test_types/block_access_list/expectations.py index ffa213bd510..8bcdeba5381 100644 --- a/src/ethereum_test_types/block_access_list/expectations.py +++ b/src/ethereum_test_types/block_access_list/expectations.py @@ -1,7 +1,8 @@ """ Block Access List expectation classes for test validation. -This module contains classes for defining and validating expected BAL values in tests. +This module contains classes for defining and validating expected +BAL values in tests. """ from typing import Any, Callable, Dict, List, Optional @@ -27,7 +28,8 @@ class BalAccountExpectation(CamelModel): """ Represents expected changes to a specific account in a block. - Same as BalAccountChange but without the address field, used for expectations. + Same as BalAccountChange but without the address field, + used for expectations. """ nonce_changes: List[BalNonceChange] = Field( @@ -102,13 +104,16 @@ def modify( Create a new expectation with a modifier for invalid test cases. Args: - modifiers: One or more functions that take and return a BlockAccessList + modifiers: One or more functions that take and return + a BlockAccessList Returns: - A new BlockAccessListExpectation instance with the modifiers applied + A new BlockAccessListExpectation instance with + the modifiers applied Example: - from ethereum_test_types.block_access_list.modifiers import remove_nonces + from ethereum_test_types.block_access_list. + modifiers import remove_nonces expectation = BlockAccessListExpectation( account_expectations={...} @@ -247,7 +252,8 @@ def _compare_account_expectations( expected: BalAccountExpectation, actual: BalAccountChange ) -> None: """ - Compare expected and actual account changes using subsequence validation. + Compare expected and actual account changes using + subsequence validation. Args: expected: The expected account changes @@ -305,7 +311,8 @@ def _compare_account_expectations( expected_slot_changes = expected_slot.slot_changes if not expected_slot_changes: - # Empty expected means any slot_changes are acceptable + # Empty expected means any + # slot_changes are acceptable pass else: # Validate slot_changes as subsequence diff --git a/src/ethereum_test_types/block_access_list/t8n.py b/src/ethereum_test_types/block_access_list/t8n.py index 808ace06f57..848b8d796af 100644 --- a/src/ethereum_test_types/block_access_list/t8n.py +++ b/src/ethereum_test_types/block_access_list/t8n.py @@ -16,8 +16,10 @@ class BlockAccessList(EthereumTestRootModel[List[BalAccountChange]]): """ Block Access List for t8n tool communication and fixtures. - This model represents the BAL exactly as defined in EIP-7928 - it is itself a list - of account changes (root model), not a container. Used for: + This model represents the BAL exactly as defined in EIP-7928 + - it is itself a list of account changes (root model), not a container. + + Used for: - Communication with t8n tools - Fixture generation - RLP encoding for hash verification diff --git a/src/ethereum_test_types/tests/test_block_access_lists.py b/src/ethereum_test_types/tests/test_block_access_lists.py index 9174202605c..06650810722 100644 --- a/src/ethereum_test_types/tests/test_block_access_lists.py +++ b/src/ethereum_test_types/tests/test_block_access_lists.py @@ -816,7 +816,8 @@ def test_absent_values_with_multiple_tx_indices(): alice: BalAccountExpectation( absent_values=BalAccountAbsentValues( nonce_changes=[ - # wrongly forbid change at txs 1 and 2 (1 exists, so should fail) + # wrongly forbid change at txs 1 and 2 + # (1 exists, so should fail) BalNonceChange(tx_index=1, post_nonce=1), BalNonceChange(tx_index=2, post_nonce=0), ] @@ -962,13 +963,19 @@ def test_bal_account_absent_values_comprehensive(): ], ) def test_bal_account_absent_values_empty_list_validation_raises(field_name, field_value): - """Test that empty lists in BalAccountAbsentValues fields raise appropriate errors.""" + """ + Test that empty lists in BalAccountAbsentValues fields + raise appropriate errors. + """ with pytest.raises(ValueError, match="Empty lists are not allowed"): BalAccountAbsentValues(**{field_name: field_value}) def test_bal_account_absent_values_empty_slot_changes_raises(): - """Test that empty slot_changes in storage_changes raises appropriate error.""" + """ + Test that empty slot_changes in storage_changes + raises appropriate error. + """ with pytest.raises(ValueError, match="Empty lists are not allowed"): BalAccountAbsentValues( storage_changes=[ From 511d1299fd0ddc017c27b07137a403b510bb3043 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Wed, 24 Sep 2025 11:37:32 +0200 Subject: [PATCH 06/16] chore: fix more malformatted tables --- tests/frontier/opcodes/test_push.py | 45 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/tests/frontier/opcodes/test_push.py b/tests/frontier/opcodes/test_push.py index f3a6794a84d..fc407f9c4d0 100644 --- a/tests/frontier/opcodes/test_push.py +++ b/tests/frontier/opcodes/test_push.py @@ -34,8 +34,8 @@ def get_input_for_push_opcode(opcode: Op) -> bytes: ) @pytest.mark.parametrize( "push_opcode", - [getattr(Op, f"PUSH{i}") for i in range(1, 33)], # Dynamically parametrize - # PUSH opcodes + # Dynamically parametrize PUSH opcodes + [getattr(Op, f"PUSH{i}") for i in range(1, 33)], ids=lambda op: str(op), ) @pytest.mark.valid_from("Frontier") @@ -52,16 +52,14 @@ def test_push(state_test: StateTestFiller, fork: Fork, pre: Alloc, push_opcode: env = Environment() """ - - - ** Bytecode explanation ** - +---------------------------------------------------+ | Bytecode | - Stack | Storage | - |---------------------------------------------------| | PUSH* excerpt | - excerpt | | | PUSH1 0 | 0 excerpt | - | | SSTORE | | [0]: excerpt | - +---------------------------------------------------+ - + ** Bytecode explanation ** + +---------------------------------------------------+ + | Bytecode | Stack | Storage | + |---------------------------------------------------| + | PUSH* excerpt | excerpt | | + | PUSH1 0 | 0 excerpt | | + | SSTORE | | [0]: excerpt | + +---------------------------------------------------+ """ contract_code = push_opcode(excerpt) + Op.PUSH1(0) + Op.SSTORE @@ -97,8 +95,7 @@ def test_stack_overflow( state_test: StateTestFiller, fork: Fork, pre: Alloc, push_opcode: Op, stack_height: int ): """ - A test to ensure that the stack overflows when the stack limit of 1024 is - exceeded. + A test the stack overflows when the stack limit of 1024 is exceeded. """ env = Environment() @@ -116,19 +113,19 @@ def test_stack_overflow( offset (0x45 for PUSH1). The last iteration will overflow the stack and the storage slot will be empty. - ** Bytecode explanation ** - +---------------------------------------------------+ | Bytecode | - Stack | Storage | - |---------------------------------------------------| | PUSH* excerpt | - excerpt | | | PUSH1 0 | 0 excerpt | - | | SSTORE | | [0]: excerpt | - +---------------------------------------------------+ - + ** Bytecode explanation ** + +---------------------------------------------------+ + | Bytecode | Stack | Storage | + |---------------------------------------------------| + | PUSH* excerpt | excerpt | | + | PUSH1 0 | 0 excerpt | | + | SSTORE | | [0]: excerpt | + +---------------------------------------------------+ """ contract_code: Bytecode = Bytecode() for _ in range(stack_height - 2): - contract_code += Op.PUSH1(0) # mostly push 0 to avoid contract size - # limit exceeded + # mostly push 0 to avoid contract size limit exceeded + contract_code += Op.PUSH1(0) contract_code += push_opcode(excerpt) * 2 + Op.SSTORE contract = pre.deploy_contract(contract_code) From e9a6a96c7ac7b56edf548ab97dc2d8b16a901bf5 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Wed, 24 Sep 2025 12:37:18 +0200 Subject: [PATCH 07/16] chore: fix broken unordered-lists/args --- src/cli/fillerconvert/fillerconvert.py | 11 ++-- src/pytest_plugins/pytest_hive/pytest_hive.py | 9 +-- .../test_beacon_root_contract.py | 15 +++-- tests/cancun/eip4844_blobs/test_blob_txs.py | 27 ++++---- .../test_blobhash_opcode_contexts.py | 24 ++++--- .../eip4844_blobs/test_excess_blob_gas.py | 23 ++++--- .../test_point_evaluation_precompile.py | 9 ++- tests/cancun/eip5656_mcopy/test_mcopy.py | 12 ++-- .../eip6780_selfdestruct/test_selfdestruct.py | 23 ++++--- .../test_count_leading_zeros.py | 21 +++--- tests/shanghai/eip3855_push0/test_push0.py | 15 +++-- .../eip3860_initcode/test_initcode.py | 65 ++++++++++++------- .../eip4895_withdrawals/test_withdrawals.py | 42 ++++++------ 13 files changed, 174 insertions(+), 122 deletions(-) diff --git a/src/cli/fillerconvert/fillerconvert.py b/src/cli/fillerconvert/fillerconvert.py index 37897d33e30..c7392fd420c 100644 --- a/src/cli/fillerconvert/fillerconvert.py +++ b/src/cli/fillerconvert/fillerconvert.py @@ -39,10 +39,11 @@ def main() -> None: verified_vectors += verify_refilled(Path(refilled_file), original_file) print(f"Total vectors verified: {verified_vectors}") - # Solidity skipped tests or - # file.endswith("stExample/solidityExampleFiller.yml") or - # file.endswith("vmPerformance/performanceTesterFiller.yml") or - # file.endswith("vmPerformance/loopExpFiller.yml") or - # file.endswith("vmPerformance/loopMulFiller.yml") or + # Solidity skipped tests + # or file.endswith("stExample/solidityExampleFiller.yml") + # or file.endswith("vmPerformance/performanceTesterFiller.yml") + # or file.endswith("vmPerformance/loopExpFiller.yml") + # or file.endswith("vmPerformance/loopMulFiller.yml") + # or # file.endswith("stRevertTest/RevertRemoteSubCallStorageOOGFiller.yml") # or file.endswith("stSolidityTest/SelfDestructFiller.yml") diff --git a/src/pytest_plugins/pytest_hive/pytest_hive.py b/src/pytest_plugins/pytest_hive/pytest_hive.py index b19ffbeb610..b1624391ef4 100644 --- a/src/pytest_plugins/pytest_hive/pytest_hive.py +++ b/src/pytest_plugins/pytest_hive/pytest_hive.py @@ -144,12 +144,9 @@ def pytest_runtest_makereport(item, call): This is used to get the test result and pass it to the hive test suite. Available as: - - result_setup - - setup result - - result_call - - test result - - result_teardown - - teardown result + - result_setup - setup result + - result_call - test result + - result_teardown - teardown result """ del call diff --git a/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py b/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py index fdfa1d36108..ea4647e0007 100644 --- a/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py +++ b/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py @@ -82,10 +82,17 @@ def test_beacon_root_contract_calls( post: Dict, ): """ - Tests the beacon root contract call using various call contexts: - `CALL` - - `DELEGATECALL` - `CALLCODE` - `STATICCALL` for different call gas amounts: - - exact gas (valid call) - extra gas (valid call) - insufficient gas - (invalid call). + Test calling the beacon root contract in various call contexts. + + These call contexts are tested: + - `CALL` + - `DELEGATECALL` + - `CALLCODE` + - `STATICCALL` + for different call gas amounts: + - exact gas (valid call) + - extra gas (valid call) + - insufficient gas (invalid call). The expected result is that the contract call will be executed if the gas amount is met and return the correct`parent_beacon_block_root`. Otherwise diff --git a/tests/cancun/eip4844_blobs/test_blob_txs.py b/tests/cancun/eip4844_blobs/test_blob_txs.py index 162ae8c3a6b..ce7be8ffa97 100644 --- a/tests/cancun/eip4844_blobs/test_blob_txs.py +++ b/tests/cancun/eip4844_blobs/test_blob_txs.py @@ -424,11 +424,12 @@ def generate_invalid_tx_max_fee_per_blob_gas_tests( tests = [] tests.append( pytest.param( - minimum_excess_blobs_for_first_increment - 1, # blob gas price is - # 1 - fork.target_blobs_per_block() + 1, # blob gas cost increases to - # above the minimum - min_base_fee_per_blob_gas, # tx max_blob_gas_cost is the minimum + # blob gas price is 1 + minimum_excess_blobs_for_first_increment - 1, + # blob gas cost increases to above the minimum + fork.target_blobs_per_block() + 1, + # tx max_blob_gas_cost is the minimum + min_base_fee_per_blob_gas, TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS, id="insufficient_max_fee_per_blob_gas", marks=pytest.mark.exception_test, @@ -437,12 +438,12 @@ def generate_invalid_tx_max_fee_per_blob_gas_tests( if (next_base_fee_per_blob_gas - min_base_fee_per_blob_gas) > 1: tests.append( pytest.param( - minimum_excess_blobs_for_first_increment - - 1, # blob gas price is one less than the minimum - fork.target_blobs_per_block() + 1, # blob gas cost increases - # to above the minimum - next_base_fee_per_blob_gas - - 1, # tx max_blob_gas_cost is one less than the minimum + # blob gas price is one less than the minimum + minimum_excess_blobs_for_first_increment - 1, + # blob gas cost increases to above the minimum + fork.target_blobs_per_block() + 1, + # tx max_blob_gas_cost is one less than the minimum + next_base_fee_per_blob_gas - 1, TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS, id="insufficient_max_fee_per_blob_gas_one_less_than_next", marks=pytest.mark.exception_test, @@ -453,8 +454,8 @@ def generate_invalid_tx_max_fee_per_blob_gas_tests( pytest.param( 0, # blob gas price is the minimum 0, # blob gas cost stays put at 1 - min_base_fee_per_blob_gas - 1, # tx max_blob_gas_cost is one - # less than the minimum + # tx max_blob_gas_cost is one less than the minimum + min_base_fee_per_blob_gas - 1, TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS, id="insufficient_max_fee_per_blob_gas_one_less_than_min", marks=pytest.mark.exception_test, diff --git a/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py b/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py index 4366ef45023..5e8459a3cdd 100644 --- a/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py +++ b/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py @@ -175,11 +175,13 @@ def test_blobhash_opcode_contexts( Tests that the `BLOBHASH` opcode functions correctly when called in different contexts. - - `BLOBHASH` opcode on the top level of the call stack. - `BLOBHASH` opcode - on the max value. - `BLOBHASH` opcode on `CALL`, `DELEGATECALL`, - `STATICCALL`, and `CALLCODE`. - `BLOBHASH` opcode on Initcode. - `BLOBHASH` - opcode on `CREATE` and `CREATE2`. - `BLOBHASH` opcode on transaction types - 0, 1 and 2. + - `BLOBHASH` opcode on the top level of the call stack. + - `BLOBHASH` opcode on the max value. + - `BLOBHASH` opcode on `CALL`, `DELEGATECALL`, `STATICCALL`, and + `CALLCODE`. + - `BLOBHASH` opcode on Initcode. + - `BLOBHASH` opcode on `CREATE` and `CREATE2`. + - `BLOBHASH` opcode on transaction types 0, 1 and 2. """ tx_to: Address post: dict[Address, Account] @@ -290,11 +292,13 @@ def test_blobhash_opcode_contexts_tx_types( Tests that the `BLOBHASH` opcode functions correctly when called in different contexts. - - `BLOBHASH` opcode on the top level of the call stack. - `BLOBHASH` opcode - on the max value. - `BLOBHASH` opcode on `CALL`, `DELEGATECALL`, - `STATICCALL`, and `CALLCODE`. - `BLOBHASH` opcode on Initcode. - `BLOBHASH` - opcode on `CREATE` and `CREATE2`. - `BLOBHASH` opcode on transaction types - 0, 1 and 2. + - `BLOBHASH` opcode on the top level of the call stack. + - `BLOBHASH` opcode on the max value. + - `BLOBHASH` opcode on `CALL`, `DELEGATECALL`, `STATICCALL`, and + `CALLCODE`. + - `BLOBHASH` opcode on Initcode. + - `BLOBHASH` opcode on `CREATE` and `CREATE2`. + - `BLOBHASH` opcode on transaction types 0, 1 and 2. """ blobhash_sstore_address = BlobhashContext.BLOBHASH_SSTORE.deploy_contract(pre=pre, indexes=[0]) tx_kwargs = { diff --git a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py index b7ea3ca29c2..f08415f7c0e 100644 --- a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py +++ b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py @@ -376,11 +376,12 @@ def test_correct_increasing_blob_gas_costs( Test calculation of the `excessBlobGas` and blob gas tx costs at value points where the cost increases to interesting amounts. - - At the first blob gas cost increase (1 to 2) - At total transaction data - cost increase to `> 2^32` - At blob gas wei cost increase to `> 2^32` - At - total transaction data cost increase to `> 2^64` - At blob gas wei cost - increase to `> 2^64` - At blob gas wei cost increase of around current - total Ether supply + - At the first blob gas cost increase (1 to 2) + - At total transaction data cost increase to `> 2^32` + - At blob gas wei cost increase to `> 2^32` + - At total transaction data cost increase to `> 2^64` + - At blob gas wei cost increase to `> 2^64` + - At blob gas wei cost increase of around current total Ether supply """ blockchain_test( pre=pre, @@ -536,9 +537,10 @@ def test_invalid_excess_blob_gas_above_target_change( """ Test rejection of blocks where the `excessBlobGas`. - - decreases more than `TARGET_BLOB_GAS_PER_BLOCK` in a single block with - zero blobs - increases more than `TARGET_BLOB_GAS_PER_BLOCK` in a single - block with max blobs + - decreases more than `TARGET_BLOB_GAS_PER_BLOCK` in a single block + with zero blobs. + - increases more than `TARGET_BLOB_GAS_PER_BLOCK` in a single block + with max blobs. """ if header_excess_blob_gas is None: raise Exception("test case is badly formatted") @@ -820,8 +822,9 @@ def test_invalid_non_multiple_excess_blob_gas( is not a multiple of Spec.GAS_PER_BLOB`. - Parent block contains `TARGET_BLOBS_PER_BLOCK + 1` blobs, but - `excessBlobGas` is off by +/-1 - Parent block contains - `TARGET_BLOBS_PER_BLOCK - 1` blobs, but `excessBlobGas` is off by +/-1 + `excessBlobGas` is off by +/-1 + - Parent block contains `TARGET_BLOBS_PER_BLOCK - 1` blobs, but + `excessBlobGas` is off by +/-1 """ if header_excess_blob_gas is None: raise Exception("test case is badly formatted") diff --git a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py index a2da764ae43..02b2a866d93 100644 --- a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py +++ b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py @@ -346,9 +346,12 @@ def test_invalid_inputs( """ Test invalid precompile calls. - - Out of bounds inputs `z` and `y` - Correct proof, commitment, z and y, - but incorrect lengths - Null inputs - Zero inputs - Correct proof, - commitment, z and y, but incorrect version versioned hash + - Out of bounds inputs `z` and `y` + - Correct proof, commitment, z and y, but incorrect lengths + - Null inputs + - Zero inputs + - Correct proof, commitment, z and y, but incorrect version versioned + hash """ state_test( env=Environment(), diff --git a/tests/cancun/eip5656_mcopy/test_mcopy.py b/tests/cancun/eip5656_mcopy/test_mcopy.py index 83db999fd15..0ad39679604 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy.py @@ -185,11 +185,13 @@ def test_valid_mcopy_operations( tx: Transaction, ): """ - Perform MCOPY operations using different offsets and lengths: - Zero inputs - - Memory rewrites (copy from and to the same location) - Memory overwrites - (copy from and to different locations) - Memory extensions (copy to a - location that is out of bounds) - Memory clear (copy from a location that - is out of bounds). + Perform MCOPY operations using different offsets and lengths. + + - Zero inputs + - Memory rewrites (copy from and to the same location) + - Memory overwrites (copy from and to different locations) + - Memory extensions (copy to a location that is out of bounds) + - Memory clear (copy from a location that is out of bounds). """ state_test( env=Environment(), diff --git a/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py b/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py index 95729a73eb9..a0f40734a13 100644 --- a/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py +++ b/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py @@ -198,9 +198,11 @@ def test_create_selfdestruct_same_tx( Behavior should be the same before and after EIP-6780. - Test using: - Different send-all recipient addresses: single, multiple, - including self - Different initial balances for the self-destructing - contract - Different opcodes: CREATE, CREATE2 + Test using: + - Different send-all recipient addresses: single, multiple, + including self + - Different initial balances for the self-destructing contract + - Different opcodes: CREATE, CREATE2 """ selfdestruct_contract_initcode = Initcode(deploy_code=selfdestruct_code) initcode_copy_from_address = pre.deploy_contract(selfdestruct_contract_initcode) @@ -351,9 +353,11 @@ def test_self_destructing_initcode( Behavior is the same before and after EIP-6780. - Test using: - Different initial balances for the self-destructing contract - - Different opcodes: CREATE, CREATE2 - Different number of calls to the - self-destructing contract in the same tx + Test using: + - Different initial balances for the self-destructing contract + - Different opcodes: CREATE, CREATE2 + - Different number of calls to the self-destructing contract in + the same tx """ initcode_copy_from_address = pre.deploy_contract(selfdestruct_code) # Our entry point is an initcode that in turn creates a self-destructing @@ -682,9 +686,10 @@ def test_selfdestruct_pre_existing( address, similar to the behavior before the EIP, but the account is not deleted. - Test using: - Different send-all recipient addresses: single, multiple, - including self - Different initial balances for the self-destructing - contract + Test using: + - Different send-all recipient addresses: single, multiple, + including self + - Different initial balances for the self-destructing contract """ selfdestruct_contract_address = pre.deploy_contract( selfdestruct_code, balance=selfdestruct_contract_initial_balance diff --git a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py index 2ca49d0779e..ecd400de2ad 100644 --- a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py +++ b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py @@ -95,12 +95,15 @@ def test_clz_opcode_scenarios( """ Test CLZ opcode functionality. - Cases: - Format 0xb000...111: leading zeros followed by ones (2**256 - 1 >> - bits) - Format 0xb010...000: single bit set at position (1 << bits) - - Test coverage: - Leading zeros pattern: 0b000...111 (0 to 256 leading - zeros) - Single bit pattern: 0b010...000 (bit at each possible position) - - Edge cases: CLZ(0) = 256, CLZ(2^256-1) = 0 + Cases: + - Format 0xb000...111: leading zeros followed by ones + (2**256 - 1 >> bits) + - Format 0xb010...000: single bit set at position (1 << bits) + + Test coverage: + - Leading zeros pattern: 0b000...111 (0 to 256 leading zeros) + - Single bit pattern: 0b010...000 (bit at each possible position) + - Edge cases: CLZ(0) = 256, CLZ(2^256-1) = 0 """ sender = pre.fund_eoa() contract_address = pre.deploy_contract( @@ -469,10 +472,8 @@ def test_clz_code_copy_operation(state_test: StateTestFiller, pre: Alloc, bits: address=target_address, dest_offset=0, offset=clz_code_offset, size=1 ) ) - + Op.SSTORE(storage.store_next(mload_value), Op.MLOAD(0)) # Store - # loaded - # CLZ - # byte + # Store loaded CLZ byte + + Op.SSTORE(storage.store_next(mload_value), Op.MLOAD(0)) ), storage={"0x00": "0xdeadbeef"}, ) diff --git a/tests/shanghai/eip3855_push0/test_push0.py b/tests/shanghai/eip3855_push0/test_push0.py index 068ef083cc3..aa3e471f469 100644 --- a/tests/shanghai/eip3855_push0/test_push0.py +++ b/tests/shanghai/eip3855_push0/test_push0.py @@ -91,8 +91,14 @@ def test_push0_contracts( class TestPush0CallContext: """ - Tests the PUSH0 operation during various call contexts including: - CALL - - CALLCODE - DELEGATECALL - STATICCALL. + Test the PUSH0 operation in various contract call contexts. + + Test PUSH0 in the following contract call contexts: + + - CALL, + - CALLCODE, + - DELEGATECALL, + - STATICCALL. """ @pytest.fixture @@ -108,8 +114,9 @@ def push0_contract_caller( self, pre: Alloc, call_opcode: Op, push0_contract_callee: Address ) -> Address: """ - Deploy contract responsible for calling the callee PUSH0 contract - returning its address. + Deploy the contract that calls the callee PUSH0 contract into `pre`. + + This fixture returns its address. """ call_code = ( Op.SSTORE(0, call_opcode(gas=100_000, address=push0_contract_callee)) diff --git a/tests/shanghai/eip3860_initcode/test_initcode.py b/tests/shanghai/eip3860_initcode/test_initcode.py index 218eec6e258..8f31bb2f206 100644 --- a/tests/shanghai/eip3860_initcode/test_initcode.py +++ b/tests/shanghai/eip3860_initcode/test_initcode.py @@ -132,8 +132,7 @@ def test_contract_creating_tx( initcode: Initcode, ): """ - Tests creating a contract using a transaction with an initcode that is - on/over the max allowed limit. + Test creating a contract with initcode that is on/over the allowed limit. """ create_contract_address = compute_create_address( address=sender, @@ -204,14 +203,19 @@ def valid_gas_test_case(initcode: Initcode, gas_test_case: str) -> bool: ) class TestContractCreationGasUsage: """ - Tests the following cases that verify the gas cost behavior of a contract - creating transaction. + Test the gas cost behavior of a contract creating transaction. + + The following scenarios are tested: 1. Test with exact intrinsic gas minus one, contract create fails and tx is - invalid. 2. Test with exact intrinsic gas, contract create fails, but tx is - valid. 3. Test with exact execution gas minus one, contract create fails, - but tx is valid. 4. Test with exact execution gas, contract create - succeeds. + invalid. + + 2. Test with exact intrinsic gas, contract create fails, but tx is valid. + + 3. Test with exact execution gas minus one, contract create fails, but tx + is valid. + + 4. Test with exact execution gas, contract create succeeds. Initcode must be within a valid EIP-3860 length. """ @@ -219,8 +223,10 @@ class TestContractCreationGasUsage: @pytest.fixture def tx_access_list(self) -> List[AccessList]: """ - On EIP-7623, we need to use an access list to raise the intrinsic gas - cost to be above the floor data cost. + Return an access list to raise the intrinsic gas cost. + + Upon EIP-7623 activation, we need to use an access list to raise the + intrinsic gas cost to be above the floor data cost. """ return [AccessList(address=Address(i), storage_keys=[]) for i in range(1, 478)] @@ -228,7 +234,9 @@ def tx_access_list(self) -> List[AccessList]: def exact_intrinsic_gas( self, fork: Fork, initcode: Initcode, tx_access_list: List[AccessList] ) -> int: - """Calculate the intrinsic tx gas cost.""" + """ + Calculate the intrinsic tx gas cost. + """ tx_intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator() assert tx_intrinsic_gas_cost_calculator( calldata=initcode, @@ -248,12 +256,16 @@ def exact_intrinsic_gas( @pytest.fixture def exact_execution_gas(self, exact_intrinsic_gas: int, initcode: Initcode) -> int: - """Calculate total execution gas cost.""" + """ + Calculate total execution gas cost. + """ return exact_intrinsic_gas + initcode.deployment_gas + initcode.execution_gas @pytest.fixture def tx_error(self, gas_test_case: str) -> TransactionException | None: """ + Return the transaction exception, or None, as expected. + Check that the transaction is invalid if too little intrinsic gas is specified, otherwise the tx is valid and succeeds. """ @@ -273,7 +285,9 @@ def tx( exact_execution_gas: int, ) -> Transaction: """ - Implement the gas_test_case by setting the gas_limit of the tx + Return a tx with `gas_limit` corresponding to the `gas_test_case`. + + Implement the gas_test_case by setting the `gas_limit` of the tx appropriately and test whether the tx succeeds or fails with appropriate error. """ @@ -311,8 +325,7 @@ def post( exact_execution_gas: int, ) -> Alloc: """ - Test that contract creation fails unless enough execution gas is - provided. + Test contract creation fails unless enough execution gas is provided. """ create_contract_address = compute_create_address( address=sender, @@ -335,8 +348,7 @@ def test_gas_usage( tx: Transaction, ): """ - Test transaction and contract creation behavior for different gas - limits. + Test transaction and contract creation using different gas limits. """ state_test( env=env, @@ -365,20 +377,23 @@ def test_gas_usage( @pytest.mark.parametrize("opcode", [Op.CREATE, Op.CREATE2], ids=get_create_id) class TestCreateInitcode: """ - Test contract creation via the CREATE/CREATE2 opcodes that have an initcode - that is on/over the max allowed limit. + Test contract creation with valid and invalid initcode lengths. + + Test contract creation via CREATE/CREATE2, parametrized by initcode that is + on/over the max allowed limit. """ @pytest.fixture def create2_salt(self) -> int: - """Salt value used for CREATE2 contract creation.""" + """ + Salt value used for CREATE2 contract creation. + """ return 0xDEADBEEF @pytest.fixture def creator_code(self, opcode: Op, create2_salt: int) -> Bytecode: """ - Generate code for the creator contract which performs the - CREATE/CREATE2 operation. + Generate code for the creator contract which calls CREATE/CREATE2. """ return ( Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE) @@ -502,8 +517,10 @@ def test_create_opcode_initcode( create2_word_cost: int, ): """ - Test contract creation via the CREATE/CREATE2 opcodes that have an - initcode that is on/over the max allowed limit. + Test contract creation with valid and invalid initcode lengths. + + Test contract creation via CREATE/CREATE2, parametrized by initcode + that is on/over the max allowed limit. """ if len(initcode) > Spec.MAX_INITCODE_SIZE: # Call returns 0 as out of gas s[0]==1 diff --git a/tests/shanghai/eip4895_withdrawals/test_withdrawals.py b/tests/shanghai/eip4895_withdrawals/test_withdrawals.py index e47d85d3e57..df2124df950 100644 --- a/tests/shanghai/eip4895_withdrawals/test_withdrawals.py +++ b/tests/shanghai/eip4895_withdrawals/test_withdrawals.py @@ -187,8 +187,7 @@ def test_use_value_in_contract( def test_balance_within_block(blockchain_test: BlockchainTestFiller, pre: Alloc): """ - Test Withdrawal balance increase within the same block, inside contract - call. + Test withdrawal balance increase within the same block in a contract call. """ save_balance_on_block_number = Op.SSTORE( Op.NUMBER, @@ -302,8 +301,7 @@ def test_multiple_withdrawals_same_address( blocks: List[Block], ): """ - Test Withdrawals can be done to the same address multiple times in the - same block. + Test withdrawals to the same address multiple times in the same block. """ # Expected post is the same for both test cases. post = {} @@ -321,8 +319,7 @@ def test_many_withdrawals( pre: Alloc, ): """ - Test Withdrawals with a count of N withdrawals in a single block where N is - a high number not expected to be seen in mainnet. + Test an unexpected high number of withdrawals in a single block. """ n = 400 withdrawals = [] @@ -359,9 +356,10 @@ def test_self_destructing_account( fork: Fork, ): """ - Test withdrawals can be done to self-destructed accounts. Account `0x100` - self-destructs and sends all its balance to `0x200`. Then, a withdrawal is - received at `0x100` with 99 wei. + Test withdrawals can be done to self-destructed accounts. + + Account `0x100` self-destructs and sends all its balance to `0x200`. Then, + a withdrawal is received at `0x100` with 99 wei. """ self_destruct_code = Op.SELFDESTRUCT(Op.CALLDATALOAD(0)) sender = pre.fund_eoa() @@ -417,7 +415,7 @@ def test_newly_created_contract( include_value_in_tx: bool, request, ): - """Test Withdrawing to a newly created contract.""" + """Test withdrawing to a newly created contract.""" sender = pre.fund_eoa() initcode = Op.RETURN(0, 1) tx = Transaction( @@ -461,7 +459,7 @@ def test_no_evm_execution( blockchain_test: BlockchainTestFiller, pre: Alloc, ): - """Test Withdrawals don't trigger EVM execution.""" + """Test withdrawals don't trigger EVM execution.""" sender = pre.fund_eoa() contracts = [pre.deploy_contract(Op.SSTORE(Op.NUMBER, 1)) for _ in range(4)] blocks = [ @@ -552,14 +550,19 @@ def test_zero_amount( test_case: ZeroAmountTestCases, ): """ - Test withdrawals with zero amount for the following cases, all withdrawals - are included in one block. + Test withdrawal scenarios with a zero amount in a single block. + + All the withdrawals in the following scenarios are included in one block. 1. Two withdrawals of zero amount to two different addresses; one to an - untouched account, one to an account with a balance. 2. As 1., but with an - additional withdrawal with positive value. 3. As 2., but with an additional - withdrawal containing the maximum value possible. 4. As 3., but with order - of withdrawals in the block reversed. + untouched account, one to an account with a balance. + + 2. As 1., but with an additional withdrawal with positive value. + + 3. As 2., but with an additional withdrawal containing the maximum value + possible. + + 4. As 3., but with order of withdrawals in the block reversed. """ empty_accounts = [pre.fund_eoa(0) for _ in range(3)] zero_balance_contract = pre.deploy_contract(Op.STOP) @@ -653,8 +656,9 @@ def test_large_amount( pre: Alloc, ): """ - Test Withdrawals that have a large gwei amount, so that (gwei * 1e9) could - overflow uint64 but not uint256. + Test withdrawals that have a large gwei amount. + + Test such that that (gwei * 1e9) could overflow uint64 but not uint256. """ withdrawals: List[Withdrawal] = [] amounts: List[int] = [ From 5d885a0a585ff5757fba2b3fa6ac3cb8f66fdb83 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Wed, 24 Sep 2025 12:37:18 +0200 Subject: [PATCH 08/16] chore: fix broken unordered-lists/args --- .../test_max_block_rlp_size.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py b/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py index 50bccb4fd85..8fb3550b717 100644 --- a/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py +++ b/tests/osaka/eip7934_block_rlp_limit/test_max_block_rlp_size.py @@ -125,12 +125,16 @@ def exact_size_transactions( The calculation uses caching to avoid recalculating the same block rlp for each fork. Calculate the block and fill with real sender for testing. - Args: sender: The sender account block_size_limit: The target block RLP - size limit fork: The fork to generate transactions for pre: Required if - emit_logs is True, used to deploy the log contract gas_limit: The gas limit - for the block emit_logs: If True, transactions will call a contract that - emits logs specific_transaction_to_include: If provided, this transaction - will be included + Args: + sender: The sender account + block_size_limit: The target block RLP size limit + fork: The fork to generate transactions for + pre: Required if emit_logs is True, used to deploy the log contract + gas_limit: The gas limit for the block + emit_logs: If True, transactions will call a contract that emits logs + specific_transaction_to_include: If provided, this transaction will + be included + """ log_contract = None if emit_logs: @@ -402,8 +406,9 @@ def test_block_at_rlp_size_limit_boundary( """ Test the block rlp size limit. - - At the limit - 1 byte, the block is valid - At the limit, the block is - valid - At the limit + 1 byte, the block is invalid + - At the limit - 1 byte, the block is valid + - At the limit, the block is valid + - At the limit + 1 byte, the block is invalid """ transactions, gas_used = exact_size_transactions( sender, From 789d1813540b8e4f3783ce8bb3afdaa9486eead9 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Wed, 24 Sep 2025 12:43:05 +0200 Subject: [PATCH 09/16] chore: improve docstrings, also for D205 --- src/cli/eest/commands/clean.py | 7 ++-- src/cli/eest/make/commands/__init__.py | 7 ++-- src/cli/eest/quotes.py | 3 +- src/ethereum_clis/clis/ethereumjs.py | 5 +-- src/ethereum_test_specs/base_static.py | 4 ++- src/ethereum_test_types/trie.py | 11 ++++--- tests/shanghai/eip3860_initcode/__init__.py | 3 +- tests/shanghai/eip3860_initcode/spec.py | 4 ++- .../eip3860_initcode/test_with_eof.py | 7 ++-- .../eip7620_eof_create/__init__.py | 33 ++++++++++--------- .../test_txcreate_failures.py | 5 +-- .../test_txcreate_validates.py | 15 +++++---- 12 files changed, 58 insertions(+), 46 deletions(-) diff --git a/src/cli/eest/commands/clean.py b/src/cli/eest/commands/clean.py index 946153e3e75..58f7b93dacc 100644 --- a/src/cli/eest/commands/clean.py +++ b/src/cli/eest/commands/clean.py @@ -18,9 +18,10 @@ @click.option("-v", "--verbose", is_flag=True, help="Show verbose output.") def clean(all_files: bool, dry_run: bool, verbose: bool): """ - Remove all generated files and directories from the repository. If `--all` - is specified, the virtual environment and .tox directory will also be - removed. + Remove all generated files and directories from the repository. + + If `--all` is specified, the virtual environment and .tox directory will + also be removed. Args: all_files (bool): Remove the virtual environment and .tox directory diff --git a/src/cli/eest/make/commands/__init__.py b/src/cli/eest/make/commands/__init__.py index e3a8ae4addd..64234b30009 100644 --- a/src/cli/eest/make/commands/__init__.py +++ b/src/cli/eest/make/commands/__init__.py @@ -1,7 +1,8 @@ """ -Holds subcommands for the make command. New subcommands must be created as -modules and exported from this package, then registered under the make command -in `cli.py`. +Holds subcommands for the make command. + +New subcommands must be created as modules and exported from this package, +then registered under the make command in `cli.py`. """ from .env import create_default_env diff --git a/src/cli/eest/quotes.py b/src/cli/eest/quotes.py index f026d062f2b..e097a31b9f8 100644 --- a/src/cli/eest/quotes.py +++ b/src/cli/eest/quotes.py @@ -52,7 +52,6 @@ def box_quote(quote): def get_quote(): """ - Return random inspirational quote related to system design formatted in a - box. + Return random inspirational quote formatted in a box. """ return box_quote(random.choice(make_something_great)) diff --git a/src/ethereum_clis/clis/ethereumjs.py b/src/ethereum_clis/clis/ethereumjs.py index 5c37822074c..59214e00faf 100644 --- a/src/ethereum_clis/clis/ethereumjs.py +++ b/src/ethereum_clis/clis/ethereumjs.py @@ -38,8 +38,9 @@ def __init__( def is_fork_supported(self, fork: Fork) -> bool: """ - Return True if the fork is supported by the tool. Currently, - EthereumJS-t8n provides no way to determine supported forks. + Return True if the fork is supported by the tool. + + Currently, EthereumJS-t8n provides no way to determine supported forks. """ return True diff --git a/src/ethereum_test_specs/base_static.py b/src/ethereum_test_specs/base_static.py index 9f64dc1c8ff..21690679cd5 100644 --- a/src/ethereum_test_specs/base_static.py +++ b/src/ethereum_test_specs/base_static.py @@ -1,4 +1,6 @@ -"""Base class to parse test cases written in static formats.""" +""" +Base class to parse test cases written in static formats. +""" import re from abc import abstractmethod diff --git a/src/ethereum_test_types/trie.py b/src/ethereum_test_types/trie.py index 261424d102c..4d0c7ba3126 100644 --- a/src/ethereum_test_types/trie.py +++ b/src/ethereum_test_types/trie.py @@ -1,4 +1,6 @@ -"""The state trie is the structure responsible for storing.""" +""" +The state trie is the structure responsible for storing. +""" import copy from dataclasses import dataclass, field @@ -131,9 +133,10 @@ class BranchNode: def encode_internal_node(node: Optional[InternalNode]) -> Extended: """ - Encode a Merkle Trie node into its RLP form. The RLP will then be - serialized into a `Bytes` and hashed unless it is less that 32 bytes when - serialized. + Encode a Merkle Trie node into its RLP form. + + The RLP will then be serialized into a `Bytes` and hashed unless it is less + that 32 bytes when serialized. This function also accepts `None`, representing the absence of a node, which is encoded to `b""`. diff --git a/tests/shanghai/eip3860_initcode/__init__.py b/tests/shanghai/eip3860_initcode/__init__.py index a6c7d4a01f2..0d50d930d9e 100644 --- a/tests/shanghai/eip3860_initcode/__init__.py +++ b/tests/shanghai/eip3860_initcode/__init__.py @@ -1,4 +1,3 @@ """ -Test [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860) - Tests for [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860). +Test [EIP-3860: Limit and meter initcode](https://eips.ethereum.org/EIPS/eip-3860). """ diff --git a/tests/shanghai/eip3860_initcode/spec.py b/tests/shanghai/eip3860_initcode/spec.py index 65dad3fcea3..67ccec1e539 100644 --- a/tests/shanghai/eip3860_initcode/spec.py +++ b/tests/shanghai/eip3860_initcode/spec.py @@ -17,7 +17,9 @@ class ReferenceSpec: @dataclass(frozen=True) class Spec: """ - Parameters from the EIP-3860 specifications as defined at + Define parameters from the EIP-3860 specifications. + + These are the parameters defined at https://eips.ethereum.org/EIPS/eip-3860#parameters. """ diff --git a/tests/shanghai/eip3860_initcode/test_with_eof.py b/tests/shanghai/eip3860_initcode/test_with_eof.py index 2dab4405b7f..f3b7318518a 100644 --- a/tests/shanghai/eip3860_initcode/test_with_eof.py +++ b/tests/shanghai/eip3860_initcode/test_with_eof.py @@ -1,6 +1,5 @@ """ -Tests interaction between edge case size CREATE / CREATE2 and EOF, including -EIP-3860 limits. +Test CREATE / CREATE2 and EOF interaction for EIP-3860 initcode limits. """ import itertools @@ -57,7 +56,9 @@ def test_legacy_create_edge_code_size( init_code: Bytecode, ): """ - Verifies that legacy initcode/deploycode having 0 or max size continues to + Test legacy initcode and deployed code edge cases with EOF enabled. + + Verify that legacy initcode/deploycode having 0 or max size continues to work in the fork where EOF is enabled. Handling of EOF magic prefix and version interferes with the handling of legacy creation, so a specific test was proposed to test behavior doesn't change. diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py index 2ef0a8613de..38bef9e6c6b 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py @@ -1,22 +1,23 @@ """ Test cases for EOF Contract Creation for EIP-7620. - EIP-7620 replaces `CREATE` and `CREATE2` with `EOFCREATE` for deploying - contracts in the EOF format. Full specification: - [EIP-7620: EOF Contract Creation](https://eips.ethereum.org/EIPS/eip-7620). - Opcodes introduced: `EOFCREATE` (`0xEC`), `RETURNCODE` (`0xEE`). - EOFCREATE, RETURNCODE, and container tests. +EIP-7620 replaces `CREATE` and `CREATE2` with `EOFCREATE` for deploying +contracts in the EOF format. Full specification: +[EIP-7620: EOF Contract Creation](https://eips.ethereum.org/EIPS/eip-7620). +Opcodes introduced: `EOFCREATE` (`0xEC`), `RETURNCODE` (`0xEE`). - evmone tests not ported: +EOFCREATE, RETURNCODE, and container tests. - - create_tx_with_eof_initcode: This calls it invalid, it is now the way to - add EOF contacts to state - - eofcreate_extcall_returncode: Per the new initcode - mode tests you cannot have RETURNCODE in a deployed contract - - eofcreate_dataloadn_referring_to_auxdata: covered by - tests.unscheduled.eip7480_data_section.test_data_opcodes. - test_data_section_succeed - - eofcreate_initcontainer_return: RETURN is banned in initcode containers - - eofcreate_initcontainer_stop: STOP is banned in initcode containers - All - TXCREATE tests. +evmone tests not ported: + +- create_tx_with_eof_initcode: This calls it invalid, it is now the way to +add EOF contacts to state +- eofcreate_extcall_returncode: Per the new initcode +mode tests you cannot have RETURNCODE in a deployed contract +- eofcreate_dataloadn_referring_to_auxdata: covered by +tests.unscheduled.eip7480_data_section.test_data_opcodes. +test_data_section_succeed +- eofcreate_initcontainer_return: RETURN is banned in initcode containers +- eofcreate_initcontainer_stop: STOP is banned in initcode containers - All +TXCREATE tests. """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py index 36e21288b99..ec480e18ff2 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py @@ -206,8 +206,9 @@ def test_txcreate_deploy_sizes( target_deploy_size: int, ): """ - Verifies a mix of runtime contract sizes mixing success and multiple size - failure modes. + Verify a mix of runtime contract sizes. + + This mixes success and multiple size failure modes. """ env = Environment() diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_validates.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_validates.py index 05a57bd32ff..1fca0845e6c 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_validates.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_validates.py @@ -88,9 +88,10 @@ def __str__(self) -> str: class Factory(Enum): """ - Kinds of systems leading up to a call to TXCREATE. DIRECT just puts the - TXCREATE in the code it generates, while *CALL ones call into another - account which does the TXCREATE. + Kinds of systems leading up to a call to TXCREATE. + + DIRECT just puts the TXCREATE in the code it generates, while *CALL ones + call into another account which does the TXCREATE. """ DIRECT = auto() @@ -108,8 +109,9 @@ def creation_snippet( input_size: int, ) -> Tuple[Bytecode, Address | None]: """ - Return snippet to cause TXCREATE to be called along with an address - which will end up in the `compute_eofcreate_address`, or None if that + Return snippet to cause TXCREATE to be called along with an address. + + This will end up in the `compute_eofcreate_address` or None if that would be the snippet itself. """ if evm_code_type not in [EVMCodeType.LEGACY, EVMCodeType.EOF_V1]: @@ -177,8 +179,7 @@ def test_txcreate_validates( access_list_a: bool, ): """ - Verifies proper validation of initcode on TXCREATE in various circumstances - of the opcode. + Verifies proper validation of initcode on TXCREATE in various scenarios. """ env = Environment() snippet_a, factory_address_a = factory_a.creation_snippet( From 9a36e09b8d1b93c8be00aa8ae75c682753288b04 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Wed, 24 Sep 2025 12:57:50 +0200 Subject: [PATCH 10/16] chore: improve docstrings, also for D205 --- src/ethereum_test_vm/opcodes.py | 2 +- .../test_tstorage_execution_contexts.py | 5 +- tests/cancun/eip4844_blobs/test_blob_txs.py | 74 +++++++++++-------- .../eip4844_blobs/test_excess_blob_gas.py | 4 +- .../test_point_evaluation_precompile.py | 12 +-- .../test_count_leading_zeros.py | 13 +++- 6 files changed, 66 insertions(+), 44 deletions(-) diff --git a/src/ethereum_test_vm/opcodes.py b/src/ethereum_test_vm/opcodes.py index aceeb6fd6ba..85b79c65e5f 100644 --- a/src/ethereum_test_vm/opcodes.py +++ b/src/ethereum_test_vm/opcodes.py @@ -1100,7 +1100,7 @@ class Opcodes(Opcode, Enum): Outputs ---- - y: the indicated byte at the least significant position. - If the byte offset is out of range, the result is 0 + If the byte offset is out of range, the result is 0 Fork ---- diff --git a/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py index ce59935b639..90dc128fb02 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py @@ -339,6 +339,9 @@ def test_subcall( """ Test transient storage with a subcall using the following opcodes. - - `CALL` - `CALLCODE` - `DELEGATECALL` - `STATICCALL` + - `CALL` + - `CALLCODE` + - `DELEGATECALL` + - `STATICCALL` """ state_test(env=env, pre=pre, post=post, tx=tx) diff --git a/tests/cancun/eip4844_blobs/test_blob_txs.py b/tests/cancun/eip4844_blobs/test_blob_txs.py index ce7be8ffa97..5b23da55bca 100644 --- a/tests/cancun/eip4844_blobs/test_blob_txs.py +++ b/tests/cancun/eip4844_blobs/test_blob_txs.py @@ -639,10 +639,12 @@ def test_insufficient_balance_blob_tx( Reject blocks where user cannot afford the blob gas specified (but max_fee_per_gas would be enough for current block). - - Transactions with max fee equal or higher than current block base fee - - Transactions with and without priority fee - Transactions with and without - value - Transactions with and without calldata - Transactions with max fee - per blob gas lower or higher than the priority fee + - Transactions with max fee equal or higher than current block base fee + - Transactions with and without priority fee + - Transactions with and without value + - Transactions with and without calldata + - Transactions with max fee per blob gas lower or higher than the priority + fee """ assert len(txs) == 1 state_test( @@ -686,10 +688,12 @@ def test_sufficient_balance_blob_tx( Check that transaction is accepted when user can exactly afford the blob gas specified (and max_fee_per_gas would be enough for current block). - - Transactions with max fee equal or higher than current block base fee - - Transactions with and without priority fee - Transactions with and without - value - Transactions with and without calldata - Transactions with max fee - per blob gas lower or higher than the priority fee + - Transactions with max fee equal or higher than current block base fee + - Transactions with and without priority fee + - Transactions with and without value + - Transactions with and without calldata + - Transactions with max fee per blob gas lower or higher than the priority + fee """ assert len(txs) == 1 state_test( @@ -737,10 +741,12 @@ def test_sufficient_balance_blob_tx_pre_fund_tx( gas specified (and max_fee_per_gas would be enough for current block) because a funding transaction is prepended in the same block. - - Transactions with max fee equal or higher than current block base fee - - Transactions with and without priority fee - Transactions with and without - value - Transactions with and without calldata - Transactions with max fee - per blob gas lower or higher than the priority fee + - Transactions with max fee equal or higher than current block base fee + - Transactions with and without priority fee + - Transactions with and without value + - Transactions with and without calldata + - Transactions with max fee per blob gas lower or higher than the priority + fee """ pre_funding_sender = pre.fund_eoa(amount=(21_000 * 100) + total_account_minimum_balance) txs = [ @@ -815,11 +821,13 @@ def test_blob_gas_subtraction_tx( Check that the blob gas fee for a transaction is subtracted from the sender balance before the transaction is executed. - - Transactions with max fee equal or higher than current block base fee - - Transactions with and without value - Transactions with and without - calldata - Transactions with max fee per blob gas lower or higher than the - priority fee - Transactions where an externally owned account sends funds - to the sender mid execution + - Transactions with max fee equal or higher than current block base fee + - Transactions with and without value + - Transactions with and without calldata + - Transactions with max fee per blob gas lower or higher than the priority + fee + - Transactions where an externally owned account sends funds to the sender + mid execution """ assert len(txs) == 1 post = { @@ -859,7 +867,7 @@ def test_insufficient_balance_blob_tx_combinations( invalid. - The amount of blobs is correct but the user cannot afford the transaction - total cost + total cost """ blockchain_test( pre=pre, @@ -910,8 +918,8 @@ def test_invalid_tx_blob_count( """ Reject blocks that include blob transactions with invalid blob counts. - - `blob count == 0` in type 3 transaction - `blob count > - MAX_BLOBS_PER_BLOCK` in type 3 transaction + - `blob count == 0` in type 3 transaction + - `blob count > MAX_BLOBS_PER_BLOCK` in type 3 transaction """ assert len(txs) == 1 state_test( @@ -955,9 +963,9 @@ def test_invalid_blob_hash_versioning_single_tx( """ Reject blob transactions with invalid blob hash version. - - Transaction with single blob with invalid version - Transaction with - multiple blobs all with invalid version - Transaction with multiple blobs - either with invalid version + - Transaction with single blob with invalid version + - Transaction with multiple blobs all with invalid version + - Transaction with multiple blobs either with invalid version """ assert len(txs) == 1 state_test( @@ -1013,10 +1021,10 @@ def test_invalid_blob_hash_versioning_multiple_txs( Reject blocks that include blob transactions with invalid blob hash version. - - Multiple blob transactions with single blob all with invalid version - - Multiple blob transactions with multiple blobs all with invalid version - - Multiple blob transactions with multiple blobs only one with invalid - version + - Multiple blob transactions with single blob all with invalid version + - Multiple blob transactions with multiple blobs all with invalid version + - Multiple blob transactions with multiple blobs only one with invalid + version """ blockchain_test( pre=pre, @@ -1156,7 +1164,8 @@ def test_blob_tx_attribute_opcodes( Test opcodes that read transaction attributes work properly for blob type transactions. - - ORIGIN - CALLER + - ORIGIN + - CALLER """ code, storage = opcode destination_account = pre.deploy_contract(code=code) @@ -1276,7 +1285,9 @@ def test_blob_tx_attribute_calldata_opcodes( Test calldata related opcodes to verify their behavior is not affected by blobs. - - CALLDATALOAD - CALLDATASIZE - CALLDATACOPY + - CALLDATALOAD + - CALLDATASIZE + - CALLDATACOPY """ code, storage = opcode destination_account = pre.deploy_contract(code=code) @@ -1336,8 +1347,9 @@ def test_blob_tx_attribute_gasprice_opcode( Test GASPRICE opcode to sanity check that the blob gas fee does not affect its calculation. - - No priority fee - Priority fee below data fee - Priority fee above data - fee + - No priority fee + - Priority fee below data fee + - Priority fee above data fee """ code, storage = opcode destination_account = pre.deploy_contract(code=code) diff --git a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py index f08415f7c0e..298460ce7db 100644 --- a/tests/cancun/eip4844_blobs/test_excess_blob_gas.py +++ b/tests/cancun/eip4844_blobs/test_excess_blob_gas.py @@ -492,8 +492,8 @@ def test_invalid_blob_gas_used_in_header( """ Test rejection of blocks where the `blobGasUsed` in the header is invalid. - - `blobGasUsed` is not equal to the number of data blobs in the block - - `blobGasUsed` is the max uint64 value + - `blobGasUsed` is not equal to the number of data blobs in the block + - `blobGasUsed` is the max uint64 value """ if header_blob_gas_used is None: raise Exception("test case is badly formatted") diff --git a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py index 02b2a866d93..24562a11e2e 100644 --- a/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py +++ b/tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py @@ -293,8 +293,8 @@ def test_valid_inputs( Test valid sanity precompile calls that are expected to succeed. - `kzg_commitment` and `kzg_proof` are set to values such that `p(z)==0` - for all values of `z`, hence `y` is tested to be zero, and call to be - successful. + for all values of `z`, hence `y` is tested to be zero, and call to be + successful. """ state_test( env=Environment(), @@ -496,8 +496,9 @@ def test_call_opcode_types( Test calling the Point Evaluation Precompile with different call types, gas and parameter configuration. - - Using CALL, DELEGATECALL, CALLCODE and STATICCALL. - Using correct and - incorrect proofs - Using barely insufficient gas + - Using CALL, DELEGATECALL, CALLCODE and STATICCALL. + - Using correct and incorrect proofs + - Using barely insufficient gas """ state_test( env=Environment(), @@ -538,7 +539,8 @@ def test_tx_entry_point( point, and measure the gas consumption. - Using `gas_limit` with exact necessary gas, insufficient gas and extra - gas. - Using correct and incorrect proofs + gas. + - Using correct and incorrect proofs """ sender = pre.fund_eoa() diff --git a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py index ecd400de2ad..31ad6c7dacd 100644 --- a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py +++ b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py @@ -504,10 +504,15 @@ def test_clz_with_memory_operation(state_test: StateTestFiller, pre: Alloc, bits expected_value = 255 - bits - # Target code pattern: PUSH32 (1 << bits) PUSH0 MSTORE - # This sequence stores a 32-byte value in memory. Later, we copy the - # immediate value from the PUSH32 instruction into memory using CODECOPY or - # EXTCODECOPY, and then load it with MLOAD for the CLZ test. + # Target code pattern: + # PUSH32 (1 << bits) + # PUSH0 + # MSTORE + # + # This sequence stores a 32-byte value in memory. + # Later, we copy the immediate value from the PUSH32 instruction into + # memory using CODECOPY or EXTCODECOPY, and then load it with MLOAD for + # the CLZ test. target_code = Op.PUSH32(1 << bits) offset = 1 From 20dbc37477f9cbd5e76da9b06107366b09c0098a Mon Sep 17 00:00:00 2001 From: danceratopz Date: Wed, 24 Sep 2025 14:13:25 +0200 Subject: [PATCH 11/16] chore: fix long or poorly formatted comments --- .../tests/test_reference_spec.py | 3 ++- .../eth_config/tests/test_execute_eth_config.py | 2 +- tests/benchmark/test_worst_compute.py | 5 ++--- tests/cancun/eip4844_blobs/spec.py | 8 +++----- tests/cancun/eip4844_blobs/test_blob_txs.py | 14 ++++++-------- tests/istanbul/eip152_blake2/spec.py | 6 ++++-- tests/osaka/eip7951_p256verify_precompiles/spec.py | 3 ++- .../prague/eip2537_bls_12_381_precompiles/spec.py | 3 ++- .../test_bls12_g1msm.py | 5 ++--- .../test_bls12_g2msm.py | 5 ++--- .../eip7002_el_triggerable_withdrawals/conftest.py | 4 +++- .../eip7620_eof_create/test_eofcreate.py | 9 ++++----- .../eip7873_tx_create/test_txcreate.py | 9 ++++----- 13 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/ethereum_test_base_types/tests/test_reference_spec.py b/src/ethereum_test_base_types/tests/test_reference_spec.py index bd94814d07d..dbb15d89ccf 100644 --- a/src/ethereum_test_base_types/tests/test_reference_spec.py +++ b/src/ethereum_test_base_types/tests/test_reference_spec.py @@ -8,7 +8,8 @@ from ..reference_spec.git_reference_spec import GitReferenceSpec from ..reference_spec.reference_spec import NoLatestKnownVersionError -# the content field from https://api.github.com/repos/ethereum/EIPs/contents/EIPS/eip-100.md +# the content field from +# https://api.github.com/repos/ethereum/EIPs/contents/EIPS/eip-100.md # as of 2023-08-29 response_content = "LS0tCmVpcDogMTAwCnRpdGxlOiBDaGFuZ2UgZGlmZmljdWx0eSBhZGp1c3Rt\ ZW50IHRvIHRhcmdldCBtZWFuIGJsb2NrIHRpbWUgaW5jbHVkaW5nIHVuY2xl\ diff --git a/src/pytest_plugins/execute/eth_config/tests/test_execute_eth_config.py b/src/pytest_plugins/execute/eth_config/tests/test_execute_eth_config.py index ec9c7bff0c4..7a7bd7df0cf 100644 --- a/src/pytest_plugins/execute/eth_config/tests/test_execute_eth_config.py +++ b/src/pytest_plugins/execute/eth_config/tests/test_execute_eth_config.py @@ -414,7 +414,7 @@ target: 15 max: 20 baseFeeUpdateFraction: 5007716 -""" +""" # W505 @pytest.fixture(scope="session") diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index a07e0332552..95610931d0c 100644 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -456,9 +456,8 @@ def test_worst_precompile_only_data_input( iteration_gas_cost = ( parameters_gas + +static_cost # Precompile static cost - + math.ceil(input_length / 32) * per_word_dynamic_cost # Precompile - # dynamic - # cost + + math.ceil(input_length / 32) * per_word_dynamic_cost + # Precompile dynamic cost + gsc.G_BASE # POP ) # From the available gas, we subtract the mem expansion costs diff --git a/tests/cancun/eip4844_blobs/spec.py b/tests/cancun/eip4844_blobs/spec.py index 309ac058e03..a531fb81ac0 100644 --- a/tests/cancun/eip4844_blobs/spec.py +++ b/tests/cancun/eip4844_blobs/spec.py @@ -138,11 +138,9 @@ def get_blob_combinations( for seq in itertools.combinations_with_replacement( range(1, min(blob_count + 1, max_blobs_per_tx) + 1), i ) # We iterate through all possible combinations - if sum(seq) == blob_count # And we only keep the ones that match the expected - # blob count - and all(tx_blobs <= max_blobs_per_tx for tx_blobs in seq) # Validate - # each - # tx + # And we only keep the ones that match the expected blob count + if sum(seq) == blob_count and all(tx_blobs <= max_blobs_per_tx for tx_blobs in seq) + # Validate each tx ] # We also add the reversed version of each combination, only if it's diff --git a/tests/cancun/eip4844_blobs/test_blob_txs.py b/tests/cancun/eip4844_blobs/test_blob_txs.py index 5b23da55bca..f4710d8f7a9 100644 --- a/tests/cancun/eip4844_blobs/test_blob_txs.py +++ b/tests/cancun/eip4844_blobs/test_blob_txs.py @@ -1317,14 +1317,12 @@ def test_blob_tx_attribute_calldata_opcodes( ) -@pytest.mark.parametrize("tx_max_priority_fee_per_gas", [0, 2]) # always below -# data fee -@pytest.mark.parametrize("tx_max_fee_per_blob_gas_delta", [0, 1]) # normal and -# above -# priority -# fee -@pytest.mark.parametrize("tx_max_fee_per_gas", [100]) # always above priority -# fee (FOR CANCUN) +# always below data fee: +@pytest.mark.parametrize("tx_max_priority_fee_per_gas", [0, 2]) +# normal and above priority fee: +@pytest.mark.parametrize("tx_max_fee_per_blob_gas_delta", [0, 1]) +# always above priority fee (FOR CANCUN) +@pytest.mark.parametrize("tx_max_fee_per_gas", [100]) @pytest.mark.parametrize("opcode", [Op.GASPRICE], indirect=True) @pytest.mark.parametrize("tx_gas", [500_000]) @pytest.mark.valid_from("Cancun") diff --git a/tests/istanbul/eip152_blake2/spec.py b/tests/istanbul/eip152_blake2/spec.py index a338ef14c54..021c94a28d0 100644 --- a/tests/istanbul/eip152_blake2/spec.py +++ b/tests/istanbul/eip152_blake2/spec.py @@ -35,7 +35,8 @@ class Spec: BLAKE2_PRECOMPILE_T_1_LENGTH = 8 BLAKE2_PRECOMPILE_F_LENGTH = 1 - # Constants for BLAKE2b and BLAKE2s spec defined at https://datatracker.ietf.org/doc/html/rfc7693#section-3.2 + # Constants for BLAKE2b and BLAKE2s spec defined at + # https://datatracker.ietf.org/doc/html/rfc7693#section-3.2 BLAKE2B_PRECOMPILE_ROUNDS = 12 BLAKE2B_PRECOMPILE_H_LENGTH = 64 @@ -47,7 +48,8 @@ class SpecTestVectors: """Defines common test parameters for the BLAKE2b precompile.""" # The following constants are used to define common test parameters - # Origin of vectors defined at https://datatracker.ietf.org/doc/html/rfc7693.html#appendix-A + # Origin of vectors defined at + # https://datatracker.ietf.org/doc/html/rfc7693.html#appendix-A BLAKE2_STATE_VECTOR = ( "48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1" "361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f" diff --git a/tests/osaka/eip7951_p256verify_precompiles/spec.py b/tests/osaka/eip7951_p256verify_precompiles/spec.py index 84532af2e82..eacb89633bc 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/spec.py +++ b/tests/osaka/eip7951_p256verify_precompiles/spec.py @@ -104,7 +104,8 @@ class Spec: INVALID_RETURN_VALUE = b"" DELEGATION_DESIGNATION = Bytes("ef0100") - # Test constants (from https://github.com/C2SP/wycheproof/blob/4a6c2bf5dc4c0b67c770233ad33961ee653996a0/testvectors/ecdsa_secp256r1_sha256_test.json#L35) + # Test constants, from: + # https://github.com/C2SP/wycheproof/blob/4a6c2bf5dc4c0b67c770233ad33961ee653996a0/testvectors/ecdsa_secp256r1_sha256_test.json#L35 H0 = H(0xBB5A52F42F9C9261ED4361F59422A1E30036E7C32B270C8807A419FECA605023) R0 = R(0x2BA3A8BE6B94D5EC80A6D9D1190A436EFFE50D85A1EEE859B8CC6AF9BD5C2E18) S0 = S(0x4CD60B855D442F5B3C7B11EB6C4E0AE7525FE710FAB9AA7C77A67F79E6FADD76) diff --git a/tests/prague/eip2537_bls_12_381_precompiles/spec.py b/tests/prague/eip2537_bls_12_381_precompiles/spec.py index 15ce33d47c5..808bcf11c8c 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/spec.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/spec.py @@ -161,7 +161,8 @@ class Spec: ] # fmt: on - # Test constants (from https://github.com/ethereum/bls12-381-tests/tree/eip-2537) + # Test constants from + # https://github.com/ethereum/bls12-381-tests/tree/eip-2537 P1 = PointG1( # random point in G1 0x112B98340EEE2777CC3C14163DEA3EC97977AC3DC5C70DA32E6E87578F44912E902CCEF9EFE28D4A78B8999DFBCA9426, 0x186B28D92356C4DFEC4B5201AD099DBDEDE3781F8998DDF929B4CD7756192185CA7B8F4EF7088F813270AC3D48868A21, diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py index 560a39009bb..8d5a4e89c33 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py @@ -176,9 +176,8 @@ def test_valid( id="scalar_too_large", ), pytest.param( - Spec.G1 + Scalar(1).x.to_bytes(16, byteorder="big"), # Invalid - # scalar - # length + # Invalid scalar length + Spec.G1 + Scalar(1).x.to_bytes(16, byteorder="big"), id="scalar_too_short", ), pytest.param( diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py index 518dd6d1dba..87a9cf77851 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g2msm.py @@ -174,9 +174,8 @@ def test_valid( id="scalar_too_large", ), pytest.param( - Spec.G2 + Scalar(1).x.to_bytes(16, byteorder="big"), # Invalid - # scalar - # length + # Invalid scalar length + Spec.G2 + Scalar(1).x.to_bytes(16, byteorder="big"), id="scalar_too_short", ), pytest.param( diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/conftest.py b/tests/prague/eip7002_el_triggerable_withdrawals/conftest.py index 898537e70a4..ac66187db06 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/conftest.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/conftest.py @@ -113,8 +113,10 @@ def blocks( timestamp += 1 return blocks + [ + # Add an empty block at the end to verify that no more withdrawal + # requests are included Block( header_verify=Header(requests_hash=Requests()), timestamp=timestamp, ) - ] # Add an empty block at the end to verify that no more withdrawal requests are included + ] diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py index a3f6a54ed53..e8a6846adb0 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py @@ -531,11 +531,10 @@ def test_address_collision( contract_address: Account( storage={ slot_create_address: salt_zero_address, - slot_create_address_2: EOFCREATE_FAILURE, # had an in- - # transaction - # collision - slot_create_address_3: EOFCREATE_FAILURE, # had a pre-existing - # collision + # had an in-transaction collision + slot_create_address_2: EOFCREATE_FAILURE, + # had a pre-existing collision + slot_create_address_3: EOFCREATE_FAILURE, slot_code_worked: value_code_worked, } ) diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate.py index 3b0e9d5d2f4..049cca14064 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate.py @@ -480,11 +480,10 @@ def test_address_collision( contract_address: Account( storage={ slot_create_address: salt_zero_address, - slot_create_address_2: TXCREATE_FAILURE, # had an in- - # transaction - # collision - slot_create_address_3: TXCREATE_FAILURE, # had a pre-existing - # collision + # had an in-transaction collision + slot_create_address_2: TXCREATE_FAILURE, + # had a pre-existing collision + slot_create_address_3: TXCREATE_FAILURE, slot_code_worked: value_code_worked, } ) From 3f709207b86240817d8d82d1fe274a0391087b17 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Wed, 24 Sep 2025 15:55:17 +0200 Subject: [PATCH 12/16] chore: manually revert and fix docstrings/comments --- src/cli/gentest/source_code_generator.py | 6 +- src/cli/gentest/test_context_providers.py | 6 +- src/cli/order_fixtures.py | 17 +- src/cli/tests/test_evm_bytes.py | 17 +- .../reference_spec/reference_spec.py | 6 +- src/ethereum_test_fixtures/consume.py | 12 +- src/ethereum_test_specs/base_static.py | 4 +- src/pytest_plugins/execute/pre_alloc.py | 4 +- .../execute/rpc/chain_builder_eth_rpc.py | 26 ++- src/pytest_plugins/filler/filler.py | 55 ++++-- src/pytest_plugins/filler/pre_alloc.py | 4 +- .../filler/tests/test_verify_sync_marker.py | 3 +- src/pytest_plugins/forks/forks.py | 6 +- .../tests/test_bad_command_line_options.py | 3 +- .../forks/tests/test_bad_validity_markers.py | 3 +- .../tests/test_fork_parametrizer_types.py | 3 +- .../spec_version_checker.py | 26 +-- tests/benchmark/test_worst_blocks.py | 53 +++-- tests/benchmark/test_worst_compute.py | 53 +++-- .../test_precompile_warming.py | 27 ++- .../eip198_modexp_precompile/helpers.py | 12 +- tests/cancun/eip4844_blobs/test_blob_txs.py | 8 +- .../eip5656_mcopy/test_mcopy_contexts.py | 5 +- .../eip145_bitwise_shift/spec.py | 52 +++-- .../test_modexp_thresholds.py | 187 +++++++++--------- .../security/test_selfdestruct_balance_bug.py | 13 +- tests/prague/__init__.py | 15 +- .../eip2537_bls_12_381_precompiles/helpers.py | 96 +++++---- .../conftest.py | 27 +-- .../eip7692_eof_v1/eip3540_eof_v1/__init__.py | 11 +- .../eip4200_relative_jumps/__init__.py | 7 +- .../eip4750_functions/__init__.py | 9 +- .../eip4750_functions/test_callf_execution.py | 17 +- .../eip7692_eof_v1/eip5450_stack/__init__.py | 11 +- .../eip7692_eof_v1/eip6206_jumpf/__init__.py | 8 +- .../eip7069_extcall/test_calls.py | 31 +-- .../eip7480_data_section/__init__.py | 11 +- .../test_eofcreate_failures.py | 6 - .../test_txcreate_failures.py | 22 +-- 39 files changed, 499 insertions(+), 383 deletions(-) diff --git a/src/cli/gentest/source_code_generator.py b/src/cli/gentest/source_code_generator.py index 35628f5f5e3..d78dc82693a 100644 --- a/src/cli/gentest/source_code_generator.py +++ b/src/cli/gentest/source_code_generator.py @@ -39,7 +39,8 @@ def get_test_source(provider: Provider, template_path: str) -> str: template_path (str): The path to the Jinja2 template file used to generate tests. - Returns: str: The formatted pytest source code. + Returns: + str: The formatted pytest source code. """ template = template_env.get_template(template_path) @@ -58,7 +59,8 @@ def format_code(code: str) -> str: Args: code (str): The Python code to be formatted. - Returns: str: The formatted Python code. + Returns: + str: The formatted Python code. """ # Create a temporary python file diff --git a/src/cli/gentest/test_context_providers.py b/src/cli/gentest/test_context_providers.py index b958d160e22..42a56f3f0d8 100644 --- a/src/cli/gentest/test_context_providers.py +++ b/src/cli/gentest/test_context_providers.py @@ -89,8 +89,10 @@ def get_context(self) -> Dict[str, Any]: """ Get the context for generating a blockchain test. - Returns: Dict[str, Any]: A dictionary containing environment, - pre-state, a transaction and its hash. + Returns: + Dict[str, Any]: A dictionary containing environment, + pre-state, a transaction and its hash. + """ self._make_rpc_calls() return { diff --git a/src/cli/order_fixtures.py b/src/cli/order_fixtures.py index dda26d76151..d35412e755f 100644 --- a/src/cli/order_fixtures.py +++ b/src/cli/order_fixtures.py @@ -33,7 +33,8 @@ def recursive_sort(item: Dict[str, Any] | List[Any]) -> Dict[str, Any] | List[An Args: item: The item to be sorted. This can be a list or a dictionary. - Returns: The sorted item. + Returns: + The sorted item. """ if isinstance(item, dict): @@ -60,7 +61,8 @@ def order_fixture(input_path: Path, output_path: Path) -> None: input_path: The Path object of the input .json file. output_path: The Path object of the output .json file. - Returns: None. + Returns: + None. """ with input_path.open("r") as f: @@ -78,10 +80,13 @@ def process_directory(input_dir: Path, output_dir: Path): and writes the sorted .json files to the corresponding locations in the output directory. - Args: input_dir: The Path object of the input directory. output_dir: The - Path object of the output directory. + Args: + input_dir: The Path object of the input directory. + output_dir: The Path object of the output directory. + + Returns: + None. - Returns: None. """ if not output_dir.exists(): output_dir.mkdir(parents=True) @@ -99,7 +104,7 @@ def process_directory(input_dir: Path, output_dir: Path): "input_dir", type=click.Path(exists=True, file_okay=False, dir_okay=True, readable=True), required=True, - help="The input directory", + help="input directory", ) @click.option( "--output", diff --git a/src/cli/tests/test_evm_bytes.py b/src/cli/tests/test_evm_bytes.py index 438c81c7807..e7e32a81e3c 100644 --- a/src/cli/tests/test_evm_bytes.py +++ b/src/cli/tests/test_evm_bytes.py @@ -13,21 +13,8 @@ "Op.SSTORE", ] complex_vector = [ - "0x7fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbeb" - "f5f527fc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdd" - "dedf6020527fe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9faf" - "bfcfdfeff60405260786040356020355f35608a565b5f515f556020516001556040" - "51600255005b5e56", - "Op.PUSH32[0xa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9bab" - "bbcbdbebf] + Op.PUSH0 + Op.MSTORE + Op.PUSH32[0xc0c1c2c3c4c5c6c7c8c" - "9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf] + Op.PUSH1[0x20] + " - "Op.MSTORE + Op.PUSH32[0xe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f" - "5f6f7f8f9fafbfcfdfeff] + Op.PUSH1[0x40] + Op.MSTORE + Op.PUSH1[0x78] + " - "Op.PUSH1[0x40] + Op.CALLDATALOAD + Op.PUSH1[0x20] + Op.CALLDATALOAD + " - "Op.PUSH0 + Op.CALLDATALOAD + Op.PUSH1[0x8a] + Op.JUMP + Op.JUMPDEST + " - "Op.PUSH0 + Op.MLOAD + Op.PUSH0 + Op.SSTORE + Op.PUSH1[0x20] + Op.MLOAD + " - "Op.PUSH1[0x1] + Op.SSTORE + Op.PUSH1[0x40] + Op.MLOAD + Op.PUSH1[0x2] + " - "Op.SSTORE + Op.STOP + Op.JUMPDEST + Op.MCOPY + Op.JUMP", + "0x7fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf5f527fc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf6020527fe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff60405260786040356020355f35608a565b5f515f55602051600155604051600255005b5e56", # noqa: E501 + "Op.PUSH32[0xa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf] + Op.PUSH0 + Op.MSTORE + Op.PUSH32[0xc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf] + Op.PUSH1[0x20] + Op.MSTORE + Op.PUSH32[0xe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff] + Op.PUSH1[0x40] + Op.MSTORE + Op.PUSH1[0x78] + Op.PUSH1[0x40] + Op.CALLDATALOAD + Op.PUSH1[0x20] + Op.CALLDATALOAD + Op.PUSH0 + Op.CALLDATALOAD + Op.PUSH1[0x8a] + Op.JUMP + Op.JUMPDEST + Op.PUSH0 + Op.MLOAD + Op.PUSH0 + Op.SSTORE + Op.PUSH1[0x20] + Op.MLOAD + Op.PUSH1[0x1] + Op.SSTORE + Op.PUSH1[0x40] + Op.MLOAD + Op.PUSH1[0x2] + Op.SSTORE + Op.STOP + Op.JUMPDEST + Op.MCOPY + Op.JUMP", # noqa: E501 ] rjump_vector = [ "0xe0fffe", diff --git a/src/ethereum_test_base_types/reference_spec/reference_spec.py b/src/ethereum_test_base_types/reference_spec/reference_spec.py index edee8e68804..3bf36113522 100644 --- a/src/ethereum_test_base_types/reference_spec/reference_spec.py +++ b/src/ethereum_test_base_types/reference_spec/reference_spec.py @@ -92,7 +92,9 @@ def parse_from_module( """ Parse the module's dict into a reference spec. - Args: module_dict: Dictionary containing module information - github_token: Optional GitHub token for API authentication + Args: + module_dict: Dictionary containing module information + github_token: Optional GitHub token for API authentication + """ pass diff --git a/src/ethereum_test_fixtures/consume.py b/src/ethereum_test_fixtures/consume.py index fa3e6c99dbf..b55f35efd47 100644 --- a/src/ethereum_test_fixtures/consume.py +++ b/src/ethereum_test_fixtures/consume.py @@ -71,11 +71,13 @@ class TestCaseIndexFile(TestCaseBase): # TODO: add pytest marks """ - ConsumerTypes = Literal["all", "direct", "rlp", "engine"] @classmethod def - _marks_default(cls): return {consumer_type: [] for consumer_type in - get_args(ConsumerTypes)} marks: Mapping[ConsumerTypes, - List[pytest.MarkDecorator]] = field( default_factory=lambda: - TestCase._marks_default() ) + ConsumerTypes = Literal["all", "direct", "rlp", "engine"] + @classmethod + def _marks_default(cls): + return {consumer_type: [] for consumer_type in get_args(ConsumerTypes)} + marks: Mapping[ConsumerTypes, List[pytest.MarkDecorator]] = field( + default_factory=lambda: TestCase._marks_default() + ) """ diff --git a/src/ethereum_test_specs/base_static.py b/src/ethereum_test_specs/base_static.py index 21690679cd5..3dd61bbebc6 100644 --- a/src/ethereum_test_specs/base_static.py +++ b/src/ethereum_test_specs/base_static.py @@ -73,7 +73,9 @@ def test_state_filler( n: int, m: int ): - assert n == 1 assert m in [1, 2] + \"\"\"Generate a test from a static state filler.\"\"\" + assert n == 1 + assert m in [1, 2] env = Environment(**self.env.model_dump()) sender = pre.fund_eoa() tx = Transaction( diff --git a/src/pytest_plugins/execute/pre_alloc.py b/src/pytest_plugins/execute/pre_alloc.py index 4ec7c4e4ae7..239de55f932 100644 --- a/src/pytest_plugins/execute/pre_alloc.py +++ b/src/pytest_plugins/execute/pre_alloc.py @@ -497,7 +497,9 @@ def empty_account(self) -> Address: does not send any transactions, ensuring that the account remains "empty." - Returns: Address: The address of the created empty account. + Returns: + Address: The address of the created empty account. + """ eoa = next(self._eoa_iterator) diff --git a/src/pytest_plugins/execute/rpc/chain_builder_eth_rpc.py b/src/pytest_plugins/execute/rpc/chain_builder_eth_rpc.py index 30820df5065..d41fd688432 100644 --- a/src/pytest_plugins/execute/rpc/chain_builder_eth_rpc.py +++ b/src/pytest_plugins/execute/rpc/chain_builder_eth_rpc.py @@ -327,9 +327,12 @@ def wait_for_transaction(self, transaction: Transaction) -> TransactionByHashRes Waits for a specific transaction to be included in a block by polling `eth_getTransactionByHash` until it is confirmed or a timeout occurs. - Args: transaction: The transaction to track. + Args: + transaction: The transaction to track. + + Returns: + The transaction details after it is included in a block. - Returns: The transaction details after it is included in a block. """ return self.wait_for_transactions([transaction])[0] @@ -344,13 +347,16 @@ def wait_for_transactions( block by polling `eth_getTransactionByHash` until they are confirmed or a timeout occurs. - Args: transactions: A list of transactions to track. + Args: + transactions: A list of transactions to track. - Returns: A list of transaction details after they are included in a - block. + Returns: + A list of transaction details after they are included in a block. + + Raises: + Exception: If one or more transactions are not included in a block + within the timeout period. - Raises: Exception: If one or more transactions are not included in a - block within the timeout period. """ tx_hashes = [tx.hash for tx in transactions] responses: List[TransactionByHashResponse] = [] @@ -400,8 +406,10 @@ class PendingTransactionHandler: Manages block generation based on the number of pending transactions or a block generation interval. - Attributes: block_generation_interval: The number of iterations after which - a block is generated if no new transactions are added (default: 10). + Attributes: + block_generation_interval: The number of iterations after which a block + is generated if no new transactions are added (default: 10). + """ chain_builder_eth_rpc: ChainBuilderEthRPC diff --git a/src/pytest_plugins/filler/filler.py b/src/pytest_plugins/filler/filler.py index 7e4f1998ffe..edb3293c874 100644 --- a/src/pytest_plugins/filler/filler.py +++ b/src/pytest_plugins/filler/filler.py @@ -63,10 +63,10 @@ class PhaseManager: The filler plugin supports two-phase execution for pre-allocation group generation: - Phase 1: Generate pre-allocation groups (pytest run with - --generate-pre-alloc-groups). + --generate-pre-alloc-groups). - Phase 2: Fill fixtures using pre-allocation - groups (pytest run with --use-pre-alloc-groups). + groups (pytest run with --use-pre-alloc-groups). Note: These are separate pytest runs orchestrated by the CLI wrapper. Each run gets a fresh PhaseManager instance (no persistence between phases). @@ -147,10 +147,13 @@ def should_generate(self, fixture_format: Type[BaseFixture] | LabeledFixtureForm """ Determine if a fixture format should be generated in the current phase. - Args: fixture_format: The fixture format to check (may be wrapped in - LabeledFixtureFormat) + Args: + fixture_format: The fixture format to check (may be wrapped in + LabeledFixtureFormat). + + Returns: + True if the format should be generated in the current phase. - Returns: True if the format should be generated in the current phase """ format_phases = fixture_format.format_phases @@ -207,7 +210,9 @@ def from_config(cls, config: pytest.Config) -> "Self": """ Initialize a filling session from pytest configuration. - Args: config: The pytest configuration object. + Args: + config: The pytest configuration object. + """ phase_manager = PhaseManager.from_config(config) instance = cls( @@ -251,9 +256,12 @@ def should_generate_format( Determine if a fixture format should be generated in the current session. - Args: fixture_format: The fixture format to check. + Args: + fixture_format: The fixture format to check. + + Returns: + True if the format should be generated. - Returns: True if the format should be generated. """ return self.format_selector.should_generate(fixture_format) @@ -261,12 +269,15 @@ def get_pre_alloc_group(self, hash_key: str) -> PreAllocGroup: """ Get a pre-allocation group by hash. - Args: hash_key: The hash of the pre-alloc group. + Args: + hash_key: The hash of the pre-alloc group. - Returns: The pre-allocation group. + Returns: + The pre-allocation group. + + Raises: + ValueError: If pre-alloc groups not initialized or hash not found. - Raises: ValueError: If pre-alloc groups not initialized or hash not - found. """ if self.pre_alloc_groups is None: raise ValueError("Pre-allocation groups not initialized") @@ -285,10 +296,13 @@ def update_pre_alloc_group(self, hash_key: str, group: PreAllocGroup) -> None: """ Update or add a pre-allocation group. - Args: hash_key: The hash of the pre-alloc group. group: The - pre-allocation group. + Args: + hash_key: The hash of the pre-alloc group. + group: The pre-allocation group. + + Raises: + ValueError: If not in pre-alloc generation phase. - Raises: ValueError: If not in pre-alloc generation phase. """ if not self.phase_manager.is_pre_alloc_generation: raise ValueError("Can only update pre-alloc groups in generation phase") @@ -311,7 +325,9 @@ def aggregate_pre_alloc_groups(self, worker_groups: PreAllocGroups) -> None: """ Aggregate pre-alloc groups from a worker process (xdist support). - Args: worker_groups: Pre-alloc groups from a worker process. + Args: + worker_groups: Pre-alloc groups from a worker process. + """ if self.pre_alloc_groups is None: self.pre_alloc_groups = PreAllocGroups(root={}) @@ -343,10 +359,11 @@ def calculate_post_state_diff(post_state: Alloc, genesis_state: Alloc) -> Alloc: - Were deleted during test execution (represented as None) Args: - post_state: Final state after test execution - genesis_state: Genesis pre-allocation state + post_state: Final state after test execution + genesis_state: Genesis pre-allocation state - Returns: Alloc containing only the state differences for efficient storage + Returns: + Alloc containing only the state differences for efficient storage """ diff: Dict[Address, Account | None] = {} diff --git a/src/pytest_plugins/filler/pre_alloc.py b/src/pytest_plugins/filler/pre_alloc.py index ef6c6509765..3bb74b3e0f5 100644 --- a/src/pytest_plugins/filler/pre_alloc.py +++ b/src/pytest_plugins/filler/pre_alloc.py @@ -273,7 +273,9 @@ def empty_account(self) -> Address: does not send any transactions, ensuring that the account remains "empty." - Returns: Address: The address of the created empty account. + Returns: + Address: The address of the created empty account. + """ eoa = next(self._eoa_iterator) diff --git a/src/pytest_plugins/filler/tests/test_verify_sync_marker.py b/src/pytest_plugins/filler/tests/test_verify_sync_marker.py index ce76da9c608..83e7450dfb8 100644 --- a/src/pytest_plugins/filler/tests/test_verify_sync_marker.py +++ b/src/pytest_plugins/filler/tests/test_verify_sync_marker.py @@ -98,7 +98,8 @@ def test_verify_sync_marker( Final counts: - Passed: 8 (base fixtures) + 2 (sync fixtures) = 10 passed - - Skipped: 0 skipped - Failed: 0 failed + - Skipped: 0 skipped + - Failed: 0 failed """ # Create proper directory structure for tests tests_dir = pytester.mkdir("tests") diff --git a/src/pytest_plugins/forks/forks.py b/src/pytest_plugins/forks/forks.py index 994a590d795..52346f366f9 100644 --- a/src/pytest_plugins/forks/forks.py +++ b/src/pytest_plugins/forks/forks.py @@ -287,8 +287,10 @@ def __init__(self, metafunc: Metafunc): The decorator must already be subclassed with the appropriate class variables before initialization. - Args: metafunc: The metafunc object that pytest uses when generating - tests. + Args: + metafunc: The metafunc object that pytest uses when generating + tests. + """ self.metafunc = metafunc diff --git a/src/pytest_plugins/forks/tests/test_bad_command_line_options.py b/src/pytest_plugins/forks/tests/test_bad_command_line_options.py index 8059bbb1c3e..5d45dd2427b 100644 --- a/src/pytest_plugins/forks/tests/test_bad_command_line_options.py +++ b/src/pytest_plugins/forks/tests/test_bad_command_line_options.py @@ -1,6 +1,5 @@ """ -Test that the correct error is produced if bad/invalid command-line arguments -are used. +Test the correct error is produced with bad/invalid command-line arguments. """ import pytest diff --git a/src/pytest_plugins/forks/tests/test_bad_validity_markers.py b/src/pytest_plugins/forks/tests/test_bad_validity_markers.py index a3ff787973f..1e33c30aedd 100644 --- a/src/pytest_plugins/forks/tests/test_bad_validity_markers.py +++ b/src/pytest_plugins/forks/tests/test_bad_validity_markers.py @@ -1,6 +1,5 @@ """ -Test that the correct error is produced if bad/invalid validity markers are -specified. +Test the correct error is produced with bad/invalid validity markers. """ import pytest diff --git a/src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py b/src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py index 49adf3eda51..94d6eb5eb1a 100644 --- a/src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py +++ b/src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py @@ -189,8 +189,7 @@ def test_fork_parametrizer( expected_parameter_sets: List[ParameterSet], ): """ - Test that the fork parametrizer correctly parametrizes tests based on the - fork name. + Test the fork parametrizer correctly parametrizes using the fork name. """ argnames, values = parameters_from_fork_parametrizer_list(fork_parametrizers) assert argnames == expected_names diff --git a/src/pytest_plugins/spec_version_checker/spec_version_checker.py b/src/pytest_plugins/spec_version_checker/spec_version_checker.py index 1ddd8d96854..b5fb41c93d7 100644 --- a/src/pytest_plugins/spec_version_checker/spec_version_checker.py +++ b/src/pytest_plugins/spec_version_checker/spec_version_checker.py @@ -45,8 +45,7 @@ def pytest_configure(config): Register the plugin's custom markers and process command-line options. Custom marker registration: - https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom - -markers + https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers """ config.addinivalue_line( "markers", @@ -74,12 +73,14 @@ def get_ref_spec_from_module( module: The module to extract reference spec from github_token: Optional GitHub token for API authentication - Raises: Exception: If the module path contains "eip" and the module does - not define a reference spec. + Raises: + Exception: If the module path contains "eip" and the module does + not define a reference spec. - Returns: spec_obj: Return None if the module path does not contain "eip", - i.e., the module is not required to define a reference spec, otherwise, - return the ReferenceSpec object as defined by the module. + Returns: + spec_obj: Return None if the module path does not contain "eip", + i.e., the module is not required to define a reference spec, otherwise, + return the ReferenceSpec object as defined by the module. """ if not is_test_for_an_eip(str(module.__file__)): @@ -167,12 +168,11 @@ def __init__(self, name: str, parent: Node, **kwargs: Any): def from_parent(cls, parent: Node, **kw: Any) -> "EIPSpecTestItem": """ Public constructor to define new tests. - https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.fr - om_parent. + https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent. Args: - parent: The parent Node - kw: Additional keyword arguments (module, github_token) + parent: The parent Node + kw: Additional keyword arguments (module, github_token) """ module = kw.pop("module", None) @@ -193,7 +193,9 @@ def reportinfo(self) -> tuple[str, int, str]: """ Get location information for this test item to use test reports. - Returns: A tuple of (path, line_number, description) + Returns: + A tuple of (path, line_number, description) + """ return "spec_version_checker", 0, f"{self.name}" diff --git a/tests/benchmark/test_worst_blocks.py b/tests/benchmark/test_worst_blocks.py index c5f625aa1b8..6d95ef657b0 100644 --- a/tests/benchmark/test_worst_blocks.py +++ b/tests/benchmark/test_worst_blocks.py @@ -124,10 +124,12 @@ def test_block_full_of_ether_transfers( """ Single test for ether transfer scenarios. - Scenarios: - a_to_a: one sender → one sender - a_to_b: one sender → one - receiver - diff_acc_to_b: multiple senders → one receiver - a_to_diff_acc: - one sender → multiple receivers - diff_acc_to_diff_acc: multiple senders → - multiple receivers + Scenarios: + - a_to_a: one sender → one sender + - a_to_b: one sender → one receiver + - diff_acc_to_b: multiple senders → one receiver + - a_to_diff_acc: one sender → multiple receivers + - diff_acc_to_diff_acc: multiple senders → multiple receivers """ senders, receivers = ether_transfer_case @@ -186,17 +188,28 @@ def test_block_full_data( """Test a block with empty payload.""" # Gas cost calculation based on EIP-7683: # (https://eips.ethereum.org/EIPS/eip-7683) - # tx.gasUsed = 21000 + max( STANDARD_TOKEN_COST * tokens_in_calldata + - # execution_gas_used + isContractCreation * (32000 + INITCODE_WORD_COST * - # words(calldata)), TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata) - # Simplified in this test case: - No execution gas used (no opcodes are - # executed) - Not a contract creation (no initcode) - # Therefore: max_token_cost = max(STANDARD_TOKEN_COST, - # TOTAL_COST_FLOOR_PER_TOKEN) tx.gasUsed = 21000 + tokens_in_calldata * - # max_token_cost + # + # tx.gasUsed = 21000 + max( + # STANDARD_TOKEN_COST * tokens_in_calldata + # + execution_gas_used + # + isContractCreation * (32000 + + # INITCODE_WORD_COST * words(calldata)), + # TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata) + # + # Simplified in this test case: + # - No execution gas used (no opcodes are executed) + # - Not a contract creation (no initcode) + # + # Therefore: + # max_token_cost = max(STANDARD_TOKEN_COST, TOTAL_COST_FLOOR_PER_TOKEN) + # tx.gasUsed = 21000 + tokens_in_calldata * max_token_cost + # # Since max(STANDARD_TOKEN_COST, TOTAL_COST_FLOOR_PER_TOKEN) = 10: - # tx.gasUsed = 21000 + tokens_in_calldata * 10 - # Token accounting: tokens_in_calldata = zero_bytes + 4 * non_zero_bytes + # tx.gasUsed = 21000 + tokens_in_calldata * 10 + # + # Token accounting: + # tokens_in_calldata = zero_bytes + 4 * non_zero_bytes + # # So we calculate how many bytes we can fit into calldata based on # available gas. @@ -265,9 +278,11 @@ def test_block_full_access_list_and_data( ] # Calculate calldata with 29% of gas for zero bytes and 71% for non-zero - # bytes Token accounting: tokens_in_calldata = zero_bytes + 4 * - # non_zero_bytes We want to split the gas budget: - 29% of gas_for_calldata - # for zero bytes - 71% of gas_for_calldata for non-zero bytes + # bytes + # Token accounting: tokens_in_calldata = zero_bytes + 4 * non_zero_bytes + # We want to split the gas budget: + # - 29% of gas_for_calldata for zero bytes + # - 71% of gas_for_calldata for non-zero bytes max_tokens_in_calldata = gas_for_calldata // total_cost_standard_per_token @@ -279,8 +294,8 @@ def test_block_full_access_list_and_data( # Zero bytes: 1 token per byte # Non-zero bytes: 4 tokens per byte num_zero_bytes = tokens_for_zero_bytes # 1 token = 1 zero byte - num_non_zero_bytes = tokens_for_non_zero_bytes // 4 # 4 tokens = 1 non- - # zero byte + # 4 tokens = 1 non-zero byte + num_non_zero_bytes = tokens_for_non_zero_bytes // 4 # Create calldata with mixed bytes calldata = bytearray() diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index 95610931d0c..6799c191d3a 100644 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -2412,11 +2412,17 @@ def test_worst_mod( ): """ Test running a block with as many MOD instructions with arguments of the - parametrized range. The test program consists of code segments evaluating - the "MOD chain": mod[0] = calldataload(0) mod[1] = numerators[indexes[0]] % - mod[0] mod[2] = numerators[indexes[1]] % mod[1] ... The "numerators" is a - pool of 15 constants pushed to the EVM stack at the program start. The - order of accessing the numerators is selected in a way the mod value + parametrized range. + + The test program consists of code segments evaluating the "MOD chain": + mod[0] = calldataload(0) + mod[1] = numerators[indexes[0]] % mod[0] + mod[2] = numerators[indexes[1]] % mod[1] ... + + The "numerators" is a pool of 15 constants pushed to the EVM stack at the + program start. + + The order of accessing the numerators is selected in a way the mod value remains in the range as long as possible. """ max_code_size = fork.max_code_size() @@ -2584,14 +2590,17 @@ def test_worst_modarith( ): """ Test running a block with as many "op" instructions with arguments of the - parametrized range. The test program consists of code segments evaluating - the "op chain": mod[0] = calldataload(0) mod[1] = (fixed_arg op - args[indexes[0]]) % mod[0] mod[2] = (fixed_arg op args[indexes[1]]) % - mod[1] The "args" is a pool of 15 constants pushed to the EVM stack at the - program start. The "fixed_arg" is the 0xFF...FF constant added to the EVM - stack by PUSH32 just before executing the "op". The order of accessing the - numerators is selected in a way the mod value remains in the range as long - as possible. + parametrized range. + The test program consists of code segments evaluating the "op chain": + mod[0] = calldataload(0) + mod[1] = (fixed_arg op args[indexes[0]]) % mod[0] + mod[2] = (fixed_arg op args[indexes[1]]) % mod[1] + The "args" is a pool of 15 constants pushed to the EVM stack at the program + start. + The "fixed_arg" is the 0xFF...FF constant added to the EVM stack by PUSH32 + just before executing the "op". + The order of accessing the numerators is selected in a way the mod value + remains in the range as long as possible. """ fixed_arg = 2**256 - 1 num_args = 15 @@ -3016,13 +3025,17 @@ def test_worst_return_revert( """Test running a block with as many RETURN or REVERT as possible.""" max_code_size = fork.max_code_size() - # Create the contract that will be called repeatedly. The bytecode of the - # contract is: ``` [CODECOPY(returned_size) -- Conditional if - # return_non_zero_data] opcode(returned_size) ``` Filling the contract up to the max size is - # a cheap way of leveraging CODECOPY to return non-zero bytes if requested. - # Note that since this is a pre-deploy this cost isn't relevant for the - # benchmark. + # Create the contract that will be called repeatedly. + # The bytecode of the contract is: + # ``` + # [CODECOPY(returned_size) -- Conditional if return_non_zero_data] + # opcode(returned_size) + # + # ``` + # Filling the contract up to the max size is a cheap way of leveraging + # CODECOPY to return non-zero bytes if requested. Note that since this + # is a pre-deploy this cost isn't + # relevant for the benchmark. mem_preparation = Op.CODECOPY(size=return_size) if return_non_zero_data else Bytecode() executable_code = mem_preparation + opcode(size=return_size) code = executable_code diff --git a/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py b/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py index e0a6131aa52..f8ad64a3d4b 100644 --- a/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py +++ b/tests/berlin/eip2929_gas_cost_increases/test_precompile_warming.py @@ -37,12 +37,15 @@ def precompile_addresses_in_predecessor_successor( Yield the addresses of precompiled contracts and whether they existed in the parent fork. - Args: fork (Fork): The transition fork instance containing precompiled - contract information. + Args: + fork (Fork): The transition fork instance containing precompiled + contract information. + + Yields: + Iterator[Tuple[str, bool]]: A tuple containing the address in + hexadecimal format and a boolean indicating whether the address + has existed in the predecessor. - Yields: Iterator[Tuple[str, bool]]: A tuple containing the address in - hexadecimal format and a boolean indicating whether the address has existed - in the predecessor. """ precompile_range = range(0x01, 0x100) predecessor_precompiles = set(get_transition_fork_predecessor(fork).precompiles()) @@ -88,11 +91,15 @@ def test_precompile_warming( Call BALANCE of a precompile addresses before and after a fork. According to EIP-2929, when a transaction begins, accessed_addresses is - initialized to include: - tx.sender, tx.to - and the set of all precompiles - - This test verifies that: 1. Precompiles that exist in the predecessor fork - are always "warm" (lower gas cost) 2. New precompiles added in a fork are - "cold" before the fork and become "warm" after + initialized to include: + - tx.sender, tx.to + - and the set of all precompiles + + This test verifies that: + 1. Precompiles that exist in the predecessor fork are always "warm" (lower + gas cost). + 2. New precompiles added in a fork are "cold" before the fork and become + "warm" after. """ sender = pre.fund_eoa() call_cost_slot = 0 diff --git a/tests/byzantium/eip198_modexp_precompile/helpers.py b/tests/byzantium/eip198_modexp_precompile/helpers.py index 0360f9ddc90..1a3855da239 100644 --- a/tests/byzantium/eip198_modexp_precompile/helpers.py +++ b/tests/byzantium/eip198_modexp_precompile/helpers.py @@ -14,11 +14,13 @@ class ModExpInput(TestParameterGroup): Helper class that defines the MODEXP precompile inputs and creates the call data from them. - Attributes: base (str): The base value for the MODEXP precompile. exponent - (str): The exponent value for the MODEXP precompile. modulus (str): The - modulus value for the MODEXP precompile. extra_data (str): Defines extra - padded data to be added at the end of the calldata to the precompile. - Defaults to an empty string. + Attributes: + base (str): The base value for the MODEXP precompile. + exponent (str): The exponent value for the MODEXP precompile. + modulus (str): The modulus value for the MODEXP precompile. + extra_data (str): Defines extra padded data to be added at the end of + the calldata to the precompile. Defaults to an empty string. + """ base: Bytes diff --git a/tests/cancun/eip4844_blobs/test_blob_txs.py b/tests/cancun/eip4844_blobs/test_blob_txs.py index f4710d8f7a9..b242595ef60 100644 --- a/tests/cancun/eip4844_blobs/test_blob_txs.py +++ b/tests/cancun/eip4844_blobs/test_blob_txs.py @@ -494,8 +494,8 @@ def test_invalid_tx_max_fee_per_blob_gas( """ Reject blocks with invalid blob txs. - - tx max_fee_per_blob_gas is barely not enough - tx max_fee_per_blob_gas is - zero + - tx max_fee_per_blob_gas is barely not enough + - tx max_fee_per_blob_gas is zero """ if non_zero_blob_gas_used_genesis_block is not None: blocks = [non_zero_blob_gas_used_genesis_block, block] @@ -524,8 +524,8 @@ def test_invalid_tx_max_fee_per_blob_gas_state( """ Reject an invalid blob transaction. - - tx max_fee_per_blob_gas is barely not enough - tx max_fee_per_blob_gas is - zero + - tx max_fee_per_blob_gas is barely not enough + - tx max_fee_per_blob_gas is zero """ assert len(txs) == 1 state_test( diff --git a/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py b/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py index 4c606d49e78..33dcc5e3c79 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py @@ -199,8 +199,9 @@ def test_no_memory_corruption_on_upper_create_stack_levels( ): """ Perform a subcall with any of the following opcodes, which uses MCOPY - during its execution, and verify that the caller's memory is unaffected: - - `CREATE` - `CREATE2`. + during its execution, and verify that the caller's memory is unaffected: + - `CREATE` + - `CREATE2`. TODO: [EOF] Add EOFCREATE opcode """ diff --git a/tests/constantinople/eip145_bitwise_shift/spec.py b/tests/constantinople/eip145_bitwise_shift/spec.py index b2df9d87a41..b8649ae2adf 100644 --- a/tests/constantinople/eip145_bitwise_shift/spec.py +++ b/tests/constantinople/eip145_bitwise_shift/spec.py @@ -28,12 +28,20 @@ def sar(shift: int, value: int) -> int: """ Simulate the EVM SAR (Signed Arithmetic Right shift) operation. - Parameters ---------- shift : int Number of bits to shift to the right - (interpreted as full unsigned; no low-8-bit truncation here). value : - int The 256-bit value to shift, interpreted as a signed integer. + Parameters + ---------- + shift : int + Number of bits to shift to the right (interpreted as full unsigned; + no low-8-bit truncation here). + value : int + The 256-bit value to shift, interpreted as a signed integer. + + Returns + ------- + int + The result of the arithmetic right shift, pushed as an unsigned + 256-bit integer on the EVM stack. - Returns ------- int The result of the arithmetic right shift, pushed as - an unsigned 256-bit integer on the EVM stack. """ mask256 = (1 << 256) - 1 # Clamp value to 256 bits @@ -61,12 +69,19 @@ def shl(shift: int, value: int) -> int: """ Simulate the EVM SHL (Logical Left shift) operation. - Parameters ---------- shift : int Number of bits to shift to the left. - value : int The 256-bit value to shift, interpreted as an unsigned - integer. + Parameters + ---------- + shift : int + Number of bits to shift to the left. + value : int + The 256-bit value to shift, interpreted as an unsigned integer. + + Returns + ------- + int + The result of the logical left shift, pushed as an unsigned + 256-bit integer on the EVM stack. - Returns ------- int The result of the logical left shift, pushed as an - unsigned 256-bit integer on the EVM stack. """ mask256 = (1 << 256) - 1 # Clamp input to 256 bits @@ -84,12 +99,19 @@ def shr(shift: int, value: int) -> int: """ Simulate the EVM SHR (Logical Right shift) operation. - Parameters ---------- shift : int Number of bits to shift to the right. - value : int The 256-bit value to shift, interpreted as an unsigned - integer. + Parameters + ---------- + shift : int + Number of bits to shift to the right. + value : int + The 256-bit value to shift, interpreted as an unsigned integer. + + Returns + ------- + int + The result of the logical right shift, pushed as an unsigned + 256-bit integer on the EVM stack. - Returns ------- int The result of the logical right shift, pushed as an - unsigned 256-bit integer on the EVM stack. """ mask256 = (1 << 256) - 1 # Clamp input to 256 bits diff --git a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py index 504781473fb..9264d3db7f7 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py +++ b/tests/osaka/eip7883_modexp_gas_increase/test_modexp_thresholds.py @@ -546,93 +546,91 @@ def create_modexp_variable_gas_test_cases(): ] # Gas calculation parameters: + # # Please refer to EIP-7883 for details of each function in the gas - # calculation. Link: https://eips.ethereum.org/EIPS/eip-7883 - # - calculate_multiplication_complexity: - Comp: if max_length <= 32 bytes, - # it is Small (S), otherwise it is Large (L) - Rel (Length Relation): base - # < modulus (<), base = modulus (=), base > modulus (>) - # - calculate_iteration_count - Iter (Iteration Case): - A: exp≤32 and - # exp=0 - B: exp≤32 and exp≠0 - C: exp>32 and low256=0 - D: exp>32 and - # low256≠0 - # - calculate_gas_cost - Clamp: True if raw gas < 500 (clamped to 500), - # False if raw gas ≥ 500 (no clamping) - - # Test case coverage table: - # ┌─────┬──────┬─────┬──────┬───────┬─────────┬───────────────────────── - # │ ID │ Comp │ Rel │ Iter │ Clamp │ Gas │ Description - # │ - # ├─────┼──────┼─────┼──────┼───────┼─────────┼───────────────────────── - # │ Z0 │ - │ - │ - │ - │ 500 │ Zero case – empty inputs - # │ │ Z1 │ S │ - │ A │ True │ 500 │ Non-zero base, zero exp, - # empty modulus │ │ Z2 │ L │ - │ A │ False │ 32768 │ - # Large base (1024B), zero exp, empty modulus │ │ Z3 │ S │ - │ C - # │ False |253952 │ Base, large zero exp (1024B), empty modulus │ │ Z4 - # │ S │ - │ D │ False │253952 │ Base, large exp (last byte=1), - # empty modulus │ │ Z5 │ S │ < │ A │ True │ 500 │ Empty - # base/exp, non-zero modulus only │ │ Z6 │ S │ < │ B │ - # False │ 3968 │ Empty base, non-zero exp and modulus │ │ Z7 │ - # L │ < │ B │ False │ 32768 │ Empty base, small exp, large modulus - # │ │ S0 │ S │ = │ A │ True │ 500 │ Small, equal, zero exp, - # clamped │ │ S1 │ S │ = │ B │ True │ 500 │ - # Small, equal, small exp, clamped │ │ S2 │ S │ = │ B - # │ False │ 4080 │ Small, equal, large exp, unclamped │ │ S3 - # │ S │ = │ C │ False │ 2048 │ Small, equal, large exp + zero - # low256 │ │ S4 │ S │ = │ D │ False │ 2048 │ Small, - # equal, large exp + non-zero low256 │ │ S5 │ S │ > │ A │ True - # │ 500 │ Small, base > mod, zero exp, clamped │ │ S6 │ S - # │ < │ B │ True │ 500 │ Small, base < mod, small exp, clamped - # │ │ L0 │ L │ = │ A │ True │ 500 │ Large, equal, zero exp, - # clamped │ │ L1 │ L │ = │ B │ False │ 12750 │ - # Large, equal, large exp, unclamped │ │ L2 │ L │ = │ C - # │ False │ 6400 │ Large, equal, large exp + zero low256 │ │ L3 - # │ L │ = │ D │ False │ 6400 │ Large, equal, large exp + non- - # zero low256 │ │ L4 │ L │ > │ B │ True │ 500 │ Large, - # base > mod, small exp, clamped │ │ L5 │ L │ < │ C │ - # False │ 9216 │ Large, base < mod, large exp + zero low256 │ │ B1 │ - # L │ < │ B │ True │ 500 │ Cross 32-byte boundary (31/33) - # │ │ B2 │ L │ > │ B │ True │ 500 │ Cross 32-byte boundary - # (33/31) │ │ B4 │ L │ = │ B │ True │ 500 │ - # Just over 32-byte boundary │ │ Z8 │ S │ = │ A - # │ True │ 500 │ All zeros except modulus │ │ Z9 - # │ S │ = │ A │ True │ 500 │ Zero modulus special case - # │ │ Z10 │ S │ = │ B │ False │ 3968 │ Zero base, large exponent - # │ │ Z11 │ S │ = │ C │ True │ 500 │ Zero base, 33B zero exp, - # non-zero modulus │ │ Z12 │ S │ = │ C │ False |253952 │ Zero - # base, large zero exp, non-zero modulus │ │ Z13 │ L │ > │ A │ - # False │ 32768 │ Large zero base, zero exp, non-zero modulus │ │ Z14 │ - # S │ = │ C │ False |253952 │ Base, large zero exp, zero modulus - # │ │ Z15 │ L │ < │ B │ False │ 32768 │ Base, small exp, large - # zero modulus │ │ Z16 │ L │ < │ C │ False │520060928│ - # Zero base, zero exp, large modulus (gas cap) | │ M1 │ L │ = │ D - # │ False │ 98176 │ Maximum values stress test │ │ M2 - # │ S │ = │ B │ True │ 500 │ Max base/mod, small exponent - # │ │ M3 │ L │ < │ D │ False │ 98176 │ Small base, max - # exponent/mod │ │ T2 │ S │ = │ B │ True │ 500 - # │ Tiny maximum values │ │ P2 │ S │ = │ B - # │ False │ 4080 │ High bit in exponent │ │ P3 - # │ L │ = │ D │ False │ 1150 │ Specific bit pattern in large - # exponent │ │ A1 │ L │ < │ C │ False │ 65536 │ - # Asymmetric: tiny base, large exp/mod │ │ A2 │ L │ > │ B - # │ True │ 500 │ Asymmetric: large base, tiny exp/mod │ │ A3 - # │ L │ > │ C │ False │ 65536 │ Asymmetric: large base/exp, tiny - # modulus │ │ W2 │ S │ = │ B │ True │ 500 │ Exactly - # 8-byte words │ │ E1 │ S │ = │ D │ True - # │ 500 │ Exponent exactly 33 bytes │ │ E2 │ S - # │ = │ B │ False │ 4080 │ High bit in exponent first byte - # │ │ E3 │ S │ = │ B │ True │ 500 │ High bit in exponent last - # byte │ │ E4 │ S │ = │ B │ False │ 4064 │ - # Maximum 32-byte exponent │ │ IC1 │ L │ = │ B - # │ True │ 500 │ Bit shift vs multiplication @ 33 bytes │ │ IC3 - # │ S │ = │ B │ True │ 500 │ Ceiling division at 7 bytes - # │ │ IC4 │ S │ = │ B │ True │ 500 │ Ceiling division at 9 - # bytes │ │ IC5 │ S │ = │ B │ False │ 2160 │ - # Bit counting in middle of exponent │ │ IC6 │ L │ = │ B - # │ True │ 500 │ Native library even byte optimization │ │ IC7 - # │ L │ = │ B │ True │ 500 │ Vector optimization 128-bit - # boundary │ │ IC9 │ S │ = │ B │ N/A │ N/A │ Zero - # modulus handling │ │ IC10│ S │ = │ B │ - # False │ 4080 │ Power-of-2 boundary with high bit │ - # └─────┴──────┴─────┴──────┴───────┴─────────┴────────────────────────── + # calculation. + # Link: https://eips.ethereum.org/EIPS/eip-7883 + # + # - calculate_multiplication_complexity: + # - Comp: if max_length <= 32 bytes, it is Small (S), otherwise it is + # Large (L) + # - Rel (Length Relation): base < modulus (<), base = modulus (=), + # base > modulus (>) + # + # - calculate_iteration_count + # - Iter (Iteration Case): + # - A: exp≤32 and exp=0 + # - B: exp≤32 and exp≠0 + # - C: exp>32 and low256=0 + # - D: exp>32 and low256≠0 + # + # - calculate_gas_cost + # - Clamp: True if raw gas < 500 (clamped to 500), False if raw gas ≥ 500 + # (no clamping) + + """ + Test case coverage table: + + ┌─────┬──────┬─────┬──────┬───────┬─────────┬───────────────────────────────────────────────┐ + │ ID │ Comp │ Rel │ Iter │ Clamp │ Gas │ Description │ + ├─────┼──────┼─────┼──────┼───────┼─────────┼───────────────────────────────────────────────┤ + │ Z0 │ - │ - │ - │ - │ 500 │ Zero case – empty inputs │ + │ Z1 │ S │ - │ A │ True │ 500 │ Non-zero base, zero exp, empty modulus │ + │ Z2 │ L │ - │ A │ False │ 32768 │ Large base (1024B), zero exp, empty modulus │ + │ Z3 │ S │ - │ C │ False |253952 │ Base, large zero exp (1024B), empty modulus │ + │ Z4 │ S │ - │ D │ False │253952 │ Base, large exp (last byte=1), empty modulus │ + │ Z5 │ S │ < │ A │ True │ 500 │ Empty base/exp, non-zero modulus only │ + │ Z6 │ S │ < │ B │ False │ 3968 │ Empty base, non-zero exp and modulus │ + │ Z7 │ L │ < │ B │ False │ 32768 │ Empty base, small exp, large modulus │ + │ S0 │ S │ = │ A │ True │ 500 │ Small, equal, zero exp, clamped │ + │ S1 │ S │ = │ B │ True │ 500 │ Small, equal, small exp, clamped │ + │ S2 │ S │ = │ B │ False │ 4080 │ Small, equal, large exp, unclamped │ + │ S3 │ S │ = │ C │ False │ 2048 │ Small, equal, large exp + zero low256 │ + │ S4 │ S │ = │ D │ False │ 2048 │ Small, equal, large exp + non-zero low256 │ + │ S5 │ S │ > │ A │ True │ 500 │ Small, base > mod, zero exp, clamped │ + │ S6 │ S │ < │ B │ True │ 500 │ Small, base < mod, small exp, clamped │ + │ L0 │ L │ = │ A │ True │ 500 │ Large, equal, zero exp, clamped │ + │ L1 │ L │ = │ B │ False │ 12750 │ Large, equal, large exp, unclamped │ + │ L2 │ L │ = │ C │ False │ 6400 │ Large, equal, large exp + zero low256 │ + │ L3 │ L │ = │ D │ False │ 6400 │ Large, equal, large exp + non-zero low256 │ + │ L4 │ L │ > │ B │ True │ 500 │ Large, base > mod, small exp, clamped │ + │ L5 │ L │ < │ C │ False │ 9216 │ Large, base < mod, large exp + zero low256 │ + │ B1 │ L │ < │ B │ True │ 500 │ Cross 32-byte boundary (31/33) │ + │ B2 │ L │ > │ B │ True │ 500 │ Cross 32-byte boundary (33/31) │ + │ B4 │ L │ = │ B │ True │ 500 │ Just over 32-byte boundary │ + │ Z8 │ S │ = │ A │ True │ 500 │ All zeros except modulus │ + │ Z9 │ S │ = │ A │ True │ 500 │ Zero modulus special case │ + │ Z10 │ S │ = │ B │ False │ 3968 │ Zero base, large exponent │ + │ Z11 │ S │ = │ C │ True │ 500 │ Zero base, 33B zero exp, non-zero modulus │ + │ Z12 │ S │ = │ C │ False |253952 │ Zero base, large zero exp, non-zero modulus │ + │ Z13 │ L │ > │ A │ False │ 32768 │ Large zero base, zero exp, non-zero modulus │ + │ Z14 │ S │ = │ C │ False |253952 │ Base, large zero exp, zero modulus │ + │ Z15 │ L │ < │ B │ False │ 32768 │ Base, small exp, large zero modulus │ + │ Z16 │ L │ < │ C │ False │520060928│ Zero base, zero exp, large modulus (gas cap) | + │ M1 │ L │ = │ D │ False │ 98176 │ Maximum values stress test │ + │ M2 │ S │ = │ B │ True │ 500 │ Max base/mod, small exponent │ + │ M3 │ L │ < │ D │ False │ 98176 │ Small base, max exponent/mod │ + │ T2 │ S │ = │ B │ True │ 500 │ Tiny maximum values │ + │ P2 │ S │ = │ B │ False │ 4080 │ High bit in exponent │ + │ P3 │ L │ = │ D │ False │ 1150 │ Specific bit pattern in large exponent │ + │ A1 │ L │ < │ C │ False │ 65536 │ Asymmetric: tiny base, large exp/mod │ + │ A2 │ L │ > │ B │ True │ 500 │ Asymmetric: large base, tiny exp/mod │ + │ A3 │ L │ > │ C │ False │ 65536 │ Asymmetric: large base/exp, tiny modulus │ + │ W2 │ S │ = │ B │ True │ 500 │ Exactly 8-byte words │ + │ E1 │ S │ = │ D │ True │ 500 │ Exponent exactly 33 bytes │ + │ E2 │ S │ = │ B │ False │ 4080 │ High bit in exponent first byte │ + │ E3 │ S │ = │ B │ True │ 500 │ High bit in exponent last byte │ + │ E4 │ S │ = │ B │ False │ 4064 │ Maximum 32-byte exponent │ + │ IC1 │ L │ = │ B │ True │ 500 │ Bit shift vs multiplication @ 33 bytes │ + │ IC3 │ S │ = │ B │ True │ 500 │ Ceiling division at 7 bytes │ + │ IC4 │ S │ = │ B │ True │ 500 │ Ceiling division at 9 bytes │ + │ IC5 │ S │ = │ B │ False │ 2160 │ Bit counting in middle of exponent │ + │ IC6 │ L │ = │ B │ True │ 500 │ Native library even byte optimization │ + │ IC7 │ L │ = │ B │ True │ 500 │ Vector optimization 128-bit boundary │ + │ IC9 │ S │ = │ B │ N/A │ N/A │ Zero modulus handling │ + │ IC10│ S │ = │ B │ False │ 4080 │ Power-of-2 boundary with high bit │ + └─────┴──────┴─────┴──────┴───────┴─────────┴───────────────────────────────────────────────┘ + """ # noqa: W505 for base, exponent, modulus, expected_result, gas_usage, test_id in test_cases: yield pytest.param( ModExpInput(base=base, exponent=exponent, modulus=modulus), @@ -680,13 +678,12 @@ def test_modexp_variable_gas_cost_exceed_tx_gas_cap(state_test, pre, tx, post): """ Test ModExp variable gas cost. Inputs with an expected gas cost over the EIP-7825 tx gas cap. - """ - # Test case coverage table (gas cap): - # ┌─────┬──────┬─────┬──────┬───────┬─────────┬───────────────────────── - # │ ID │ Comp │ Rel │ Iter │ Clamp │ Gas │ Description - # │ - # ├─────┼──────┼─────┼──────┼───────┼─────────┼───────────────────────── - # │ Z16 │ L │ < │ C │ False │520060928│ Zero base, zero exp, large - # modulus (gas cap) | - # └─────┴──────┴─────┴──────┴───────┴─────────┴───────────────────────── + + Test case coverage table (gas cap): + ┌─────┬──────┬─────┬──────┬───────┬─────────┬───────────────────────────────────────────────┐ + │ ID │ Comp │ Rel │ Iter │ Clamp │ Gas │ Description │ + ├─────┼──────┼─────┼──────┼───────┼─────────┼───────────────────────────────────────────────┤ + │ Z16 │ L │ < │ C │ False │520060928│ Zero base, zero exp, large modulus (gas cap) | + └─────┴──────┴─────┴──────┴───────┴─────────┴───────────────────────────────────────────────┘ + """ # noqa: W505 state_test(pre=pre, tx=tx, post=post) diff --git a/tests/paris/security/test_selfdestruct_balance_bug.py b/tests/paris/security/test_selfdestruct_balance_bug.py index da14a74eaf1..e67eace66d9 100644 --- a/tests/paris/security/test_selfdestruct_balance_bug.py +++ b/tests/paris/security/test_selfdestruct_balance_bug.py @@ -8,8 +8,8 @@ To reproduce the issue with this test case: 1. Fill the test with the most recent geth evm version. -2. Run the fixture - output within a vulnerable geth version: v1.9.20 > geth >= v1.9.4. +2. Run the fixture output within a vulnerable geth version: + v1.9.20 > geth >= v1.9.4. """ import pytest @@ -48,10 +48,11 @@ def test_tx_selfdestruct_balance_bug(blockchain_test: BlockchainTestFiller, pre: 5. Store the balance of `0xaa` after the second transaction is processed. No self-destruct. Expected outcome: 5 wei. - 6. Verify that: - Call within tx 1 is successful, i.e `0xaa` - self-destructed. - The balances of `0xaa` after each tx are correct. - - During tx 2, code in `0xaa` does not execute, hence self-destruct mechanism - does not trigger. + 6. Verify that: + - Call within tx 1 is successful, i.e `0xaa` self-destructed. + - The balances of `0xaa` after each tx are correct. + - During tx 2, code in `0xaa` does not execute, + hence self-destruct mechanism does not trigger. TODO: EOF - This test could be parametrized for EOFCREATE """ diff --git a/tests/prague/__init__.py b/tests/prague/__init__.py index 473ba6bdead..7a26fa5de34 100644 --- a/tests/prague/__init__.py +++ b/tests/prague/__init__.py @@ -4,14 +4,9 @@ Devnet Specifications: -- [ethpandaops/ -pectra-devnet-5](https://notes.ethereum.org/@ethpandaops/pectra-devnet-5). -- [ethpandaops/ -pectra-devnet-4](https://notes.ethereum.org/@ethpandaops/pectra-devnet-4). -- [ethpandaops/ -pectra-devnet-3](https://notes.ethereum.org/@ethpandaops/pectra-devnet-3). -- [ethpandaops/ -pectra-devnet-2](https://notes.ethereum.org/@ethpandaops/pectra-devnet-2). -- [ethpandaops/ -pectra-devnet-1](https://notes.ethereum.org/@ethpandaops/pectra-devnet-1). +- [ethpandaops/pectra-devnet-5](https://notes.ethereum.org/@ethpandaops/pectra-devnet-5). +- [ethpandaops/pectra-devnet-4](https://notes.ethereum.org/@ethpandaops/pectra-devnet-4). +- [ethpandaops/pectra-devnet-3](https://notes.ethereum.org/@ethpandaops/pectra-devnet-3). +- [ethpandaops/pectra-devnet-2](https://notes.ethereum.org/@ethpandaops/pectra-devnet-2). +- [ethpandaops/pectra-devnet-1](https://notes.ethereum.org/@ethpandaops/pectra-devnet-1). """ diff --git a/tests/prague/eip2537_bls_12_381_precompiles/helpers.py b/tests/prague/eip2537_bls_12_381_precompiles/helpers.py index c9720581c08..0fe15471524 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/helpers.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/helpers.py @@ -79,8 +79,9 @@ def vectors_from_file(filename: str) -> List: def add_points_g1(point_a: PointG1, point_b: PointG1) -> PointG1: """ - Add two points in G1 using standard formulas. For points P = (x, y) and Q = - (u, v), compute R = P + Q. + Add two points in G1 using standard formulas. + + For points P = (x, y) and Q = (u, v), compute R = P + Q. """ if point_a.x == 0 and point_a.y == 0: return point_b @@ -96,8 +97,10 @@ def add_points_g1(point_a: PointG1, point_b: PointG1) -> PointG1: def add_points_g2(point_a: PointG2, point_b: PointG2) -> PointG2: """ - Add two points in G2 using standard formulas. For points P = ((x_0, x_1), - (y_0, y_1)) and Q = ((u_0, u_1), (v_0, v_1)), compute R = P + Q. + Add two points in G2 using standard formulas. + + For points P = ((x_0, x_1), (y_0, y_1)) and + Q = ((u_0, u_1), (v_0, v_1)), compute R = P + Q. """ if point_a.x == (0, 0) and point_a.y == (0, 0): return point_b @@ -117,10 +120,12 @@ class BLSPointGenerator: """ Generator for points on the BLS12-381 curve with various properties. - Provides methods to generate points with specific properties: - on the - standard curve - in the correct r-order subgroup or not - on the curve or - not - on an isomorphic curve (not standard curve) but in the correct - r-order subgroup + Provides methods to generate points with specific properties: + - on the standard curve + - in the correct r-order subgroup or not + - on the curve or not + - on an isomorphic curve (not standard curve) but in the correct + r-order subgroup Additional resource that helped the class implementation: https://hackmd.io/@benjaminion/bls12-381 @@ -729,43 +734,60 @@ def generate_g2_map_isogeny_kernel_points(cls) -> List[FP2]: For reference we can imagine the map to curve function as a simple 2 step process, where an input t value is mapped to a point on the - auxiliary curve via a SWU map, and then that point is mapped to the BLS - curve via a 3-isogeny. For reference: - - https://eips.ethereum.org/assets/eip-2537/field_to_curve + auxiliary curve via a SWU map, and then that point is mapped to the + BLS curve via a 3-isogeny. For reference: + - https://eips.ethereum.org/assets/eip-2537/field_to_curve Note we cannot use sage math directly within EEST as it is not a pure python library and requires an external dependency to be installed on the system machine. - ```sage q = - 0x1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153F - FFFB9FEFFFFFFFFAAAB Fp = GF(q) R. = PolynomialRing(Fp) Fp2. = - Fp.extension(x^2 + 1) E2 = EllipticCurve(Fp2, [0, 4*(1+u)]) ISO_3_A = - 240 * u ISO_3_B = 1012 * (1 + u) ISO_3_Z = -(2 + u) Ei = - EllipticCurve(Fp2, [ISO_3_A, ISO_3_B]) iso = EllipticCurveIsogeny(E=E2, - kernel=None, codomain=Ei, degree=3).dual() x_den_k0 = - 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153f - fffb9feffffffffaa63 * u x_den_k1 = 0xc + - 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153f - fffb9feffffffffaa9f * u for (x, _) in iso.kernel_polynomial().roots(): - y_squared = x^3 + ISO_3_A * x + ISO_3_B is_on_curve = - y_squared.is_square() print("Root is on curve:" if is_on_curve else - "Warning: Root is not on the curve") inv_factor = (x * ISO_3_A / - -ISO_3_B) - 1 if inv_factor == 0: continue discriminant = 1 + 4 / - inv_factor if not discriminant.is_square(): continue for sign in [1, - -1]: zt2 = (-1 + sign * discriminant.sqrt()) / 2 t2 = zt2 / ISO_3_Z if - t2.is_square(): t = t2.sqrt() # Perform the proper SWU mapping tv1_num - = ISO_3_Z^2 * t^4 + ISO_3_Z * t^2 tv1 = 1 / tv1_num x1 = (-ISO_3_B / - ISO_3_A) * (1 + tv1) gx1 = x1^3 + ISO_3_A * x1 + ISO_3_B x2 = ISO_3_Z * - t^2 * x1 swu_x = x1 if gx1.is_square() else x2 x_den_value = swu_x^2 + - x_den_k1 * swu_x + x_den_k0 is_kernel_point = (x_den_value == 0) - print("Is a kernel point:", is_kernel_point) print(t) ``` + ```sage + q = 0x1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB + Fp = GF(q) + R. = PolynomialRing(Fp) + Fp2. = Fp.extension(x^2 + 1) + E2 = EllipticCurve(Fp2, [0, 4*(1+u)]) + ISO_3_A = 240 * u + ISO_3_B = 1012 * (1 + u) + ISO_3_Z = -(2 + u) + Ei = EllipticCurve(Fp2, [ISO_3_A, ISO_3_B]) + iso = EllipticCurveIsogeny(E=E2, kernel=None, codomain=Ei, degree=3).dual() + x_den_k0 = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63 * u + x_den_k1 = 0xc + 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9f * u + for (x, _) in iso.kernel_polynomial().roots(): + y_squared = x^3 + ISO_3_A * x + ISO_3_B + is_on_curve = y_squared.is_square() + print("Root is on curve:" if is_on_curve else "Warning: Root is not on the curve") + inv_factor = (x * ISO_3_A / -ISO_3_B) - 1 + if inv_factor == 0: + continue + discriminant = 1 + 4 / inv_factor + if not discriminant.is_square(): + continue + for sign in [1, -1]: + zt2 = (-1 + sign * discriminant.sqrt()) / 2 + t2 = zt2 / ISO_3_Z + if t2.is_square(): + t = t2.sqrt() + # Perform the proper SWU mapping + tv1_num = ISO_3_Z^2 * t^4 + ISO_3_Z * t^2 + tv1 = 1 / tv1_num + x1 = (-ISO_3_B / ISO_3_A) * (1 + tv1) + gx1 = x1^3 + ISO_3_A * x1 + ISO_3_B + x2 = ISO_3_Z * t^2 * x1 + swu_x = x1 if gx1.is_square() else x2 + x_den_value = swu_x^2 + x_den_k1 * swu_x + x_den_k0 + is_kernel_point = (x_den_value == 0) + print("Is a kernel point:", is_kernel_point) + print(t) + ``` Add the script contents to a file called `points.sage`, run `sage points.sage`! - Please see the sage math installation guide to replicate: - - https://doc.sagemath.org/html/en/installation/index.html + Please see the sage math installation guide to replicate: + - https://doc.sagemath.org/html/en/installation/index.html As G2 uses an 3-degree isogeny, its kernel contains exactly 3 points on the auxiliary curve that maps to the point at infinity on the BLS @@ -793,5 +815,5 @@ def generate_g2_map_isogeny_kernel_points(cls) -> List[FP2]: G2 that map to the point at infinity on the BLS curve. This is why we return an empty list here. It is kept for consistency with the G1 case, and documentation purposes. - """ + """ # noqa: E501, W505 return [] diff --git a/tests/prague/eip7623_increase_calldata_cost/conftest.py b/tests/prague/eip7623_increase_calldata_cost/conftest.py index 7e021f7184c..d4031dbfbb7 100644 --- a/tests/prague/eip7623_increase_calldata_cost/conftest.py +++ b/tests/prague/eip7623_increase_calldata_cost/conftest.py @@ -135,19 +135,24 @@ def tx_data( cases where the floor gas cost is equal or barely greater than the intrinsic gas cost. - We have two different types of tests: - - FLOOR_GAS_COST_LESS_THAN_OR_EQUAL_TO_INTRINSIC_GAS: The floor gas cost is - less than or equal to the intrinsic gas cost, which means that the size of - the tokens in the data are not enough to trigger the floor gas cost. - - FLOOR_GAS_COST_GREATER_THAN_INTRINSIC_GAS: The floor gas cost is greater - than the intrinsic gas cost, which means that the size of the tokens in the - data are enough to trigger the floor gas cost. + We have two different types of tests: + + - FLOOR_GAS_COST_LESS_THAN_OR_EQUAL_TO_INTRINSIC_GAS: The floor gas cost is + less than or equal to the intrinsic gas cost, which means that the size + of the tokens in the data are not enough to trigger the floor gas cost. + + - FLOOR_GAS_COST_GREATER_THAN_INTRINSIC_GAS: The floor gas cost is greater + than the intrinsic gas cost, which means that the size of the tokens in + the data are enough to trigger the floor gas cost. E.g. Given a transaction with a single access list and a single storage - key, its intrinsic gas cost (as of Prague fork) can be calculated as: - - 21,000 gas for the transaction - 2,400 gas for the access list - 1,900 gas - for the storage key - 16 gas for each non-zero byte in the data - 4 gas for - each zero byte in the data + key, its intrinsic gas cost (as of Prague fork) can be calculated as: + + - 21,000 gas for the transaction + - 2,400 gas for the access list + - 1,900 gas for the storage key + - 16 gas for each non-zero byte in the data + - 4 gas for each zero byte in the data Its floor data gas cost can be calculated as: - 21,000 gas for the transaction - 40 gas for each non-zero byte in the data - 10 gas for each diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py index e47fa8864fa..3d699145372 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/__init__.py @@ -1,9 +1,10 @@ """ EOF - EVM Object Format v1 tests. - Test cases for - [EIP-3540: EOF - EVM Object Format v1](https://eips.ethereum.org/EIPS/eip-3540). - EIP-3540 introduces a structured format for EVM bytecode, with separate - sections for code and data. Opcodes introduced: None (defines a new - bytecode structure but no new opcodes). +Test cases for +[EIP-3540: EOF - EVM Object Format v1](https://eips.ethereum.org/EIPS/eip-3540). + +EIP-3540 introduces a structured format for EVM bytecode, with separate +sections for code and data. Opcodes introduced: None (defines a new +bytecode structure but no new opcodes). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py index c01c8ade58e..f08cf8e60ec 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4200_relative_jumps/__init__.py @@ -1,6 +1,7 @@ """ Test cases for [EIP-4200: EOF - Static relative jumps](https://eips.ethereum.org/EIPS/eip-4200). - EIP-4200 replaces dynamic jump instructions with relative jump offsets for - improved control flow predictability. Opcodes introduced: `RJUMP` (`0xE0`), - `RJUMPI` (`0xE1`), `RJUMPV` (`0xE2`). + +EIP-4200 replaces dynamic jump instructions with relative jump offsets for +improved control flow predictability. Opcodes introduced: `RJUMP` (`0xE0`), +`RJUMPI` (`0xE1`), `RJUMPV` (`0xE2`). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py index ba7a019fdd9..3889e560814 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/__init__.py @@ -1,6 +1,7 @@ """ -Test cases for [EIP-4750: EOF - Functions](https://eips.ethereum.org/EIPS/eip-4750) - EIP-4750 formalizes functions in the EVM object format, introducing - callable units of code. Opcodes introduced: `CALLF` (`0xE3`), `RETF` - (`0xE4`). +Test cases for [EIP-4750: EOF - Functions](https://eips.ethereum.org/EIPS/eip-4750). + +EIP-4750 formalizes functions in the EVM object format, introducing +callable units of code. Opcodes introduced: `CALLF` (`0xE3`), `RETF` +(`0xE4`). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_callf_execution.py b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_callf_execution.py index 79df463246a..b0b1d2a0f54 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_callf_execution.py +++ b/tests/unscheduled/eip7692_eof_v1/eip4750_functions/test_callf_execution.py @@ -459,10 +459,12 @@ def test_callf_sneaky_stack_overflow( CALLF where a normal execution would not overflow, but EIP-4750 CALLF rule #3 triggers. - Code Section 0 - Mostly fills the stack Code Section 1 - jumper to 2, so - container verification passes (we want a runtime failure) Code Section 2 - - Could require too much stack, but doesn't as it JUMPFs to 3 Code Section 3 - - Writes canary values + Code Section 0 - Mostly fills the stack + Code Section 1 - jumper to 2, so container verification passes (we want a + runtime failure) + Code Section 2 - Could require too much stack, but doesn't as it JUMPFs + to 3 + Code Section 3 - Writes canary values The intent is to catch implementations of CALLF that don't enforce rule #3 """ @@ -559,9 +561,10 @@ def test_callf_max_stack( #4 triggers. Code Section 0 - calls #1 with the configured height, but we load some - operands so the return stack does not overflow Code Section 1 - expands - stack, calls #2, THEN recursively calls itself until input is zero, and - returns. Code Section 2 - Just returns, zero inputs, zero outputs + operands so the return stack does not overflow + Code Section 1 - expands stack, calls #2, THEN recursively calls itself + until input is zero, and returns. + Code Section 2 - Just returns, zero inputs, zero outputs This will catch CALLF execution rule #3: always fail if the operand stack is full. Not checking rule 3 results in a call to section 2 and not diff --git a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py index c09e062349f..3935e40789c 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip5450_stack/__init__.py @@ -1,9 +1,8 @@ """ -EOF Stack Validation tests - Tests for - [EIP-5450: EOF - Stack Validation](https://eips.ethereum.org/EIPS/eip-5450). +Tests for +[EIP-5450: EOF - Stack Validation](https://eips.ethereum.org/EIPS/eip-5450). - EIP-5450 defines stack validation requirements to ensure consistent - behavior during execution. Opcodes introduced: None (specifies validation - rules for stack usage). +EIP-5450 defines stack validation requirements to ensure consistent +behavior during execution. Opcodes introduced: None (specifies validation +rules for stack usage). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py index d9c5e46fb10..dcd27c79cd4 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/__init__.py @@ -1,5 +1,7 @@ """ -Test cases for [EIP-6206: EOF - JUMPF and non-returning functions](https://eips.ethereum.org/EIPS/eip-6206). - EIP-6206 adds a conditional forward jump instruction and support for - functions without return values. Opcodes introduced: `JUMPF` (`0xE5`). +Test cases for [EIP-6206: EOF - JUMPF and non-returning functions](https:// +eips.ethereum.org/EIPS/eip-6206). + +EIP-6206 adds a conditional forward jump instruction and support for +functions without return values. Opcodes introduced: `JUMPF` (`0xE5`). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py index a1755efb86d..d39e9e035f8 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py @@ -1065,16 +1065,19 @@ def test_eof_calls_msg_depth( gas_limit = int(200000 * (64 / 63) ** 1024) env = Environment(gas_limit=gas_limit) - # Flow of the test: `callee_code` is recursively calling itself, passing - # msg depth as calldata (kept with the `MSTORE(0, ADD(...))`). When maximum - # msg depth is reached the call fails and starts returning. The deep-most - # frame returns: - current reached msg depth (expected to be the maximum - # 1024), with the `MSTORE(32, ADD(...))` - the respective return code of - # the EXT*CALL (expected to be 1 - light failure), with the `MSTORE(64, - # NOOP)`. Note the `NOOP` is just to appease the `Op.MSTORE` call, the - # return code value is actually coming from the `Op.DUP1` When unwinding - # the msg call stack, the intermediate frames return whatever the deeper - # callee returned with the `RETURNDATACOPY` instruction. + # Flow of the test: + # `callee_code` is recursively calling itself, passing msg depth as + # calldata (kept with the `MSTORE(0, ADD(...))`). When maximum msg depth is + # reached the call fails and starts returning. The deep-most frame returns: + # - current reached msg depth (expected to be the maximum 1024), with the + # `MSTORE(32, ADD(...))` + # - the respective return code of the EXT*CALL (expected to be 1 - light + # failure), with the `MSTORE(64, NOOP)`. Note the `NOOP` is just to + # appease the `Op.MSTORE` call, the return code value is actually + # coming from the `Op.DUP1` + # When unwinding the msg call stack, the intermediate frames return + # whatever the deeper callee returned with the `RETURNDATACOPY` + # instruction. # Memory offsets layout: # - 0 - input - msg depth @@ -1093,9 +1096,11 @@ def test_eof_calls_msg_depth( + opcode(address=Op.ADDRESS, args_size=32) # duplicate return code for the `returndatacopy_block` below + Op.DUP1 - # if return code was: - 1, we're in the deep-most frame, - # `deep_most_result_block` returns the actual result - 0, we're in an - # intermediate frame, `returndatacopy_block` only passes on the result + # if return code was: + # - 1, we're in the deep-most frame, `deep_most_result_block` returns + # the actual result + # - 0, we're in an intermediate frame, `returndatacopy_block` only + # passes on the result + Op.RJUMPI[rjump_offset] + returndatacopy_block + deep_most_result_block diff --git a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py index 5d726f12940..ee7f967e8f0 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7480_data_section/__init__.py @@ -1,8 +1,9 @@ """ Test cases for EOF Data section access instructions for EIP-7480. - EIP-7480 specifies instructions for accessing data stored in the dedicated - data section of the EOF format. Full specification: [EIP-7480: EOF - Data - section access instructions](https://eips.ethereum.org/EIPS/eip-7480). - Opcodes introduced: `DATALOAD` (`0xD0`), `DATALOADN` (`0xD1`), `DATASIZE` - (`0xD2`), `DATACOPY` (`0xD3`). + +EIP-7480 specifies instructions for accessing data stored in the dedicated +data section of the EOF format. Full specification: [EIP-7480: EOF - Data +section access instructions](https://eips.ethereum.org/EIPS/eip-7480). +Opcodes introduced: `DATALOAD` (`0xD0`), `DATALOADN` (`0xD1`), `DATASIZE` +(`0xD2`), `DATACOPY` (`0xD3`). """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py index 6fa47cd4da9..1089180f330 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py @@ -142,12 +142,6 @@ def test_initcode_aborts( """ - - - - - - Size of the factory portion of test_eofcreate_deploy_sizes, but as the runtime code is dynamic, we have to use a pre-calculated size """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py index ec480e18ff2..1eaa0fe14cf 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py @@ -177,12 +177,6 @@ def test_initcode_aborts( """ - - - - - - Size of the initcode portion of test_txcreate_deploy_sizes, but as the runtime code is dynamic, we have to use a pre-calculated size """ @@ -798,13 +792,15 @@ def test_reentrant_txcreate( + Op.STOP, storage={0: 0xB17D, 1: 0xB17D}, # a canary to be overwritten ) - # Flow is: reenter flag 0 -> factory -> reenter flag 0 -> initcode -> - # reenter -> reenter flag 1 -> factory -> reenter flag 1 -> (!) initcode -> - # stop, if the EIP-161 nonce bump is not implemented. If it is, it fails - # before second inicode marked (!). Storage in 0 should have the address - # from the outer TXCREATE. Storage in 1 should have 0 from the inner - # TXCREATE. For the created contract storage in `slot_counter` should be 1 - # as initcode executes only once + # Flow is: reenter flag 0 -> factory -> reenter flag 0 -> initcode + # -> reenter -> reenter flag 1 -> factory -> reenter flag 1 + # -> (!) initcode -> stop, + # if the EIP-161 nonce bump is not implemented. If it is, it fails before + # second initcode marked (!). + # Storage in 0 should have the address from the outer TXCREATE. + # Storage in 1 should have 0 from the inner TXCREATE. + # For the created contract storage in `slot_counter` should be 1 as + # initcode executes only once post = { contract_address: Account( storage={ From c6d36484d4b305f177e3a5a2aafa7c6062a4b12c Mon Sep 17 00:00:00 2001 From: danceratopz Date: Wed, 24 Sep 2025 16:43:21 +0200 Subject: [PATCH 13/16] fix: bad string formatting fix in unit test --- src/pytest_plugins/consume/tests/test_consume_args.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pytest_plugins/consume/tests/test_consume_args.py b/src/pytest_plugins/consume/tests/test_consume_args.py index 455c82aee34..58646879261 100644 --- a/src/pytest_plugins/consume/tests/test_consume_args.py +++ b/src/pytest_plugins/consume/tests/test_consume_args.py @@ -137,9 +137,11 @@ def copy_consume_test_paths(pytester: Pytester): shutil.move("conftest.py", target_dir / "conftest.py") -single_test_id = "src/pytest_plugins/consume/direct/" -"test_via_direct.py::test_fixture[CollectOnlyFixtureConsumer-tests/" -f"{MINIMAL_TEST_FILE_NAME}::test_function[fork_Shanghai-state_test]]" +single_test_id = ( + "src/pytest_plugins/consume/direct/" + "test_via_direct.py::test_fixture[CollectOnlyFixtureConsumer-tests/" + f"{MINIMAL_TEST_FILE_NAME}::test_function[fork_Shanghai-state_test]]" +) @pytest.mark.parametrize( From 8486fcb51787d389c68ee0e1480e57a1fda4cd50 Mon Sep 17 00:00:00 2001 From: Felix H Date: Thu, 25 Sep 2025 12:41:59 +0000 Subject: [PATCH 14/16] last batch of manual fixes --- .../blob_transaction.py | 5 +- tests/benchmark/test_worst_bytecode.py | 21 ++-- tests/benchmark/test_worst_compute.py | 35 +++---- tests/benchmark/test_worst_memory.py | 11 ++- .../eip198_modexp_precompile/helpers.py | 13 ++- tests/cancun/eip1153_tstore/__init__.py | 27 ++++-- .../test_tstorage_create_contexts.py | 12 ++- .../test_tstorage_execution_contexts.py | 10 +- .../eip1153_tstore/test_tstore_reentrancy.py | 30 +++--- .../test_beacon_root_contract.py | 4 +- .../eip4844_blobs/test_blobhash_opcode.py | 12 +-- .../test_blobhash_opcode_contexts.py | 6 +- ..._dynamic_create2_selfdestruct_collision.py | 76 ++++++++++----- .../test_reentrancy_selfdestruct_revert.py | 12 ++- .../eip6780_selfdestruct/test_selfdestruct.py | 22 +++-- .../test_selfdestruct_revert.py | 21 ++-- tests/frontier/identity_precompile/common.py | 13 ++- tests/frontier/opcodes/test_call.py | 44 ++++----- .../test_call_and_callcode_gas_calculation.py | 51 +++++----- tests/frontier/opcodes/test_calldataload.py | 13 ++- tests/frontier/opcodes/test_calldatasize.py | 13 ++- .../frontier/precompiles/test_precompiles.py | 20 ++-- tests/frontier/scenarios/common.py | 41 ++++---- .../scenarios/scenarios/call_combinations.py | 16 ++-- tests/istanbul/eip152_blake2/common.py | 34 ++++--- .../eip7823_modexp_upper_bounds/conftest.py | 9 +- .../test_tx_gas_limit.py | 28 ++++-- .../eip7883_modexp_gas_increase/conftest.py | 10 +- .../test_count_leading_zeros.py | 11 ++- .../conftest.py | 5 +- .../test_p256verify.py | 35 ++++--- .../security/test_selfdestruct_balance_bug.py | 4 +- .../conftest.py | 36 ++++--- .../test_bls12_g1mul.py | 4 +- ...t_bls12_variable_length_input_contracts.py | 27 +++--- .../test_block_hashes.py | 15 +-- tests/prague/eip6110_deposits/helpers.py | 26 ++--- .../helpers.py | 8 -- .../prague/eip7251_consolidations/helpers.py | 18 ---- .../conftest.py | 7 +- .../test_refunds.py | 15 +-- tests/prague/eip7702_set_code_tx/test_gas.py | 27 ------ .../eip7702_set_code_tx/test_set_code_txs.py | 20 ++-- .../test_set_code_txs_2.py | 96 ++++++++++++------- .../test_all_opcodes_in_container.py | 14 +-- .../eip3540_eof_v1/test_eof_example.py | 22 +++-- .../eip6206_jumpf/test_jumpf_execution.py | 7 +- .../eip7069_extcall/test_calls.py | 9 +- .../eip7620_eof_create/__init__.py | 19 ++-- .../test_eofcreate_failures.py | 52 ++++++---- .../test_txcreate_failures.py | 24 +++-- tests/unscheduled/eip7692_eof_v1/gas_test.py | 13 ++- 52 files changed, 645 insertions(+), 478 deletions(-) diff --git a/src/ethereum_test_execution/blob_transaction.py b/src/ethereum_test_execution/blob_transaction.py index 66c4e3c236e..21bedbf4ddb 100644 --- a/src/ethereum_test_execution/blob_transaction.py +++ b/src/ethereum_test_execution/blob_transaction.py @@ -124,8 +124,9 @@ def execute( assert blob_response is not None local_blobs_and_proofs = list(versioned_hashes.values()) - assert len(blob_response) == len(local_blobs_and_proofs), "Expected " - f"{len(local_blobs_and_proofs)} blobs and proofs, got {len(blob_response)}." + assert len(blob_response) == len(local_blobs_and_proofs), ( + f"Expected {len(local_blobs_and_proofs)} blobs and proofs, got {len(blob_response)}." + ) for expected_blob, received_blob in zip( local_blobs_and_proofs, blob_response.root, strict=True diff --git a/tests/benchmark/test_worst_bytecode.py b/tests/benchmark/test_worst_bytecode.py index 818522066b9..14227394040 100644 --- a/tests/benchmark/test_worst_bytecode.py +++ b/tests/benchmark/test_worst_bytecode.py @@ -382,10 +382,18 @@ def test_worst_create( initcode_template_contract = pre.deploy_contract(code=code) - # Create the benchmark contract which has the following design: ``` - # PUSH(value) [EXTCODECOPY(full initcode_template_contract) -- Conditional - # that non_zero_data is True]` JUMPDEST (#) (CREATE|CREATE2) - # (CREATE|CREATE2) ... JUMP(#) ``` + # Create the benchmark contract which has the following design: + # ``` + # PUSH(value) + # [EXTCODECOPY(full initcode_template_contract) + # -> Conditional that non_zero_data is True] + # + # JUMPDEST (#) + # (CREATE|CREATE2) + # (CREATE|CREATE2) + # ... + # JUMP(#) + # ``` code_prefix = ( Op.PUSH3(code_size) + Op.PUSH1(value) @@ -407,8 +415,9 @@ def test_worst_create( if opcode == Op.CREATE # For CREATE2: we manually push the arguments because we leverage the # return value of previous CREATE2 calls as salt for the next CREATE2 - # call. - DUP4 is targeting the PUSH1(value) from the code_prefix. - - # DUP3 is targeting the EXTCODESIZE value pushed in code_prefix. + # call. + # - DUP4 is targeting the PUSH1(value) from the code_prefix. + # - DUP3 is targeting the EXTCODESIZE value pushed in code_prefix. else Op.DUP3 + Op.PUSH0 + Op.DUP4 + Op.CREATE2 ) code = code_loop_precompile_call(code_prefix, attack_block, fork) diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index 6799c191d3a..504b2310510 100644 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -381,12 +381,15 @@ def test_worst_keccak( # max_iters_loop contains how many keccak calls can be done per loop. The # loop is as big as possible bounded by the maximum code size. + # # The loop structure is: JUMPDEST + [attack iteration] + PUSH0 + JUMP - # Now calculate available gas for [attack iteration]: Numerator = - # max_code_size-3. The -3 is for the JUMPDEST, PUSH0 and JUMP. Denominator - # = (PUSHN + PUSH1 + KECCAK256 + POP) + PUSH1_DATA + PUSHN_DATA TODO: the - # testing framework uses PUSH1(0) instead of PUSH0 which is suboptimal for - # the attack, whenever this is fixed adjust accordingly. + # + # Now calculate available gas for [attack iteration]: + # Numerator = max_code_size-3. The -3 is for the JUMPDEST, PUSH0 and JUMP + # Denominator = (PUSHN + PUSH1 + KECCAK256 + POP) + PUSH1_DATA + PUSHN_DATA + # + # TODO: the testing framework uses PUSH1(0) instead of PUSH0 which is + # suboptimal for the attack, whenever this is fixed adjust accordingly. start_code = Op.JUMPDEST + Op.PUSH20[optimal_input_length] loop_code = Op.POP(Op.SHA3(Op.PUSH0, Op.DUP1)) end_code = Op.POP + Op.JUMP(Op.PUSH0) @@ -2486,16 +2489,15 @@ def test_worst_mod( mod = initial_mod indexes = [] while mod >= mod_min: - results = [n % mod for n in numerators] # Compute results for each - # numerator. - i = max(range(len(results)), key=results.__getitem__) # And pick - # the best - # one. + # Compute results for each numerator. + results = [n % mod for n in numerators] + # And pick the best one. + i = max(range(len(results)), key=results.__getitem__) mod = results[i] indexes.append(i) - assert len(indexes) > numerators_min_len # Disable if you want to find - # longer MOD chains. + # Disable if you want to find longer MOD chains. + assert len(indexes) > numerators_min_len if len(indexes) > numerators_min_len: break seed += 1 @@ -2650,14 +2652,13 @@ def test_worst_modarith( indexes: list[int] = [] while mod >= mod_min and len(indexes) < op_chain_len: results = [op_fn(a, fixed_arg) % mod for a in args] - i = max(range(len(results)), key=results.__getitem__) # And pick - # the best - # one. + # And pick the best one. + i = max(range(len(results)), key=results.__getitem__) mod = results[i] indexes.append(i) - assert len(indexes) == op_chain_len # Disable if you want to find - # longer op chains. + # Disable if you want to find longer op chains. + assert len(indexes) == op_chain_len if len(indexes) == op_chain_len: break seed += 1 diff --git a/tests/benchmark/test_worst_memory.py b/tests/benchmark/test_worst_memory.py index 4ec6b96df20..689dcf06325 100644 --- a/tests/benchmark/test_worst_memory.py +++ b/tests/benchmark/test_worst_memory.py @@ -228,8 +228,15 @@ def test_worst_returndatacopy( jumpdest = Op.JUMPDEST jump_back = Op.JUMP(len(returndata_gen)) - # The attack loop is constructed as: ``` JUMPDEST(#) RETURNDATACOPY(...) - # RETURNDATACOPY(...) ... STATICCALL(address=helper_contract) JUMP(#) ``` + # The attack loop is constructed as: + # ``` + # JUMPDEST(#) + # RETURNDATACOPY(...) + # RETURNDATACOPY(...) + # ... + # STATICCALL(address=helper_contract) + # JUMP(#) + # ``` # The goal is that once per (big) loop iteration, the helper contract is # called to generate fresh returndata to continue calling RETURNDATACOPY. max_iters_loop = ( diff --git a/tests/byzantium/eip198_modexp_precompile/helpers.py b/tests/byzantium/eip198_modexp_precompile/helpers.py index 1a3855da239..6439c3bfe01 100644 --- a/tests/byzantium/eip198_modexp_precompile/helpers.py +++ b/tests/byzantium/eip198_modexp_precompile/helpers.py @@ -19,7 +19,8 @@ class ModExpInput(TestParameterGroup): exponent (str): The exponent value for the MODEXP precompile. modulus (str): The modulus value for the MODEXP precompile. extra_data (str): Defines extra padded data to be added at the end of - the calldata to the precompile. Defaults to an empty string. + the calldata to the precompile. + Defaults to an empty string. """ @@ -135,9 +136,13 @@ class ModExpOutput(TestParameterGroup): """ Expected test result. - Attributes: call_success (bool): The return_code from CALL, 0 indicates - unsuccessful call (out-of-gas), 1 indicates call succeeded. returned_data - (str): The output returnData is the expected output of the call + Attributes: + call_success (bool): The return_code from CALL, 0 indicates + unsuccessful call (out-of-gas), 1 indicates call + succeeded. + returned_data(str): The output returnData is the expected + output of the call. + """ call_success: bool = True diff --git a/tests/cancun/eip1153_tstore/__init__.py b/tests/cancun/eip1153_tstore/__init__.py index 96885cdf5c5..dabae5a7d57 100644 --- a/tests/cancun/eip1153_tstore/__init__.py +++ b/tests/cancun/eip1153_tstore/__init__.py @@ -19,20 +19,27 @@ class PytestParameterEnum(Enum): can be used to create a parametrize decorator that can be applied to tests, for example, - ```python @TStorageCallContextTestCases.parametrize() def - test_function(test_value): pass ``` + ```python + @TStorageCallContextTestCases.parametrize() + def test_function(test_value): + pass + ``` Classes which derive from this class must define each test case as a different enum field with a dictionary as value. - The dictionary must contain: i. A `description` key with a string value - describing the test case. ii. (Optional) A `pytest_marks` key with a single - mark or list of pytest marks to apply to the test case. For example, - - ``` pytest_marks=pytest.mark.xfail ``` or - - ``` pytest_marks=[pytest.mark.xfail, pytest.mark.skipif] ``` iii. - (Optional) An `id` key with the name of the test. + The dictionary must contain: + i. A `description` key with a string value describing the test case. + ii. (Optional) A `pytest_marks` key with a single mark or list of pytest + marks to apply to the test case. For example: + ``` + pytest_marks=pytest.mark.xfail + ``` + or + ``` + pytest_marks=[pytest.mark.xfail, pytest.mark.skipif] + ``` + iii. (Optional) An `id` key with the name of the test. The rest of the keys in the dictionary are the parameters of the test case. diff --git a/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py index 353a5b1b631..efe83bcd13d 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_create_contexts.py @@ -134,11 +134,13 @@ class InitcodeTestCases(PytestParameterEnum): @InitcodeTestCases.parametrize() class TestTransientStorageInContractCreation: """ - Test transient storage in contract creation contexts. - TSTORE/TLOAD in - initcode should not be able to access the creator's transient storage. - - TSTORE/TLOAD in initcode should be able to access the created contract's - transient storage. - TSTORE/TLOAD in creator contract should be able to use - its own transient storage. + Test transient storage in contract creation contexts. + - TSTORE/TLOAD in initcode should not be able to access the creator's + transient storage. + - TSTORE/TLOAD in initcode should be able to access the created contract's + transient storage. + - TSTORE/TLOAD in creator contract should be able to use its own + transient storage. """ @pytest.fixture() diff --git a/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py b/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py index 90dc128fb02..b710ff493e7 100644 --- a/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py +++ b/tests/cancun/eip1153_tstore/test_tstorage_execution_contexts.py @@ -257,10 +257,8 @@ class CallContextTestCases(PytestParameterEnum, metaclass=DynamicCallContextTest + Op.SSTORE(1, Op.TLOAD(0)) + Op.STOP ), - "callee_bytecode": Op.TSTORE(0, unchecked=True) # calling with stack - # underflow still - # fails - + Op.STOP, + # calling with stack underflow still fails + "callee_bytecode": Op.TSTORE(0, unchecked=True) + Op.STOP, "expected_caller_storage": {0: 0, 1: 420}, "expected_callee_storage": {}, } @@ -275,8 +273,8 @@ class CallContextTestCases(PytestParameterEnum, metaclass=DynamicCallContextTest + Op.SSTORE(1, Op.TLOAD(0)) + Op.STOP ), - "callee_bytecode": Op.TLOAD(0) + Op.STOP, # calling tload does not - # cause the call to fail + # calling tload does not cause the call to fail + "callee_bytecode": Op.TLOAD(0) + Op.STOP, "expected_caller_storage": {0: 1, 1: 420}, "expected_callee_storage": {}, } diff --git a/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py b/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py index e7e3bdf7af0..557eb211ee1 100644 --- a/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py +++ b/tests/cancun/eip1153_tstore/test_tstore_reentrancy.py @@ -56,26 +56,28 @@ def test_tstore_reentrancy( """ Ported .json vectors. - (06_tstoreInReentrancyCallFiller.yml) Reentrant calls access the same - transient storage + (06_tstoreInReentrancyCallFiller.yml) + Reentrant calls access the same transient storage - (07_tloadAfterReentrancyStoreFiller.yml) Successfully returned calls do not - revert transient storage writes + (07_tloadAfterReentrancyStoreFiller.yml) + Successfully returned calls do not revert transient storage writes - (08_revertUndoesTransientStoreFiller.yml) Revert undoes the transient - storage writes from a call. + (08_revertUndoesTransientStoreFiller.yml) + Revert undoes the transient storage writes from a call. - (09_revertUndoesAllFiller.yml) Revert undoes all the transient storage - writes to the same key from the failed call. + (09_revertUndoesAllFiller.yml) + Revert undoes all the transient storage writes to the same key + from the failed call. - (11_tstoreDelegateCallFiller.yml) delegatecall manipulates transient - storage in the context of the current address. + (11_tstoreDelegateCallFiller.yml) + delegatecall manipulates transient storage in the context of + the current address. - (13_tloadStaticCallFiller.yml) Transient storage cannot be manipulated in a - static context, tstore reverts + (13_tloadStaticCallFiller.yml) + Transient storage cannot be manipulated in a static context, tstore reverts - (20_oogUndoesTransientStoreInCallFiller.yml) Out of gas undoes the - transient storage writes from a call. + (20_oogUndoesTransientStoreInCallFiller.yml) + Out of gas undoes the transient storage writes from a call. """ tload_value_set_before_call = 80 tload_value_set_in_call = 90 diff --git a/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py b/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py index ea4647e0007..7ffb004920f 100644 --- a/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py +++ b/tests/cancun/eip4788_beacon_root/test_beacon_root_contract.py @@ -277,8 +277,8 @@ def test_invalid_beacon_root_calldata_value( post: Dict, ): """ - Tests the beacon root contract call using invalid input values: - zero - calldata. + Tests the beacon root contract call using invalid input values: + - zero calldata. Contract should revert. """ diff --git a/tests/cancun/eip4844_blobs/test_blobhash_opcode.py b/tests/cancun/eip4844_blobs/test_blobhash_opcode.py index 471095b6533..c265bd0214a 100644 --- a/tests/cancun/eip4844_blobs/test_blobhash_opcode.py +++ b/tests/cancun/eip4844_blobs/test_blobhash_opcode.py @@ -84,11 +84,11 @@ def create_blob_hashes_list(length: int, max_blobs_per_tx: int) -> List[List[Has Create list of MAX_BLOBS_PER_TX blob hashes using `random_blob_hashes`. Cycle over random_blob_hashes to get a large list of length: - MAX_BLOBS_PER_TX * length -> [0x01, 0x02, 0x03, 0x04, ..., 0x0A, 0x0B, - 0x0C, 0x0D] + MAX_BLOBS_PER_TX * length + -> [0x01, 0x02, 0x03, 0x04, ..., 0x0A, 0x0B, 0x0C, 0x0D] - Then split list into smaller chunks of MAX_BLOBS_PER_TX -> [[0x01, - 0x02, 0x03, 0x04], ..., [0x0a, 0x0b, 0x0c, 0x0d]] + Then split list into smaller chunks of MAX_BLOBS_PER_TX + -> [[0x01, 0x02, 0x03, 0x04], ..., [0x0a, 0x0b, 0x0c, 0x0d]] """ b_hashes = [ random_blob_hashes[i % len(random_blob_hashes)] @@ -281,8 +281,8 @@ def test_blobhash_invalid_blob_index( invalid indexes. Includes cases where the index is negative (`index < 0`) or exceeds the - maximum number of `blob_versioned_hash` values stored: (`index >= - len(tx.message.blob_versioned_hashes)`). + maximum number of `blob_versioned_hash` values stored: + (`index >= len(tx.message.blob_versioned_hashes)`). It confirms that the returned value is a zeroed `bytes32` for each case. """ diff --git a/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py b/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py index 5e8459a3cdd..41d85d2b255 100644 --- a/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py +++ b/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py @@ -76,8 +76,10 @@ def deploy_contract( """ Deploy a contract with the given context and indexes. - Args: pre: The pre state to deploy the contract on indexes: The indexes - to request using the BLOBHASH opcode + Args: + pre: The pre state to deploy the contract on + indexes: The indexes to request using the BLOBHASH opcode + """ match self: case BlobhashContext.BLOBHASH_SSTORE | BlobhashContext.BLOBHASH_RETURN: diff --git a/tests/cancun/eip6780_selfdestruct/test_dynamic_create2_selfdestruct_collision.py b/tests/cancun/eip6780_selfdestruct/test_dynamic_create2_selfdestruct_collision.py index 90582de7807..d46db3d6509 100644 --- a/tests/cancun/eip6780_selfdestruct/test_dynamic_create2_selfdestruct_collision.py +++ b/tests/cancun/eip6780_selfdestruct/test_dynamic_create2_selfdestruct_collision.py @@ -53,16 +53,24 @@ def test_dynamic_create2_selfdestruct_collision( Perform a CREATE2, make sure that the initcode sets at least a couple of storage keys, then on a different call, in the same tx, perform a - self-destruct. Then: a) on the same tx, attempt to recreate the contract - <=== Covered in this test 1) and create2 contract already in the state 2) - and create2 contract is not in the state b) on a different tx, attempt to - recreate the contract Perform a CREATE2, make sure that the initcode sets - at least a couple of storage keys, then in a different tx, perform a - self-destruct. Then: a) on the same tx, attempt to recreate the contract b) - on a different tx, attempt to recreate the contract Verify that the test - case described in - https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22156575/2024-01-06 - +Mainnet+Halting+Event + self-destruct. + Then: + a) on the same tx, attempt to recreate the contract + -> Covered in this test + 1) and create2 contract already in the state + 2) and create2 contract is not in the state + b) on a different tx, attempt to recreate the contract + + Perform a CREATE2, make sure that the initcode sets at least a couple + of storage keys, then in a different tx, perform a self-destruct. + + Then: + a) on the same tx, attempt to recreate the contract + b) on a different tx, attempt to recreate the contract + + Check the test case described in + https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/ + 22156575/2024-01-06+Mainnet+Halting+Event """ assert call_create2_contract_in_between or call_create2_contract_at_the_end, "invalid test" @@ -228,14 +236,24 @@ def test_dynamic_create2_selfdestruct_collision_two_different_transactions( Perform a CREATE2, make sure that the initcode sets at least a couple of storage keys, then on a different call, in the same tx, perform a - self-destruct. Then: a) on the same tx, attempt to recreate the contract 1) - and create2 contract already in the state 2) and create2 contract is not in - the state b) on a different tx, attempt to recreate the contract <=== - Covered in this test Perform a CREATE2, make sure that the initcode sets at + self-destruct. + + Then: + a) on the same tx, attempt to recreate the contract + 1) and create2 contract already in the state + 2) and create2 contract is not in the state + b) on a different tx, attempt to recreate the contract + -> Covered in this test + + Perform a CREATE2, make sure that the initcode sets at least a couple of storage keys, then in a different tx, perform a - self-destruct. Then: a) on the same tx, attempt to recreate the contract b) - on a different tx, attempt to recreate the contract Verify that the test - case described in + self-destruct. + + Then: + a) on the same tx, attempt to recreate the contract + b) on a different tx, attempt to recreate the contract + + Check the test case described in https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22156575/2024-01-06 +Mainnet+Halting+Event """ @@ -374,7 +392,9 @@ def test_dynamic_create2_selfdestruct_collision_two_different_transactions( storage={ code_worked: 0x01, # Second create2 will not collide before Cancun as the first tx - # calls selfdestruct After cancun it will collide only if + # calls selfdestruct + # + # After cancun it will collide only if # create2_dest_already_in_state otherwise the first tx creates and # deletes it second_create2_result: ( @@ -461,13 +481,21 @@ def test_dynamic_create2_selfdestruct_collision_multi_tx( Perform a CREATE2, make sure that the initcode sets at least a couple of storage keys, then on a different call, in the same or different tx but - same block, perform a self-destruct. Then: a) on the same tx, attempt to - recreate the contract b) on a different tx, attempt to recreate the - contract Perform a CREATE2, make sure that the initcode sets at least a + same block, perform a self-destruct. + Then: + a) on the same tx, attempt to recreate the contract + b) on a different tx, attempt to recreate the contract + + Perform a CREATE2, make sure that the initcode sets at least a couple of storage keys, then in a different tx, perform a self-destruct. - Then: a) on the same tx, attempt to recreate the contract <=== - Covered in this test b) on a different tx, attempt to recreate the contract - <=== Covered in this test Verify that the test case described in + + Then: + a) on the same tx, attempt to recreate the contract + -> Covered in this test + b) on a different tx, attempt to recreate the contract + -> Covered in this test + + Check the test case described in https://lf-hyperledger.atlassian.net/wiki/spaces/BESU/pages/22156575/2024-01-06 +Mainnet+Halting+Event """ diff --git a/tests/cancun/eip6780_selfdestruct/test_reentrancy_selfdestruct_revert.py b/tests/cancun/eip6780_selfdestruct/test_reentrancy_selfdestruct_revert.py index 6706ea1e08e..36d13853c46 100644 --- a/tests/cancun/eip6780_selfdestruct/test_reentrancy_selfdestruct_revert.py +++ b/tests/cancun/eip6780_selfdestruct/test_reentrancy_selfdestruct_revert.py @@ -145,11 +145,13 @@ def test_reentrancy_selfdestruct_revert( """ Suicide reentrancy scenario. - Call|Callcode|Delegatecall the contract S. S self destructs. Call the - revert proxy contract R. R Calls|Callcode|Delegatecall S. S self destructs - (for the second time). R reverts (including the effects of the second - selfdestruct). It is expected the S is self destructed after the - transaction. + Call|Callcode|Delegatecall the contract S. + S self destructs. + Call the revert proxy contract R. + R Calls|Callcode|Delegatecall S. + S self destructs (for the second time). + R reverts (including the effects of the second selfdestruct). + It is expected the S is self destructed after the transaction. """ post = { # Second caller unchanged as call gets reverted diff --git a/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py b/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py index a0f40734a13..79daddd8d25 100644 --- a/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py +++ b/tests/cancun/eip6780_selfdestruct/test_selfdestruct.py @@ -475,8 +475,9 @@ def test_self_destructing_initcode_create_tx( Behavior should be the same before and after EIP-6780. - Test using: - Different initial balances for the self-destructing contract - - Different transaction value amounts + Test using: + - Different initial balances for the self-destructing contract + - Different transaction value amounts """ tx = Transaction( sender=sender, @@ -500,8 +501,8 @@ def test_self_destructing_initcode_create_tx( state_test(pre=pre, post=post, tx=tx) -@pytest.mark.parametrize("create_opcode", [Op.CREATE2]) # Can only recreate -# using CREATE2 +# Can only recreate using CREATE2 +@pytest.mark.parametrize("create_opcode", [Op.CREATE2]) @pytest.mark.parametrize( "sendall_recipient_addresses", [ @@ -528,10 +529,10 @@ def test_recreate_self_destructed_contract_different_txs( selfdestruct_contract_initial_balance: int, sendall_recipient_addresses: List[Address], create_opcode: Op, - recreate_times: int, # Number of times to recreate the contract in - # different transactions - call_times: int, # Number of times to call the self-destructing contract - # in the same tx + # Number of times to recreate the contract in different transactions + recreate_times: int, + # Number of times to call the self-destructing contract in the same tx + call_times: int, ): """ Test that a contract can be recreated after it has self-destructed, over @@ -539,8 +540,9 @@ def test_recreate_self_destructed_contract_different_txs( Behavior should be the same before and after EIP-6780. - Test using: - Different initial balances for the self-destructing contract - - Contract creating opcodes that are not CREATE + Test using: + - Different initial balances for the self-destructing contract + - Contract creating opcodes that are not CREATE """ selfdestruct_contract_initcode = Initcode(deploy_code=selfdestruct_code) initcode_copy_from_address = pre.deploy_contract(selfdestruct_contract_initcode) diff --git a/tests/cancun/eip6780_selfdestruct/test_selfdestruct_revert.py b/tests/cancun/eip6780_selfdestruct/test_selfdestruct_revert.py index 0e5c86fde5c..e42f98c6d1a 100644 --- a/tests/cancun/eip6780_selfdestruct/test_selfdestruct_revert.py +++ b/tests/cancun/eip6780_selfdestruct/test_selfdestruct_revert.py @@ -63,9 +63,11 @@ def recursive_revert_contract_code( selfdestruct_with_transfer_contract_address: Address, ) -> Bytecode: """ - Contract code that: Given selfdestructable contract A, transfer value to A - and call A.selfdestruct. Then, recurse into a new call which transfers - value to A, call A.selfdestruct, and reverts. + Contract code that: + Given selfdestructable contract A, transfer value to A + and call A.selfdestruct. + Then, recurse into a new call which transfers value to A, + call A.selfdestruct, and reverts. """ # Common prefix for all three cases: # case 1: selfdestruct_on_outer_call=1 @@ -362,9 +364,8 @@ def test_selfdestruct_created_in_same_tx_with_revert( # noqa SC200 Op.CREATE( 0, 0, - len(bytes(selfdestruct_with_transfer_contract_initcode)), # Value - # # - # Offset + # Value Offset + len(bytes(selfdestruct_with_transfer_contract_initcode)), ), ) @@ -502,11 +503,11 @@ def test_selfdestruct_not_created_in_same_tx_with_revert( code=selfdestruct_with_transfer_contract_code, storage=Storage( { - # 2 value transfers: 1 in outer call, 1 in reverted inner - # call + # 2 value transfers: + # 1 in outer call, 1 in reverted inner call 0: 1, # type: ignore - # 2 selfdestructs: 1 in outer call, 1 in reverted inner - # call # noqa SC100 + # 2 selfdestructs: + # 1 in outer call, 1 in reverted inner call 1: 0, # type: ignore } ), diff --git a/tests/frontier/identity_precompile/common.py b/tests/frontier/identity_precompile/common.py index fcf28be3eb4..be7dc17c42f 100644 --- a/tests/frontier/identity_precompile/common.py +++ b/tests/frontier/identity_precompile/common.py @@ -42,13 +42,16 @@ def generate_identity_call_bytecode( Generate bytecode for calling the identity precompile with given memory values. - Args: storage (Storage): The storage object to use for storing values. - call_type (Op): The type of call opcode (CALL or CALLCODE). memory_values - (Tuple[int, ...]): Values to store in memory before the call. call_args - (CallArgs): Arguments for the CALL opcode. call_succeeds (bool): Whether - the call should succeed or not. + Args: + storage (Storage): The storage object to use for storing values. + call_type (Op): The type of call opcode (CALL or CALLCODE). + memory_values(Tuple[int, ...]): Values to store in memory before + the call. + call_args(CallArgs): Arguments for the CALL opcode. + call_succeeds (bool): Whether the call should succeed or not. Returns: Bytecode: The generated bytecode for the identity precompile call. + """ code = Bytecode() diff --git a/tests/frontier/opcodes/test_call.py b/tests/frontier/opcodes/test_call.py index 301d49d0fe9..e5fead6786c 100644 --- a/tests/frontier/opcodes/test_call.py +++ b/tests/frontier/opcodes/test_call.py @@ -37,17 +37,16 @@ def test_call_large_offset_mstore( call_measure = CodeGasMeasure( code=Op.CALL(gas=0, ret_offset=mem_offset, ret_size=0), - overhead_cost=gsc.G_VERY_LOW * len(Op.CALL.kwargs), # Cost of pushing - # CALL args + # Cost of pushing CALL args + overhead_cost=gsc.G_VERY_LOW * len(Op.CALL.kwargs), extra_stack_items=1, # Because CALL pushes 1 item to the stack sstore_key=0, stop=False, # Because it's the first CodeGasMeasure ) mstore_measure = CodeGasMeasure( code=Op.MSTORE(offset=mem_offset, value=1), - overhead_cost=gsc.G_VERY_LOW * len(Op.MSTORE.kwargs), # Cost of - # pushing MSTORE - # args + # Cost of pushing MSTORE args + overhead_cost=gsc.G_VERY_LOW * len(Op.MSTORE.kwargs), extra_stack_items=0, sstore_key=1, ) @@ -101,23 +100,25 @@ def test_call_memory_expands_on_early_revert( sender = pre.fund_eoa() gsc = fork.gas_costs() - ret_size = 128 # arbitrary number, greater than memory size to trigger an - # expansion + # arbitrary number, greater than memory size to trigger an expansion + ret_size = 128 call_measure = CodeGasMeasure( - code=Op.CALL(gas=0, value=100, ret_size=ret_size), # CALL with value - overhead_cost=gsc.G_VERY_LOW * len(Op.CALL.kwargs), # Cost of pushing - # CALL args - extra_stack_items=1, # Because CALL pushes 1 item to the stack + # CALL with value + code=Op.CALL(gas=0, value=100, ret_size=ret_size), + # Cost of pushing CALL args + overhead_cost=gsc.G_VERY_LOW * len(Op.CALL.kwargs), + # Because CALL pushes 1 item to the stack + extra_stack_items=1, sstore_key=0, - stop=False, # Because it's the first CodeGasMeasure + # Because it's the first CodeGasMeasure + stop=False, ) mstore_measure = CodeGasMeasure( - code=Op.MSTORE(offset=ret_size // 2, value=1), # Low offset for not - # expanding memory - overhead_cost=gsc.G_VERY_LOW * len(Op.MSTORE.kwargs), # Cost of - # pushing MSTORE - # args + # Low offset for not expanding memory + code=Op.MSTORE(offset=ret_size // 2, value=1), + # Cost of pushing MSTORE args + overhead_cost=gsc.G_VERY_LOW * len(Op.MSTORE.kwargs), extra_stack_items=0, sstore_key=1, ) @@ -133,8 +134,8 @@ def test_call_memory_expands_on_early_revert( ) memory_expansion_gas_calc = fork.memory_expansion_gas_calculator() - # call cost: address_access_cost + new_acc_cost + memory_expansion_cost + - # value - stipend + # call cost: + # address_access_cost+new_acc_cost+memory_expansion_cost+value-stipend call_cost = ( gsc.G_COLD_ACCOUNT_ACCESS + gsc.G_NEW_ACCOUNT @@ -183,9 +184,8 @@ def test_call_large_args_offset_size_zero( call_measure = CodeGasMeasure( code=call_opcode(gas=0, args_offset=very_large_offset, args_size=0), - overhead_cost=gsc.G_VERY_LOW * len(call_opcode.kwargs), # Cost of - # pushing - # xCALL args + # Cost of pushing xCALL args + overhead_cost=gsc.G_VERY_LOW * len(call_opcode.kwargs), extra_stack_items=1, # Because xCALL pushes 1 item to the stack sstore_key=0, ) diff --git a/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py b/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py index 223b9501236..61ac377bacc 100644 --- a/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py +++ b/tests/frontier/opcodes/test_call_and_callcode_gas_calculation.py @@ -47,29 +47,25 @@ from ethereum_test_vm import Opcodes as Op """ - - -PUSH opcode cost is 3, GAS opcode cost is 2. We need 6 PUSH's and one GAS to -fill the stack for both CALL & CALLCODE, in the callee contract. +PUSH opcode cost is 3, GAS opcode cost is 2. +We need 6 PUSH's and one GAS to fill the stack for both CALL & CALLCODE, +in the callee contract. """ CALLEE_INIT_STACK_GAS = 6 * 3 + 2 """ - - -CALL gas breakdowns: (https://www.evm.codes/#f1) memory_exp_cost + -code_exec_cost + address_access_cost + positive_value_cost + empty_account_cost +CALL gas breakdowns: (https://www.evm.codes/#f1) +memory_exp_cost + code_exec_cost + address_access_cost + +positive_value_cost + empty_account_cost = 0 + 0 + 2600 + 9000 + 25000 = 36600 """ CALL_GAS = 36600 CALL_SUFFICIENT_GAS = CALL_GAS + CALLEE_INIT_STACK_GAS """ - - -CALLCODE gas breakdowns: (https://www.evm.codes/#f2) memory_exp_cost + -code_exec_cost + address_access_cost + positive_value_cost = 0 + 0 + 2600 + -9000 = 11600 +CALLCODE gas breakdowns: (https://www.evm.codes/#f2) +memory_exp_cost + code_exec_cost + address_access_cost + +positive_value_cost = 0 + 0 + 2600 + 9000 = 11600 """ CALLCODE_GAS = 11600 CALLCODE_SUFFICIENT_GAS = CALLCODE_GAS + CALLEE_INIT_STACK_GAS @@ -78,9 +74,12 @@ @pytest.fixture def callee_code(pre: Alloc, callee_opcode: Op) -> Bytecode: """ - Code called by the caller contract: PUSH1 0x00 * 4 PUSH1 0x01 <- for - positive value transfer PUSH2 Contract.nonexistent GAS <- value doesn't - matter CALL/CALLCODE. + Code called by the caller contract: + PUSH1 0x00 * 4 + PUSH1 0x01 <- for positive value transfer + PUSH2 Contract.nonexistent + GAS <- value doesn't matter + CALL/CALLCODE. """ # The address needs to be empty and different for each execution of the # fixture, otherwise the calculations (empty_account_cost) are incorrect. @@ -102,9 +101,13 @@ def callee_address(pre: Alloc, callee_code: Bytecode) -> Address: @pytest.fixture def caller_code(caller_gas_limit: int, callee_address: Address) -> Bytecode: """ - Code to CALL the callee contract: PUSH1 0x00 * 5 PUSH2 Contract.callee - PUSH2 caller_gas <- gas limit set for CALL to callee contract CALL PUSH1 - 0x00 SSTORE. + Code to CALL the callee contract: + PUSH1 0x00 * 5 + PUSH2 Contract.callee + PUSH2 caller_gas <- gas limit set for CALL to callee contract + CALL + PUSH1 0x00 + SSTORE. """ return Op.SSTORE(0, Op.CALL(caller_gas_limit, callee_address, 0, 0, 0, 0, 0)) @@ -112,9 +115,13 @@ def caller_code(caller_gas_limit: int, callee_address: Address) -> Bytecode: @pytest.fixture def caller_address(pre: Alloc, caller_code: Bytecode) -> Address: """ - Code to CALL the callee contract: PUSH1 0x00 * 5 PUSH2 Contract.callee - PUSH2 caller_gas <- gas limit set for CALL to callee contract CALL PUSH1 - 0x00 SSTORE. + Code to CALL the callee contract: + PUSH1 0x00 * 5 + PUSH2 Contract.callee + PUSH2 caller_gas <- gas limit set for CALL to callee contract + CALL + PUSH1 0x00 + SSTORE. """ return pre.deploy_contract(caller_code, balance=0x03) diff --git a/tests/frontier/opcodes/test_calldataload.py b/tests/frontier/opcodes/test_calldataload.py index 8dbd00d7542..9776e66e054 100644 --- a/tests/frontier/opcodes/test_calldataload.py +++ b/tests/frontier/opcodes/test_calldataload.py @@ -52,13 +52,16 @@ def test_calldataload( """ Test `CALLDATALOAD` opcode. - Tests two scenarios: - calldata_source is "contract": CALLDATALOAD reads - from calldata passed by another contract - calldata_source is "tx": - CALLDATALOAD reads directly from transaction calldata + Tests two scenarios: + - calldata_source is "contract": CALLDATALOAD reads from calldata + passed by another contract + - calldata_source is "tx": CALLDATALOAD reads directly from + transaction calldata Based on - https://github.com/ethereum/tests/blob/ae4791077e8fcf716136e70fe8392f1a1f1495fb - /src/GeneralStateTestsFiller/VMTests/vmTests/calldatacopyFiller.yml + https://github.com/ethereum/tests/blob/ + ae4791077e8fcf716136e70fe8392f1a1f1495fb/src/ + GeneralStateTestsFiller/VMTests/vmTests/calldatacopyFiller.yml """ contract_address = pre.deploy_contract( Op.SSTORE(0, Op.CALLDATALOAD(offset=calldata_offset)) + Op.STOP, diff --git a/tests/frontier/opcodes/test_calldatasize.py b/tests/frontier/opcodes/test_calldatasize.py index 9134290e48b..2106524015d 100644 --- a/tests/frontier/opcodes/test_calldatasize.py +++ b/tests/frontier/opcodes/test_calldatasize.py @@ -29,13 +29,16 @@ def test_calldatasize( """ Test `CALLDATASIZE` opcode. - Tests two scenarios: - calldata_source is "contract": CALLDATASIZE reads - from calldata passed by another contract - calldata_source is "tx": - CALLDATASIZE reads directly from transaction calldata + Tests two scenarios: + - calldata_source is "contract": CALLDATASIZE reads from calldata + passed by another contract + - calldata_source is "tx": CALLDATASIZE reads directly from + transaction calldata Based on - https://github.com/ethereum/tests/blob/81862e4848585a438d64f911a19b3825f0f4cd95 - /src/GeneralStateTestsFiller/VMTests/vmTests/calldatasizeFiller.yml + https://github.com/ethereum/tests/blob/ + 81862e4848585a438d64f911a19b3825f0f4cd95/src/ + GeneralStateTestsFiller/VMTests/vmTests/calldatasizeFiller.yml """ contract_address = pre.deploy_contract(Op.SSTORE(key=0x0, value=Op.CALLDATASIZE)) calldata = b"\x01" * args_size diff --git a/tests/frontier/precompiles/test_precompiles.py b/tests/frontier/precompiles/test_precompiles.py index 4ec016cfd01..b7ba6b91428 100644 --- a/tests/frontier/precompiles/test_precompiles.py +++ b/tests/frontier/precompiles/test_precompiles.py @@ -21,12 +21,14 @@ def precompile_addresses(fork: Fork) -> Iterator[Tuple[Address, bool]]: Yield the addresses of precompiled contracts and their support status for a given fork. - Args: fork (Fork): The fork instance containing precompiled contract - information. + Args: + fork (Fork): The fork instance containing precompiled + contract information. Yields: Iterator[Tuple[str, bool]]: A tuple containing the address in hexadecimal format and a boolean indicating whether the address is a supported precompile. + """ supported_precompiles = fork.precompiles() @@ -59,17 +61,21 @@ def test_precompiles( """ Tests the behavior of precompiled contracts in the Ethereum state test. - Args: state_test (StateTestFiller): The state test filler object used to - run the test. address (str): The address of the precompiled contract to - test. precompile_exists (bool): A flag indicating whether the precompiled - contract exists at the given address. pre (Alloc): The allocation object - used to deploy the contract and set up the initial state. + Args: + state_test (StateTestFiller): The state test filler object used to + run the test. + address (str): The address of the precompiled contract to test. + precompile_exists (bool): A flag indicating whether the precompiled + contract exists at the given address. + pre (Alloc): The allocation object used to deploy the contract and + set up the initial state. This test deploys a contract that performs two CALL operations to the specified address and a fixed address (0x10000), measuring the gas used for each call. It then stores the difference in gas usage in storage slot 0. The test verifies the expected storage value based on whether the precompiled contract exists at the given address. + """ env = Environment() diff --git a/tests/frontier/scenarios/common.py b/tests/frontier/scenarios/common.py index ff72071545c..1d7a95296c7 100644 --- a/tests/frontier/scenarios/common.py +++ b/tests/frontier/scenarios/common.py @@ -62,10 +62,12 @@ class ProgramResult: """ Describe expected result of a program. - Attributes: result (int | ScenarioExpectOpcode): The result of the program - from_fork (Fork): The result is only valid from this fork (default: - Frontier) static_support (bool): Can be verified in static context - (default: True) + Attributes: + result (int | ScenarioExpectOpcode): The result of the program + from_fork (Fork): The result is only valid from this fork + (default: Frontier) + static_support (bool): Can be verified in static context (default: True) + """ result: int | ScenarioExpectOpcode @@ -152,10 +154,12 @@ class ScenarioGeneratorInput: """ Parameters for the scenario generator function. - Attributes: fork (Fork): Fork for which we ask to generate scenarios pre - (Alloc): Access to the state to be able to deploy contracts into pre - operation (Bytecode): Evm bytecode program that will be tested - external_address (Address): Static external address for ext opcodes + Attributes: + fork (Fork): Fork for which we ask to generate scenarios + pre(Alloc): Access to the state to be able to deploy contracts into pre + operation (Bytecode): Evm bytecode program that will be tested + external_address (Address): Static external address for ext opcodes + """ fork: Fork @@ -168,11 +172,14 @@ class Scenario: """ Describe test scenario that will be run in test for each program. - Attributes: category (str): Scenario category name name (str): Scenario - name for the test vector code (Address): Address that is an entry point for - scenario code env (ScenarioEnvironment): Evm values for - ScenarioExpectAddress map reverting (bool): If scenario reverts program - execution, making result 0 (default: False) + Attributes: + category (str): Scenario category name + name (str): Scenario name for the test vector + code (Address): Address that is an entry point for scenario code + env (ScenarioEnvironment): Evm values for ScenarioExpectAddress map + reverting (bool): If scenario reverts program execution, + making result 0 (default: False) + """ category: str @@ -184,10 +191,10 @@ class Scenario: def make_gas_hash_contract(pre: Alloc) -> Address: """ - Contract that spends unique amount of gas based on input Used for the - values we can't predict, can be gas consuming on high values So that if we - can't check exact value in expect section, we at least could spend unique - gas amount. + Contract that spends unique amount of gas based on input. + Used for the values we can't predict, can be gas consuming on high values. + So that if we can't check exact value in expect section, we at least + could spend unique gas amount. """ gas_hash_address = pre.deploy_contract( code=Op.MSTORE(0, 0) diff --git a/tests/frontier/scenarios/scenarios/call_combinations.py b/tests/frontier/scenarios/scenarios/call_combinations.py index f5b42c48695..318c48d08e3 100644 --- a/tests/frontier/scenarios/scenarios/call_combinations.py +++ b/tests/frontier/scenarios/scenarios/call_combinations.py @@ -59,10 +59,14 @@ def generate(self) -> List[Scenario]: test at scenario_input.operation_contract and put it in the context of call combinations. - Example: root_contract -> call -> scenario_contract -> first_call -> - sub_contract sub_contact -> second_call -> code We assume that code - always returns it's result That we pass as return value in - scenario_contract for the post state verification + Example: + root_contract -> call -> scenario_contract -> first_call -> + sub_contract sub_contact -> second_call -> code + + We assume that code always returns its result. + That we pass as return value in scenario_contract for the + post state verification. + """ scenarios_list: List[Scenario] = [] @@ -168,8 +172,8 @@ def _generate_two_call_scenario(self, first_call: Opcode, second_call: Opcode) - def _compute_code_caller() -> Address: """ Calculate who is the code caller in program_contract's code in - given sequence root -CALL-> scenario_contract -(first_call)-> - sub_contract -(second_call)-> program. + given sequence root -CALL-> scenario_contract -(first_call) + -> sub_contract -(second_call)-> program. """ code_caller: Address = root_contract if first_call == Op.DELEGATECALL: diff --git a/tests/istanbul/eip152_blake2/common.py b/tests/istanbul/eip152_blake2/common.py index b2f159dd080..2f0ab7ba7cb 100644 --- a/tests/istanbul/eip152_blake2/common.py +++ b/tests/istanbul/eip152_blake2/common.py @@ -13,15 +13,21 @@ class Blake2bInput(TestParameterGroup): Helper class that defines the BLAKE2b precompile inputs and creates the call data from them. Returns all inputs encoded as bytes. - Attributes: rounds_length (int): An optional integer representing the bytes - length for the number of rounds. Defaults to the expected length of 4. - rounds (int | str): A hex string or integer value representing the number - of rounds. h (str): A hex string that represents the state vector. m (str): - A hex string that represents the message block vector. t_0 (int | str): A - hex string or integer value that represents the first offset counter. t_1 - (int | str): A hex string or integer value that represents the second - offset counter. f (bool): An optional boolean that represents the final - block indicator flag. Defaults to True. + Attributes: + rounds_length (int): An optional integer representing the bytes + length for the number of rounds. + Defaults to the expected length of 4. + rounds (int | str): A hex string or integer value representing the number + of rounds. + h (str): A hex string that represents the state vector. + m (str): A hex string that represents the message block vector. + t_0 (int | str): A hex string or integer value that represents + the first offset counter. + t_1(int | str): A hex string or integer value that represents the second + offset counter. + f (bool): An optional boolean that represents the final block indicator + flag. Defaults to True. + """ rounds_length: int = Spec.BLAKE2_PRECOMPILE_ROUNDS_LENGTH @@ -55,10 +61,12 @@ class ExpectedOutput(TestParameterGroup): """ Expected test result. - Attributes: call_succeeds (str | bool): A hex string or boolean to indicate - whether the call was successful or not. data_1 (str): String value of the - first updated state vector. data_2 (str): String value of the second - updated state vector. + Attributes: + call_succeeds (str | bool): A hex string or boolean to indicate + whether the call was successful or not. + data_1 (str): String value of the first updated state vector. + data_2 (str): String value of the second updated state vector. + """ call_succeeds: str | bool diff --git a/tests/osaka/eip7823_modexp_upper_bounds/conftest.py b/tests/osaka/eip7823_modexp_upper_bounds/conftest.py index 1eb4fcafdf7..663cd5456d3 100644 --- a/tests/osaka/eip7823_modexp_upper_bounds/conftest.py +++ b/tests/osaka/eip7823_modexp_upper_bounds/conftest.py @@ -60,9 +60,12 @@ def gas_measure_contract( Deploys a contract that measures ModExp gas consumption and execution result. - Always stored: storage[0]: precompile call success storage[1]: return data - length from precompile Only if the precompile call succeeds: storage[2]: - gas consumed by precompile storage[3]: hash of return data from precompile + Always stored: + storage[0]: precompile call success + storage[1]: return data length from precompile + Only if the precompile call succeeds: + storage[2]: gas consumed by precompile + storage[3]: hash of return data from precompile """ call_code = Op.CALL( precompile_gas, diff --git a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py index 5eca0d23e58..5c23a5571b9 100644 --- a/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py +++ b/tests/osaka/eip7825_transaction_gas_limit_cap/test_tx_gas_limit.py @@ -311,9 +311,13 @@ def test_tx_gas_limit_cap_full_calldata( # Gas cost calculation based on EIP-7623: # (https://eips.ethereum.org/EIPS/eip-7623) - # Simplified in this test case: - No execution gas used (no opcodes are - # executed) - Not a contract creation (no initcode) - # Token accounting: tokens_in_calldata = zero_bytes + 4 * non_zero_bytes + # + # Simplified in this test case: + # - No execution gas used (no opcodes are executed) + # - Not a contract creation (no initcode) + # + # Token accounting: + # tokens_in_calldata = zero_bytes + 4 * non_zero_bytes byte_data = b"\x00" if zero_byte else b"\xff" @@ -383,10 +387,14 @@ def test_tx_gas_limit_cap_contract_creation( # Craft a contract creation transaction that exceeds the transaction gas # limit cap - # Total cost = intrinsic cost (base tx cost + contract creation cost) + - # calldata cost + init code execution cost - # The contract body is filled with JUMPDEST instructions, so: total cost = - # intrinsic cost + calldata cost + (num_of_jumpdest * 1 gas) + # + # Total cost = + # intrinsic cost (base tx cost + contract creation cost) + # + calldata cost + init code execution cost + # + # The contract body is filled with JUMPDEST instructions, so: + # total cost = intrinsic cost + calldata cost + (num_of_jumpdest * 1 gas) + # # If the total cost exceeds the tx limit cap, the transaction should fail total_cost = intrinsic_cost(contract_creation=True, calldata=code) + num_of_bytes @@ -597,9 +605,11 @@ def test_tx_gas_limit_cap_authorized_tx( # 21000 + 16 * non-zero calldata bytes + 4 * zero calldata bytes + 1900 * # access list storage key count + 2400 * access list address count + # PER_EMPTY_ACCOUNT_COST * authorization list length + # # There is no calldata and no storage keys in this test case and the access - # address list count is equal to the authorization list length total cost = - # 21000 + (2400 + 25_000) * auth_list_length + # address list count is equal to the authorization list length + # + # total cost = 21000 + (2400 + 25_000) * auth_list_length auth_address = pre.deploy_contract(code=Op.STOP) diff --git a/tests/osaka/eip7883_modexp_gas_increase/conftest.py b/tests/osaka/eip7883_modexp_gas_increase/conftest.py index 559ceebd902..2740800c663 100644 --- a/tests/osaka/eip7883_modexp_gas_increase/conftest.py +++ b/tests/osaka/eip7883_modexp_gas_increase/conftest.py @@ -111,9 +111,13 @@ def gas_measure_contract( Deploys a contract that measures ModExp gas consumption and execution result. - Always stored: storage[0]: precompile call success storage[1]: return data - length from precompile Only if the precompile call succeeds: storage[2]: - gas consumed by precompile storage[3]: hash of return data from precompile + Always stored: + storage[0]: precompile call success + storage[1]: return data length from precompile + + Only if the precompile call succeeds: + storage[2]: gas consumed by precompile + storage[3]: hash of return data from precompile """ assert call_opcode in [Op.CALL, Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL] value = [0] if call_opcode in [Op.CALL, Op.CALLCODE] else [] diff --git a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py index 31ad6c7dacd..f2592a81898 100644 --- a/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py +++ b/tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py @@ -332,11 +332,12 @@ def test_clz_fork_transition(blockchain_test: BlockchainTestFiller, pre: Alloc): ), callee_address: Account( storage={ - 14_999: "0xdeadbeef", # CLZ not valid before fork, storage - # unchanged - 15_000: 155, # CLZ valid on transition block, CLZ(1 << - # 100) = 155 - 15_001: 155, # CLZ continues to be valid after transition + # CLZ not valid before fork, storage unchanged + 14_999: "0xdeadbeef", + # CLZ valid on transition block, CLZ(1 << 100) = 155 + 15_000: 155, + # CLZ continues to be valid after transition + 15_001: 155, } ), }, diff --git a/tests/osaka/eip7951_p256verify_precompiles/conftest.py b/tests/osaka/eip7951_p256verify_precompiles/conftest.py index e944f994572..179eebd87ca 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/conftest.py +++ b/tests/osaka/eip7951_p256verify_precompiles/conftest.py @@ -61,8 +61,11 @@ def call_opcode() -> Op: @pytest.fixture def call_contract_post_storage() -> Storage: """ - Storage of the test contract after the transaction is executed. Note: + Storage of the test contract after the transaction is executed. + + Note: Fixture `call_contract_code` fills the actual expected storage values. + """ return Storage() diff --git a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py index e954a85cbe7..e908fe23107 100644 --- a/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py +++ b/tests/osaka/eip7951_p256verify_precompiles/test_p256verify.py @@ -179,9 +179,10 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t ), pytest.param( # Invalid curve attack: This point satisfies y² = x³ - 3x + 1 (mod - # p) instead of the correct P-256 equation y² = x³ - 3x + b where b - # = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53... + # p) instead of the correct P-256 equation y² = x³ - 3x + b where + # b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53... # ...B0F63BCE3C3E27D2604B + # # This tests that the implementation properly validates the curve # equation and rejects points on different curves (CVE-2020-0601 # class vulnerability) @@ -193,9 +194,11 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t id="invalid_curve_attack_b_equals_one", ), pytest.param( - # Invalid curve attack: Singular curve with b = 0 Point satisfies - # y² = x³ - 3x (mod p) - a singular/degenerate curve Singular - # curves have discriminant = 0 and provide no security guarantees + # Invalid curve attack: Singular curve with b = 0 + # Point satisfies y² = x³ - 3x (mod p) - a singular/degenerate + # curve + # Singular curves have discriminant = 0 and provide no security + # guarantees. # This tests rejection of points on curves with catastrophic # security failures Spec.H0 @@ -206,10 +209,13 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t id="invalid_curve_attack_singular_b_zero", ), pytest.param( - # Invalid curve attack: Boundary value b = p-1 Point satisfies y² = - # x³ - 3x + (p-1) (mod p) Tests proper parameter validation at - # modular arithmetic boundaries Ensures implementations handle - # field arithmetic edge cases correctly + # Invalid curve attack: Boundary value b = p-1 + # Point satisfies y² = x³ - 3x + (p-1) (mod p) + # + # Tests proper parameter validation at + # modular arithmetic boundaries. + # Ensures implementations handle field arithmetic edge cases + # correctly. Spec.H0 + Spec.R0 + Spec.S0 @@ -218,10 +224,13 @@ def test_wycheproof_extra(state_test: StateTestFiller, pre: Alloc, post: dict, t id="invalid_curve_attack_b_equals_p_minus_1", ), pytest.param( - # Invalid curve attack: Small discriminant curve with b = 2 Point - # satisfies y² = x³ - 3x + 2 (mod p) Curves with small - # discriminants are vulnerable to specialized attacks Tests - # rejection of cryptographically weak curve parameters + # Invalid curve attack: Small discriminant curve with b = 2 + # Point satisfies y² = x³ - 3x + 2 (mod p) + # + # Curves with small discriminants are vulnerable to specialized + # attacks. + # + # Tests rejection of cryptographically weak curve parameters. Spec.H0 + Spec.R0 + Spec.S0 + X(0x1) + Y(0x0), id="invalid_curve_attack_small_discriminant", ), diff --git a/tests/paris/security/test_selfdestruct_balance_bug.py b/tests/paris/security/test_selfdestruct_balance_bug.py index e67eace66d9..99bed4248a4 100644 --- a/tests/paris/security/test_selfdestruct_balance_bug.py +++ b/tests/paris/security/test_selfdestruct_balance_bug.py @@ -34,8 +34,8 @@ def test_tx_selfdestruct_balance_bug(blockchain_test: BlockchainTestFiller, pre: Test that the vulnerability is not present by checking the balance of the `0xaa` contract after executing specific transactions. - 1. Start with contract `0xaa` which has initial balance of 3 wei. `0xaa` - contract code simply performs a self-destruct to itself. + 1. Start with contract `0xaa` which has initial balance of 3 wei. + `0xaa` contract code simply performs a self-destruct to itself. 2. Send a transaction (tx 1) to invoke caller contract `0xcc` (which has a balance of 1 wei), which in turn invokes `0xaa` with a 1 wei call. diff --git a/tests/prague/eip2537_bls_12_381_precompiles/conftest.py b/tests/prague/eip2537_bls_12_381_precompiles/conftest.py index 880f85a5cd2..8ae554bff0b 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/conftest.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/conftest.py @@ -65,8 +65,11 @@ def call_opcode() -> Op: @pytest.fixture def call_contract_post_storage() -> Storage: """ - Storage of the test contract after the transaction is executed. Note: + Storage of the test contract after the transaction is executed. + + Note: Fixture `call_contract_code` fills the actual expected storage values. + """ return Storage() @@ -95,18 +98,25 @@ def call_contract_code( """ Code of the test contract. - Args: precompile_address: Address of the precompile to call. - precompile_gas: Gas cost for the precompile, which is automatically - calculated by the `precompile_gas` fixture, but can be overridden in the - test. precompile_gas_modifier: Gas cost modifier for the precompile, which - is automatically set to zero by the `precompile_gas_modifier` fixture, but - can be overridden in the test. expected_output: Expected output of the - precompile call. This value is used to determine if the call is expected to - succeed or fail. call_succeeds: Boolean that indicates if the call is - expected to succeed or fail. call_opcode: Type of call used to call the - precompile (Op.CALL, Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL). - call_contract_post_storage: Storage of the test contract after the - transaction is executed. + Args: + precompile_address: Address of the precompile to call. + precompile_gas: Gas cost for the precompile, which is automatically + calculated by the `precompile_gas` fixture, but can + be overridden in the test. + precompile_gas_modifier: Gas cost modifier for the precompile, which + is automatically set to zero by the + `precompile_gas_modifier` fixture, but + can be overridden in the test. + expected_output: Expected output of the precompile call. + This value is used to determine if the call is + expected to succeed or fail. + call_succeeds: Boolean that indicates if the call is expected to + succeed or fail. + call_opcode: Type of call used to call the precompile (Op.CALL, + Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL). + call_contract_post_storage: Storage of the test contract after the + transaction is executed. + """ expected_output = bytes(expected_output) diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py index d03e29b9481..9824f875bd4 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1mul.py @@ -185,8 +185,8 @@ def test_valid( id="swapped_coordinates_times_0", ), pytest.param( - PointG1(0x01, 0x07) + Scalar(0), # Point on wrong curve y^2 = x^3 - # + 5 + # Point on wrong curve y^2 = x^3 + 5 + PointG1(0x01, 0x07) + Scalar(0), id="point_on_wrong_curve_times_0", ), pytest.param( diff --git a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py index 4be5d751171..8cc70be6aff 100644 --- a/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py +++ b/tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py @@ -89,17 +89,22 @@ def call_contract_code( given gas and data length, data being passed to the precompile is all zeros. - Args: precompile_address: Address of the precompile to call. - precompile_gas_list: List of gas values to be used to call the precompile, - one for each call. precompile_data_length_list: List of data lengths to be - used to call the precompile, one for each call. gas_modifier: Integer to - add to the gas passed to the precompile. input_length_modifier: Integer to - add to the length of the input passed to the precompile. expected_output: - Expected output of the contract, it is only used to determine if the call - is expected to succeed or fail. call_opcode: Type of call used to call the - precompile (Op.CALL, Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL). - call_contract_post_storage: Storage of the test contract after the - transaction is executed. + Args: + precompile_address: Address of the precompile to call. + precompile_gas_list: List of gas values to be used to call the + precompile, one for each call. + precompile_data_length_list: List of data lengths to be used to call + the precompile, one for each call. + gas_modifier: Integer to add to the gas passed to the precompile. + input_length_modifier: Integer to add to the length of the input + passed to the precompile. + expected_output: Expected output of the contract, it is only used to + determine if the call is expected to succeed or fail. + call_opcode: Type of call used to call the precompile (Op.CALL, + Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL). + call_contract_post_storage: Storage of the test contract after the + transaction is executed. + """ expected_output = bytes(expected_output) diff --git a/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py b/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py index 35128bbefdb..28c8c0e3419 100644 --- a/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py +++ b/tests/prague/eip2935_historical_block_hashes_from_state/test_block_hashes.py @@ -35,12 +35,15 @@ def generate_block_check_code( Generate EVM code to check that the block hashes are correctly stored in the state. - Args: check_block_number (int): The block number to check. - current_block_number (int): The current block number where the check is - taking place. fork_block_number (int): The block number of the fork - transition. storage (Storage): The storage object to use. - check_contract_first (bool): Whether to check the contract first, for slot - warming checks. + Args: + check_block_number (int): The block number to check. + current_block_number (int): The current block number where the check is + taking place. + fork_block_number (int): The block number of the fork transition. + storage (Storage): The storage object to use. + check_contract_first (bool): Whether to check the contract first, + for slot warming checks. + """ contract_ret_offset = 32 diff --git a/tests/prague/eip6110_deposits/helpers.py b/tests/prague/eip6110_deposits/helpers.py index 9634cdd4925..8c06c1f307c 100644 --- a/tests/prague/eip6110_deposits/helpers.py +++ b/tests/prague/eip6110_deposits/helpers.py @@ -84,12 +84,9 @@ class DepositRequest(DepositRequestBase): """Calldata modifier function.""" extra_wei: int = 0 """ - - Extra amount in wei to be sent with the deposit. If this value modulo 10**9 is not zero, the deposit will be invalid. The value can be negative but if the total value is negative, an exception will be raised. - """ interaction_contract_address: ClassVar[Address] = Address(Spec.DEPOSIT_CONTRACT_ADDRESS) @@ -123,8 +120,12 @@ def calldata(self) -> bytes: Return the calldata needed to call the beacon chain deposit contract and make the deposit. - deposit( bytes calldata pubkey, bytes calldata withdrawal_credentials, - bytes calldata signature, bytes32 deposit_data_root ) + deposit( + bytes calldata pubkey, + bytes calldata withdrawal_credentials, + bytes calldata signature, + bytes32 deposit_data_root + ) """ offset_length = 32 pubkey_offset = offset_length * 3 + len(self.deposit_data_root) @@ -148,8 +149,13 @@ def log(self, *, include_abi_encoding: bool = True) -> bytes: """ Return the log data for the deposit event. - event DepositEvent( bytes pubkey, bytes withdrawal_credentials, bytes - amount, bytes signature, bytes index ); + event DepositEvent( + bytes pubkey, + bytes withdrawal_credentials, + bytes amount, + bytes signature, + bytes index + ); """ data = bytearray(576) if include_abi_encoding: @@ -268,18 +274,12 @@ class DepositContract(DepositInteractionBase): """Type of call to be made to the deposit contract.""" call_depth: int = 2 """ - - Frame depth of the beacon chain deposit contract when it executes the deposit requests. - """ extra_code: Bytecode = field(default_factory=Bytecode) """ - - Extra code to be included in the contract that sends the deposit requests. - """ @property diff --git a/tests/prague/eip7002_el_triggerable_withdrawals/helpers.py b/tests/prague/eip7002_el_triggerable_withdrawals/helpers.py index 4c8cea1b399..d8fa578a6c0 100644 --- a/tests/prague/eip7002_el_triggerable_withdrawals/helpers.py +++ b/tests/prague/eip7002_el_triggerable_withdrawals/helpers.py @@ -17,8 +17,6 @@ class WithdrawalRequest(WithdrawalRequestBase): fee: int = 0 """ - - Fee to be paid to the system contract for the withdrawal request. This is different from `amount` which is the amount of gwei to be withdrawn on the beacon chain. @@ -133,17 +131,11 @@ class WithdrawalRequestContract(WithdrawalRequestInteractionBase): contract_balance: int = 1_000_000_000_000_000_000 """ - - Balance of the contract that will make the call to the pre-deploy contract. - """ contract_address: Address | None = None """ - - Address of the contract that will make the call to the pre-deploy contract. - """ entry_address: Address | None = None """Address to send the transaction to.""" diff --git a/tests/prague/eip7251_consolidations/helpers.py b/tests/prague/eip7251_consolidations/helpers.py index 05eeca37ac2..20795482dbb 100644 --- a/tests/prague/eip7251_consolidations/helpers.py +++ b/tests/prague/eip7251_consolidations/helpers.py @@ -126,29 +126,11 @@ class ConsolidationRequestContract(ConsolidationRequestInteractionBase): contract_balance: int = 1_000_000_000_000_000_000 """ - - - - - - Balance of the contract that will make the call to the pre-deploy contract. - - - """ contract_address: Address | None = None """ - - - - - - Address of the contract that will make the call to the pre-deploy contract. - - - """ entry_address: Address | None = None """Address to send the transaction to.""" diff --git a/tests/prague/eip7623_increase_calldata_cost/conftest.py b/tests/prague/eip7623_increase_calldata_cost/conftest.py index d4031dbfbb7..a4f30d29113 100644 --- a/tests/prague/eip7623_increase_calldata_cost/conftest.py +++ b/tests/prague/eip7623_increase_calldata_cost/conftest.py @@ -154,9 +154,10 @@ def tx_data( - 16 gas for each non-zero byte in the data - 4 gas for each zero byte in the data - Its floor data gas cost can be calculated as: - 21,000 gas for the - transaction - 40 gas for each non-zero byte in the data - 10 gas for each - zero byte in the data + Its floor data gas cost can be calculated as: + - 21,000 gas for the transaction + - 40 gas for each non-zero byte in the data + - 10 gas for each zero byte in the data Notice that the data included in the transaction affects both the intrinsic gas cost and the floor data cost, but at different rates. diff --git a/tests/prague/eip7623_increase_calldata_cost/test_refunds.py b/tests/prague/eip7623_increase_calldata_cost/test_refunds.py index 2fa3d80eed5..94908fdf0df 100644 --- a/tests/prague/eip7623_increase_calldata_cost/test_refunds.py +++ b/tests/prague/eip7623_increase_calldata_cost/test_refunds.py @@ -34,19 +34,13 @@ class RefundTestType(Enum): EXECUTION_GAS_MINUS_REFUND_GREATER_THAN_DATA_FLOOR = 0 """ - - The execution gas minus the refund is greater than the data floor, hence the execution gas cost is charged. - """ EXECUTION_GAS_MINUS_REFUND_LESS_THAN_DATA_FLOOR = 1 """ - - The execution gas minus the refund is less than the data floor, hence the data floor cost is charged. - """ EXECUTION_GAS_MINUS_REFUND_EQUAL_TO_DATA_FLOOR = 2 """The execution gas minus the refund is equal to the data floor.""" @@ -298,10 +292,11 @@ def test_gas_refunds_from_data_floor( raise ValueError("Invalid refund test type") if gas_used < tx_floor_data_cost: gas_used = tx_floor_data_cost - # This is the actual test verification: - During test filling, the receipt - # returned by the transition tool (t8n) is verified against the expected - # receipt. - During test consumption, this is reflected in the balance - # difference and the state root. + # This is the actual test verification: + # - During test filling, the receipt returned by the transition tool + # (t8n) is verified against the expected receipt. + # - During test consumption, this is reflected in the balance difference + # and the state root. tx.expected_receipt = TransactionReceipt(gas_used=gas_used) state_test( pre=pre, diff --git a/tests/prague/eip7702_set_code_tx/test_gas.py b/tests/prague/eip7702_set_code_tx/test_gas.py index 1ff2140f019..1b416b28fbe 100644 --- a/tests/prague/eip7702_set_code_tx/test_gas.py +++ b/tests/prague/eip7702_set_code_tx/test_gas.py @@ -105,17 +105,8 @@ class AuthorityWithProperties: """The type of the address the authority was before the authorization.""" invalidity_type: AuthorizationInvalidityType | None """ - - - - - - Whether the authorization will be invalid and if so, which type of invalidity it is. - - - """ @property @@ -209,36 +200,18 @@ class AuthorizationWithProperties: """The authorization tuple to be used in the transaction.""" invalidity_type: AuthorizationInvalidityType | None """ - - - - - - Whether the authorization is invalid and if so, which type of invalidity it is. - - - """ authority_type: AddressType """The type of the address the authority was before the authorization.""" skip: bool """ - - - - - - Whether the authorization should be skipped and therefore not included in the transaction. Used for tests where the authorization was already in the state before the transaction was created. - - - """ @property diff --git a/tests/prague/eip7702_set_code_tx/test_set_code_txs.py b/tests/prague/eip7702_set_code_tx/test_set_code_txs.py index d9ee6efcb34..c401488bd4e 100644 --- a/tests/prague/eip7702_set_code_tx/test_set_code_txs.py +++ b/tests/prague/eip7702_set_code_tx/test_set_code_txs.py @@ -3188,9 +3188,10 @@ def test_delegation_clearing( circumstances. - pre_set_delegation_code: The code to set on the account before clearing - delegation, or None if the account should not have any code set. - - self_sponsored: Whether the delegation clearing transaction is - self-sponsored. + delegation, or None if the account should not + have any code set. + - self_sponsored: Whether the delegation clearing transaction is + self-sponsored. """ # noqa: D417 pre_set_delegation_address: Address | None = None if pre_set_delegation_code is not None: @@ -3279,9 +3280,10 @@ def test_delegation_clearing_tx_to( Tests directly calling the account which delegation is being cleared. - pre_set_delegation_code: The code to set on the account before clearing - delegation, or None if the account should not have any code set. - - self_sponsored: Whether the delegation clearing transaction is - self-sponsored. + delegation, or None if the account should not + have any code set. + - self_sponsored: Whether the delegation clearing transaction is + self-sponsored. """ # noqa: D417 pre_set_delegation_address: Address | None = None if pre_set_delegation_code is not None: @@ -3502,8 +3504,10 @@ def test_creating_delegation_designation_contract( initcode_is_delegation_designation: bool, ): """ - Tx -> create -> pointer bytecode Attempt to deploy contract with magic - bytes result in no contract being created. + Tx -> create -> pointer bytecode. + + Attempt to deploy contract with magic bytes result in no + contract being created. """ env = Environment() diff --git a/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py b/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py index e362e98f9ee..ef4208b76d2 100644 --- a/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py +++ b/tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py @@ -42,8 +42,9 @@ def test_pointer_contract_pointer_loop(state_test: StateTestFiller, pre: Alloc): """ Tx -> call -> pointer A -> contract A -> pointer B -> contract loop C. - Call pointer that goes more level of depth to call a contract loop Loop is - created only if pointers are set with auth tuples + Call pointer that goes more level of depth to call a contract loop. + + Loop is created only if pointers are set with auth tuples. """ env = Environment() @@ -139,7 +140,9 @@ def test_pointer_to_pointer(state_test: StateTestFiller, pre: Alloc): @pytest.mark.valid_from("Prague") def test_pointer_normal(blockchain_test: BlockchainTestFiller, pre: Alloc): """ - Tx -> call -> pointer A -> contract Other normal tx can interact with + Tx -> call -> pointer A -> contract. + + Other normal tx can interact with previously assigned pointers. """ env = Environment() @@ -199,9 +202,11 @@ def test_pointer_normal(blockchain_test: BlockchainTestFiller, pre: Alloc): @pytest.mark.valid_from("Prague") def test_pointer_measurements(blockchain_test: BlockchainTestFiller, pre: Alloc): """ - Check extcode* operations on pointer before and after pointer is set Check - context opcode results when called under pointer call Opcodes have context - of an original pointer account (balance, storage). + Check extcode* operations on pointer before and after pointer is set. + + Check context opcode results when called under pointer call. + + Opcodes have context of an original pointer account (balance, storage). """ env = Environment() @@ -330,9 +335,10 @@ def test_call_to_precompile_in_pointer_context( state_test: StateTestFiller, pre: Alloc, precompile: int ): """ - Tx -> call -> pointer A -> precompile contract Make sure that gas consumed - when calling precompiles in normal call are the same As from inside the - pointer context call. + Tx -> call -> pointer A -> precompile contract. + + Make sure that gas consumed when calling precompiles in normal call + are the same As from inside the pointer context call. """ env = Environment() @@ -811,8 +817,9 @@ def test_pointer_call_followed_by_direct_call( @pytest.mark.valid_from("Prague") def test_pointer_to_static(state_test: StateTestFiller, pre: Alloc): """ - Tx -> call -> pointer A -> static -> static violation Verify that static - context is active when called under pointer. + Tx -> call -> pointer A -> static -> static violation. + + Verify that static context is active when called under pointer. """ env = Environment() storage: Storage = Storage() @@ -857,8 +864,9 @@ def test_pointer_to_static(state_test: StateTestFiller, pre: Alloc): @pytest.mark.valid_from("Prague") def test_static_to_pointer(state_test: StateTestFiller, pre: Alloc): """ - Tx -> staticcall -> pointer A -> static violation Verify that static - context is active when make sub call to pointer. + Tx -> staticcall -> pointer A -> static violation. + + Verify that static context is active when make sub call to pointer. """ env = Environment() storage: Storage = Storage() @@ -902,7 +910,11 @@ def test_static_to_pointer(state_test: StateTestFiller, pre: Alloc): @pytest.mark.valid_from("EOFv1") def test_pointer_to_eof(state_test: StateTestFiller, pre: Alloc): - """Tx -> call -> pointer A -> EOF Pointer to eof contract works.""" + """ + Tx -> call -> pointer A -> EOF. + + Pointer to eof contract works. + """ env = Environment() storage: Storage = Storage() sender = pre.fund_eoa() @@ -1019,8 +1031,9 @@ def test_contract_storage_to_pointer_with_storage( ): """ Tx call -> contract with storage -> pointer A with storage -> - storage/tstorage modify Check storage/tstorage modifications when - interacting with pointers. + storage/tstorage modify. + + Check storage/tstorage modifications when interacting with pointers. """ env = Environment() @@ -1122,8 +1135,10 @@ class ReentryAction(IntEnum): @pytest.mark.valid_from("Prague") def test_pointer_reentry(state_test: StateTestFiller, pre: Alloc): """ - Check operations when reenter the pointer again TODO: feel free to extend - the code checks under given scenarios in switch case. + Check operations when reenter the pointer again. + + TODO: feel free to extend the code checks under given scenarios in + switch case. """ env = Environment() arg_contract = 0 @@ -1180,8 +1195,9 @@ def test_pointer_reentry(state_test: StateTestFiller, pre: Alloc): ), ), Case( - # This code is executed under pointer -> proxy -> pointer - # -> contract so pointer calling the code of it's dest + # This code is executed under + # pointer -> proxy -> pointer -> contract + # so pointer calling the code of it's dest # after reentry to itself condition=Op.EQ(Op.MLOAD(arg_action), ReentryAction.MEASURE_VALUES_CONTRACT), action=Op.SSTORE(storage_b.store_next(sender, "origin"), Op.ORIGIN()) @@ -1226,9 +1242,11 @@ def test_pointer_reentry(state_test: StateTestFiller, pre: Alloc): @pytest.mark.valid_from("Prague") def test_eoa_init_as_pointer(state_test: StateTestFiller, pre: Alloc): """ - It was agreed before that senders don't have code And there were issues - with tests sending transactions from account's with code With EIP7702 it is - again possible, let's check the test runners are ok. + It was agreed before that senders don't have code. + + And there were issues with tests sending transactions from account's + with code With EIP7702 it is again possible, + let's check the test runners are ok. """ env = Environment() storage = Storage() @@ -1259,14 +1277,17 @@ def test_call_pointer_to_created_from_create_after_oog_call_again( """ Set pointer to account that we are about to create. - Pointer is set to create address that is yet not in the state During the - call, address is created. pointer is called from init code to do nothing + Pointer is set to create address that is yet not in the state. + + During the call, address is created. pointer is called from init code + to do nothing. + Then after account is created it is called again to run created code - Then revert / no revert + Then revert / no revert. Call pointer again from the upper level to ensure it does not call reverted - code + code. """ env = Environment() @@ -1556,7 +1577,9 @@ def test_pointer_resets_an_empty_code_account_with_storage( ): """ So in Block1 we create a sender with empty code, but non empty storage - using pointers In Block2 we create account that perform suicide, then we + using pointers. + + In Block2 we create account that perform suicide, then we check that when calling a pointer, that points to newly created account and runs suicide, is not deleted as well as its storage. @@ -1633,8 +1656,10 @@ def test_pointer_resets_an_empty_code_account_with_storage( sender=sender, ) - # Block 2 Sender with storage and pointer code calling selfdestruct on - # itself But it points to a newly created account, check that pointer + # Block 2 + # Sender with storage and pointer code calling selfdestruct on itself + # + # But it points to a newly created account, check that pointer # storage is not deleted suicide_dest = pre.fund_eoa(amount=0) deploy_code = Op.SSTORE(5, 5) + Op.SELFDESTRUCT(suicide_dest) @@ -1690,9 +1715,14 @@ def test_pointer_resets_an_empty_code_account_with_storage( pre=pre, post=post, blocks=[ - # post = { pointer: Account(nonce=2, balance=0, - # storage=pointer_storage, code=bytes()), sender: - # Account(storage=pointer_storage, code=bytes()), } + # post = { + # pointer: Account(nonce=2, + # balance=0, + # storage=pointer_storage, + # code=bytes() + # ), + # sender: Account(storage=pointer_storage, code=bytes()) + # } Block( txs=[ tx_set_pointer_storage, diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_all_opcodes_in_container.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_all_opcodes_in_container.py index 0fa6a3de26b..314c6998384 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_all_opcodes_in_container.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_all_opcodes_in_container.py @@ -331,12 +331,14 @@ def test_all_unreachable_terminating_opcodes_before_stop( ) @pytest.mark.parametrize( "exception", - # We test two types of exceptions here: 1. Invalid max stack height, where - # we modify the `max_stack_height` field of the code section to the maximum - # stack height allowed by the EIP-3540, so the code still has to be checked - # for stack overflow. 2. Max stack height above limit, where we don't - # modify the `max_stack_height` field of the code section, so the actual - # code doesn't have to be verified for the stack overflow. + # We test two types of exceptions here: + # 1. Invalid max stack height, where we modify the `max_stack_height` + # field of the code section to the maximum stack height allowed by + # the EIP-3540, so the code still has to be checked for stack overflow. + # + # 2. Max stack height above limit, where we don't modify the + # `max_stack_height` field of the code section, so the actual + # code doesn't have to be verified for the stack overflow. [EOFException.INVALID_MAX_STACK_INCREASE, EOFException.MAX_STACK_INCREASE_ABOVE_LIMIT], ) def test_all_opcodes_stack_overflow( diff --git a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_eof_example.py b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_eof_example.py index c8995a94653..5263afbedce 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_eof_example.py +++ b/tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/test_eof_example.py @@ -68,9 +68,9 @@ def test_eof_example(eof_test: EOFTestFiller): def test_eof_example_custom_fields(eof_test: EOFTestFiller): """Example of python EOF container class tuning.""" # if you need to overwrite certain structure bytes, you can use - # customization this is useful for unit testing the eof structure format, + # customization. this is useful for unit testing the eof structure format, # you can reorganize sections and overwrite the header bytes for testing - # purposes most of the combinations are covered by the unit tests + # purposes. most of the combinations are covered by the unit tests # This features are subject for development and will change in the future @@ -97,22 +97,26 @@ def test_eof_example_custom_fields(eof_test: EOFTestFiller): data="0xef", # custom_size overrides the size bytes, so you can put only 1 # byte into data but still make the header size of 2 to produce - # invalid section if custom_size != len(data), the section will - # be invalid + # invalid section + # + # if custom_size != len(data), the section will be invalid custom_size=1, ), ], # auto generate types section based on provided code sections # AutoSection.ONLY_BODY - means the section will be generated only for - # the body bytes AutoSection.ONLY_BODY - means the section will be - # generated only for the header bytes + # the body bytes + # + # AutoSection.ONLY_BODY - means the section will be generated only for + # the header bytes auto_type_section=AutoSection.AUTO, # auto generate default data section (0x empty), by default is True auto_data_section=True, - # auto sort section by order 01 02 03 04 AutoSection.ONLY_BODY - means - # the sorting will be done only for the body bytes + # auto sort section by order 01 02 03 04 + # AutoSection.ONLY_BODY - means the sorting will be done only for the + # body bytes # AutoSection.ONLY_BODY - means the section will be done only for the - # header bytes + # header bytes auto_sort_sections=AutoSection.AUTO, ) diff --git a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_execution.py b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_execution.py index b85813b98a3..b26d7702de3 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_execution.py +++ b/tests/unscheduled/eip7692_eof_v1/eip6206_jumpf/test_jumpf_execution.py @@ -444,9 +444,12 @@ def test_jumpf_stack_overflow( so we need to ensure the rule is checked. `no_overflow` - the stack does not overflow at JUMPF call, executes to end + `rule_overflow` - reserved stack rule triggers, but execution would not - overflow if allowed `execution_overflow` - execution would overflow (but - still blocked by reserved stack rule) + overflow if allowed + + `execution_overflow` - execution would overflow (but still blocked by + reserved stack rule) """ eof_state_test( container=Container( diff --git a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py index d39e9e035f8..55c2c67ba89 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7069_extcall/test_calls.py @@ -1056,9 +1056,12 @@ def test_eof_calls_msg_depth( opcode: Op, ): """ - Test EOF contracts calls handle msg depth limit correctly (1024). NOTE: due - to block gas limit and the 63/64th rule this limit is unlikely to be hit on - mainnet. + Test EOF contracts calls handle msg depth limit correctly (1024). + + Note: + due to block gas limit and the 63/64th rule this limit is unlikely + to be hit on mainnet. + """ # Not a precise gas_limit formula, but enough to exclude risk of gas # causing the failure. diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py index 38bef9e6c6b..4156e92a7a5 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/__init__.py @@ -2,22 +2,25 @@ Test cases for EOF Contract Creation for EIP-7620. EIP-7620 replaces `CREATE` and `CREATE2` with `EOFCREATE` for deploying -contracts in the EOF format. Full specification: +contracts in the EOF format. + +Full specification: [EIP-7620: EOF Contract Creation](https://eips.ethereum.org/EIPS/eip-7620). + Opcodes introduced: `EOFCREATE` (`0xEC`), `RETURNCODE` (`0xEE`). EOFCREATE, RETURNCODE, and container tests. evmone tests not ported: - - create_tx_with_eof_initcode: This calls it invalid, it is now the way to -add EOF contacts to state + add EOF contacts to state - eofcreate_extcall_returncode: Per the new initcode -mode tests you cannot have RETURNCODE in a deployed contract + mode tests you cannot have RETURNCODE in a + deployed contract - eofcreate_dataloadn_referring_to_auxdata: covered by -tests.unscheduled.eip7480_data_section.test_data_opcodes. -test_data_section_succeed + tests.unscheduled.eip7480_data_section. + test_data_opcodes.test_data_section_succeed - eofcreate_initcontainer_return: RETURN is banned in initcode containers -- eofcreate_initcontainer_stop: STOP is banned in initcode containers - All -TXCREATE tests. +- eofcreate_initcontainer_stop: STOP is banned in initcode containers +- All TXCREATE tests. """ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py index 1089180f330..1b3872b5c0a 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7620_eof_create/test_eofcreate_failures.py @@ -315,7 +315,9 @@ def test_auxdata_size_failures(state_test: StateTestFiller, pre: Alloc, auxdata_ deployed_container_size = len(smallest_runtime_subcontainer) + auxdata_size # Storage in 0 will have address in first test, 0 in all other cases - # indicating failure Storage 1 in 1 is a canary to see if EOFCREATE opcode + # indicating failure + # + # Storage 1 in 1 is a canary to see if EOFCREATE opcode # halted success = deployed_container_size <= MAX_BYTECODE_SIZE post = { @@ -377,7 +379,9 @@ def test_eofcreate_insufficient_stipend( balance=value - 1, ) # create will fail but not trigger a halt, so canary at storage 1 should be - # set also validate target created contract fails + # set + # + # also validate target created contract fails post = { contract_address: Account( storage={ @@ -680,14 +684,15 @@ def test_eof_eofcreate_msg_depth( ): """ Test EOFCREATE handles msg depth limit correctly (1024). + NOTE: due to block gas limit and the 63/64th rule this limit is - unlikely to be hit on mainnet. + unlikely to be hit on mainnet. NOTE: See `tests/unscheduled/eip7692_eof_v1/eip7069_extcall/ - test_calls.py::test_eof_calls_msg_depth` for more explanations and - comments. Most notable deviation from that test is that here calls - and `EOFCREATE`s alternate in order to reach the max depth. - `who_fails` decides whether the failing depth 1024 will be on a call - or on an `EOFCREATE` to happen. + test_calls.py::test_eof_calls_msg_depth` for more explanations and + comments. Most notable deviation from that test is that here calls + and `EOFCREATE`s alternate in order to reach the max depth. + `who_fails` decides whether the failing depth 1024 will be on a call + or on an `EOFCREATE` to happen. """ # Not a precise gas_limit formula, but enough to exclude risk of gas # causing the failure. @@ -809,17 +814,19 @@ def test_reentrant_eofcreate( Section.Container(smallest_runtime_subcontainer), ] ) - # Factory: Passes on its input into the initcode. It's 0 first time, 1 the - # second time. Saves the result of deployment in slot 0 first time, 1 the - # second time. + # Factory: + # Passes on its input into the initcode. + # It's 0 first time, 1 the second time. + # Saves the result of deployment in slot 0 first time, 1 the + # second time. contract_address = pre.deploy_contract( code=Container( sections=[ Section.Code( Op.CALLDATACOPY(0, 0, 32) + Op.MSTORE(32, Op.ADDRESS) - # 1st word - copied from input (reenter flag), 2nd word - - # `this.address`. + # 1st word - copied from input (reenter flag) + # 2nd word - `this.address` + Op.SSTORE(Op.CALLDATALOAD(0), Op.EOFCREATE[0](input_size=64)) + Op.STOP, ), @@ -828,13 +835,18 @@ def test_reentrant_eofcreate( ), storage={0: 0xB17D, 1: 0xB17D}, # a canary to be overwritten ) - # Flow is: reenter flag 0 -> factory -> reenter flag 0 -> initcode -> - # reenter -> reenter flag 1 -> factory -> reenter flag 1 -> (!) initcode -> - # stop, if the EIP-161 nonce bump is not implemented. If it is, it fails - # before second inicode marked (!). Storage in 0 should have the address - # from the outer EOFCREATE. Storage in 1 should have 0 from the inner - # EOFCREATE. For the created contract storage in `slot_counter` should be 1 - # as initcode executes only once + # Flow is: + # reenter flag 0 -> factory -> reenter flag 0 -> initcode -> + # reenter -> reenter flag 1 -> factory -> reenter flag 1 -> (!) initcode + # -> stop + # if the EIP-161 nonce bump is not implemented. + # + # If it is, it fails before second inicode marked (!). + # + # Storage in 0 should have the address from the outer EOFCREATE. + # Storage in 1 should have 0 from the inner EOFCREATE. For the created + # contract storage in `slot_counter` should be 1 as initcode + # executes only once. post = { contract_address: Account( storage={ diff --git a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py index 1eaa0fe14cf..2fd81705454 100644 --- a/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py +++ b/tests/unscheduled/eip7692_eof_v1/eip7873_tx_create/test_txcreate_failures.py @@ -312,8 +312,9 @@ def test_auxdata_size_failures(state_test: StateTestFiller, pre: Alloc, auxdata_ deployed_container_size = len(smallest_runtime_subcontainer) + auxdata_size # Storage in 0 will have address in first test, 0 in all other cases - # indicating failure Storage 1 in 1 is a canary to see if TXCREATE opcode - # halted + # indicating failure + # + # Storage 1 in 1 is a canary to see if TXCREATE opcode halted success = deployed_container_size <= MAX_BYTECODE_SIZE post = { contract_address: Account( @@ -369,8 +370,10 @@ def test_txcreate_insufficient_stipend( + Op.STOP, balance=value - 1, ) - # create will fail but not trigger a halt, so canary at storage 1 should be - # set also validate target created contract fails + # create will fail but not trigger a halt, so canary at storage 1 + # should be set + # + # also validate target created contract fails post = { contract_address: Account( storage={ @@ -763,7 +766,7 @@ def test_reentrant_txcreate( # Calls into the factory contract with 1 as input. reenter_code = Op.MSTORE(0, 1) + Op.EXTCALL(address=Op.CALLDATALOAD(32), args_size=32) # Initcode: if given 0 as 1st word of input will call into the factory - # again. 2nd word of input is the address of the factory. + # again. 2nd word of input is the address of the factory. initcontainer = Container( sections=[ Section.Code( @@ -777,14 +780,15 @@ def test_reentrant_txcreate( ] ) initcode_hash = initcontainer.hash - # Factory: Passes on its input into the initcode. It's 0 first time, 1 the - # second time. Saves the result of deployment in slot 0 first time, 1 the - # second time. + # Factory: + # Passes on its input into the initcode. + # It's 0 first time, 1 the second time. + # Saves the result of deployment in slot 0 first time, 1 the second time. contract_address = pre.deploy_contract( code=Op.CALLDATACOPY(0, 0, 32) + Op.MSTORE(32, Op.ADDRESS) - # 1st word - copied from input (reenter flag), 2nd word - - # `this.address`. + # 1st word - copied from input (reenter flag) + # 2nd word - `this.address` + Op.SSTORE( Op.CALLDATALOAD(0), Op.TXCREATE(tx_initcode_hash=initcode_hash, input_size=64), diff --git a/tests/unscheduled/eip7692_eof_v1/gas_test.py b/tests/unscheduled/eip7692_eof_v1/gas_test.py index 7a493b87d96..eaeeb1fd83c 100644 --- a/tests/unscheduled/eip7692_eof_v1/gas_test.py +++ b/tests/unscheduled/eip7692_eof_v1/gas_test.py @@ -111,11 +111,14 @@ def gas_test( + ( ( # do an oog gas run, unless skipped with - # `out_of_gas_testing=False`: - DUP7 is the gas of the - # baseline gas run, after other CALL args were pushed - - # subtract the gas charged by the harness - add warm gas - # charged by the subject - subtract `oog_difference` to - # cause OOG exception (1 by default) + # `out_of_gas_testing=False`: + # + # - DUP7 is the gas of the baseline gas run, after other + # CALL args were pushed + # - subtract the gas charged by the harness + # - add warm gas charged by the subject + # - subtract `oog_difference` to cause OOG exception + # (1 by default) Op.SSTORE( slot_oog_call_result, Op.CALL( From bff747c947102d5a4e02dcaf8fa8b86e0ba65a18 Mon Sep 17 00:00:00 2001 From: Felix H Date: Thu, 25 Sep 2025 12:50:12 +0000 Subject: [PATCH 15/16] fix --- src/ethereum_test_benchmark/__init__.py | 5 +++- .../benchmark_code_generator.py | 24 ++++++++++++++----- src/ethereum_test_specs/benchmark.py | 20 ++++++++++++---- .../tests/test_benchmark.py | 13 +++++++--- src/ethereum_test_vm/bytecode.py | 5 +++- 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/ethereum_test_benchmark/__init__.py b/src/ethereum_test_benchmark/__init__.py index 60f0e66a5fb..fb8b71a207f 100644 --- a/src/ethereum_test_benchmark/__init__.py +++ b/src/ethereum_test_benchmark/__init__.py @@ -1,4 +1,7 @@ -"""Benchmark code generator classes for creating optimized bytecode patterns.""" +""" +Benchmark code generator classes for +creating optimized bytecode patterns. +""" from .benchmark_code_generator import ( BenchmarkCodeGenerator, diff --git a/src/ethereum_test_benchmark/benchmark_code_generator.py b/src/ethereum_test_benchmark/benchmark_code_generator.py index 9c2c9b7814a..311b4132c3b 100644 --- a/src/ethereum_test_benchmark/benchmark_code_generator.py +++ b/src/ethereum_test_benchmark/benchmark_code_generator.py @@ -1,4 +1,7 @@ -"""Benchmark code generator classes for creating optimized bytecode patterns.""" +""" +Benchmark code generator classes for creating +optimized bytecode patterns. +""" from ethereum_test_forks import Fork from ethereum_test_specs.benchmark import BenchmarkCodeGenerator @@ -13,7 +16,8 @@ class JumpLoopGenerator(BenchmarkCodeGenerator): def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: """Deploy the looping contract.""" # Benchmark Test Structure: - # setup + JUMPDEST + attack + attack + ... + attack + JUMP(setup_length) + # setup + JUMPDEST + attack + attack + ... + + # attack + JUMP(setup_length) code = self.generate_repeated_code(self.attack_block, self.setup, fork) self._contract_address = pre.deploy_contract(code=code) @@ -30,13 +34,17 @@ def generate_transaction(self, pre: Alloc, gas_limit: int, fork: Fork) -> Transa class ExtCallGenerator(BenchmarkCodeGenerator): - """Generates bytecode that fills the contract to maximum allowed code size.""" + """ + Generates bytecode that fills the contract to + maximum allowed code size. + """ def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: """Deploy both target and caller contracts.""" # Benchmark Test Structure: # There are two contracts: - # 1. The target contract that executes certain operation but not loop (e.g. PUSH) + # 1. The target contract that executes certain operation + # but not loop (e.g. PUSH) # 2. The loop contract that calls the target contract in a loop max_iterations = min( @@ -49,8 +57,12 @@ def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: ) # Create caller contract that repeatedly calls the target contract - # attack = POP(STATICCALL(GAS, target_contract_address, 0, 0, 0, 0)) - # setup + JUMPDEST + attack + attack + ... + attack + JUMP(setup_length) + # attack = POP( + # STATICCALL(GAS, target_contract_address, 0, 0, 0, 0) + # ) + # + # setup + JUMPDEST + attack + attack + ... + attack + + # JUMP(setup_length) code_sequence = Op.POP(Op.STATICCALL(Op.GAS, self._target_contract_address, 0, 0, 0, 0)) caller_code = self.generate_repeated_code(code_sequence, Bytecode(), fork) diff --git a/src/ethereum_test_specs/benchmark.py b/src/ethereum_test_specs/benchmark.py index 440faa8b844..c6fdd1b644b 100644 --- a/src/ethereum_test_specs/benchmark.py +++ b/src/ethereum_test_specs/benchmark.py @@ -54,7 +54,10 @@ def generate_transaction(self, pre: Alloc, gas_limit: int, fork: Fork) -> Transa def generate_repeated_code( self, repeated_code: Bytecode, setup: Bytecode, fork: Fork ) -> Bytecode: - """Calculate the maximum number of iterations that can fit in the code size limit.""" + """ + Calculate the maximum number of iterations that + can fit in the code size limit. + """ assert len(repeated_code) > 0, "repeated_code cannot be empty" max_code_size = fork.max_code_size() @@ -114,7 +117,10 @@ class BenchmarkTest(BaseTest): @classmethod def pytest_parameter_name(cls) -> str: - """Return the parameter name used in pytest to select this spec type.""" + """ + Return the parameter name used in pytest + to select this spec type. + """ return "benchmark_test" @classmethod @@ -124,7 +130,10 @@ def discard_fixture_format_by_marks( fork: Fork, markers: List[pytest.Mark], ) -> bool: - """Discard a fixture format from filling if the appropriate marker is used.""" + """ + Discard a fixture format from filling if the + appropriate marker is used. + """ if "blockchain_test_only" in [m.name for m in markers]: return fixture_format != BlockchainFixture if "blockchain_test_engine_only" in [m.name for m in markers]: @@ -136,7 +145,10 @@ def get_genesis_environment(self, fork: Fork) -> Environment: return self.env def split_transaction(self, tx: Transaction, gas_limit_cap: int | None) -> List[Transaction]: - """Split a transaction that exceeds the gas limit cap into multiple transactions.""" + """ + Split a transaction that exceeds the gas + limit cap into multiple transactions. + """ if gas_limit_cap is None: tx.gas_limit = HexNumber(self.gas_benchmark_value) return [tx] diff --git a/src/ethereum_test_specs/tests/test_benchmark.py b/src/ethereum_test_specs/tests/test_benchmark.py index bd4a699720b..6511e427fc5 100644 --- a/src/ethereum_test_specs/tests/test_benchmark.py +++ b/src/ethereum_test_specs/tests/test_benchmark.py @@ -1,4 +1,7 @@ -"""Tests for the BenchmarkTest class and its transaction splitting functionality.""" +""" +Tests for the BenchmarkTest class and its +transaction splitting functionality. +""" import pytest @@ -20,7 +23,10 @@ ], ) def test_split_transaction(gas_benchmark_value_millions: int, expected_splits: int): - """Test that transaction splitting works correctly for Osaka fork gas cap.""" + """ + Test that transaction splitting works + correctly for Osaka fork gas cap. + """ gas_benchmark_value = gas_benchmark_value_millions * 1_000_000 gas_limit_cap = 16_000_000 # Osaka's transaction gas limit cap @@ -100,6 +106,7 @@ def test_split_transaction_edge_cases(gas_benchmark_value: int, gas_limit_cap: i # When no cap, gas_limit should be benchmark value assert split_txs[0].gas_limit == gas_benchmark_value else: - # When cap > benchmark, gas_limit should be min of tx.gas_limit and benchmark + # When cap > benchmark, gas_limit should be + # min of tx.gas_limit and benchmark assert benchmark_test.tx is not None, "Transaction should not be None" assert split_txs[0].gas_limit == min(benchmark_test.tx.gas_limit, gas_benchmark_value) diff --git a/src/ethereum_test_vm/bytecode.py b/src/ethereum_test_vm/bytecode.py index 6e60c83b799..298f80c6e21 100644 --- a/src/ethereum_test_vm/bytecode.py +++ b/src/ethereum_test_vm/bytecode.py @@ -245,7 +245,10 @@ def keccak256(self) -> Hash: def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> PlainValidatorFunctionSchema: - """Provide Pydantic core schema for Bytecode serialization and validation.""" + """ + Provide Pydantic core schema for Bytecode + serialization and validation. + """ return no_info_plain_validator_function( cls, serialization=plain_serializer_function_ser_schema( From f75fc01cbcb464fad84afd5c6a892c5b07451c78 Mon Sep 17 00:00:00 2001 From: Felix H Date: Thu, 25 Sep 2025 15:38:09 +0000 Subject: [PATCH 16/16] fix --- src/cli/pytest_commands/fill.py | 5 ++++- src/cli/pytest_commands/processors.py | 10 ++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/cli/pytest_commands/fill.py b/src/cli/pytest_commands/fill.py index d0f6d06b455..87d5af00419 100644 --- a/src/cli/pytest_commands/fill.py +++ b/src/cli/pytest_commands/fill.py @@ -191,7 +191,10 @@ def _is_watch_mode(self, args: List[str]) -> bool: return any(flag in args for flag in ["--watch", "--watcherfall"]) def _is_verbose_watch_mode(self, args: List[str]) -> bool: - """Check if verbose watch flag (--watcherfall) is present in arguments.""" + """ + Check if verbose watch flag (--watcherfall) + is present in arguments. + """ return "--watcherfall" in args def execute(self, pytest_args: List[str]) -> None: diff --git a/src/cli/pytest_commands/processors.py b/src/cli/pytest_commands/processors.py index 8e0f2d2e0cd..b63cd3a132b 100644 --- a/src/cli/pytest_commands/processors.py +++ b/src/cli/pytest_commands/processors.py @@ -120,10 +120,16 @@ def _has_parallelism_flag(self, args: List[str]) -> bool: class WatchFlagsProcessor(ArgumentProcessor): - """Processes --watch and --watcherfall flags for file watching functionality.""" + """ + Processes --watch and --watcherfall flags + for file watching functionality. + """ def process_args(self, args: List[str]) -> List[str]: - """Remove --watch and --watcherfall flags from args passed to pytest.""" + """ + Remove --watch and --watcherfall + flags from args passed to pytest. + """ return [arg for arg in args if arg not in ["--watch", "--watcherfall"]]