@@ -534,21 +534,20 @@ def block(
534534 )
535535
536536
537- def all_valid_blob_combinations ( ) -> List [Tuple [int , ...]]:
537+ def blob_combinations ( max_blob_count : int ) -> List [Tuple [int , ...]]:
538538 """
539- Returns all valid blob tx combinations for a given block ,
539+ Returns all blob tx combinations for a given max_blob_count ,
540540 assuming the given MAX_BLOBS_PER_BLOCK
541541 """
542542 all = [
543543 seq
544544 for i in range (
545- SpecHelpers . max_blobs_per_block () , 0 , - 1
546- ) # We can have from 1 to at most MAX_BLOBS_PER_BLOCK blobs per block
545+ max_blob_count , 0 , - 1
546+ ) # We generate combinations have from 1 to at most max_blob_count blobs per block
547547 for seq in itertools .combinations_with_replacement (
548- range (1 , SpecHelpers . max_blobs_per_block () + 1 ), i
548+ range (1 , max_blob_count + 1 ), i
549549 ) # We iterate through all possible combinations
550- if sum (seq )
551- <= SpecHelpers .max_blobs_per_block () # And we only keep the ones that are valid
550+ if sum (seq ) == max_blob_count # And we only keep the ones that are valid
552551 ]
553552 # We also add the reversed version of each combination, only if it's not
554553 # already in the list. E.g. (2, 1, 1) is added from (1, 1, 2) but not
@@ -557,28 +556,24 @@ def all_valid_blob_combinations() -> List[Tuple[int, ...]]:
557556 return all
558557
559558
559+ def all_valid_blob_combinations () -> List [Tuple [int , ...]]:
560+ """
561+ Returns all valid blob tx combinations for a given block,
562+ assuming the given MAX_BLOBS_PER_BLOCK
563+ """
564+ return [
565+ item
566+ for row in [blob_combinations (i ) for i in range (1 , SpecHelpers .max_blobs_per_block () + 1 )]
567+ for item in row
568+ ]
569+
570+
560571def invalid_blob_combinations () -> List [Tuple [int , ...]]:
561572 """
562573 Returns invalid blob tx combinations for a given block that use up to
563574 MAX_BLOBS_PER_BLOCK+1 blobs
564575 """
565- all = [
566- seq
567- for i in range (
568- SpecHelpers .max_blobs_per_block () + 1 , 0 , - 1
569- ) # We can have from 1 to at most MAX_BLOBS_PER_BLOCK blobs per block
570- for seq in itertools .combinations_with_replacement (
571- range (1 , SpecHelpers .max_blobs_per_block () + 2 ), i
572- ) # We iterate through all possible combinations
573- if sum (seq )
574- == SpecHelpers .max_blobs_per_block () + 1 # And we only keep the ones that match the
575- # expected invalid blob count
576- ]
577- # We also add the reversed version of each combination, only if it's not
578- # already in the list. E.g. (4, 1) is added from (1, 4) but not
579- # (1, 1, 1, 1, 1) because its reversed version is identical.
580- all += [tuple (reversed (x )) for x in all if tuple (reversed (x )) not in all ]
581- return all
576+ return blob_combinations (SpecHelpers .max_blobs_per_block () + 1 )
582577
583578
584579@pytest .mark .parametrize (
@@ -611,6 +606,40 @@ def test_valid_blob_tx_combinations(
611606 )
612607
613608
609+ @pytest .mark .parametrize (
610+ "blobs_per_tx" ,
611+ blob_combinations (SpecHelpers .max_blobs_per_block_prague ()),
612+ )
613+ @pytest .mark .valid_from ("Prague" )
614+ def test_valid_blob_tx_combinations_prague (
615+ blockchain_test : BlockchainTestFiller ,
616+ pre : Alloc ,
617+ env : Environment ,
618+ block : Block ,
619+ ):
620+ """
621+ Test all valid blob combinations in a single block, assuming a given value of
622+ `MAX_BLOBS_PER_BLOCK`, for Prague.
623+
624+ This assumes a block can include from 1 and up to `MAX_BLOBS_PER_BLOCK` transactions where all
625+ transactions contain at least 1 blob, and the sum of all blobs in a block is at
626+ most `MAX_BLOBS_PER_BLOCK`.
627+
628+ This test is parametrized with all valid blob transaction combinations for a given block, and
629+ therefore if value of `MAX_BLOBS_PER_BLOCK` changes, this test is automatically updated.
630+
631+ This test is specifically for Prague, as the blob gas price is different from Cancun,
632+ but furthermore, this is not the actual limit of blobs for Prague, since the value is
633+ actually dynamically from the beacon chain and the actual limit can be higher.
634+ """
635+ blockchain_test (
636+ pre = pre ,
637+ post = {},
638+ blocks = [block ],
639+ genesis_environment = env ,
640+ )
641+
642+
614643@pytest .mark .parametrize (
615644 "parent_excess_blobs,parent_blobs,tx_max_fee_per_blob_gas,tx_error" ,
616645 [
@@ -774,6 +803,39 @@ def test_invalid_block_blob_count(
774803 )
775804
776805
806+ @pytest .mark .parametrize (
807+ "blobs_per_tx" ,
808+ invalid_blob_combinations (),
809+ )
810+ @pytest .mark .parametrize (
811+ "tx_error" ,
812+ [TransactionException .TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED ],
813+ ids = ["" ],
814+ indirect = True ,
815+ )
816+ @pytest .mark .valid_from ("Cancun" )
817+ def test_invalid_block_blob_count_above_max (
818+ blockchain_test : BlockchainTestFiller ,
819+ pre : Alloc ,
820+ env : Environment ,
821+ block : Block ,
822+ ):
823+ """
824+ Test all invalid blob combinations in a single block, where the sum of all blobs in a block is
825+ at `MAX_BLOBS_PER_BLOCK + 1`.
826+
827+ This test is parametrized with all blob transaction combinations exceeding
828+ `MAX_BLOBS_PER_BLOCK` by one for a given block, and
829+ therefore if value of `MAX_BLOBS_PER_BLOCK` changes, this test is automatically updated.
830+ """
831+ blockchain_test (
832+ pre = pre ,
833+ post = {},
834+ blocks = [block ],
835+ genesis_environment = env ,
836+ )
837+
838+
777839@pytest .mark .parametrize (
778840 "tx_access_list" ,
779841 [[], [AccessList (address = 100 , storage_keys = [100 , 200 ])]],
@@ -1013,13 +1075,13 @@ def test_insufficient_balance_blob_tx_combinations(
10131075@pytest .mark .parametrize (
10141076 "blobs_per_tx,tx_error" ,
10151077 [
1016- ([0 ], TransactionException .TYPE_3_TX_ZERO_BLOBS ),
1017- (
1078+ pytest . param ([0 ], TransactionException .TYPE_3_TX_ZERO_BLOBS , id = "too_few_blobs" ),
1079+ pytest . param (
10181080 [SpecHelpers .max_blobs_per_block () + 1 ],
10191081 TransactionException .TYPE_3_TX_BLOB_COUNT_EXCEEDED ,
1082+ id = "too_many_blobs" ,
10201083 ),
10211084 ],
1022- ids = ["too_few_blobs" , "too_many_blobs" ],
10231085 indirect = ["tx_error" ],
10241086)
10251087@pytest .mark .valid_from ("Cancun" )
@@ -1048,6 +1110,68 @@ def test_invalid_tx_blob_count(
10481110 )
10491111
10501112
1113+ @pytest .mark .parametrize (
1114+ "blobs_per_tx,tx_error" ,
1115+ [
1116+ pytest .param (
1117+ [SpecHelpers .max_blobs_per_block () + 1 ],
1118+ TransactionException .TYPE_3_TX_BLOB_COUNT_EXCEEDED ,
1119+ id = "cancun_max_plus_one" ,
1120+ ),
1121+ pytest .param (
1122+ [SpecHelpers .max_blobs_per_block_prague ()],
1123+ TransactionException .TYPE_3_TX_BLOB_COUNT_EXCEEDED ,
1124+ id = "prague_max" ,
1125+ ),
1126+ pytest .param (
1127+ [SpecHelpers .max_blobs_per_block_prague () + 1 ],
1128+ TransactionException .TYPE_3_TX_BLOB_COUNT_EXCEEDED ,
1129+ id = "prague_max_plus_one" ,
1130+ ),
1131+ pytest .param (
1132+ [64 ],
1133+ TransactionException .TYPE_3_TX_BLOB_COUNT_EXCEEDED ,
1134+ id = "64" ,
1135+ ),
1136+ pytest .param (
1137+ [128 ],
1138+ TransactionException .TYPE_3_TX_BLOB_COUNT_EXCEEDED ,
1139+ id = "128" ,
1140+ ),
1141+ pytest .param (
1142+ [1024 ],
1143+ TransactionException .TYPE_3_TX_BLOB_COUNT_EXCEEDED ,
1144+ id = "1024" ,
1145+ ),
1146+ ],
1147+ indirect = ["tx_error" ],
1148+ )
1149+ @pytest .mark .valid_from ("Cancun" )
1150+ def test_invalid_tx_blob_count_above_max (
1151+ state_test : StateTestFiller ,
1152+ state_env : Environment ,
1153+ pre : Alloc ,
1154+ txs : List [Transaction ],
1155+ header_verify : Optional [Header ],
1156+ rlp_modifier : Optional [Header ],
1157+ ):
1158+ """
1159+ Reject blocks that include blob transactions with excessive blob counts in Cancun.
1160+
1161+ Starting from Prague, all of these transactions are valid because of the assumption
1162+ that the CL has verified the maximum blob count on its end.
1163+ """
1164+ assert len (txs ) == 1
1165+ state_test (
1166+ pre = pre ,
1167+ post = {},
1168+ tx = txs [0 ],
1169+ env = state_env ,
1170+ blockchain_test_header_verify = header_verify ,
1171+ blockchain_test_rlp_modifier = rlp_modifier ,
1172+ )
1173+
1174+
10511175@pytest .mark .parametrize (
10521176 "blob_hashes_per_tx" ,
10531177 [
0 commit comments