@@ -320,3 +320,100 @@ func TestTracedBlockProducer_ValidateBlock_Error(t *testing.T) {
320320 require .Equal (t , codes .Error , span .Status ().Code )
321321 require .Equal (t , "validation failed" , span .Status ().Description )
322322}
323+
324+ // TestTracedBlockProducer_RetrieveBatch_ErrorWithValue verifies that when the inner
325+ // function returns both a value and an error, the value is passed through (not nil).
326+ // this is important for cases like ErrNoTransactionsInBatch where valid data accompanies the error.
327+ func TestTracedBlockProducer_RetrieveBatch_ErrorWithValue (t * testing.T ) {
328+ expectedBatch := & BatchData {
329+ Batch : & coresequencer.Batch {
330+ Transactions : [][]byte {},
331+ },
332+ }
333+ mock := & mockBlockProducer {
334+ retrieveBatchFn : func (ctx context.Context ) (* BatchData , error ) {
335+ return expectedBatch , errors .New ("no transactions in batch" )
336+ },
337+ }
338+ producer , sr := setupBlockProducerTrace (t , mock )
339+ ctx := context .Background ()
340+
341+ batch , err := producer .RetrieveBatch (ctx )
342+ require .Error (t , err )
343+ require .Equal (t , "no transactions in batch" , err .Error ())
344+ require .NotNil (t , batch , "batch should not be nil when inner returns value with error" )
345+ require .Same (t , expectedBatch , batch , "batch should be the same instance returned by inner" )
346+
347+ spans := sr .Ended ()
348+ require .Len (t , spans , 1 )
349+ span := spans [0 ]
350+ require .Equal (t , codes .Error , span .Status ().Code )
351+ }
352+
353+ // TestTracedBlockProducer_CreateBlock_ErrorWithValue verifies that when the inner
354+ // function returns both values and an error, the values are passed through (not nil).
355+ func TestTracedBlockProducer_CreateBlock_ErrorWithValue (t * testing.T ) {
356+ expectedHeader := & types.SignedHeader {
357+ Header : types.Header {
358+ BaseHeader : types.BaseHeader {
359+ Height : 100 ,
360+ },
361+ },
362+ }
363+ expectedData := & types.Data {
364+ Txs : types.Txs {[]byte ("tx1" )},
365+ }
366+ mock := & mockBlockProducer {
367+ createBlockFn : func (ctx context.Context , height uint64 , batchData * BatchData ) (* types.SignedHeader , * types.Data , error ) {
368+ return expectedHeader , expectedData , errors .New ("partial failure" )
369+ },
370+ }
371+ producer , sr := setupBlockProducerTrace (t , mock )
372+ ctx := context .Background ()
373+
374+ header , data , err := producer .CreateBlock (ctx , 100 , nil )
375+ require .Error (t , err )
376+ require .Equal (t , "partial failure" , err .Error ())
377+ require .NotNil (t , header , "header should not be nil when inner returns value with error" )
378+ require .NotNil (t , data , "data should not be nil when inner returns value with error" )
379+ require .Same (t , expectedHeader , header , "header should be the same instance returned by inner" )
380+ require .Same (t , expectedData , data , "data should be the same instance returned by inner" )
381+
382+ spans := sr .Ended ()
383+ require .Len (t , spans , 1 )
384+ span := spans [0 ]
385+ require .Equal (t , codes .Error , span .Status ().Code )
386+ }
387+
388+ // TestTracedBlockProducer_ApplyBlock_ErrorWithValue verifies that when the inner
389+ // function returns both a state and an error, the state is passed through (not zero value).
390+ func TestTracedBlockProducer_ApplyBlock_ErrorWithValue (t * testing.T ) {
391+ expectedState := types.State {
392+ AppHash : []byte {0xde , 0xad , 0xbe , 0xef },
393+ LastBlockHeight : 50 ,
394+ }
395+ mock := & mockBlockProducer {
396+ applyBlockFn : func (ctx context.Context , header types.Header , data * types.Data ) (types.State , error ) {
397+ return expectedState , errors .New ("partial apply failure" )
398+ },
399+ }
400+ producer , sr := setupBlockProducerTrace (t , mock )
401+ ctx := context .Background ()
402+
403+ header := types.Header {
404+ BaseHeader : types.BaseHeader {
405+ Height : 50 ,
406+ },
407+ }
408+
409+ state , err := producer .ApplyBlock (ctx , header , & types.Data {})
410+ require .Error (t , err )
411+ require .Equal (t , "partial apply failure" , err .Error ())
412+ require .Equal (t , expectedState .AppHash , state .AppHash , "state should preserve AppHash when inner returns value with error" )
413+ require .Equal (t , expectedState .LastBlockHeight , state .LastBlockHeight , "state should preserve LastBlockHeight when inner returns value with error" )
414+
415+ spans := sr .Ended ()
416+ require .Len (t , spans , 1 )
417+ span := spans [0 ]
418+ require .Equal (t , codes .Error , span .Status ().Code )
419+ }
0 commit comments