@@ -2,6 +2,7 @@ use std::sync::Arc;
22use std:: time:: Duration ;
33
44use mina_p2p_messages:: v2:: { MinaBaseUserCommandStableV2 , MinaBlockBlockStableV2 } ;
5+ use openmina_core:: constants:: PROTOCOL_VERSION ;
56use rand:: prelude:: * ;
67
78use openmina_core:: block:: BlockWithHash ;
@@ -73,8 +74,27 @@ pub struct State {
7374 applied_actions_count : u64 ,
7475}
7576
77+ #[ derive( Serialize , Deserialize , Debug , Clone ) ]
78+ pub enum BlockPrevalidationError {
79+ GenesisNotReady ,
80+ ReceivedTooEarly {
81+ current_global_slot : u32 ,
82+ block_global_slot : u32 ,
83+ } ,
84+ ReceivedTooLate {
85+ current_global_slot : u32 ,
86+ block_global_slot : u32 ,
87+ delta : u32 ,
88+ } ,
89+ InvalidGenesisProtocolState ,
90+ InvalidProtocolVersion ,
91+ MismatchedProtocolVersion ,
92+ ConsantsMismatch ,
93+ InvalidDeltaBlockChainProof ,
94+ }
95+
7696// Substate accessors that will be used in reducers
77- use openmina_core:: { impl_substate_access, SubstateAccess } ;
97+ use openmina_core:: { bug_condition , impl_substate_access, SubstateAccess } ;
7898
7999impl_substate_access ! ( State , SnarkState , snark) ;
80100impl_substate_access ! ( State , SnarkBlockVerifyState , snark. block_verify) ;
@@ -356,15 +376,19 @@ impl State {
356376 } )
357377 }
358378
359- pub fn prevalidate_block ( & self , block : & ArcBlockWithHash ) -> bool {
379+ pub fn prevalidate_block (
380+ & self ,
381+ block : & ArcBlockWithHash ,
382+ ) -> Result < ( ) , BlockPrevalidationError > {
360383 let Some ( ( genesis, cur_global_slot) ) =
361384 None . or_else ( || Some ( ( self . genesis_block ( ) ?, self . cur_global_slot ( ) ?) ) )
362385 else {
363386 // we don't have genesis block. This should be impossible
364387 // because we don't even know chain_id before we have genesis
365388 // block, so we can't be connected to any peers from which
366389 // we would receive a block.
367- return false ;
390+ bug_condition ! ( "Tried to prevalidate a block before the genesis block was ready" ) ;
391+ return Err ( BlockPrevalidationError :: GenesisNotReady ) ;
368392 } ;
369393
370394 // received_at_valid_time
@@ -375,23 +399,60 @@ impl State {
375399 let delta = genesis. constants ( ) . delta . as_u32 ( ) ;
376400 if cur_global_slot < block_global_slot {
377401 // Too_early
378- return false ;
402+ return Err ( BlockPrevalidationError :: ReceivedTooEarly {
403+ current_global_slot : cur_global_slot,
404+ block_global_slot,
405+ } ) ;
379406 } else if cur_global_slot. saturating_sub ( block_global_slot) > delta {
380407 // Too_late
381- return false ;
408+ return Err ( BlockPrevalidationError :: ReceivedTooLate {
409+ current_global_slot : cur_global_slot,
410+ block_global_slot,
411+ delta,
412+ } ) ;
382413 }
383414 }
384415
385- if block. constants ( ) != genesis. constants ( ) {
386- return false ;
416+ if block. header ( ) . genesis_state_hash ( ) != genesis. hash ( ) {
417+ return Err ( BlockPrevalidationError :: InvalidGenesisProtocolState ) ;
387418 }
388419
389- if block. header ( ) . genesis_state_hash ( ) != genesis. hash ( ) {
390- return false ;
420+ let ( protocol_versions_are_valid, protocol_version_matches_daemon) = {
421+ let min_transaction_version = 1 . into ( ) ;
422+ let v = & block. header ( ) . current_protocol_version ;
423+ let nv = block
424+ . header ( )
425+ . proposed_protocol_version_opt
426+ . as_ref ( )
427+ . unwrap_or ( v) ;
428+
429+ // Our version values are unsigned, so there is no need to check that the
430+ // other parts are not negative.
431+ let valid = v. transaction >= min_transaction_version
432+ && nv. transaction >= min_transaction_version;
433+ let compatible = v. transaction == PROTOCOL_VERSION . transaction
434+ && v. network == PROTOCOL_VERSION . network ;
435+
436+ ( valid, compatible)
437+ } ;
438+
439+ if !protocol_versions_are_valid {
440+ return Err ( BlockPrevalidationError :: InvalidProtocolVersion ) ;
441+ } else if !protocol_version_matches_daemon {
442+ return Err ( BlockPrevalidationError :: MismatchedProtocolVersion ) ;
443+ }
444+
445+ // NOTE: currently these cannot change between blocks, but that
446+ // may not always be true?
447+ if block. constants ( ) != genesis. constants ( ) {
448+ return Err ( BlockPrevalidationError :: ConsantsMismatch ) ;
391449 }
392450
393- // TODO(binier): more checks.
394- true
451+ // TODO(tizoc): check for InvalidDeltaBlockChainProof
452+ // https://github.com/MinaProtocol/mina/blob/d800da86a764d8d37ffb8964dd8d54d9f522b358/src/lib/mina_block/validation.ml#L369
453+ // https://github.com/MinaProtocol/mina/blob/d800da86a764d8d37ffb8964dd8d54d9f522b358/src/lib/transition_chain_verifier/transition_chain_verifier.ml
454+
455+ Ok ( ( ) )
395456 }
396457
397458 pub fn should_log_node_id ( & self ) -> bool {
0 commit comments