@@ -23,14 +23,14 @@ use blockifier_reexecution::state_reader::prefetched_state_reader::{
2323use blockifier_reexecution:: state_reader:: rpc_objects:: { BlockHeader , BlockId } ;
2424use blockifier_reexecution:: state_reader:: rpc_state_reader:: RpcStateReader ;
2525use serde:: { Deserialize , Serialize } ;
26- use starknet_api:: block:: { BlockHash , BlockInfo } ;
26+ use starknet_api:: block:: { BlockHash , BlockInfo , StarknetVersion } ;
2727use starknet_api:: block_hash:: block_hash_calculator:: { concat_counts, BlockHeaderCommitments } ;
2828use starknet_api:: contract_class:: SierraVersion ;
2929use starknet_api:: core:: ClassHash ;
3030use starknet_api:: transaction:: fields:: Fee ;
3131use starknet_api:: transaction:: { InvokeTransaction , MessageToL1 , Transaction , TransactionHash } ;
3232use starknet_api:: versioned_constants_logic:: VersionedConstantsTrait ;
33- use tracing:: error;
33+ use tracing:: { error, warn } ;
3434
3535use crate :: errors:: VirtualBlockExecutorError ;
3636
@@ -85,13 +85,45 @@ pub(crate) struct BaseBlockInfo {
8585 pub ( crate ) prev_base_block_hash : BlockHash ,
8686}
8787
88+ /// Parses the block header's Starknet version, tolerating versions newer than this binary knows.
89+ ///
90+ /// `StarknetVersion` is a closed enum, so a block produced by a Starknet version released after
91+ /// this binary was built can't be parsed. The prover runs the OS with the latest versioned
92+ /// constants regardless of the block's version, so a *strictly newer* version is treated as
93+ /// `StarknetVersion::LATEST`. Older or malformed versions still error — we only forgive the
94+ /// forward-compatibility case, never mask genuinely unsupported data.
95+ pub ( crate ) fn forward_compatible_starknet_version (
96+ raw_version : & str ,
97+ ) -> Result < StarknetVersion , VirtualBlockExecutorError > {
98+ if let Ok ( version) = StarknetVersion :: try_from ( raw_version. to_string ( ) ) {
99+ return Ok ( version) ;
100+ }
101+ let latest = StarknetVersion :: LATEST ;
102+ // Compare numerically: Vec<u8> orders lexicographically, matching version ordering
103+ // (major, minor, patch, [fourth]).
104+ let version_bytes: Result < Vec < u8 > , _ > =
105+ raw_version. split ( '.' ) . map ( |component| component. parse :: < u8 > ( ) ) . collect ( ) ;
106+ match version_bytes {
107+ Ok ( version_bytes) if version_bytes > Vec :: < u8 > :: from ( latest) => {
108+ warn ! (
109+ "Block header reports unknown Starknet version '{raw_version}', newer than the \
110+ latest known version {latest}; falling back to {latest} for proving."
111+ ) ;
112+ Ok ( latest)
113+ }
114+ _ => Err ( VirtualBlockExecutorError :: TransactionExecutionError ( format ! (
115+ "Unsupported Starknet version '{raw_version}' (latest known: {latest})"
116+ ) ) ) ,
117+ }
118+ }
119+
88120impl BaseBlockInfo {
89121 /// Creates a `BaseBlockInfo` from a block header and chain info.
90122 ///
91123 /// When `use_latest_versioned_constants` is `true`, the latest versioned constants are used
92124 /// instead of the ones matching the block's Starknet version.
93125 pub ( crate ) fn new (
94- header : BlockHeader ,
126+ mut header : BlockHeader ,
95127 chain_info : ChainInfo ,
96128 use_latest_versioned_constants : bool ,
97129 ) -> Result < Self , VirtualBlockExecutorError > {
@@ -110,6 +142,10 @@ impl BaseBlockInfo {
110142 ) ,
111143 } ;
112144
145+ // Forward compatibility: tolerate versions newer than this binary knows (see helper).
146+ let starknet_version = forward_compatible_starknet_version ( & header. starknet_version ) ?;
147+ header. starknet_version = starknet_version. to_string ( ) ;
148+
113149 let block_info: BlockInfo = header. try_into ( ) . map_err ( |e| {
114150 VirtualBlockExecutorError :: TransactionExecutionError ( format ! (
115151 "Failed to convert block header to block info: {e}"
0 commit comments