55""" # noqa: E501
66
77from itertools import permutations
8- from typing import Any , Generator , List
8+ from typing import Any , Dict , Generator , List , Tuple
99
1010import pytest
1111
1818 BlockchainTestFiller ,
1919 BlockException ,
2020 Bytecode ,
21+ Bytes ,
2122 Environment ,
2223 Header ,
2324 Requests ,
2627 Transaction ,
2728)
2829from ethereum_test_tools import Opcodes as Op
30+ from pytest_plugins import fork_covariant_parametrize
2931
3032from ..eip6110_deposits .helpers import DepositContract , DepositRequest , DepositTransaction
3133from ..eip6110_deposits .spec import Spec as Spec_EIP6110
@@ -214,6 +216,10 @@ def get_contract_permutations(n: int = 3) -> Generator[Any, None, None]:
214216 ],
215217 id = "withdrawal_from_eoa+consolidation_from_eoa+withdrawal_from_contract" ,
216218 ),
219+ pytest .param (
220+ [],
221+ id = "empty_requests" ,
222+ ),
217223 ],
218224)
219225def test_valid_deposit_withdrawal_consolidation_requests (
@@ -320,148 +326,154 @@ def test_valid_deposit_withdrawal_consolidation_request_from_same_tx(
320326 )
321327
322328
323- invalid_requests_block_combinations = [
324- pytest .param (
325- [],
326- [], # Even with no requests, the requests hash is not sha256(b""),
327- # but sha256(sha256(b"\0") ++ sha256(b"\1") ++ sha256(b"\2") ++ ...)
328- BlockException .INVALID_REQUESTS ,
329- id = "no_requests_empty_list" ,
330- ),
331- pytest .param (
332- [
333- single_deposit_from_eoa (0 ),
334- ],
335- [
336- single_deposit (0 ),
337- ],
338- BlockException .INVALID_REQUESTS ,
339- id = "single_deposit_incomplete_requests_list" ,
340- ),
341- pytest .param (
342- [
343- single_deposit_from_eoa (0 ),
344- ],
345- [],
346- BlockException .INVALID_REQUESTS ,
347- id = "single_deposit_empty_requests_list" ,
348- ),
349- # Incorrect order tests
350- pytest .param (
351- [
352- single_deposit_from_eoa (0 ),
353- ],
354- [
355- b"" ,
356- single_deposit (0 ),
357- b"" ,
329+ def invalid_requests_block_combinations (fork : Fork ) -> List [Any ]:
330+ """
331+ Return a list of invalid request combinations for the given fork.
332+
333+ In the event of a new request type, the `all_request_types` dictionary should be updated
334+ with the new request type and its corresponding request-generating transaction.
335+ """
336+ assert fork .max_request_type () == 2 , "Test update is needed for new request types"
337+
338+ all_request_types : Dict [
339+ str ,
340+ Tuple [
341+ DepositTransaction | WithdrawalRequestTransaction | ConsolidationRequestTransaction ,
342+ DepositRequest | WithdrawalRequest | ConsolidationRequest ,
358343 ],
359- BlockException .INVALID_REQUESTS ,
360- id = "single_deposit_incorrect_order_1" ,
361- ),
362- pytest .param (
363- [
344+ ] = {
345+ "deposit" : (
364346 single_deposit_from_eoa (0 ),
365- ],
366- [
367- b"" ,
368- b"" ,
369347 single_deposit (0 ),
370- ],
371- BlockException .INVALID_REQUESTS ,
372- id = "single_deposit_incorrect_order_2" ,
373- ),
374- pytest .param (
375- [
376- single_withdrawal_from_eoa (0 ),
377- ],
378- [
379- single_withdrawal (0 ).with_source_address (TestAddress ),
380- b"" ,
381- b"" ,
382- ],
383- BlockException .INVALID_REQUESTS ,
384- id = "single_withdrawal_incorrect_order_1" ,
385- ),
386- pytest .param (
387- [
348+ ),
349+ "withdrawal" : (
388350 single_withdrawal_from_eoa (0 ),
389- ],
390- [
391- b"" ,
392- b"" ,
393351 single_withdrawal (0 ).with_source_address (TestAddress ),
394- ],
395- BlockException .INVALID_REQUESTS ,
396- id = "single_withdrawal_incorrect_order_2" ,
397- ),
398- pytest .param (
399- [
352+ ),
353+ "consolidation" : (
400354 single_consolidation_from_eoa (0 ),
401- ],
402- [
403355 single_consolidation (0 ).with_source_address (TestAddress ),
404- b"" ,
405- b"" ,
406- ],
407- BlockException .INVALID_REQUESTS ,
408- id = "single_consolidation_incorrect_order_1" ,
409- ),
410- pytest .param (
411- [
412- single_consolidation_from_eoa (0 ),
413- ],
414- [
415- b"" ,
416- single_consolidation (0 ).with_source_address (TestAddress ),
417- b"" ,
418- ],
419- BlockException .INVALID_REQUESTS ,
420- id = "single_consolidation_incorrect_order_2" ,
421- ),
422- pytest .param (
423- [
424- single_deposit_from_eoa (0 ),
425- single_withdrawal_from_eoa (0 ),
426- ],
427- [
428- single_deposit (0 ),
429- single_withdrawal (0 ).with_source_address (TestAddress ),
430- ],
431- BlockException .INVALID_REQUESTS ,
432- id = "single_deposit_single_withdrawal_incomplete_requests_list" ,
433- ),
434- pytest .param (
435- [
436- single_deposit_from_eoa (0 ),
437- single_withdrawal_from_eoa (0 ),
438- ],
439- [
440- single_deposit (0 ),
441- ],
442- BlockException .INVALID_REQUESTS ,
443- id = "single_deposit_single_withdrawal_incomplete_requests_list_2" ,
444- ),
445- pytest .param (
446- [
447- single_deposit_from_eoa (0 ),
448- single_withdrawal_from_eoa (0 ),
449- single_consolidation_from_eoa (0 ),
450- ],
451- [
452- single_deposit (0 ),
453- single_withdrawal (0 ).with_source_address (TestAddress ),
454- ],
455- BlockException .INVALID_REQUESTS ,
456- id = "single_deposit_single_withdrawal_single_consolidation_incomplete_requests_list" ,
457- ),
458- ]
356+ ),
357+ }
358+
359+ # - Empty requests list with invalid hash
360+ combinations = [
361+ pytest .param (
362+ [],
363+ [
364+ bytes ([i ]) for i in range (fork .max_request_type () + 1 )
365+ ], # Using empty requests, calculate the hash using an invalid calculation method:
366+ # sha256(sha256(b"\0") ++ sha256(b"\1") ++ sha256(b"\2") ++ ...)
367+ BlockException .INVALID_REQUESTS ,
368+ id = "no_requests_invalid_hash_calculation_method" ,
369+ ),
370+ pytest .param (
371+ [],
372+ [
373+ bytes ([]) for _ in range (fork .max_request_type () + 1 )
374+ ], # Using empty requests, calculate the hash using an invalid calculation method:
375+ # sha256(sha256(b"") ++ sha256(b"") ++ sha256(b"") ++ ...)
376+ BlockException .INVALID_REQUESTS ,
377+ id = "no_requests_invalid_hash_calculation_method_2" ,
378+ ),
379+ ]
459380
381+ # - Missing request or request type byte tests
382+ for request_type , (eoa_request , block_request ) in all_request_types .items ():
383+ combinations .extend (
384+ [
385+ pytest .param (
386+ [eoa_request ],
387+ [
388+ block_request
389+ ], # The request type byte missing because we need to use the `Requests` class
390+ BlockException .INVALID_REQUESTS ,
391+ id = f"single_{ request_type } _missing_type_byte" ,
392+ ),
393+ pytest .param (
394+ [eoa_request ],
395+ [],
396+ BlockException .INVALID_REQUESTS ,
397+ id = f"single_{ request_type } _empty_requests_list" ,
398+ ),
399+ ]
400+ )
460401
461- @pytest .mark .parametrize (
462- "requests,block_body_override_requests,exception" ,
463- invalid_requests_block_combinations ,
464- indirect = ["block_body_override_requests" ],
402+ # - Incorrect order tests
403+ correct_order : List [Bytes ] = Requests (
404+ * [r [1 ] for r in all_request_types .values ()]
405+ ).requests_list # Requests automatically adds the type byte
406+ correct_order_transactions : List [
407+ DepositTransaction | WithdrawalRequestTransaction | ConsolidationRequestTransaction
408+ ] = [r [0 ] for r in all_request_types .values ()]
409+
410+ # Send first element to the end
411+ combinations .append (
412+ pytest .param (
413+ correct_order_transactions [1 :] + [correct_order_transactions [0 ]],
414+ correct_order [1 :] + [correct_order [0 ]],
415+ BlockException .INVALID_REQUESTS ,
416+ id = "incorrect_order_first_request_at_end" ,
417+ ),
418+ )
419+
420+ # Send second element to the end
421+ combinations .append (
422+ pytest .param (
423+ [correct_order_transactions [0 ]]
424+ + correct_order_transactions [2 :]
425+ + [correct_order_transactions [1 ]],
426+ [correct_order [0 ]] + correct_order [2 :] + [correct_order [1 ]],
427+ BlockException .INVALID_REQUESTS ,
428+ id = "incorrect_order_second_request_at_end" ,
429+ ),
430+ )
431+
432+ # Bring last element to the beginning
433+ combinations .append (
434+ pytest .param (
435+ [correct_order_transactions [- 1 ]] + correct_order_transactions [:- 1 ],
436+ [correct_order [- 1 ]] + correct_order [:- 1 ],
437+ BlockException .INVALID_REQUESTS ,
438+ id = "incorrect_order_last_request_at_beginning" ,
439+ ),
440+ )
441+
442+ # - Duplicate request tests
443+ for request_type , (eoa_request , block_request ) in all_request_types .items ():
444+ combinations .append (
445+ pytest .param (
446+ [eoa_request ],
447+ Requests (block_request ).requests_list * 2 ,
448+ BlockException .INVALID_REQUESTS ,
449+ id = f"duplicate_{ request_type } _request" ,
450+ ),
451+ )
452+
453+ # - Extra invalid request tests
454+ combinations .append (
455+ pytest .param (
456+ correct_order_transactions ,
457+ correct_order + [b"" ],
458+ BlockException .INVALID_REQUESTS ,
459+ id = "extra_empty_request" ,
460+ ),
461+ )
462+ combinations .append (
463+ pytest .param (
464+ correct_order_transactions ,
465+ correct_order + [bytes ([fork .max_request_type () + 1 ])],
466+ BlockException .INVALID_REQUESTS ,
467+ id = "extra_invalid_type_request" ,
468+ ),
469+ )
470+
471+ return combinations
472+
473+
474+ @fork_covariant_parametrize (
475+ parameter_names = "requests,block_body_override_requests,exception" ,
476+ fn = invalid_requests_block_combinations ,
465477)
466478def test_invalid_deposit_withdrawal_consolidation_requests (
467479 blockchain_test : BlockchainTestFiller ,
@@ -484,10 +496,9 @@ def test_invalid_deposit_withdrawal_consolidation_requests(
484496 )
485497
486498
487- @pytest .mark .parametrize (
488- "requests,block_body_override_requests,exception" ,
489- invalid_requests_block_combinations ,
490- indirect = ["block_body_override_requests" ],
499+ @fork_covariant_parametrize (
500+ parameter_names = "requests,block_body_override_requests,exception" ,
501+ fn = invalid_requests_block_combinations ,
491502)
492503@pytest .mark .parametrize ("correct_requests_hash_in_header" , [True ])
493504def test_invalid_deposit_withdrawal_consolidation_requests_engine (
0 commit comments