From 1e83b77242432a6d1f3fa4109ac055c7d4114142 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 08:45:39 +0000 Subject: [PATCH 1/3] Initial plan From 74e8ec3cbb4679acccb35beb1547935d26cba681 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 08:48:46 +0000 Subject: [PATCH 2/3] Implement PR #3075 review comments: update test context usage and add regression test Co-authored-by: julienrbrt <29894366+julienrbrt@users.noreply.github.com> --- block/internal/pruner/pruner_test.go | 82 +++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/block/internal/pruner/pruner_test.go b/block/internal/pruner/pruner_test.go index d8dbc534a..c38ef50ec 100644 --- a/block/internal/pruner/pruner_test.go +++ b/block/internal/pruner/pruner_test.go @@ -2,6 +2,7 @@ package pruner import ( "context" + "encoding/binary" "testing" "time" @@ -32,7 +33,7 @@ func (e *execMetaAdapter) PruneExec(ctx context.Context, height uint64) error { func TestPrunerPruneMetadata(t *testing.T) { t.Parallel() - ctx := context.Background() + ctx := t.Context() kv := dssync.MutexWrap(ds.NewMapDatastore()) stateStore := store.New(kv) @@ -67,7 +68,7 @@ func TestPrunerPruneMetadata(t *testing.T) { func TestPrunerPruneBlocksWithoutDA(t *testing.T) { t.Parallel() - ctx := context.Background() + ctx := t.Context() kv := dssync.MutexWrap(ds.NewMapDatastore()) stateStore := store.New(kv) @@ -128,7 +129,7 @@ func TestPrunerPruneBlocksWithoutDA(t *testing.T) { func TestPrunerPruneBlocksWithDAEnabled(t *testing.T) { t.Parallel() - ctx := context.Background() + ctx := t.Context() kv := dssync.MutexWrap(ds.NewMapDatastore()) stateStore := store.New(kv) @@ -163,3 +164,78 @@ func TestPrunerPruneBlocksWithDAEnabled(t *testing.T) { require.NoError(t, err, "expected block data at height %d to still exist (no pruning should have happened)", h) } } + +// TestPrunerPruneBlocksWithDAWhenStoreHeightLessThanDAHeight is a regression test that verifies +// pruning behavior when DA is enabled and store height is less than DA inclusion height. +// This ensures the pruner uses min(storeHeight, daInclusionHeight) as the upper bound. +func TestPrunerPruneBlocksWithDAWhenStoreHeightLessThanDAHeight(t *testing.T) { + t.Parallel() + + ctx := t.Context() + kv := dssync.MutexWrap(ds.NewMapDatastore()) + stateStore := store.New(kv) + + // Create blocks up to height 100 + for height := uint64(1); height <= 100; height++ { + header := &types.SignedHeader{Header: types.Header{BaseHeader: types.BaseHeader{Height: height}}} + data := &types.Data{} + sig := types.Signature([]byte{byte(height)}) + + batch, err := stateStore.NewBatch(ctx) + require.NoError(t, err) + require.NoError(t, batch.SaveBlockData(header, data, &sig)) + require.NoError(t, batch.SetHeight(height)) + require.NoError(t, batch.UpdateState(types.State{LastBlockHeight: height})) + require.NoError(t, batch.Commit()) + } + + // Set DA inclusion height to 150 (higher than store height of 100) + // This simulates the case where DA has confirmed blocks beyond what's in the local store + daInclusionHeight := uint64(150) + daInclusionHeightBz := make([]byte, 8) + binary.LittleEndian.PutUint64(daInclusionHeightBz, daInclusionHeight) + require.NoError(t, stateStore.SetMetadata(ctx, store.DAIncludedHeightKey, daInclusionHeightBz)) + + execAdapter := &execMetaAdapter{existing: make(map[uint64]struct{})} + for h := uint64(1); h <= 100; h++ { + execAdapter.existing[h] = struct{}{} + } + + // Test with DA enabled - should use min(storeHeight=100, daInclusionHeight=150) = 100 + cfg := config.PruningConfig{ + Mode: config.PruningModeAll, + Interval: config.DurationWrapper{Duration: 1 * time.Second}, + KeepRecent: 10, + } + + pruner := New(zerolog.New(zerolog.NewTestWriter(t)), stateStore, execAdapter, cfg, 100*time.Millisecond, "localhost:1234") // DA enabled + require.NoError(t, pruner.pruneBlocks()) + + // Verify blocks were pruned correctly + // Upper bound should be min(100, 150) = 100 + // Target height = 100 - 10 (KeepRecent) = 90 + // Batch size = 40 blocks (1s interval / 100ms block time * 4) + // So we expect to prune from height 1 up to min(0 + 40, 90) = 40 + + height, err := stateStore.Height(ctx) + require.NoError(t, err) + require.Equal(t, uint64(100), height) + + // Verify old blocks were pruned (up to height 40) + for h := uint64(1); h <= 40; h++ { + _, _, err := stateStore.GetBlockData(ctx, h) + require.Error(t, err, "expected block data at height %d to be pruned", h) + } + + // Verify blocks after batch were kept + for h := uint64(41); h <= 100; h++ { + _, _, err := stateStore.GetBlockData(ctx, h) + require.NoError(t, err, "expected block data at height %d to be kept", h) + } + + // Verify exec metadata was also pruned (strictly less than 40) + for h := uint64(1); h < 40; h++ { + _, exists := execAdapter.existing[h] + require.False(t, exists, "expected exec metadata at height %d to be pruned", h) + } +} From 793ad7254920bfccc82c2f225d2f5feafcba90bc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 08:57:36 +0000 Subject: [PATCH 3/3] Remove invalid regression test - DA inclusion height cannot exceed store height Co-authored-by: julienrbrt <29894366+julienrbrt@users.noreply.github.com> --- block/internal/pruner/pruner_test.go | 76 ---------------------------- 1 file changed, 76 deletions(-) diff --git a/block/internal/pruner/pruner_test.go b/block/internal/pruner/pruner_test.go index c38ef50ec..8f0ad4773 100644 --- a/block/internal/pruner/pruner_test.go +++ b/block/internal/pruner/pruner_test.go @@ -2,7 +2,6 @@ package pruner import ( "context" - "encoding/binary" "testing" "time" @@ -164,78 +163,3 @@ func TestPrunerPruneBlocksWithDAEnabled(t *testing.T) { require.NoError(t, err, "expected block data at height %d to still exist (no pruning should have happened)", h) } } - -// TestPrunerPruneBlocksWithDAWhenStoreHeightLessThanDAHeight is a regression test that verifies -// pruning behavior when DA is enabled and store height is less than DA inclusion height. -// This ensures the pruner uses min(storeHeight, daInclusionHeight) as the upper bound. -func TestPrunerPruneBlocksWithDAWhenStoreHeightLessThanDAHeight(t *testing.T) { - t.Parallel() - - ctx := t.Context() - kv := dssync.MutexWrap(ds.NewMapDatastore()) - stateStore := store.New(kv) - - // Create blocks up to height 100 - for height := uint64(1); height <= 100; height++ { - header := &types.SignedHeader{Header: types.Header{BaseHeader: types.BaseHeader{Height: height}}} - data := &types.Data{} - sig := types.Signature([]byte{byte(height)}) - - batch, err := stateStore.NewBatch(ctx) - require.NoError(t, err) - require.NoError(t, batch.SaveBlockData(header, data, &sig)) - require.NoError(t, batch.SetHeight(height)) - require.NoError(t, batch.UpdateState(types.State{LastBlockHeight: height})) - require.NoError(t, batch.Commit()) - } - - // Set DA inclusion height to 150 (higher than store height of 100) - // This simulates the case where DA has confirmed blocks beyond what's in the local store - daInclusionHeight := uint64(150) - daInclusionHeightBz := make([]byte, 8) - binary.LittleEndian.PutUint64(daInclusionHeightBz, daInclusionHeight) - require.NoError(t, stateStore.SetMetadata(ctx, store.DAIncludedHeightKey, daInclusionHeightBz)) - - execAdapter := &execMetaAdapter{existing: make(map[uint64]struct{})} - for h := uint64(1); h <= 100; h++ { - execAdapter.existing[h] = struct{}{} - } - - // Test with DA enabled - should use min(storeHeight=100, daInclusionHeight=150) = 100 - cfg := config.PruningConfig{ - Mode: config.PruningModeAll, - Interval: config.DurationWrapper{Duration: 1 * time.Second}, - KeepRecent: 10, - } - - pruner := New(zerolog.New(zerolog.NewTestWriter(t)), stateStore, execAdapter, cfg, 100*time.Millisecond, "localhost:1234") // DA enabled - require.NoError(t, pruner.pruneBlocks()) - - // Verify blocks were pruned correctly - // Upper bound should be min(100, 150) = 100 - // Target height = 100 - 10 (KeepRecent) = 90 - // Batch size = 40 blocks (1s interval / 100ms block time * 4) - // So we expect to prune from height 1 up to min(0 + 40, 90) = 40 - - height, err := stateStore.Height(ctx) - require.NoError(t, err) - require.Equal(t, uint64(100), height) - - // Verify old blocks were pruned (up to height 40) - for h := uint64(1); h <= 40; h++ { - _, _, err := stateStore.GetBlockData(ctx, h) - require.Error(t, err, "expected block data at height %d to be pruned", h) - } - - // Verify blocks after batch were kept - for h := uint64(41); h <= 100; h++ { - _, _, err := stateStore.GetBlockData(ctx, h) - require.NoError(t, err, "expected block data at height %d to be kept", h) - } - - // Verify exec metadata was also pruned (strictly less than 40) - for h := uint64(1); h < 40; h++ { - _, exists := execAdapter.existing[h] - require.False(t, exists, "expected exec metadata at height %d to be pruned", h) - } -}