Skip to content

Commit 5660535

Browse files
authored
fix: return values correctly not nil (#3004)
1 parent 555a48d commit 5660535

File tree

2 files changed

+100
-3
lines changed

2 files changed

+100
-3
lines changed

block/internal/executing/tracing.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (t *tracedBlockProducer) RetrieveBatch(ctx context.Context) (*BatchData, er
4848
if err != nil {
4949
span.RecordError(err)
5050
span.SetStatus(codes.Error, err.Error())
51-
return nil, err
51+
return batchData, err
5252
}
5353

5454
if batchData != nil && batchData.Batch != nil {
@@ -77,7 +77,7 @@ func (t *tracedBlockProducer) CreateBlock(ctx context.Context, height uint64, ba
7777
if err != nil {
7878
span.RecordError(err)
7979
span.SetStatus(codes.Error, err.Error())
80-
return nil, nil, err
80+
return header, data, err
8181
}
8282
return header, data, nil
8383
}
@@ -95,7 +95,7 @@ func (t *tracedBlockProducer) ApplyBlock(ctx context.Context, header types.Heade
9595
if err != nil {
9696
span.RecordError(err)
9797
span.SetStatus(codes.Error, err.Error())
98-
return types.State{}, err
98+
return state, err
9999
}
100100

101101
span.SetAttributes(

block/internal/executing/tracing_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)