@@ -203,88 +203,112 @@ func TestForcedInclusionRetriever_RetrieveForcedIncludedTxs_MultiHeightEpoch(t *
203203 assert .Equal (t , len (event .Txs ), expectedTxCount )
204204}
205205
206- func TestForcedInclusionRetriever_processForcedInclusionBlobs (t * testing.T ) {
206+ func TestForcedInclusionRetriever_RetrieveForcedIncludedTxs_ErrorHandling (t * testing.T ) {
207207 client := mocks .NewMockClient (t )
208- client .On ("GetForcedInclusionNamespace" ).Return (datypes .NamespaceFromString ("test-fi-ns" ).Bytes ()).Maybe ()
208+ fiNs := datypes .NamespaceFromString ("test-fi-ns" ).Bytes ()
209+ client .On ("HasForcedInclusionNamespace" ).Return (true ).Maybe ()
210+ client .On ("GetForcedInclusionNamespace" ).Return (fiNs ).Maybe ()
211+ client .On ("Retrieve" , mock .Anything , uint64 (100 ), fiNs ).Return (datypes.ResultRetrieve {
212+ BaseResult : datypes.BaseResult {
213+ Code : datypes .StatusError ,
214+ Message : "test error" ,
215+ },
216+ }).Once ()
209217
210218 gen := genesis.Genesis {
211219 DAStartHeight : 100 ,
212- DAEpochForcedInclusion : 10 ,
220+ DAEpochForcedInclusion : 1 , // Single height epoch
213221 }
214222
215223 retriever := NewForcedInclusionRetriever (client , zerolog .Nop (), config .DefaultConfig (), gen .DAStartHeight , gen .DAEpochForcedInclusion )
216224 defer retriever .Stop ()
225+ ctx := context .Background ()
217226
218- tests := []struct {
219- name string
220- result datypes.ResultRetrieve
221- height uint64
222- expectedTxCount int
223- expectError bool
224- }{
225- {
226- name : "success with blobs" ,
227- result : datypes.ResultRetrieve {
228- BaseResult : datypes.BaseResult {
229- Code : datypes .StatusSuccess ,
230- },
231- Data : [][]byte {[]byte ("tx1" ), []byte ("tx2" )},
232- },
233- height : 100 ,
234- expectedTxCount : 2 ,
235- expectError : false ,
236- },
237- {
238- name : "not found" ,
239- result : datypes.ResultRetrieve {
240- BaseResult : datypes.BaseResult {
241- Code : datypes .StatusNotFound ,
242- },
243- },
244- height : 100 ,
245- expectedTxCount : 0 ,
246- expectError : false ,
247- },
248- {
249- name : "error status" ,
250- result : datypes.ResultRetrieve {
251- BaseResult : datypes.BaseResult {
252- Code : datypes .StatusError ,
253- Message : "test error" ,
254- },
255- },
256- height : 100 ,
257- expectError : true ,
258- },
259- {
260- name : "empty blobs are skipped" ,
261- result : datypes.ResultRetrieve {
262- BaseResult : datypes.BaseResult {
263- Code : datypes .StatusSuccess ,
264- },
265- Data : [][]byte {[]byte ("tx1" ), {}, []byte ("tx2" )},
266- },
267- height : 100 ,
268- expectedTxCount : 2 ,
269- expectError : false ,
270- },
227+ // Should return empty event with no error (errors are logged and retried later)
228+ event , err := retriever .RetrieveForcedIncludedTxs (ctx , 100 )
229+ assert .NilError (t , err )
230+ assert .Assert (t , event != nil )
231+ assert .Equal (t , len (event .Txs ), 0 )
232+ }
233+
234+ func TestForcedInclusionRetriever_RetrieveForcedIncludedTxs_EmptyBlobsSkipped (t * testing.T ) {
235+ client := mocks .NewMockClient (t )
236+ fiNs := datypes .NamespaceFromString ("test-fi-ns" ).Bytes ()
237+ client .On ("HasForcedInclusionNamespace" ).Return (true ).Maybe ()
238+ client .On ("GetForcedInclusionNamespace" ).Return (fiNs ).Maybe ()
239+ client .On ("Retrieve" , mock .Anything , uint64 (100 ), fiNs ).Return (datypes.ResultRetrieve {
240+ BaseResult : datypes.BaseResult {Code : datypes .StatusSuccess , Timestamp : time .Now ()},
241+ Data : [][]byte {[]byte ("tx1" ), {}, []byte ("tx2" ), nil , []byte ("tx3" )},
242+ }).Once ()
243+
244+ gen := genesis.Genesis {
245+ DAStartHeight : 100 ,
246+ DAEpochForcedInclusion : 1 , // Single height epoch
247+ }
248+
249+ retriever := NewForcedInclusionRetriever (client , zerolog .Nop (), config .DefaultConfig (), gen .DAStartHeight , gen .DAEpochForcedInclusion )
250+ defer retriever .Stop ()
251+ ctx := context .Background ()
252+
253+ event , err := retriever .RetrieveForcedIncludedTxs (ctx , 100 )
254+ assert .NilError (t , err )
255+ assert .Assert (t , event != nil )
256+ // Should skip empty and nil blobs
257+ assert .Equal (t , len (event .Txs ), 3 )
258+ assert .DeepEqual (t , event .Txs [0 ], []byte ("tx1" ))
259+ assert .DeepEqual (t , event .Txs [1 ], []byte ("tx2" ))
260+ assert .DeepEqual (t , event .Txs [2 ], []byte ("tx3" ))
261+ }
262+
263+ func TestForcedInclusionRetriever_RetrieveForcedIncludedTxs_OrderPreserved (t * testing.T ) {
264+ // Test that transactions are returned in height order even when fetched out of order
265+ testBlobsByHeight := map [uint64 ][][]byte {
266+ 100 : {[]byte ("tx-100-1" ), []byte ("tx-100-2" )},
267+ 101 : {[]byte ("tx-101-1" )},
268+ 102 : {[]byte ("tx-102-1" ), []byte ("tx-102-2" )},
271269 }
272270
273- for _ , tt := range tests {
274- t .Run (tt .name , func (t * testing.T ) {
275- event := & ForcedInclusionEvent {
276- Txs : [][]byte {},
277- }
278-
279- err := retriever .processRetrieveResult (event , tt .result , tt .height )
280-
281- if tt .expectError {
282- assert .Assert (t , err != nil )
283- } else {
284- assert .NilError (t , err )
285- assert .Equal (t , len (event .Txs ), tt .expectedTxCount )
286- assert .Equal (t , event .Timestamp , time.Time {})
287- }
288- })
271+ client := mocks .NewMockClient (t )
272+ fiNs := datypes .NamespaceFromString ("test-fi-ns" ).Bytes ()
273+ client .On ("HasForcedInclusionNamespace" ).Return (true ).Maybe ()
274+ client .On ("GetForcedInclusionNamespace" ).Return (fiNs ).Maybe ()
275+ // Return heights out of order to test ordering is preserved
276+ client .On ("Retrieve" , mock .Anything , uint64 (102 ), fiNs ).Return (datypes.ResultRetrieve {
277+ BaseResult : datypes.BaseResult {Code : datypes .StatusSuccess , Timestamp : time .Now ()},
278+ Data : testBlobsByHeight [102 ],
279+ }).Once ()
280+ client .On ("Retrieve" , mock .Anything , uint64 (100 ), fiNs ).Return (datypes.ResultRetrieve {
281+ BaseResult : datypes.BaseResult {Code : datypes .StatusSuccess , Timestamp : time .Now ()},
282+ Data : testBlobsByHeight [100 ],
283+ }).Once ()
284+ client .On ("Retrieve" , mock .Anything , uint64 (101 ), fiNs ).Return (datypes.ResultRetrieve {
285+ BaseResult : datypes.BaseResult {Code : datypes .StatusSuccess , Timestamp : time .Now ()},
286+ Data : testBlobsByHeight [101 ],
287+ }).Once ()
288+
289+ gen := genesis.Genesis {
290+ DAStartHeight : 100 ,
291+ DAEpochForcedInclusion : 3 , // Epoch: 100-102
292+ }
293+
294+ retriever := NewForcedInclusionRetriever (client , zerolog .Nop (), config .DefaultConfig (), gen .DAStartHeight , gen .DAEpochForcedInclusion )
295+ defer retriever .Stop ()
296+ ctx := context .Background ()
297+
298+ event , err := retriever .RetrieveForcedIncludedTxs (ctx , 102 )
299+ assert .NilError (t , err )
300+ assert .Assert (t , event != nil )
301+
302+ // Verify transactions are in height order: 100, 100, 101, 102, 102
303+ expectedOrder := [][]byte {
304+ []byte ("tx-100-1" ),
305+ []byte ("tx-100-2" ),
306+ []byte ("tx-101-1" ),
307+ []byte ("tx-102-1" ),
308+ []byte ("tx-102-2" ),
309+ }
310+ assert .Equal (t , len (event .Txs ), len (expectedOrder ))
311+ for i , expected := range expectedOrder {
312+ assert .DeepEqual (t , event .Txs [i ], expected )
289313 }
290314}
0 commit comments