@@ -191,14 +191,18 @@ pub struct CircuitConfig {
191191 /// cached vk value to save some initial cost, for debugging only
192192 #[ serde( default ) ]
193193 pub vks : HashMap < ProofType , String > ,
194+ /// Child circuit VKs used to enable OpenVM deferral for aggregation tasks.
195+ /// Required for batch (child=chunk) and bundle (child=batch) proving in v0.9.0+.
196+ #[ serde( default ) ]
197+ pub child_circuit_vks : HashMap < ProofType , String > ,
194198}
195199
196200pub struct LocalProver {
197201 config : LocalProverConfig ,
198202 next_task_id : u64 ,
199203 current_task : Option < JoinHandle < Result < String > > > ,
200204
201- handlers : HashMap < String , Arc < dyn CircuitsHandler > > ,
205+ handlers : HashMap < String , Arc < Mutex < UniversalHandler > > > ,
202206}
203207
204208#[ async_trait]
@@ -325,39 +329,44 @@ impl LocalProver {
325329 }
326330 let prover_task: ProvingTask = prover_task. into ( ) ;
327331 let vk = hex:: encode ( & prover_task. vk ) ;
328- let handler = if let Some ( handler) = self . handlers . get ( & vk) {
329- handler. clone ( )
330- } else {
331- let base_config = self
332+
333+ let parent_handler = self
334+ . get_or_load_handler ( & req. hard_fork_name , req. proof_type , & vk)
335+ . await ?;
336+
337+ // OpenVM v2+ aggregation circuits (batch/bundle) need deferral enabled
338+ // using their immediate child circuit's prover.
339+ let child_proof_type = match req. proof_type {
340+ ProofType :: Batch => Some ( ProofType :: Chunk ) ,
341+ ProofType :: Bundle => Some ( ProofType :: Batch ) ,
342+ _ => None ,
343+ } ;
344+ if let Some ( child_type) = child_proof_type {
345+ let child_vk = self
332346 . config
333347 . circuits
334348 . get ( & req. hard_fork_name )
349+ . and_then ( |c| c. child_circuit_vks . get ( & child_type) )
335350 . ok_or_else ( || {
336351 eyre:: eyre!(
337- "coordinator sent unexpected forkname {}" ,
352+ "missing child circuit vk for {:?} in fork {}" ,
353+ child_type,
338354 req. hard_fork_name
339355 )
340- } ) ?;
341- let url_base = if let Some ( url) = base_config. location_data . asset_detours . get ( & vk) {
342- url. clone ( )
343- } else {
344- base_config
345- . location_data
346- . gen_asset_url ( & vk, req. proof_type ) ?
347- } ;
348- let asset_path = base_config
349- . location_data
350- . get_asset ( & vk, & url_base, & base_config. workspace_path )
356+ } ) ?
357+ . clone ( ) ;
358+ let child_handler = self
359+ . get_or_load_handler ( & req. hard_fork_name , child_type, & child_vk)
351360 . await ?;
352- let circuits_handler = Arc :: new ( Mutex :: new ( UniversalHandler :: new ( & asset_path ) ? ) ) ;
353- self . handlers . insert ( vk , circuits_handler . clone ( ) ) ;
354- circuits_handler
355- } ;
361+ let mut parent_guard = parent_handler . lock ( ) . await ;
362+ let child_guard = child_handler . lock ( ) . await ;
363+ parent_guard . enable_deferral ( & * child_guard ) ? ;
364+ }
356365
357366 let handle = Handle :: current ( ) ;
358367 let is_evm = req. proof_type == ProofType :: Bundle ;
359368 let task_handle = tokio:: task:: spawn_blocking ( move || {
360- handle. block_on ( handler . get_proof_data ( & prover_task, is_evm) )
369+ handle. block_on ( parent_handler . get_proof_data ( & prover_task, is_evm) )
361370 } ) ;
362371 self . current_task = Some ( task_handle) ;
363372
@@ -372,4 +381,34 @@ impl LocalProver {
372381 ..Default :: default ( )
373382 } )
374383 }
384+
385+ /// Load a handler for the given fork/proof-type/vk, reusing a cached one if available.
386+ async fn get_or_load_handler (
387+ & mut self ,
388+ fork_name : & str ,
389+ proof_type : ProofType ,
390+ vk : & str ,
391+ ) -> Result < Arc < Mutex < UniversalHandler > > > {
392+ if let Some ( handler) = self . handlers . get ( vk) {
393+ return Ok ( handler. clone ( ) ) ;
394+ }
395+
396+ let base_config = self
397+ . config
398+ . circuits
399+ . get ( fork_name)
400+ . ok_or_else ( || eyre:: eyre!( "coordinator sent unexpected forkname {}" , fork_name) ) ?;
401+ let url_base = if let Some ( url) = base_config. location_data . asset_detours . get ( vk) {
402+ url. clone ( )
403+ } else {
404+ base_config. location_data . gen_asset_url ( vk, proof_type) ?
405+ } ;
406+ let asset_path = base_config
407+ . location_data
408+ . get_asset ( vk, & url_base, & base_config. workspace_path )
409+ . await ?;
410+ let handler = Arc :: new ( Mutex :: new ( UniversalHandler :: new ( & asset_path) ?) ) ;
411+ self . handlers . insert ( vk. to_string ( ) , handler. clone ( ) ) ;
412+ Ok ( handler)
413+ }
375414}
0 commit comments