Skip to content

Commit 584a3e5

Browse files
authored
fix(syncing): handle incorrect da response (#2713)
<!-- Please read and fill out this form before submitting your PR. Please make sure you have reviewed our contributors guide before submitting your first PR. NOTE: PR titles should follow semantic commits: https://www.conventionalcommits.org/en/v1.0.0/ --> ## Overview Noticed when trying to sync from da using a wrong working endpoint. Not all errors were handled. <!-- Please provide an explanation of the PR, including the appropriate context, background, goal, and rationale. If there is an issue with this information, please provide a tl;dr and link the issue. Ex: Closes #<issue number> -->
1 parent 78eeece commit 584a3e5

File tree

3 files changed

+46
-31
lines changed

3 files changed

+46
-31
lines changed

block/internal/syncing/da_retriever.go

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"context"
66
"errors"
77
"fmt"
8-
"strings"
98
"time"
109

1110
"github.com/rs/zerolog"
@@ -72,10 +71,6 @@ func (r *DARetriever) RetrieveFromDA(ctx context.Context, daHeight uint64) ([]co
7271

7372
blobsResp, err := r.fetchBlobs(ctx, daHeight)
7473
if err != nil {
75-
if strings.Contains(err.Error(), coreda.ErrHeightFromFuture.Error()) {
76-
return nil, fmt.Errorf("%w: height from future", coreda.ErrHeightFromFuture)
77-
}
78-
7974
return nil, err
8075
}
8176

@@ -84,11 +79,6 @@ func (r *DARetriever) RetrieveFromDA(ctx context.Context, daHeight uint64) ([]co
8479
return nil, err
8580
}
8681

87-
if blobsResp.Code == coreda.StatusNotFound {
88-
r.logger.Debug().Uint64("da_height", daHeight).Msg("no blob data found")
89-
return nil, coreda.ErrBlobNotFound
90-
}
91-
9282
r.logger.Debug().Int("blobs", len(blobsResp.Data)).Uint64("da_height", daHeight).Msg("retrieved blob data")
9383
return r.processBlobs(ctx, blobsResp.Data, daHeight), nil
9484
}
@@ -107,13 +97,15 @@ func (r *DARetriever) fetchBlobs(ctx context.Context, daHeight uint64) (coreda.R
10797

10898
// Validate responses
10999
headerErr := r.validateBlobResponse(headerRes, daHeight)
110-
dataErr := r.validateBlobResponse(dataRes, daHeight)
100+
// ignoring error not found, as data can have data
101+
if headerErr != nil && !errors.Is(headerErr, coreda.ErrBlobNotFound) {
102+
return headerRes, headerErr
103+
}
111104

112-
// Handle errors
113-
if errors.Is(headerErr, coreda.ErrHeightFromFuture) || errors.Is(dataErr, coreda.ErrHeightFromFuture) {
114-
return coreda.ResultRetrieve{
115-
BaseResult: coreda.BaseResult{Code: coreda.StatusHeightFromFuture},
116-
}, fmt.Errorf("%w: height from future", coreda.ErrHeightFromFuture)
105+
dataErr := r.validateBlobResponse(dataRes, daHeight)
106+
// ignoring error not found, as header can have data
107+
if dataErr != nil && !errors.Is(dataErr, coreda.ErrBlobNotFound) {
108+
return dataRes, dataErr
117109
}
118110

119111
// Combine successful results
@@ -127,28 +119,35 @@ func (r *DARetriever) fetchBlobs(ctx context.Context, daHeight uint64) (coreda.R
127119

128120
if headerRes.Code == coreda.StatusSuccess {
129121
combinedResult.Data = append(combinedResult.Data, headerRes.Data...)
130-
if len(headerRes.IDs) > 0 {
131-
combinedResult.IDs = append(combinedResult.IDs, headerRes.IDs...)
132-
}
122+
combinedResult.IDs = append(combinedResult.IDs, headerRes.IDs...)
133123
}
134124

135125
if dataRes.Code == coreda.StatusSuccess {
136126
combinedResult.Data = append(combinedResult.Data, dataRes.Data...)
137-
if len(dataRes.IDs) > 0 {
138-
combinedResult.IDs = append(combinedResult.IDs, dataRes.IDs...)
139-
}
127+
combinedResult.IDs = append(combinedResult.IDs, dataRes.IDs...)
128+
}
129+
130+
// Re-throw error not found if both were not found.
131+
if len(combinedResult.Data) == 0 && len(combinedResult.IDs) == 0 {
132+
r.logger.Debug().Uint64("da_height", daHeight).Msg("no blob data found")
133+
combinedResult.Code = coreda.StatusNotFound
134+
combinedResult.Message = coreda.ErrBlobNotFound.Error()
135+
return combinedResult, coreda.ErrBlobNotFound
140136
}
141137

142138
return combinedResult, nil
143139
}
144140

145141
// validateBlobResponse validates a blob response from DA layer
142+
// those are the only error code returned by da.RetrieveWithHelpers
146143
func (r *DARetriever) validateBlobResponse(res coreda.ResultRetrieve, daHeight uint64) error {
147144
switch res.Code {
148145
case coreda.StatusError:
149146
return fmt.Errorf("DA retrieval failed: %s", res.Message)
150147
case coreda.StatusHeightFromFuture:
151148
return fmt.Errorf("%w: height from future", coreda.ErrHeightFromFuture)
149+
case coreda.StatusNotFound:
150+
return fmt.Errorf("%w: blob not found", coreda.ErrBlobNotFound)
152151
case coreda.StatusSuccess:
153152
r.logger.Debug().Uint64("da_height", daHeight).Msg("successfully retrieved from DA")
154153
return nil

block/internal/syncing/da_retriever_test.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,28 @@ func makeSignedDataBytes(t *testing.T, chainID string, height uint64, proposer [
6969
return bin, sd
7070
}
7171

72+
func TestDARetriever_RetrieveFromDA_Invalid(t *testing.T) {
73+
ds := dssync.MutexWrap(datastore.NewMapDatastore())
74+
st := store.New(ds)
75+
cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop())
76+
assert.NoError(t, err)
77+
78+
mockDA := testmocks.NewMockDA(t)
79+
80+
mockDA.EXPECT().GetIDs(mock.Anything, mock.Anything, mock.Anything).
81+
Return(nil, errors.New("just invalid")).Maybe()
82+
83+
r := NewDARetriever(mockDA, cm, config.DefaultConfig(), genesis.Genesis{}, common.DefaultBlockOptions(), zerolog.Nop())
84+
events, err := r.RetrieveFromDA(context.Background(), 42)
85+
assert.Error(t, err)
86+
assert.Len(t, events, 0)
87+
}
88+
7289
func TestDARetriever_RetrieveFromDA_NotFound(t *testing.T) {
7390
ds := dssync.MutexWrap(datastore.NewMapDatastore())
7491
st := store.New(ds)
7592
cm, err := cache.NewManager(config.DefaultConfig(), st, zerolog.Nop())
76-
require.NoError(t, err)
93+
assert.NoError(t, err)
7794

7895
mockDA := testmocks.NewMockDA(t)
7996

@@ -83,7 +100,7 @@ func TestDARetriever_RetrieveFromDA_NotFound(t *testing.T) {
83100

84101
r := NewDARetriever(mockDA, cm, config.DefaultConfig(), genesis.Genesis{}, common.DefaultBlockOptions(), zerolog.Nop())
85102
events, err := r.RetrieveFromDA(context.Background(), 42)
86-
require.Error(t, err, coreda.ErrBlobNotFound)
103+
assert.True(t, errors.Is(err, coreda.ErrBlobNotFound))
87104
assert.Len(t, events, 0)
88105
}
89106

block/internal/syncing/syncer.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,6 @@ func (s *Syncer) syncLoop() {
247247
lastDataHeight := initialHeight
248248

249249
// Backoff control when DA replies with errors
250-
var hffDelay time.Duration
251250
var nextDARequestAt time.Time
252251

253252
blockTicker := time.NewTicker(s.config.Node.BlockTime.Duration)
@@ -280,16 +279,16 @@ func (s *Syncer) syncLoop() {
280279
nextDARequestAt = time.Time{}
281280
} else {
282281
// Back off exactly by DA block time to avoid overloading
283-
hffDelay = s.config.DA.BlockTime.Duration
284-
if hffDelay <= 0 {
285-
hffDelay = 2 * time.Second
282+
backoffDelay := s.config.DA.BlockTime.Duration
283+
if backoffDelay <= 0 {
284+
backoffDelay = 2 * time.Second
286285
}
287-
nextDARequestAt = now.Add(hffDelay)
286+
nextDARequestAt = now.Add(backoffDelay)
288287

289288
if s.isHeightFromFutureError(err) {
290-
s.logger.Debug().Dur("delay", hffDelay).Uint64("da_height", daHeight).Msg("height from future; backing off DA requests")
289+
s.logger.Debug().Dur("delay", backoffDelay).Uint64("da_height", daHeight).Msg("height from future; backing off DA requests")
291290
} else {
292-
s.logger.Error().Err(err).Dur("delay", hffDelay).Uint64("da_height", daHeight).Msg("failed to retrieve from DA; backing off DA requests")
291+
s.logger.Error().Err(err).Dur("delay", backoffDelay).Uint64("da_height", daHeight).Msg("failed to retrieve from DA; backing off DA requests")
293292
}
294293
}
295294
} else {

0 commit comments

Comments
 (0)