Skip to content

Commit ed06373

Browse files
feat: add backward compatibility for legacy namespace migration
- Add namespaceMigrationCompleted tracking with atomic.Bool for thread safety - Implement disk persistence using store metadata to survive restarts - Check legacy namespace first if migration not completed - Auto-mark migration complete when new namespaces have data or no data found - Add TODO comment for XO testnet reset as requested Co-authored-by: Marko <tac0turtle@users.noreply.github.com>
1 parent 2075b11 commit ed06373

File tree

2 files changed

+68
-1
lines changed

2 files changed

+68
-1
lines changed

block/manager.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ const (
4747
// This is temporary solution. It will be removed in future versions.
4848
maxSubmitAttempts = 30
4949

50+
// Key for storing namespace migration state in the store
51+
namespaceMigrationKey = "namespace_migration_completed"
52+
5053
// Applies to the headerInCh and dataInCh, 10000 is a large enough number for headers per DA block.
5154
eventInChLength = 10000
5255
)
@@ -168,6 +171,10 @@ type Manager struct {
168171
// validatorHasherProvider is used to provide the validator hash for the header.
169172
// It is used to set the validator hash in the header.
170173
validatorHasherProvider types.ValidatorHasherProvider
174+
175+
// namespaceMigrationCompleted tracks whether we have completed the migration
176+
// from legacy namespace to separate header/data namespaces
177+
namespaceMigrationCompleted *atomic.Bool
171178
}
172179

173180
// getInitialState tries to load lastState from Store, and if it's not available it reads genesis.
@@ -400,13 +407,19 @@ func NewManager(
400407
txNotifyCh: make(chan struct{}, 1), // Non-blocking channel
401408
signaturePayloadProvider: managerOpts.SignaturePayloadProvider,
402409
validatorHasherProvider: managerOpts.ValidatorHasherProvider,
410+
namespaceMigrationCompleted: &atomic.Bool{},
403411
}
404412

405413
// initialize da included height
406414
if height, err := m.store.GetMetadata(ctx, storepkg.DAIncludedHeightKey); err == nil && len(height) == 8 {
407415
m.daIncludedHeight.Store(binary.LittleEndian.Uint64(height))
408416
}
409417

418+
// initialize namespace migration state
419+
if migrationData, err := m.store.GetMetadata(ctx, namespaceMigrationKey); err == nil && len(migrationData) > 0 {
420+
m.namespaceMigrationCompleted.Store(migrationData[0] == 1)
421+
}
422+
410423
// Set the default publishBlock implementation
411424
m.publishBlock = m.publishBlockInternal
412425

@@ -418,6 +431,12 @@ func NewManager(
418431
return m, nil
419432
}
420433

434+
// setNamespaceMigrationCompleted marks the namespace migration as completed and persists it to disk
435+
func (m *Manager) setNamespaceMigrationCompleted(ctx context.Context) error {
436+
m.namespaceMigrationCompleted.Store(true)
437+
return m.store.SetMetadata(ctx, namespaceMigrationKey, []byte{1})
438+
}
439+
421440
// PendingHeaders returns the pending headers.
422441
func (m *Manager) PendingHeaders() *PendingHeaders {
423442
return m.pendingHeaders

block/retriever.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,37 @@ func (m *Manager) fetchBlobs(ctx context.Context, daHeight uint64) (coreda.Resul
224224
// Record DA retrieval retry attempt
225225
m.recordDAMetrics("retrieval", DAModeRetry)
226226

227+
// TODO: Remove this once XO resets their testnet
228+
// Check if we should still try the old namespace for backward compatibility
229+
if !m.namespaceMigrationCompleted.Load() {
230+
// First, try the legacy namespace if we haven't completed migration
231+
legacyNamespace := []byte(m.config.DA.Namespace)
232+
if legacyNamespace != nil && len(legacyNamespace) > 0 {
233+
legacyRes := types.RetrieveWithHelpers(ctx, m.da, m.logger, daHeight, legacyNamespace)
234+
235+
// Handle legacy namespace errors
236+
if legacyRes.Code == coreda.StatusError {
237+
m.recordDAMetrics("retrieval", DAModeFail)
238+
err = fmt.Errorf("failed to retrieve from legacy namespace: %s", legacyRes.Message)
239+
return legacyRes, err
240+
}
241+
242+
if legacyRes.Code == coreda.StatusHeightFromFuture {
243+
err = fmt.Errorf("%w: height from future", coreda.ErrHeightFromFuture)
244+
return coreda.ResultRetrieve{BaseResult: coreda.BaseResult{Code: coreda.StatusHeightFromFuture}}, err
245+
}
246+
247+
// If legacy namespace has data, use it and return
248+
if legacyRes.Code == coreda.StatusSuccess {
249+
m.logger.Debug().Uint64("daHeight", daHeight).Msg("found data in legacy namespace")
250+
return legacyRes, nil
251+
}
252+
253+
// Legacy namespace returned not found, so try new namespaces
254+
m.logger.Debug().Uint64("daHeight", daHeight).Msg("no data in legacy namespace, trying new namespaces")
255+
}
256+
}
257+
227258
// Try to retrieve from both header and data namespaces
228259
headerNamespace := []byte(m.config.DA.GetHeaderNamespace())
229260
dataNamespace := []byte(m.config.DA.GetDataNamespace())
@@ -273,10 +304,27 @@ func (m *Manager) fetchBlobs(ctx context.Context, daHeight uint64) (coreda.Resul
273304
}
274305
}
275306

276-
// If both returned not found, return not found
307+
// Handle not found cases and migration completion
277308
if headerRes.Code == coreda.StatusNotFound && dataRes.Code == coreda.StatusNotFound {
278309
combinedResult.Code = coreda.StatusNotFound
279310
combinedResult.Message = "no blobs found in either namespace"
311+
312+
// If we haven't completed migration and found no data in new namespaces,
313+
// mark migration as complete to avoid future legacy namespace checks
314+
if !m.namespaceMigrationCompleted.Load() {
315+
if err := m.setNamespaceMigrationCompleted(ctx); err != nil {
316+
m.logger.Error().Err(err).Msg("failed to mark namespace migration as completed")
317+
} else {
318+
m.logger.Info().Uint64("daHeight", daHeight).Msg("marked namespace migration as completed - no more legacy namespace checks")
319+
}
320+
}
321+
} else if (headerRes.Code == coreda.StatusSuccess || dataRes.Code == coreda.StatusSuccess) && !m.namespaceMigrationCompleted.Load() {
322+
// Found data in new namespaces, mark migration as complete
323+
if err := m.setNamespaceMigrationCompleted(ctx); err != nil {
324+
m.logger.Error().Err(err).Msg("failed to mark namespace migration as completed")
325+
} else {
326+
m.logger.Info().Uint64("daHeight", daHeight).Msg("found data in new namespaces - marked migration as completed")
327+
}
280328
}
281329

282330
return combinedResult, err

0 commit comments

Comments
 (0)