@@ -11,7 +11,10 @@ use light_client::{
1111} ;
1212use light_hasher:: hash_chain:: create_hash_chain_from_slice;
1313
14- use crate :: processor:: v2:: { common:: clamp_to_u16, BatchContext } ;
14+ use crate :: {
15+ logging:: should_emit_rate_limited_warning,
16+ processor:: v2:: { common:: clamp_to_u16, BatchContext } ,
17+ } ;
1518
1619pub ( crate ) fn lock_recover < ' a , T > ( mutex : & ' a Mutex < T > , name : & ' static str ) -> MutexGuard < ' a , T > {
1720 match mutex. lock ( ) {
@@ -496,71 +499,57 @@ impl StreamingAddressQueue {
496499 if available < end || start >= end {
497500 return Ok ( None ) ;
498501 }
499- let actual_end = end;
500502 let data = lock_recover ( & self . data , "streaming_address_queue.data" ) ;
501503
502- let min_len = [
503- data. addresses . len ( ) ,
504- data. low_element_values . len ( ) ,
505- data. low_element_next_values . len ( ) ,
506- data. low_element_indices . len ( ) ,
507- data. low_element_next_indices . len ( ) ,
508- ]
509- . into_iter ( )
510- . min ( )
511- . unwrap_or ( 0 ) ;
512- if min_len < actual_end {
513- return Err ( anyhow ! (
514- "incomplete batch data: min field length {} < required end {}" ,
515- min_len,
516- actual_end
517- ) ) ;
518- }
519-
520- let addresses = data. addresses [ start..actual_end] . to_vec ( ) ;
521- if addresses. is_empty ( ) {
522- return Ok ( None ) ;
523- }
524- let expected_len = addresses. len ( ) ;
525- let Some ( low_element_values) = data
526- . low_element_values
527- . get ( start..end)
528- . map ( |slice| slice. to_vec ( ) )
529- else {
530- return Ok ( None ) ;
531- } ;
532- let Some ( low_element_next_values) = data
533- . low_element_next_values
534- . get ( start..end)
535- . map ( |slice| slice. to_vec ( ) )
536- else {
537- return Ok ( None ) ;
538- } ;
539- let Some ( low_element_indices) = data
540- . low_element_indices
541- . get ( start..end)
542- . map ( |slice| slice. to_vec ( ) )
504+ // `available` can be bumped before every parallel array is filled,
505+ // so a missing range here means "not ready yet" — return Ok(None)
506+ // and let the caller retry on the next tick.
507+ let range = start..end;
508+ let (
509+ Some ( addresses) ,
510+ Some ( low_element_values) ,
511+ Some ( low_element_next_values) ,
512+ Some ( low_element_indices) ,
513+ Some ( low_element_next_indices) ,
514+ ) = (
515+ data. addresses . get ( range. clone ( ) ) . map ( <[ _ ] >:: to_vec) ,
516+ data. low_element_values
517+ . get ( range. clone ( ) )
518+ . map ( <[ _ ] >:: to_vec) ,
519+ data. low_element_next_values
520+ . get ( range. clone ( ) )
521+ . map ( <[ _ ] >:: to_vec) ,
522+ data. low_element_indices
523+ . get ( range. clone ( ) )
524+ . map ( <[ _ ] >:: to_vec) ,
525+ data. low_element_next_indices
526+ . get ( range. clone ( ) )
527+ . map ( <[ _ ] >:: to_vec) ,
528+ )
543529 else {
544530 return Ok ( None ) ;
545531 } ;
546- let Some ( low_element_next_indices) = data
547- . low_element_next_indices
548- . get ( start..end)
549- . map ( |slice| slice. to_vec ( ) )
550- else {
551- return Ok ( None ) ;
532+
533+ // Proofs can also be unavailable if the indexer hasn't populated the
534+ // merkle nodes for this range yet — return Ok(None) and retry. Log
535+ // at warn (rate-limited) so persistent failures are still visible.
536+ let low_element_proofs = match data. reconstruct_proofs :: < HEIGHT > ( range) {
537+ Ok ( proofs) => proofs,
538+ Err ( error) => {
539+ if should_emit_rate_limited_warning (
540+ "address_queue_proofs_not_ready" ,
541+ std:: time:: Duration :: from_secs ( 60 ) ,
542+ ) {
543+ tracing:: warn!(
544+ ?error,
545+ start,
546+ end,
547+ "address proof reconstruction not ready, retrying"
548+ ) ;
549+ }
550+ return Ok ( None ) ;
551+ }
552552 } ;
553- if [
554- low_element_values. len ( ) ,
555- low_element_next_values. len ( ) ,
556- low_element_indices. len ( ) ,
557- low_element_next_indices. len ( ) ,
558- ]
559- . iter ( )
560- . any ( |& len| len != expected_len)
561- {
562- return Ok ( None ) ;
563- }
564553
565554 let leaves_hashchain = match data. leaves_hash_chains . get ( hashchain_idx) . copied ( ) {
566555 Some ( hashchain) => hashchain,
@@ -582,15 +571,11 @@ impl StreamingAddressQueue {
582571 } ;
583572
584573 Ok ( Some ( AddressBatchSnapshot {
585- low_element_values : data. low_element_values [ start..actual_end] . to_vec ( ) ,
586- low_element_next_values : data. low_element_next_values [ start..actual_end] . to_vec ( ) ,
587- low_element_indices : data. low_element_indices [ start..actual_end] . to_vec ( ) ,
588- low_element_next_indices : data. low_element_next_indices [ start..actual_end] . to_vec ( ) ,
589- low_element_proofs : data
590- . reconstruct_proofs :: < HEIGHT > ( start..actual_end)
591- . map_err ( |error| {
592- anyhow ! ( "incomplete batch data: failed to reconstruct proofs: {error}" )
593- } ) ?,
574+ low_element_values,
575+ low_element_next_values,
576+ low_element_indices,
577+ low_element_next_indices,
578+ low_element_proofs,
594579 addresses,
595580 leaves_hashchain,
596581 } ) )
0 commit comments