From 58ffcf22bf7582f68db5f316a2b8d1c87b93bf28 Mon Sep 17 00:00:00 2001 From: spencer-tb Date: Sat, 1 Jun 2024 13:55:01 +0700 Subject: [PATCH 01/14] chore(fw): create contracts folder for bin files. --- .../forks/{ => contracts}/deposit_contract.bin | Bin .../forks/{ => contracts}/history_contract.bin | Bin .../forks/{ => contracts}/withdrawal_request.bin | Bin src/ethereum_test_forks/forks/forks.py | 10 +++++----- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/ethereum_test_forks/forks/{ => contracts}/deposit_contract.bin (100%) rename src/ethereum_test_forks/forks/{ => contracts}/history_contract.bin (100%) rename src/ethereum_test_forks/forks/{ => contracts}/withdrawal_request.bin (100%) diff --git a/src/ethereum_test_forks/forks/deposit_contract.bin b/src/ethereum_test_forks/forks/contracts/deposit_contract.bin similarity index 100% rename from src/ethereum_test_forks/forks/deposit_contract.bin rename to src/ethereum_test_forks/forks/contracts/deposit_contract.bin diff --git a/src/ethereum_test_forks/forks/history_contract.bin b/src/ethereum_test_forks/forks/contracts/history_contract.bin similarity index 100% rename from src/ethereum_test_forks/forks/history_contract.bin rename to src/ethereum_test_forks/forks/contracts/history_contract.bin diff --git a/src/ethereum_test_forks/forks/withdrawal_request.bin b/src/ethereum_test_forks/forks/contracts/withdrawal_request.bin similarity index 100% rename from src/ethereum_test_forks/forks/withdrawal_request.bin rename to src/ethereum_test_forks/forks/contracts/withdrawal_request.bin diff --git a/src/ethereum_test_forks/forks/forks.py b/src/ethereum_test_forks/forks/forks.py index 19a616eda8..3939a761d0 100644 --- a/src/ethereum_test_forks/forks/forks.py +++ b/src/ethereum_test_forks/forks/forks.py @@ -529,8 +529,8 @@ def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[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 + and the exits contract for EIP-7002. """ new_allocation = {} @@ -542,7 +542,7 @@ def pre_allocation_blockchain(cls) -> Mapping: storage[i] = next_hash next_hash = sha256(next_hash + next_hash).digest() - with open(CURRENT_FOLDER / "deposit_contract.bin", mode="rb") as f: + with open(CURRENT_FOLDER / "contracts/deposit_contract.bin", mode="rb") as f: new_allocation.update( { 0x00000000219AB540356CBB839CBE05303D7705FA: { @@ -554,7 +554,7 @@ def pre_allocation_blockchain(cls) -> Mapping: ) # Add the withdrawal request contract - with open(CURRENT_FOLDER / "withdrawal_request.bin", mode="rb") as f: + with open(CURRENT_FOLDER / "contracts/withdrawal_request.bin", mode="rb") as f: new_allocation.update( { 0x00A3CA265EBCB825B45F985A16CEFB49958CE017: { @@ -565,7 +565,7 @@ def pre_allocation_blockchain(cls) -> Mapping: ) # Add the history storage contract - with open(CURRENT_FOLDER / "history_contract.bin", mode="rb") as f: + with open(CURRENT_FOLDER / "contracts/history_contract.bin", mode="rb") as f: new_allocation.update( { 0x25A219378DAD9B3503C8268C9CA836A52427A4FB: { From c2d3dcda3d8660ecbc84d33d07dd960ff68b6e3e Mon Sep 17 00:00:00 2001 From: spencer-tb Date: Sat, 1 Jun 2024 13:57:02 +0700 Subject: [PATCH 02/14] feat(fw): remove history storage contract. --- .../forks/contracts/history_contract.bin | Bin 54 -> 0 bytes src/ethereum_test_forks/forks/forks.py | 11 ----------- 2 files changed, 11 deletions(-) delete mode 100644 src/ethereum_test_forks/forks/contracts/history_contract.bin diff --git a/src/ethereum_test_forks/forks/contracts/history_contract.bin b/src/ethereum_test_forks/forks/contracts/history_contract.bin deleted file mode 100644 index 250b34be25d3a48604c1a117adb0537d2b1b8cfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54 ycmYdLFcVBL3{PNmW{x)%OwbIEH%(MvU~~pCfsA-lwvhOs1cms|(eZHlF9QH)l@DtG diff --git a/src/ethereum_test_forks/forks/forks.py b/src/ethereum_test_forks/forks/forks.py index 3939a761d0..387b2ee495 100644 --- a/src/ethereum_test_forks/forks/forks.py +++ b/src/ethereum_test_forks/forks/forks.py @@ -564,17 +564,6 @@ def pre_allocation_blockchain(cls) -> Mapping: } ) - # Add the history storage contract - with open(CURRENT_FOLDER / "contracts/history_contract.bin", mode="rb") as f: - new_allocation.update( - { - 0x25A219378DAD9B3503C8268C9CA836A52427A4FB: { - "nonce": 1, - "code": f.read(), - } - } - ) - return new_allocation | super(Prague, cls).pre_allocation_blockchain() @classmethod From 87cd57098c82d156a8bbed2a2048ce5e09247087 Mon Sep 17 00:00:00 2001 From: spencer-tb Date: Sat, 1 Jun 2024 14:08:02 +0700 Subject: [PATCH 03/14] feat(tests): update eip2935 transtion tests to new spec. --- .../spec.py | 4 +- .../test_block_hashes.py | 114 ++++++++++++------ whitelist.txt | 2 + 3 files changed, 85 insertions(+), 35 deletions(-) diff --git a/tests/prague/eip2935_historical_block_hashes_from_state/spec.py b/tests/prague/eip2935_historical_block_hashes_from_state/spec.py index 0757c98a23..068ac880c5 100644 --- a/tests/prague/eip2935_historical_block_hashes_from_state/spec.py +++ b/tests/prague/eip2935_historical_block_hashes_from_state/spec.py @@ -1,6 +1,7 @@ """ Defines EIP-2935 specification constants and functions. """ + from dataclasses import dataclass @@ -14,7 +15,7 @@ class ReferenceSpec: version: str -ref_spec_2935 = ReferenceSpec("EIPS/eip-2935.md", "3ab311ccd6029c080fb2a8b9615d493dfc093377") +ref_spec_2935 = ReferenceSpec("EIPS/eip-2935.md", "1cbdaf0ffa622e0cb4ec16a552c2f78522652150") @dataclass(frozen=True) @@ -24,6 +25,7 @@ class Spec: https://eips.ethereum.org/EIPS/eip-2935 """ + FORK_TIMESTAMP = 15_000 HISTORY_STORAGE_ADDRESS = 0x25A219378DAD9B3503C8268C9CA836A52427A4FB HISTORY_SERVE_WINDOW = 8192 BLOCKHASH_OLD_WINDOW = 256 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 c6cee6a8ce..707eadd5c9 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 @@ -24,18 +24,16 @@ REFERENCE_SPEC_GIT_PATH = ref_spec_2935.git_path REFERENCE_SPEC_VERSION = ref_spec_2935.version -FORK_TIMESTAMP = 15_000 - def generate_block_check_code( block_number: int | None, populated_blockhash: bool, - populated_contract: bool, + populated_history_storage_contract: bool, storage: Storage, check_contract_first: bool = False, ) -> Bytecode: """ - Generate EVM code to check that the blockhashes are correctly stored in the state. + Generate EVM code to check that the block hashes are correctly stored in the state. Args: block_number (int | None): The block number to check (or None to return empty code). @@ -49,7 +47,7 @@ def generate_block_check_code( return Bytecode() blockhash_key = storage.store_next(not populated_blockhash) - contract_key = storage.store_next(not populated_contract) + contract_key = storage.store_next(not populated_history_storage_contract) check_blockhash = Op.SSTORE(blockhash_key, Op.ISZERO(Op.BLOCKHASH(block_number))) check_contract = ( @@ -63,7 +61,7 @@ def generate_block_check_code( else: code = check_blockhash + check_contract - if populated_contract and populated_blockhash: + if populated_history_storage_contract and populated_blockhash: # Both values must be equal code += Op.SSTORE(storage.store_next(True), Op.EQ(Op.MLOAD(0), Op.BLOCKHASH(block_number))) @@ -71,22 +69,25 @@ def generate_block_check_code( @pytest.mark.parametrize( - "blocks_before_fork", + "blocks_before_fork, blocks_after_fork", [ - pytest.param(1, id="fork_at_1"), - pytest.param(Spec.BLOCKHASH_OLD_WINDOW, id="fork_at_BLOCKHASH_OLD_WINDOW"), + [1, 1], + [Spec.BLOCKHASH_OLD_WINDOW + 1, 10], + [Spec.BLOCKHASH_OLD_WINDOW + 1, Spec.BLOCKHASH_OLD_WINDOW + 1], pytest.param( Spec.BLOCKHASH_OLD_WINDOW + 1, - id="fork_at_BLOCKHASH_OLD_WINDOW_plus_1", + Spec.HISTORY_SERVE_WINDOW + 1, + marks=pytest.mark.slow, ), pytest.param( - Spec.BLOCKHASH_OLD_WINDOW + 2, - id="fork_at_BLOCKHASH_OLD_WINDOW_plus_2", + Spec.HISTORY_SERVE_WINDOW + 1, + 10, + marks=pytest.mark.slow, ), pytest.param( Spec.HISTORY_SERVE_WINDOW + 1, - id="fork_at_HISTORY_SERVE_WINDOW_plus_1", - marks=pytest.mark.skip("To be re-evaluated when updating the tests for new spec"), + Spec.HISTORY_SERVE_WINDOW + 1, + marks=pytest.mark.slow, ), ], ) @@ -95,14 +96,19 @@ def test_block_hashes_history_at_transition( blockchain_test: BlockchainTestFiller, pre: Alloc, blocks_before_fork: int, + blocks_after_fork: int, ): """ - Test the fork transition and that the block hashes of previous blocks, even blocks - before the fork, are included in the state at the moment of the transition. + 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. """ - # Fork happens at timestamp 15_000, and genesis counts as a block before fork. blocks: List[Block] = [] - assert blocks_before_fork >= 1 and blocks_before_fork < FORK_TIMESTAMP + assert blocks_before_fork >= 1 and blocks_before_fork < Spec.FORK_TIMESTAMP sender = pre.fund_eoa(10_000_000_000) post: Dict[Address, Account] = {} @@ -110,13 +116,13 @@ def test_block_hashes_history_at_transition( for i in range(1, 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 + # 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. + # And `HISTORY_STORAGE_ADDRESS` should be empty. code = Bytecode() storage = Storage() - # Check the last block before the window + # Check the last block before blockhash the window code += generate_block_check_code( block_number=( i - Spec.BLOCKHASH_OLD_WINDOW - 1 @@ -124,11 +130,11 @@ def test_block_hashes_history_at_transition( else None # Chain not long enough, no block to check ), populated_blockhash=False, - populated_contract=False, + populated_history_storage_contract=False, storage=storage, ) - # Check the first block inside the window + # Check the first block inside blockhash the window code += generate_block_check_code( block_number=( i - Spec.BLOCKHASH_OLD_WINDOW @@ -136,7 +142,7 @@ def test_block_hashes_history_at_transition( else 0 # Entire chain is inside the window, check genesis ), populated_blockhash=True, - populated_contract=False, + populated_history_storage_contract=False, storage=storage, ) @@ -154,33 +160,33 @@ def test_block_hashes_history_at_transition( # Add the fork block current_block_number = len(blocks) + 1 txs = [] - # On the block after the fork, BLOCKHASH must return values for the last - # Spec.HISTORY_SERVE_WINDOW blocks. - # And HISTORY_STORAGE_ADDRESS should be also serve the same values. + # On the fork block, `BLOCKHASH` must still return values for the last 256 blocks. + # `HISTORY_STORAGE_ADDRESS` system contract will store the blockhash for this block during + # block processing, such that its servable on the subsequent blocks after. code = Bytecode() storage = Storage() # Check the last block before the window code += generate_block_check_code( block_number=( - current_block_number - Spec.HISTORY_SERVE_WINDOW - 1 - if current_block_number > Spec.HISTORY_SERVE_WINDOW + current_block_number - Spec.BLOCKHASH_OLD_WINDOW - 1 + if current_block_number > Spec.BLOCKHASH_OLD_WINDOW else None # Chain not long enough, no block to check ), populated_blockhash=False, - populated_contract=False, + populated_history_storage_contract=False, storage=storage, ) # Check the first block inside the window code += generate_block_check_code( block_number=( - current_block_number - Spec.HISTORY_SERVE_WINDOW - if current_block_number > Spec.HISTORY_SERVE_WINDOW + current_block_number - Spec.BLOCKHASH_OLD_WINDOW + if current_block_number > Spec.BLOCKHASH_OLD_WINDOW else 0 # Entire chain is inside the window, check genesis ), populated_blockhash=True, - populated_contract=True, + populated_history_storage_contract=False, storage=storage, ) @@ -194,7 +200,47 @@ def test_block_hashes_history_at_transition( ) post[code_address] = Account(storage=storage) - blocks.append(Block(timestamp=FORK_TIMESTAMP, txs=txs)) + blocks.append(Block(timestamp=Spec.FORK_TIMESTAMP, txs=txs)) + + # Add blocks after the fork transition to gradually fill up the `HISTORY_SERVE_WINDOW` + for i in range(1, blocks_after_fork + 1): + 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. + code = Bytecode() + storage = Storage() + + # Check that each block can return previous blockhashes within `BLOCKHASH_OLD_WINDOW`` + for j in range(1, min(i, Spec.BLOCKHASH_OLD_WINDOW) + 1): + code += generate_block_check_code( + block_number=(current_block_number - j), + populated_blockhash=True, + populated_history_storage_contract=True, + storage=storage, + ) + + # Check that each block can return previous blockhashes within `HISTORY_SERVE_WINDOW` + for j in range(Spec.BLOCKHASH_OLD_WINDOW + 1, min(i, Spec.HISTORY_SERVE_WINDOW) + 1): + code += generate_block_check_code( + block_number=(current_block_number - j), + populated_blockhash=False, + populated_history_storage_contract=True, + storage=storage, + ) + + code_address = pre.deploy_contract(code) + txs.append( + Transaction( + to=code_address, + gas_limit=10_000_000, + sender=sender, + ) + ) + post[code_address] = Account(storage=storage) + + blocks.append(Block(timestamp=Spec.FORK_TIMESTAMP + 0x0C, txs=txs)) blockchain_test( genesis_environment=Environment(), diff --git a/whitelist.txt b/whitelist.txt index aee48455bd..52d4df4889 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -30,6 +30,7 @@ BlockchainTestFiller BlockchainTests BlockException blockhash +blockhashes blocknum blocktest bls @@ -311,6 +312,7 @@ sandboxed secp256k1 selfbalance ser +servable setitem sha SHA From 09e1b4d4ffba0dda2181a2d55325de6a7e30d9bc Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 25 Jun 2024 14:36:33 +0000 Subject: [PATCH 04/14] typo --- .../test_block_hashes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 707eadd5c9..8d482ed2ee 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 @@ -38,7 +38,7 @@ def generate_block_check_code( Args: block_number (int | None): The block number to check (or None to return empty code). populated_blockhash (bool): Whether the blockhash should be populated. - populated_contract (bool): Whether the contract should be populated. + populated_history_storage_contract (bool): Whether the contract should be populated. storage (Storage): The storage object to use. check_contract_first (bool): Whether to check the contract first, for slot warming checks. """ From ddc05b6839245591b8081d59eeeb37ace65e3b45 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 25 Jun 2024 14:49:18 +0000 Subject: [PATCH 05/14] fix(forks): History contract --- setup.cfg | 2 +- .../forks/contracts/history_contract.bin | Bin 0 -> 100 bytes src/ethereum_test_forks/forks/forks.py | 19 ++++++++++++++---- 3 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 src/ethereum_test_forks/forks/contracts/history_contract.bin diff --git a/setup.cfg b/setup.cfg index 11bbe16a83..46ef7d375b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -51,7 +51,7 @@ ethereum_test_tools = py.typed ethereum_test_forks = py.typed - forks/*.bin + forks/contracts/*.bin evm_transition_tool = py.typed pytest_plugins = diff --git a/src/ethereum_test_forks/forks/contracts/history_contract.bin b/src/ethereum_test_forks/forks/contracts/history_contract.bin new file mode 100644 index 0000000000000000000000000000000000000000..84b6d9f3868c72ab0b065f8e0ab6573e008c4d16 GIT binary patch literal 100 zcmXpm{*MX%i6n%Fr^CeKO$8Hz!xI>tnL#Y?@OaZi1qMcE5HnH!f4r$!NPJL&Lj33G ScsTtx8mLJAKS+;QC<6d6g)&b7 literal 0 HcmV?d00001 diff --git a/src/ethereum_test_forks/forks/forks.py b/src/ethereum_test_forks/forks/forks.py index 387b2ee495..4d11dc603f 100644 --- a/src/ethereum_test_forks/forks/forks.py +++ b/src/ethereum_test_forks/forks/forks.py @@ -529,8 +529,8 @@ def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[int]: @classmethod def pre_allocation_blockchain(cls) -> Mapping: """ - Prague requires pre-allocation of the beacon chain deposit contract for EIP-6110 - and the exits contract for EIP-7002. + 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 = {} @@ -542,7 +542,7 @@ def pre_allocation_blockchain(cls) -> Mapping: storage[i] = next_hash next_hash = sha256(next_hash + next_hash).digest() - with open(CURRENT_FOLDER / "contracts/deposit_contract.bin", mode="rb") as f: + with open(CURRENT_FOLDER / "contracts" / "deposit_contract.bin", mode="rb") as f: new_allocation.update( { 0x00000000219AB540356CBB839CBE05303D7705FA: { @@ -554,7 +554,7 @@ def pre_allocation_blockchain(cls) -> Mapping: ) # Add the withdrawal request contract - with open(CURRENT_FOLDER / "contracts/withdrawal_request.bin", mode="rb") as f: + with open(CURRENT_FOLDER / "contracts" / "withdrawal_request.bin", mode="rb") as f: new_allocation.update( { 0x00A3CA265EBCB825B45F985A16CEFB49958CE017: { @@ -564,6 +564,17 @@ def pre_allocation_blockchain(cls) -> Mapping: } ) + # Add the history storage contract + with open(CURRENT_FOLDER / "contracts" / "history_contract.bin", mode="rb") as f: + new_allocation.update( + { + 0x0AAE40965E6800CD9B1F4B05FF21581047E3F91E: { + "nonce": 1, + "code": f.read(), + } + } + ) + return new_allocation | super(Prague, cls).pre_allocation_blockchain() @classmethod From f524a05b6215392158ddac999cff8c406387b820 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 25 Jun 2024 16:08:20 +0000 Subject: [PATCH 06/14] fix(tests): nits --- .../test_block_hashes.py | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) 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 8d482ed2ee..0763f6d385 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 @@ -26,7 +26,7 @@ def generate_block_check_code( - block_number: int | None, + block_number: int, populated_blockhash: bool, populated_history_storage_contract: bool, storage: Storage, @@ -42,8 +42,8 @@ def generate_block_check_code( storage (Storage): The storage object to use. check_contract_first (bool): Whether to check the contract first, for slot warming checks. """ - if block_number is None: - # No block number to check + if block_number < 0: + # Block number outside of range, nothing to check return Bytecode() blockhash_key = storage.store_next(not populated_blockhash) @@ -68,6 +68,10 @@ def generate_block_check_code( return code +# TODO: Test at transition: `BLOCKHASH_OLD_WINDOW + 1` blocks before transition +# TODO: Test post fork: `HISTORY_SERVE_WINDOW` + 1 blocks after transition + + @pytest.mark.parametrize( "blocks_before_fork, blocks_after_fork", [ @@ -112,6 +116,7 @@ def test_block_hashes_history_at_transition( sender = pre.fund_eoa(10_000_000_000) post: Dict[Address, Account] = {} + current_block_number = 1 for i in range(1, blocks_before_fork): txs: List[Transaction] = [] @@ -124,11 +129,7 @@ def test_block_hashes_history_at_transition( # Check the last block before blockhash the window code += generate_block_check_code( - block_number=( - i - Spec.BLOCKHASH_OLD_WINDOW - 1 - if i > Spec.BLOCKHASH_OLD_WINDOW - else None # Chain not long enough, no block to check - ), + block_number=i - Spec.BLOCKHASH_OLD_WINDOW - 1, populated_blockhash=False, populated_history_storage_contract=False, storage=storage, @@ -146,19 +147,19 @@ def test_block_hashes_history_at_transition( storage=storage, ) - code_address = pre.deploy_contract(code) + check_before_fork_code = pre.deploy_contract(code) txs.append( Transaction( - to=code_address, + to=check_before_fork_code, gas_limit=10_000_000, sender=sender, ) ) - post[code_address] = Account(storage=storage) + post[check_before_fork_code] = Account(storage=storage) blocks.append(Block(timestamp=i, txs=txs)) + current_block_number += 1 # Add the fork block - current_block_number = len(blocks) + 1 txs = [] # On the fork block, `BLOCKHASH` must still return values for the last 256 blocks. # `HISTORY_STORAGE_ADDRESS` system contract will store the blockhash for this block during @@ -168,11 +169,7 @@ def test_block_hashes_history_at_transition( # Check the last block before the window code += generate_block_check_code( - block_number=( - current_block_number - Spec.BLOCKHASH_OLD_WINDOW - 1 - if current_block_number > Spec.BLOCKHASH_OLD_WINDOW - else None # Chain not long enough, no block to check - ), + block_number=current_block_number - Spec.BLOCKHASH_OLD_WINDOW - 1, populated_blockhash=False, populated_history_storage_contract=False, storage=storage, @@ -190,21 +187,21 @@ def test_block_hashes_history_at_transition( storage=storage, ) - code_address = pre.deploy_contract(code) + check_fork_block_code = pre.deploy_contract(code) txs.append( Transaction( - to=code_address, + to=check_fork_block_code, gas_limit=10_000_000, sender=sender, ) ) - post[code_address] = Account(storage=storage) + post[check_fork_block_code] = Account(storage=storage) blocks.append(Block(timestamp=Spec.FORK_TIMESTAMP, txs=txs)) + current_block_number += 1 # Add blocks after the fork transition to gradually fill up the `HISTORY_SERVE_WINDOW` for i in range(1, blocks_after_fork + 1): - 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 @@ -230,17 +227,18 @@ def test_block_hashes_history_at_transition( storage=storage, ) - code_address = pre.deploy_contract(code) + check_blocks_after_fork_code = pre.deploy_contract(code) txs.append( Transaction( - to=code_address, + to=check_blocks_after_fork_code, gas_limit=10_000_000, sender=sender, ) ) - post[code_address] = Account(storage=storage) + post[check_blocks_after_fork_code] = Account(storage=storage) blocks.append(Block(timestamp=Spec.FORK_TIMESTAMP + 0x0C, txs=txs)) + current_block_number += 1 blockchain_test( genesis_environment=Environment(), From 4b36bbaa0e3dcb5a7c0dc784c04fd13d5b7cb74f Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 25 Jun 2024 18:16:12 +0000 Subject: [PATCH 07/14] fix(tests): HISTORY_STORAGE_ADDRESS spec update --- tests/prague/eip2935_historical_block_hashes_from_state/spec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/prague/eip2935_historical_block_hashes_from_state/spec.py b/tests/prague/eip2935_historical_block_hashes_from_state/spec.py index 068ac880c5..8c8bf7120f 100644 --- a/tests/prague/eip2935_historical_block_hashes_from_state/spec.py +++ b/tests/prague/eip2935_historical_block_hashes_from_state/spec.py @@ -26,6 +26,6 @@ class Spec: """ FORK_TIMESTAMP = 15_000 - HISTORY_STORAGE_ADDRESS = 0x25A219378DAD9B3503C8268C9CA836A52427A4FB + HISTORY_STORAGE_ADDRESS = 0x0AAE40965E6800CD9B1F4B05FF21581047E3F91E HISTORY_SERVE_WINDOW = 8192 BLOCKHASH_OLD_WINDOW = 256 From 71ed19c3765891265eba8ce417670ed0f5df521d Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 25 Jun 2024 18:17:39 +0000 Subject: [PATCH 08/14] fix(tests): refactor transition tests, helper function, add post fork test --- .../test_block_hashes.py | 263 ++++++++++-------- 1 file changed, 154 insertions(+), 109 deletions(-) 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 0763f6d385..167c0077e1 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 @@ -7,15 +7,7 @@ import pytest -from ethereum_test_tools import ( - Account, - Address, - Alloc, - Block, - BlockchainTestFiller, - Bytecode, - Environment, -) +from ethereum_test_tools import Account, Address, Alloc, Block, BlockchainTestFiller, Bytecode from ethereum_test_tools import Opcodes as Op from ethereum_test_tools import Storage, Transaction @@ -26,9 +18,9 @@ def generate_block_check_code( - block_number: int, - populated_blockhash: bool, - populated_history_storage_contract: bool, + check_block_number: int, + current_block_number: int, + fork_block_number: int, storage: Storage, check_contract_first: bool = False, ) -> Bytecode: @@ -36,22 +28,34 @@ def generate_block_check_code( Generate EVM code to check that the block hashes are correctly stored in the state. Args: - block_number (int | None): The block number to check (or None to return empty code). - populated_blockhash (bool): Whether the blockhash should be populated. - populated_history_storage_contract (bool): Whether the contract should be populated. + 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. """ - if block_number < 0: + if check_block_number < 0: # Block number outside of range, nothing to check return Bytecode() + populated_blockhash = ( + check_block_number >= current_block_number - Spec.BLOCKHASH_OLD_WINDOW + and check_block_number < current_block_number + ) + populated_history_storage_contract = ( + check_block_number >= fork_block_number - 1 + and current_block_number - check_block_number < Spec.HISTORY_SERVE_WINDOW + and check_block_number < current_block_number + ) + blockhash_key = storage.store_next(not populated_blockhash) + blockhash_key.label += f", check_block_number={check_block_number}" contract_key = storage.store_next(not populated_history_storage_contract) + contract_key.label += f", check_block_number={check_block_number}" - check_blockhash = Op.SSTORE(blockhash_key, Op.ISZERO(Op.BLOCKHASH(block_number))) + check_blockhash = Op.SSTORE(blockhash_key, Op.ISZERO(Op.BLOCKHASH(check_block_number))) check_contract = ( - Op.MSTORE(0, block_number) + Op.MSTORE(0, check_block_number) + Op.POP(Op.CALL(Op.GAS, Spec.HISTORY_STORAGE_ADDRESS, 0, 0, 32, 0, 32)) + Op.SSTORE(contract_key, Op.ISZERO(Op.MLOAD(0))) ) @@ -63,7 +67,9 @@ def generate_block_check_code( if populated_history_storage_contract and populated_blockhash: # Both values must be equal - code += Op.SSTORE(storage.store_next(True), Op.EQ(Op.MLOAD(0), Op.BLOCKHASH(block_number))) + store_equal_key = storage.store_next(True) + store_equal_key.label += f", check_block_number={check_block_number}" + code += Op.SSTORE(store_equal_key, Op.EQ(Op.MLOAD(0), Op.BLOCKHASH(check_block_number))) return code @@ -75,24 +81,9 @@ def generate_block_check_code( @pytest.mark.parametrize( "blocks_before_fork, blocks_after_fork", [ - [1, 1], + [1, 2], [Spec.BLOCKHASH_OLD_WINDOW + 1, 10], - [Spec.BLOCKHASH_OLD_WINDOW + 1, Spec.BLOCKHASH_OLD_WINDOW + 1], - pytest.param( - Spec.BLOCKHASH_OLD_WINDOW + 1, - Spec.HISTORY_SERVE_WINDOW + 1, - marks=pytest.mark.slow, - ), - pytest.param( - Spec.HISTORY_SERVE_WINDOW + 1, - 10, - marks=pytest.mark.slow, - ), - pytest.param( - Spec.HISTORY_SERVE_WINDOW + 1, - Spec.HISTORY_SERVE_WINDOW + 1, - marks=pytest.mark.slow, - ), + [1, Spec.BLOCKHASH_OLD_WINDOW + 1], ], ) @pytest.mark.valid_at_transition_to("Prague") @@ -117,8 +108,9 @@ def test_block_hashes_history_at_transition( sender = pre.fund_eoa(10_000_000_000) post: Dict[Address, Account] = {} current_block_number = 1 + fork_block_number = current_block_number + blocks_before_fork - for i in range(1, blocks_before_fork): + 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 @@ -129,119 +121,172 @@ def test_block_hashes_history_at_transition( # Check the last block before blockhash the window code += generate_block_check_code( - block_number=i - Spec.BLOCKHASH_OLD_WINDOW - 1, - populated_blockhash=False, - populated_history_storage_contract=False, + check_block_number=current_block_number - Spec.BLOCKHASH_OLD_WINDOW - 1, + current_block_number=current_block_number, + fork_block_number=fork_block_number, storage=storage, ) # Check the first block inside blockhash the window code += generate_block_check_code( - block_number=( - i - Spec.BLOCKHASH_OLD_WINDOW - if i > Spec.BLOCKHASH_OLD_WINDOW + check_block_number=( + current_block_number - Spec.BLOCKHASH_OLD_WINDOW + if current_block_number > Spec.BLOCKHASH_OLD_WINDOW else 0 # Entire chain is inside the window, check genesis ), - populated_blockhash=True, - populated_history_storage_contract=False, + current_block_number=current_block_number, + fork_block_number=fork_block_number, storage=storage, ) - check_before_fork_code = pre.deploy_contract(code) + check_blocks_before_fork_address = pre.deploy_contract(code) txs.append( Transaction( - to=check_before_fork_code, + to=check_blocks_before_fork_address, gas_limit=10_000_000, sender=sender, ) ) - post[check_before_fork_code] = Account(storage=storage) - blocks.append(Block(timestamp=i, txs=txs)) + post[check_blocks_before_fork_address] = Account(storage=storage) + 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` + 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. + code = Bytecode() + storage = Storage() + + # 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, + current_block_number=current_block_number, + fork_block_number=fork_block_number, + storage=storage, + ) + + check_blocks_after_fork_address = pre.deploy_contract(code) + txs.append( + Transaction( + to=check_blocks_after_fork_address, + gas_limit=10_000_000, + sender=sender, + ) + ) + post[check_blocks_after_fork_address] = Account(storage=storage) + + blocks.append(Block(timestamp=Spec.FORK_TIMESTAMP + i, txs=txs)) + current_block_number += 1 + + blockchain_test( + pre=pre, + blocks=blocks, + post=post, + ) + + +@pytest.mark.parametrize( + "block_count,check_contract_first", + [ + pytest.param(1, False, id="single_block_check_blockhash_first"), + pytest.param(1, True, id="single_block_check_contract_first"), + pytest.param(2, False, id="two_blocks_check_blockhash_first"), + pytest.param(2, True, id="two_blocks_check_contract_first"), + pytest.param( + Spec.HISTORY_SERVE_WINDOW + 1, + False, + marks=pytest.mark.slow, + id="full_history_check_blockhash_first", + ), + ], +) +@pytest.mark.valid_from("Prague") +def test_block_hashes_history( + blockchain_test: BlockchainTestFiller, + pre: Alloc, + block_count: int, + 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. + """ + blocks: List[Block] = [] + + sender = pre.fund_eoa(10_000_000_000) + post: Dict[Address, Account] = {} + current_block_number = 1 + fork_block_number = 0 # We fork at genesis + + for i in range(block_count - 1): + # Generate empty blocks after the fork. + blocks.append(Block(txs=[])) current_block_number += 1 - # Add the fork block txs = [] - # On the fork block, `BLOCKHASH` must still return values for the last 256 blocks. - # `HISTORY_STORAGE_ADDRESS` system contract will store the blockhash for this block during - # block processing, such that its servable on the subsequent blocks after. + # 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 the last block before the window + # Check the first block outside of the window if any code += generate_block_check_code( - block_number=current_block_number - Spec.BLOCKHASH_OLD_WINDOW - 1, - populated_blockhash=False, - populated_history_storage_contract=False, + check_block_number=current_block_number - Spec.HISTORY_SERVE_WINDOW - 1, + current_block_number=current_block_number, + fork_block_number=fork_block_number, storage=storage, + check_contract_first=check_contract_first, ) # Check the first block inside the window code += generate_block_check_code( - block_number=( - current_block_number - Spec.BLOCKHASH_OLD_WINDOW - if current_block_number > Spec.BLOCKHASH_OLD_WINDOW - else 0 # Entire chain is inside the window, check genesis - ), - populated_blockhash=True, - populated_history_storage_contract=False, + check_block_number=current_block_number - Spec.HISTORY_SERVE_WINDOW, + current_block_number=current_block_number, + fork_block_number=fork_block_number, + storage=storage, + check_contract_first=check_contract_first, + ) + + # Check the first block outside the BLOCKHASH window + code += generate_block_check_code( + check_block_number=current_block_number - Spec.BLOCKHASH_OLD_WINDOW - 1, + current_block_number=current_block_number, + fork_block_number=fork_block_number, + storage=storage, + check_contract_first=check_contract_first, + ) + + # Check the previous block + code += generate_block_check_code( + check_block_number=current_block_number - 1, + current_block_number=current_block_number, + fork_block_number=fork_block_number, storage=storage, + check_contract_first=check_contract_first, ) - check_fork_block_code = pre.deploy_contract(code) + check_blocks_after_fork_address = pre.deploy_contract(code) txs.append( Transaction( - to=check_fork_block_code, + to=check_blocks_after_fork_address, gas_limit=10_000_000, sender=sender, ) ) - post[check_fork_block_code] = Account(storage=storage) + post[check_blocks_after_fork_address] = Account(storage=storage) - blocks.append(Block(timestamp=Spec.FORK_TIMESTAMP, txs=txs)) + blocks.append(Block(txs=txs)) current_block_number += 1 - # Add blocks after the fork transition to gradually fill up the `HISTORY_SERVE_WINDOW` - for i in range(1, blocks_after_fork + 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. - code = Bytecode() - storage = Storage() - - # Check that each block can return previous blockhashes within `BLOCKHASH_OLD_WINDOW`` - for j in range(1, min(i, Spec.BLOCKHASH_OLD_WINDOW) + 1): - code += generate_block_check_code( - block_number=(current_block_number - j), - populated_blockhash=True, - populated_history_storage_contract=True, - storage=storage, - ) - - # Check that each block can return previous blockhashes within `HISTORY_SERVE_WINDOW` - for j in range(Spec.BLOCKHASH_OLD_WINDOW + 1, min(i, Spec.HISTORY_SERVE_WINDOW) + 1): - code += generate_block_check_code( - block_number=(current_block_number - j), - populated_blockhash=False, - populated_history_storage_contract=True, - storage=storage, - ) - - check_blocks_after_fork_code = pre.deploy_contract(code) - txs.append( - Transaction( - to=check_blocks_after_fork_code, - gas_limit=10_000_000, - sender=sender, - ) - ) - post[check_blocks_after_fork_code] = Account(storage=storage) - - blocks.append(Block(timestamp=Spec.FORK_TIMESTAMP + 0x0C, txs=txs)) - current_block_number += 1 - blockchain_test( - genesis_environment=Environment(), pre=pre, blocks=blocks, post=post, From 0f70fb1087fbd09f0e0c0773f7419e0e66312a46 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 25 Jun 2024 18:56:48 +0000 Subject: [PATCH 09/14] fix(tests): logic fixes --- .../test_block_hashes.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) 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 167c0077e1..589012c79c 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 @@ -39,12 +39,12 @@ def generate_block_check_code( return Bytecode() populated_blockhash = ( - check_block_number >= current_block_number - Spec.BLOCKHASH_OLD_WINDOW + current_block_number - check_block_number <= Spec.BLOCKHASH_OLD_WINDOW and check_block_number < current_block_number ) populated_history_storage_contract = ( check_block_number >= fork_block_number - 1 - and current_block_number - check_block_number < Spec.HISTORY_SERVE_WINDOW + and current_block_number - check_block_number <= Spec.HISTORY_SERVE_WINDOW and check_block_number < current_block_number ) @@ -201,7 +201,7 @@ def test_block_hashes_history_at_transition( Spec.HISTORY_SERVE_WINDOW + 1, False, marks=pytest.mark.slow, - id="full_history_check_blockhash_first", + id="full_history_plus_one_check_blockhash_first", ), ], ) @@ -225,9 +225,9 @@ def test_block_hashes_history( current_block_number = 1 fork_block_number = 0 # We fork at genesis - for i in range(block_count - 1): + for _ in range(block_count - 1): # Generate empty blocks after the fork. - blocks.append(Block(txs=[])) + blocks.append(Block()) current_block_number += 1 txs = [] @@ -264,6 +264,15 @@ def test_block_hashes_history( check_contract_first=check_contract_first, ) + # Check the first block inside the BLOCKHASH window + code += generate_block_check_code( + check_block_number=current_block_number - Spec.BLOCKHASH_OLD_WINDOW, + current_block_number=current_block_number, + fork_block_number=fork_block_number, + storage=storage, + check_contract_first=check_contract_first, + ) + # Check the previous block code += generate_block_check_code( check_block_number=current_block_number - 1, From 6b991e61ef56de6a51498fa658c09d75b7267ff1 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 25 Jun 2024 19:14:32 +0000 Subject: [PATCH 10/14] fix --- .../test_block_hashes.py | 3 --- 1 file changed, 3 deletions(-) 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 589012c79c..ecbeed95e0 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 @@ -49,9 +49,7 @@ def generate_block_check_code( ) blockhash_key = storage.store_next(not populated_blockhash) - blockhash_key.label += f", check_block_number={check_block_number}" contract_key = storage.store_next(not populated_history_storage_contract) - contract_key.label += f", check_block_number={check_block_number}" check_blockhash = Op.SSTORE(blockhash_key, Op.ISZERO(Op.BLOCKHASH(check_block_number))) check_contract = ( @@ -68,7 +66,6 @@ def generate_block_check_code( if populated_history_storage_contract and populated_blockhash: # Both values must be equal store_equal_key = storage.store_next(True) - store_equal_key.label += f", check_block_number={check_block_number}" code += Op.SSTORE(store_equal_key, Op.EQ(Op.MLOAD(0), Op.BLOCKHASH(check_block_number))) return code From 96b6a90d472e4e3d67c99372654c6d67b9e1cebc Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 25 Jun 2024 19:25:00 +0000 Subject: [PATCH 11/14] fix: ref spec sha --- tests/prague/eip2935_historical_block_hashes_from_state/spec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/prague/eip2935_historical_block_hashes_from_state/spec.py b/tests/prague/eip2935_historical_block_hashes_from_state/spec.py index 8c8bf7120f..b0b7336bd2 100644 --- a/tests/prague/eip2935_historical_block_hashes_from_state/spec.py +++ b/tests/prague/eip2935_historical_block_hashes_from_state/spec.py @@ -15,7 +15,7 @@ class ReferenceSpec: version: str -ref_spec_2935 = ReferenceSpec("EIPS/eip-2935.md", "1cbdaf0ffa622e0cb4ec16a552c2f78522652150") +ref_spec_2935 = ReferenceSpec("EIPS/eip-2935.md", "68d54a80a4f5b9c0cf4ae3a10586d63ef221de36") @dataclass(frozen=True) From 03174dddf7e020e522a506aba89299a07d655123 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 25 Jun 2024 19:44:46 +0000 Subject: [PATCH 12/14] feat(fw): Add `storage.canary()` --- src/ethereum_test_tools/common/types.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ethereum_test_tools/common/types.py b/src/ethereum_test_tools/common/types.py index 0a826e72fb..571df14edc 100644 --- a/src/ethereum_test_tools/common/types.py +++ b/src/ethereum_test_tools/common/types.py @@ -324,6 +324,13 @@ def must_be_equal(self, address: Address, other: "Storage | None"): elif other[key] != 0: raise Storage.KeyValueMismatch(address=address, key=key, want=0, got=other[key]) + def canary(self) -> "Storage": + """ + Returns 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}) + class Account(CopyValidateModel): """ From 5ac9b46b1c91d3eff8bdc7386225f5e820a0116f Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 25 Jun 2024 19:45:03 +0000 Subject: [PATCH 13/14] new(tests): add invalid block number requests --- .../test_block_hashes.py | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) 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 ecbeed95e0..57ca2e0ca2 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 @@ -297,3 +297,61 @@ def test_block_hashes_history( blocks=blocks, post=post, ) + + +@pytest.mark.parametrize( + "block_number,reverts", + [ + pytest.param(1, False, id="current_block"), + pytest.param(2, False, id="future_block"), + pytest.param(2**64 - 1, False, id="2**64-1"), + pytest.param(2**64, True, id="2**64"), + ], +) +@pytest.mark.valid_from("Prague") +def test_invalid_history_contract_calls( + blockchain_test: BlockchainTestFiller, + pre: Alloc, + block_number: int, + reverts: bool, +): + """ + 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. + """ + storage = Storage() + + return_code_slot = storage.store_next(not reverts) + returned_block_hash_slot = storage.store_next(0) + block_hash_opcode_slot = storage.store_next(0) + + # Check the first block outside of the window if any + code = ( + Op.MSTORE(0, block_number) + + Op.SSTORE( + return_code_slot, Op.CALL(Op.GAS, Spec.HISTORY_STORAGE_ADDRESS, 0, 0, 32, 32, 64) + ) + + Op.SSTORE(returned_block_hash_slot, Op.MLOAD(32)) + + Op.SSTORE(block_hash_opcode_slot, Op.BLOCKHASH(block_number)) + ) + check_contract_address = pre.deploy_contract(code, storage=storage.canary()) + + txs = [ + Transaction( + to=check_contract_address, + gas_limit=10_000_000, + sender=pre.fund_eoa(), + ) + ] + post = {check_contract_address: Account(storage=storage)} + + blocks = [Block(txs=txs)] + blockchain_test( + pre=pre, + blocks=blocks, + post=post, + reverts=reverts, + ) From 537869864dc6653bab1c3b47992d407194af39a9 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 25 Jun 2024 20:43:04 +0000 Subject: [PATCH 14/14] changelog --- docs/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8309108c72..28dc2e7546 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -17,7 +17,7 @@ Test fixtures for use by clients are available for each release on the [Github r - ✨ Add tests for [EIP-6110: Supply validator deposits on chain](https://eips.ethereum.org/EIPS/eip-6110) ([#530](https://github.com/ethereum/execution-spec-tests/pull/530)). - ✨ Add tests for [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002) ([#530](https://github.com/ethereum/execution-spec-tests/pull/530)). - ✨ Add tests for [EIP-7685: General purpose execution layer requests](https://eips.ethereum.org/EIPS/eip-7685) ([#530](https://github.com/ethereum/execution-spec-tests/pull/530)). -- ✨ Add tests for [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935) ([#564](https://github.com/ethereum/execution-spec-tests/pull/564)). +- ✨ Add tests for [EIP-2935: Serve historical block hashes from state](https://eips.ethereum.org/EIPS/eip-2935) ([#564](https://github.com/ethereum/execution-spec-tests/pull/564), [#585](https://github.com/ethereum/execution-spec-tests/pull/585)). - ✨ Add tests for [EIP-4200: EOF - Static relative jumps](https://eips.ethereum.org/EIPS/eip-4200) ([#581](https://github.com/ethereum/execution-spec-tests/pull/581)). - ✨ Add tests for [EIP-7069: EOF - Revamped CALL instructions](https://eips.ethereum.org/EIPS/eip-7069) ([#595](https://github.com/ethereum/execution-spec-tests/pull/595)). - 🐞 Fix typos in self-destruct collision test from erroneous pytest parametrization ([#608](https://github.com/ethereum/execution-spec-tests/pull/608)).