@@ -140,6 +140,14 @@ impl Consensus<BerachainBlock> for BerachainBeaconConsensus {
140140
141141 if self . chain_spec . is_prague1_active_at_timestamp ( block. header ( ) . timestamp ) {
142142 self . validate_pol_transaction ( block) ?;
143+ } else if let Some ( index) = block
144+ . body ( )
145+ . transactions ( )
146+ . position ( |tx| matches ! ( tx, BerachainTxEnvelope :: Berachain ( _) ) )
147+ {
148+ return Err ( ConsensusError :: Other ( format ! (
149+ "PoL transaction found at position {index} before Prague1 fork activation"
150+ ) ) ) ;
143151 }
144152 Ok ( ( ) )
145153 }
@@ -170,160 +178,129 @@ mod tests {
170178 use super :: * ;
171179 use crate :: {
172180 chainspec:: BerachainChainSpec ,
173- primitives:: header:: BlsPublicKey ,
174- transaction:: pol:: { create_pol_transaction, validate_pol_transaction } ,
181+ primitives:: { BerachainBlockBody , BerachainHeader , header:: BlsPublicKey } ,
182+ transaction:: { BerachainTxEnvelope , pol:: create_pol_transaction} ,
175183 } ;
176- use alloy_primitives:: U256 ;
177- use reth_chainspec:: EthChainSpec ;
184+ use alloy_consensus:: { EMPTY_OMMER_ROOT_HASH , Signed , TxLegacy , constants:: EMPTY_WITHDRAWALS } ;
185+ use alloy_eips:: eip4895:: Withdrawals ;
186+ use alloy_primitives:: { Address , BlockHash , TxKind , U256 } ;
187+ use reth_primitives_traits:: { BlockBody , SealedBlock , SealedHeader } ;
178188 use std:: sync:: Arc ;
179189
180190 fn mock_berachain_chainspec ( ) -> Arc < BerachainChainSpec > {
181- Arc :: new ( BerachainChainSpec :: default ( ) )
191+ crate :: test :: bepolia_chainspec ( )
182192 }
183193
184194 fn mock_bls_pubkey ( ) -> BlsPublicKey {
185195 BlsPublicKey :: from ( [ 1u8 ; 48 ] )
186196 }
187197
188198 #[ test]
189- fn test_consensus_creation ( ) {
190- let chain_spec = mock_berachain_chainspec ( ) ;
191- let consensus = BerachainBeaconConsensus :: new ( chain_spec) ;
192-
193- assert_eq ! ( consensus. chain_spec. chain_id( ) , 1 ) ;
194- }
195-
196- #[ test]
197- fn test_pol_transaction_creation_and_validation ( ) {
199+ fn test_pre_prague1_pol_transaction_rejected ( ) {
198200 let chain_spec = mock_berachain_chainspec ( ) ;
201+ let consensus = BerachainBeaconConsensus :: new ( chain_spec. clone ( ) ) ;
199202 let pubkey = mock_bls_pubkey ( ) ;
200203 let block_number = U256 :: from ( 10 ) ;
201204 let base_fee = 1000u64 ;
202205
203- let pol_tx_envelope =
204- create_pol_transaction ( chain_spec. clone ( ) , pubkey, block_number, base_fee) ;
205-
206- assert ! ( pol_tx_envelope. is_ok( ) , "PoL transaction creation should succeed" ) ;
207-
208- let pol_tx = match pol_tx_envelope. unwrap ( ) {
209- crate :: transaction:: BerachainTxEnvelope :: Berachain ( sealed_tx) => sealed_tx,
210- _ => panic ! ( "Expected PoL transaction" ) ,
211- } ;
212-
213- let validation_result =
214- validate_pol_transaction ( & pol_tx, chain_spec. clone ( ) , pubkey, block_number, base_fee) ;
215-
216- assert ! ( validation_result. is_ok( ) , "Valid PoL transaction should pass validation" ) ;
217- }
218-
219- #[ test]
220- fn test_pol_transaction_validation_wrong_pubkey ( ) {
221- let chain_spec = mock_berachain_chainspec ( ) ;
222- let correct_pubkey = mock_bls_pubkey ( ) ;
223- let wrong_pubkey = BlsPublicKey :: from ( [ 2u8 ; 48 ] ) ;
224- let block_number = U256 :: from ( 10 ) ;
225- let base_fee = 1000u64 ;
226-
227- let pol_tx_envelope =
228- create_pol_transaction ( chain_spec. clone ( ) , correct_pubkey, block_number, base_fee)
229- . unwrap ( ) ;
230-
231- let pol_tx = match pol_tx_envelope {
232- crate :: transaction:: BerachainTxEnvelope :: Berachain ( sealed_tx) => sealed_tx,
233- _ => panic ! ( "Expected PoL transaction" ) ,
234- } ;
235-
236- let validation_result =
237- validate_pol_transaction ( & pol_tx, chain_spec, wrong_pubkey, block_number, base_fee) ;
238-
206+ // Verify Prague1 activation timestamp for context
239207 assert ! (
240- validation_result . is_err ( ) ,
241- "PoL transaction with wrong pubkey should fail validation "
208+ !chain_spec . is_prague1_active_at_timestamp ( 0 ) ,
209+ "Timestamp 0 should be before Prague1 activation "
242210 ) ;
243- assert ! ( validation_result. unwrap_err( ) . to_string( ) . contains( "hash mismatch" ) ) ;
244- }
245-
246- #[ test]
247- fn test_pol_transaction_validation_wrong_base_fee ( ) {
248- let chain_spec = mock_berachain_chainspec ( ) ;
249- let pubkey = mock_bls_pubkey ( ) ;
250- let block_number = U256 :: from ( 10 ) ;
251- let correct_base_fee = 1000u64 ;
252- let wrong_base_fee = 2000u64 ;
253211
212+ // Create a PoL transaction
254213 let pol_tx_envelope =
255- create_pol_transaction ( chain_spec. clone ( ) , pubkey, block_number, correct_base_fee)
256- . unwrap ( ) ;
214+ create_pol_transaction ( chain_spec, pubkey, block_number, base_fee) . unwrap ( ) ;
215+
216+ // Create a block body with the PoL transaction
217+ let transactions = vec ! [ pol_tx_envelope] ;
218+ let block_body = BerachainBlockBody {
219+ transactions : transactions. clone ( ) ,
220+ withdrawals : Some ( Withdrawals :: default ( ) ) ,
221+ ..Default :: default ( )
222+ } ;
257223
258- let pol_tx = match pol_tx_envelope {
259- crate :: transaction:: BerachainTxEnvelope :: Berachain ( sealed_tx) => sealed_tx,
260- _ => panic ! ( "Expected PoL transaction" ) ,
224+ // Create a header with timestamp BEFORE Prague1 activation
225+ let header = BerachainHeader {
226+ number : block_number. to :: < u64 > ( ) ,
227+ timestamp : 0 , // Pre-Prague1 timestamp (Prague1 activates at 1754496000)
228+ base_fee_per_gas : Some ( base_fee) ,
229+ ommers_hash : EMPTY_OMMER_ROOT_HASH ,
230+ transactions_root : block_body. calculate_tx_root ( ) ,
231+ withdrawals_root : Some ( EMPTY_WITHDRAWALS ) ,
232+ blob_gas_used : Some ( 0 ) ,
233+ ..Default :: default ( )
261234 } ;
262235
263- let validation_result =
264- validate_pol_transaction ( & pol_tx, chain_spec, pubkey, block_number, wrong_base_fee) ;
236+ let sealed_header = SealedHeader :: new ( header, BlockHash :: ZERO ) ;
237+ let block = SealedBlock :: from_sealed_parts ( sealed_header, block_body) ;
238+
239+ // Validation should fail because PoL transaction exists before Prague1
240+ let result = consensus. validate_block_pre_execution ( & block) ;
241+ assert ! ( result. is_err( ) , "Pre-Prague1 block with PoL transaction should fail validation" ) ;
265242
243+ let error_msg = result. unwrap_err ( ) . to_string ( ) ;
266244 assert ! (
267- validation_result . is_err ( ) ,
268- "PoL transaction with wrong base fee should fail validation "
245+ error_msg . contains ( "before Prague1 fork activation" ) ,
246+ "Error should mention Prague1 fork activation "
269247 ) ;
270- assert ! ( validation_result . unwrap_err ( ) . to_string ( ) . contains( "hash mismatch" ) ) ;
248+ assert ! ( error_msg . contains( "position 0" ) , "Error should indicate PoL transaction position" ) ;
271249 }
272250
273251 #[ test]
274- fn test_pol_transaction_validation_wrong_block_number ( ) {
252+ fn test_pre_prague1_normal_transactions_accepted ( ) {
275253 let chain_spec = mock_berachain_chainspec ( ) ;
276- let pubkey = mock_bls_pubkey ( ) ;
277- let correct_block_number = U256 :: from ( 10 ) ;
278- let wrong_block_number = U256 :: from ( 20 ) ;
279- let base_fee = 1000u64 ;
280-
281- let pol_tx_envelope =
282- create_pol_transaction ( chain_spec. clone ( ) , pubkey, correct_block_number, base_fee)
283- . unwrap ( ) ;
284-
285- let pol_tx = match pol_tx_envelope {
286- crate :: transaction:: BerachainTxEnvelope :: Berachain ( sealed_tx) => sealed_tx,
287- _ => panic ! ( "Expected PoL transaction" ) ,
288- } ;
289-
290- let validation_result =
291- validate_pol_transaction ( & pol_tx, chain_spec, pubkey, wrong_block_number, base_fee) ;
254+ let consensus = BerachainBeaconConsensus :: new ( chain_spec. clone ( ) ) ;
292255
256+ // Verify Prague1 activation timestamp for context
293257 assert ! (
294- validation_result . is_err ( ) ,
295- "PoL transaction with wrong block number should fail validation "
258+ !chain_spec . is_prague1_active_at_timestamp ( 0 ) ,
259+ "Timestamp 0 should be before Prague1 activation "
296260 ) ;
297- assert ! ( validation_result. unwrap_err( ) . to_string( ) . contains( "hash mismatch" ) ) ;
298- }
299-
300- #[ test]
301- fn test_pol_transaction_deterministic_hashes ( ) {
302- let chain_spec = mock_berachain_chainspec ( ) ;
303- let pubkey = mock_bls_pubkey ( ) ;
304- let block_number = U256 :: from ( 42 ) ;
305- let base_fee = 1337u64 ;
306261
307- let pol_tx1_envelope =
308- create_pol_transaction ( chain_spec. clone ( ) , pubkey, block_number, base_fee) . unwrap ( ) ;
262+ // Create normal Ethereum transaction
263+ let tx = TxLegacy {
264+ chain_id : Some ( 1 ) ,
265+ nonce : 0 ,
266+ gas_price : 1000 ,
267+ gas_limit : 21000 ,
268+ to : TxKind :: Call ( Address :: ZERO ) ,
269+ value : U256 :: ZERO ,
270+ input : Default :: default ( ) ,
271+ } ;
309272
310- let pol_tx2_envelope =
311- create_pol_transaction ( chain_spec, pubkey, block_number, base_fee) . unwrap ( ) ;
273+ let signature = alloy_primitives:: Signature :: test_signature ( ) ;
274+ let signed_tx = Signed :: new_unhashed ( tx, signature) ;
275+ let eth_tx_envelope =
276+ BerachainTxEnvelope :: Ethereum ( alloy_consensus:: TxEnvelope :: Legacy ( signed_tx) ) ;
312277
313- let pol_tx1 = match pol_tx1_envelope {
314- crate :: transaction:: BerachainTxEnvelope :: Berachain ( sealed_tx) => sealed_tx,
315- _ => panic ! ( "Expected PoL transaction" ) ,
278+ let transactions = vec ! [ eth_tx_envelope] ;
279+ let block_body = BerachainBlockBody {
280+ transactions : transactions. clone ( ) ,
281+ withdrawals : Some ( Withdrawals :: default ( ) ) ,
282+ ..Default :: default ( )
316283 } ;
317284
318- let pol_tx2 = match pol_tx2_envelope {
319- crate :: transaction:: BerachainTxEnvelope :: Berachain ( sealed_tx) => sealed_tx,
320- _ => panic ! ( "Expected PoL transaction" ) ,
285+ let header = BerachainHeader {
286+ number : 10 ,
287+ timestamp : 0 , // Pre-Prague1 timestamp
288+ base_fee_per_gas : Some ( 1000 ) ,
289+ ommers_hash : EMPTY_OMMER_ROOT_HASH ,
290+ transactions_root : block_body. calculate_tx_root ( ) ,
291+ withdrawals_root : Some ( EMPTY_WITHDRAWALS ) ,
292+ blob_gas_used : Some ( 0 ) ,
293+ ..Default :: default ( )
321294 } ;
322295
323- assert_eq ! (
324- pol_tx1. hash( ) ,
325- pol_tx2. hash( ) ,
326- "Identical PoL transactions should have identical hashes"
296+ let sealed_header = SealedHeader :: new ( header, BlockHash :: ZERO ) ;
297+ let block = SealedBlock :: from_sealed_parts ( sealed_header, block_body) ;
298+
299+ // Validation should succeed for normal transactions pre-Prague1
300+ let result = consensus. validate_block_pre_execution ( & block) ;
301+ assert ! (
302+ result. is_ok( ) ,
303+ "Pre-Prague1 block with normal transactions should pass validation"
327304 ) ;
328305 }
329306}
0 commit comments