@@ -28,11 +28,12 @@ import (
2828)
2929
3030// makeSignedHeaderBytes builds a valid SignedHeader and returns its binary encoding and the object
31- func makeSignedHeaderBytes (t * testing.T , chainID string , height uint64 , proposer []byte , pub crypto.PubKey , signer signerpkg.Signer , appHash []byte ) ([]byte , * types.SignedHeader ) {
31+ func makeSignedHeaderBytes (t * testing.T , chainID string , height uint64 , proposer []byte , pub crypto.PubKey , signer signerpkg.Signer , appHash []byte , dataHash [] byte ) ([]byte , * types.SignedHeader ) {
3232 hdr := & types.SignedHeader {
3333 Header : types.Header {
3434 BaseHeader : types.BaseHeader {ChainID : chainID , Height : height , Time : uint64 (time .Now ().Add (time .Duration (height ) * time .Second ).UnixNano ())},
3535 AppHash : appHash ,
36+ DataHash : dataHash ,
3637 ProposerAddress : proposer ,
3738 },
3839 Signer : types.Signer {PubKey : pub , Address : proposer },
@@ -115,12 +116,8 @@ func TestDARetriever_ProcessBlobs_HeaderAndData_Success(t *testing.T) {
115116
116117 r := NewDARetriever (nil , cm , config .DefaultConfig (), gen , common .DefaultBlockOptions (), zerolog .Nop ())
117118
118- // Build one header and one data blob at same height
119- _ , lastState := types.State {}, types.State {}
120- _ = lastState // placeholder to keep parity with helper pattern
121-
122- hdrBin , _ := makeSignedHeaderBytes (t , gen .ChainID , 2 , addr , pub , signer , nil )
123- dataBin , _ := makeSignedDataBytes (t , gen .ChainID , 2 , addr , pub , signer , 2 )
119+ dataBin , data := makeSignedDataBytes (t , gen .ChainID , 2 , addr , pub , signer , 2 )
120+ hdrBin , _ := makeSignedHeaderBytes (t , gen .ChainID , 2 , addr , pub , signer , nil , data .Hash ())
124121
125122 events := r .processBlobs (context .Background (), [][]byte {hdrBin , dataBin }, 77 )
126123 require .Len (t , events , 1 )
@@ -141,7 +138,7 @@ func TestDARetriever_ProcessBlobs_HeaderOnly_EmptyDataExpected(t *testing.T) {
141138 r := NewDARetriever (nil , cm , config .DefaultConfig (), gen , common .DefaultBlockOptions (), zerolog .Nop ())
142139
143140 // Header with no data hash present should trigger empty data creation (per current logic)
144- hb , _ := makeSignedHeaderBytes (t , gen .ChainID , 3 , addr , pub , signer , nil )
141+ hb , _ := makeSignedHeaderBytes (t , gen .ChainID , 3 , addr , pub , signer , nil , nil )
145142
146143 events := r .processBlobs (context .Background (), [][]byte {hb }, 88 )
147144 require .Len (t , events , 1 )
@@ -160,7 +157,7 @@ func TestDARetriever_TryDecodeHeaderAndData_Basic(t *testing.T) {
160157 gen := genesis.Genesis {ChainID : "tchain" , InitialHeight : 1 , StartTime : time .Now ().Add (- time .Second ), ProposerAddress : addr }
161158 r := NewDARetriever (nil , cm , config .DefaultConfig (), gen , common .DefaultBlockOptions (), zerolog .Nop ())
162159
163- hb , sh := makeSignedHeaderBytes (t , gen .ChainID , 5 , addr , pub , signer , nil )
160+ hb , sh := makeSignedHeaderBytes (t , gen .ChainID , 5 , addr , pub , signer , nil , nil )
164161 gotH := r .tryDecodeHeader (hb , 123 )
165162 require .NotNil (t , gotH )
166163 assert .Equal (t , sh .Hash ().String (), gotH .Hash ().String ())
@@ -225,8 +222,8 @@ func TestDARetriever_RetrieveFromDA_TwoNamespaces_Success(t *testing.T) {
225222 gen := genesis.Genesis {ChainID : "tchain" , InitialHeight : 1 , StartTime : time .Now ().Add (- time .Second ), ProposerAddress : addr }
226223
227224 // Prepare header/data blobs
228- hdrBin , _ := makeSignedHeaderBytes (t , gen .ChainID , 9 , addr , pub , signer , nil )
229- dataBin , _ := makeSignedDataBytes (t , gen .ChainID , 9 , addr , pub , signer , 1 )
225+ dataBin , data := makeSignedDataBytes (t , gen .ChainID , 9 , addr , pub , signer , 1 )
226+ hdrBin , _ := makeSignedHeaderBytes (t , gen .ChainID , 9 , addr , pub , signer , nil , data . Hash () )
230227
231228 cfg := config .DefaultConfig ()
232229 cfg .DA .Namespace = "nsHdr"
@@ -255,3 +252,43 @@ func TestDARetriever_RetrieveFromDA_TwoNamespaces_Success(t *testing.T) {
255252 assert .Equal (t , uint64 (9 ), events [0 ].Header .Height ())
256253 assert .Equal (t , uint64 (9 ), events [0 ].Data .Height ())
257254}
255+
256+ func TestDARetriever_ProcessBlobs_CrossDAHeightMatching (t * testing.T ) {
257+ ds := dssync .MutexWrap (datastore .NewMapDatastore ())
258+ st := store .New (ds )
259+ cm , err := cache .NewManager (config .DefaultConfig (), st , zerolog .Nop ())
260+ require .NoError (t , err )
261+
262+ addr , pub , signer := buildSyncTestSigner (t )
263+ gen := genesis.Genesis {ChainID : "tchain" , InitialHeight : 1 , StartTime : time .Now ().Add (- time .Second ), ProposerAddress : addr }
264+
265+ r := NewDARetriever (nil , cm , config .DefaultConfig (), gen , common .DefaultBlockOptions (), zerolog .Nop ())
266+
267+ // Create header and data for the same block height but from different DA heights
268+ dataBin , data := makeSignedDataBytes (t , gen .ChainID , 5 , addr , pub , signer , 2 )
269+ hdrBin , _ := makeSignedHeaderBytes (t , gen .ChainID , 5 , addr , pub , signer , nil , data .Hash ())
270+
271+ // Process header from DA height 100 first
272+ events1 := r .processBlobs (context .Background (), [][]byte {hdrBin }, 100 )
273+ require .Len (t , events1 , 0 , "should not create event yet - data is missing" )
274+
275+ // Verify header is stored in pending headers
276+ require .Contains (t , r .pendingHeaders , uint64 (5 ), "header should be stored as pending" )
277+ require .Contains (t , r .headerDAHeights , uint64 (5 ), "header DA height should be tracked" )
278+ assert .Equal (t , uint64 (100 ), r .headerDAHeights [5 ])
279+
280+ // Process data from DA height 102
281+ events2 := r .processBlobs (context .Background (), [][]byte {dataBin }, 102 )
282+ require .Len (t , events2 , 1 , "should create event when matching data arrives" )
283+
284+ event := events2 [0 ]
285+ assert .Equal (t , uint64 (5 ), event .Header .Height ())
286+ assert .Equal (t , uint64 (5 ), event .Data .Height ())
287+ assert .Equal (t , uint64 (102 ), event .DaHeight , "DaHeight should be the height where data was processed" )
288+ assert .Equal (t , uint64 (100 ), event .HeaderDaIncludedHeight , "HeaderDaIncludedHeight should be where header was included" )
289+
290+ // Verify pending maps are cleared
291+ require .NotContains (t , r .pendingHeaders , uint64 (5 ), "header should be removed from pending" )
292+ require .NotContains (t , r .pendingData , uint64 (5 ), "data should be removed from pending" )
293+ require .NotContains (t , r .headerDAHeights , uint64 (5 ), "header DA height should be removed" )
294+ }
0 commit comments