@@ -2,6 +2,7 @@ package pruner
22
33import (
44 "context"
5+ "encoding/binary"
56 "testing"
67 "time"
78
@@ -32,7 +33,7 @@ func (e *execMetaAdapter) PruneExec(ctx context.Context, height uint64) error {
3233func TestPrunerPruneMetadata (t * testing.T ) {
3334 t .Parallel ()
3435
35- ctx := context . Background ()
36+ ctx := t . Context ()
3637 kv := dssync .MutexWrap (ds .NewMapDatastore ())
3738 stateStore := store .New (kv )
3839
@@ -67,7 +68,7 @@ func TestPrunerPruneMetadata(t *testing.T) {
6768func TestPrunerPruneBlocksWithoutDA (t * testing.T ) {
6869 t .Parallel ()
6970
70- ctx := context . Background ()
71+ ctx := t . Context ()
7172 kv := dssync .MutexWrap (ds .NewMapDatastore ())
7273 stateStore := store .New (kv )
7374
@@ -128,7 +129,7 @@ func TestPrunerPruneBlocksWithoutDA(t *testing.T) {
128129func TestPrunerPruneBlocksWithDAEnabled (t * testing.T ) {
129130 t .Parallel ()
130131
131- ctx := context . Background ()
132+ ctx := t . Context ()
132133 kv := dssync .MutexWrap (ds .NewMapDatastore ())
133134 stateStore := store .New (kv )
134135
@@ -163,3 +164,78 @@ func TestPrunerPruneBlocksWithDAEnabled(t *testing.T) {
163164 require .NoError (t , err , "expected block data at height %d to still exist (no pruning should have happened)" , h )
164165 }
165166}
167+
168+ // TestPrunerPruneBlocksWithDAWhenStoreHeightLessThanDAHeight is a regression test that verifies
169+ // pruning behavior when DA is enabled and store height is less than DA inclusion height.
170+ // This ensures the pruner uses min(storeHeight, daInclusionHeight) as the upper bound.
171+ func TestPrunerPruneBlocksWithDAWhenStoreHeightLessThanDAHeight (t * testing.T ) {
172+ t .Parallel ()
173+
174+ ctx := t .Context ()
175+ kv := dssync .MutexWrap (ds .NewMapDatastore ())
176+ stateStore := store .New (kv )
177+
178+ // Create blocks up to height 100
179+ for height := uint64 (1 ); height <= 100 ; height ++ {
180+ header := & types.SignedHeader {Header : types.Header {BaseHeader : types.BaseHeader {Height : height }}}
181+ data := & types.Data {}
182+ sig := types .Signature ([]byte {byte (height )})
183+
184+ batch , err := stateStore .NewBatch (ctx )
185+ require .NoError (t , err )
186+ require .NoError (t , batch .SaveBlockData (header , data , & sig ))
187+ require .NoError (t , batch .SetHeight (height ))
188+ require .NoError (t , batch .UpdateState (types.State {LastBlockHeight : height }))
189+ require .NoError (t , batch .Commit ())
190+ }
191+
192+ // Set DA inclusion height to 150 (higher than store height of 100)
193+ // This simulates the case where DA has confirmed blocks beyond what's in the local store
194+ daInclusionHeight := uint64 (150 )
195+ daInclusionHeightBz := make ([]byte , 8 )
196+ binary .LittleEndian .PutUint64 (daInclusionHeightBz , daInclusionHeight )
197+ require .NoError (t , stateStore .SetMetadata (ctx , store .DAIncludedHeightKey , daInclusionHeightBz ))
198+
199+ execAdapter := & execMetaAdapter {existing : make (map [uint64 ]struct {})}
200+ for h := uint64 (1 ); h <= 100 ; h ++ {
201+ execAdapter .existing [h ] = struct {}{}
202+ }
203+
204+ // Test with DA enabled - should use min(storeHeight=100, daInclusionHeight=150) = 100
205+ cfg := config.PruningConfig {
206+ Mode : config .PruningModeAll ,
207+ Interval : config.DurationWrapper {Duration : 1 * time .Second },
208+ KeepRecent : 10 ,
209+ }
210+
211+ pruner := New (zerolog .New (zerolog .NewTestWriter (t )), stateStore , execAdapter , cfg , 100 * time .Millisecond , "localhost:1234" ) // DA enabled
212+ require .NoError (t , pruner .pruneBlocks ())
213+
214+ // Verify blocks were pruned correctly
215+ // Upper bound should be min(100, 150) = 100
216+ // Target height = 100 - 10 (KeepRecent) = 90
217+ // Batch size = 40 blocks (1s interval / 100ms block time * 4)
218+ // So we expect to prune from height 1 up to min(0 + 40, 90) = 40
219+
220+ height , err := stateStore .Height (ctx )
221+ require .NoError (t , err )
222+ require .Equal (t , uint64 (100 ), height )
223+
224+ // Verify old blocks were pruned (up to height 40)
225+ for h := uint64 (1 ); h <= 40 ; h ++ {
226+ _ , _ , err := stateStore .GetBlockData (ctx , h )
227+ require .Error (t , err , "expected block data at height %d to be pruned" , h )
228+ }
229+
230+ // Verify blocks after batch were kept
231+ for h := uint64 (41 ); h <= 100 ; h ++ {
232+ _ , _ , err := stateStore .GetBlockData (ctx , h )
233+ require .NoError (t , err , "expected block data at height %d to be kept" , h )
234+ }
235+
236+ // Verify exec metadata was also pruned (strictly less than 40)
237+ for h := uint64 (1 ); h < 40 ; h ++ {
238+ _ , exists := execAdapter .existing [h ]
239+ require .False (t , exists , "expected exec metadata at height %d to be pruned" , h )
240+ }
241+ }
0 commit comments