@@ -292,3 +292,78 @@ func TestDARetriever_ProcessBlobs_CrossDAHeightMatching(t *testing.T) {
292292 require .NotContains (t , r .pendingData , uint64 (5 ), "data should be removed from pending" )
293293 require .NotContains (t , r .headerDAHeights , uint64 (5 ), "header DA height should be removed" )
294294}
295+
296+ func TestDARetriever_ProcessBlobs_MultipleHeadersCrossDAHeightMatching (t * testing.T ) {
297+ ds := dssync .MutexWrap (datastore .NewMapDatastore ())
298+ st := store .New (ds )
299+ cm , err := cache .NewManager (config .DefaultConfig (), st , zerolog .Nop ())
300+ require .NoError (t , err )
301+
302+ addr , pub , signer := buildSyncTestSigner (t )
303+ gen := genesis.Genesis {ChainID : "tchain" , InitialHeight : 1 , StartTime : time .Now ().Add (- time .Second ), ProposerAddress : addr }
304+
305+ r := NewDARetriever (nil , cm , config .DefaultConfig (), gen , common .DefaultBlockOptions (), zerolog .Nop ())
306+
307+ // Create multiple headers and data for different block heights
308+ data3Bin , data3 := makeSignedDataBytes (t , gen .ChainID , 3 , addr , pub , signer , 1 )
309+ data4Bin , data4 := makeSignedDataBytes (t , gen .ChainID , 4 , addr , pub , signer , 2 )
310+ data5Bin , data5 := makeSignedDataBytes (t , gen .ChainID , 5 , addr , pub , signer , 1 )
311+
312+ hdr3Bin , _ := makeSignedHeaderBytes (t , gen .ChainID , 3 , addr , pub , signer , nil , data3 .Hash ())
313+ hdr4Bin , _ := makeSignedHeaderBytes (t , gen .ChainID , 4 , addr , pub , signer , nil , data4 .Hash ())
314+ hdr5Bin , _ := makeSignedHeaderBytes (t , gen .ChainID , 5 , addr , pub , signer , nil , data5 .Hash ())
315+
316+ // Process multiple headers from DA height 200 - should be stored as pending
317+ events1 := r .processBlobs (context .Background (), [][]byte {hdr3Bin , hdr4Bin , hdr5Bin }, 200 )
318+ require .Len (t , events1 , 0 , "should not create events yet - all data is missing" )
319+
320+ // Verify all headers are stored in pending
321+ require .Contains (t , r .pendingHeaders , uint64 (3 ), "header 3 should be pending" )
322+ require .Contains (t , r .pendingHeaders , uint64 (4 ), "header 4 should be pending" )
323+ require .Contains (t , r .pendingHeaders , uint64 (5 ), "header 5 should be pending" )
324+ assert .Equal (t , uint64 (200 ), r .headerDAHeights [3 ])
325+ assert .Equal (t , uint64 (200 ), r .headerDAHeights [4 ])
326+ assert .Equal (t , uint64 (200 ), r .headerDAHeights [5 ])
327+
328+ // Process some data from DA height 203 - should create partial events
329+ events2 := r .processBlobs (context .Background (), [][]byte {data3Bin , data5Bin }, 203 )
330+ require .Len (t , events2 , 2 , "should create events for heights 3 and 5" )
331+
332+ // Sort events by height for consistent testing
333+ if events2 [0 ].Header .Height () > events2 [1 ].Header .Height () {
334+ events2 [0 ], events2 [1 ] = events2 [1 ], events2 [0 ]
335+ }
336+
337+ // Verify event for height 3
338+ assert .Equal (t , uint64 (3 ), events2 [0 ].Header .Height ())
339+ assert .Equal (t , uint64 (3 ), events2 [0 ].Data .Height ())
340+ assert .Equal (t , uint64 (203 ), events2 [0 ].DaHeight )
341+ assert .Equal (t , uint64 (200 ), events2 [0 ].HeaderDaIncludedHeight )
342+
343+ // Verify event for height 5
344+ assert .Equal (t , uint64 (5 ), events2 [1 ].Header .Height ())
345+ assert .Equal (t , uint64 (5 ), events2 [1 ].Data .Height ())
346+ assert .Equal (t , uint64 (203 ), events2 [1 ].DaHeight )
347+ assert .Equal (t , uint64 (200 ), events2 [1 ].HeaderDaIncludedHeight )
348+
349+ // Verify header 4 is still pending (no matching data yet)
350+ require .Contains (t , r .pendingHeaders , uint64 (4 ), "header 4 should still be pending" )
351+ require .NotContains (t , r .pendingHeaders , uint64 (3 ), "header 3 should be removed from pending" )
352+ require .NotContains (t , r .pendingHeaders , uint64 (5 ), "header 5 should be removed from pending" )
353+
354+ // Process remaining data from DA height 205
355+ events3 := r .processBlobs (context .Background (), [][]byte {data4Bin }, 205 )
356+ require .Len (t , events3 , 1 , "should create event for height 4" )
357+
358+ // Verify final event for height 4
359+ assert .Equal (t , uint64 (4 ), events3 [0 ].Header .Height ())
360+ assert .Equal (t , uint64 (4 ), events3 [0 ].Data .Height ())
361+ assert .Equal (t , uint64 (205 ), events3 [0 ].DaHeight )
362+ assert .Equal (t , uint64 (200 ), events3 [0 ].HeaderDaIncludedHeight )
363+
364+ // Verify all pending maps are now clear
365+ require .NotContains (t , r .pendingHeaders , uint64 (4 ), "header 4 should be removed from pending" )
366+ require .Len (t , r .pendingHeaders , 0 , "all headers should be processed" )
367+ require .Len (t , r .pendingData , 0 , "all data should be processed" )
368+ require .Len (t , r .headerDAHeights , 0 , "all header DA heights should be cleared" )
369+ }
0 commit comments