Skip to content

Commit 9d04241

Browse files
Expose height to DA height mapping
1 parent 7d85ee0 commit 9d04241

11 files changed

Lines changed: 127 additions & 37 deletions

File tree

‎block/da_includer.go‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ func (m *Manager) DAIncluderLoop(ctx context.Context, errCh chan<- error) {
2828
break
2929
}
3030
if daIncluded {
31+
m.logger.Debug("both header and data are DA-included, advancing height", "height", nextHeight)
32+
if err := m.SetRollkitHeightToDAHeight(ctx, nextHeight); err != nil {
33+
errCh <- fmt.Errorf("failed to set rollkit height to DA height: %w", err)
34+
return
35+
}
3136
// Both header and data are DA-included, so we can advance the height
3237
if err := m.incrementDAIncludedHeight(ctx); err != nil {
3338
errCh <- fmt.Errorf("error while incrementing DA included height: %w", err)

‎block/da_includer_test.go‎

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package block
33
import (
44
"context"
55
"encoding/binary"
6+
"fmt"
67
"sync"
78
"testing"
89
"time"
@@ -53,11 +54,19 @@ func TestDAIncluderLoop_AdvancesHeightWhenBothDAIncluded(t *testing.T) {
5354
header, data := types.GetRandomBlock(5, 1, "testchain")
5455
headerHash := header.Hash().String()
5556
dataHash := data.DACommitment().String()
56-
m.headerCache.SetDAIncluded(headerHash)
57-
m.dataCache.SetDAIncluded(dataHash)
57+
m.headerCache.SetDAIncluded(headerHash, uint64(1))
58+
m.dataCache.SetDAIncluded(dataHash, uint64(1))
5859

59-
store.On("GetBlockData", mock.Anything, uint64(5)).Return(header, data, nil).Once()
60+
store.On("GetBlockData", mock.Anything, uint64(5)).Return(header, data, nil).Times(2)
6061
store.On("GetBlockData", mock.Anything, uint64(6)).Return(nil, nil, assert.AnError).Once()
62+
// Mock expectations for SetRollkitHeightToDAHeight method
63+
headerHeightBytes := make([]byte, 8)
64+
binary.LittleEndian.PutUint64(headerHeightBytes, uint64(1))
65+
store.On("SetMetadata", mock.Anything, fmt.Sprintf("%s/%d/h", RollkitHeightToDAHeightKey, uint64(5)), headerHeightBytes).Return(nil).Once()
66+
dataHeightBytes := make([]byte, 8)
67+
binary.LittleEndian.PutUint64(dataHeightBytes, uint64(1))
68+
store.On("SetMetadata", mock.Anything, fmt.Sprintf("%s/%d/d", RollkitHeightToDAHeightKey, uint64(5)), dataHeightBytes).Return(nil).Once()
69+
// Mock expectations for incrementDAIncludedHeight method
6170
heightBytes := make([]byte, 8)
6271
binary.LittleEndian.PutUint64(heightBytes, expectedDAIncludedHeight)
6372
store.On("SetMetadata", mock.Anything, DAIncludedHeightKey, heightBytes).Return(nil).Once()
@@ -93,7 +102,7 @@ func TestDAIncluderLoop_StopsWhenHeaderNotDAIncluded(t *testing.T) {
93102

94103
header, data := types.GetRandomBlock(5, 1, "testchain")
95104
// m.headerCache.SetDAIncluded(headerHash) // Not set
96-
m.dataCache.SetDAIncluded(data.DACommitment().String())
105+
m.dataCache.SetDAIncluded(data.DACommitment().String(), uint64(1))
97106

98107
store.On("GetBlockData", mock.Anything, uint64(5)).Return(header, data, nil).Once()
99108

@@ -124,7 +133,7 @@ func TestDAIncluderLoop_StopsWhenDataNotDAIncluded(t *testing.T) {
124133

125134
header, data := types.GetRandomBlock(5, 1, "testchain")
126135
headerHash := header.Hash().String()
127-
m.headerCache.SetDAIncluded(headerHash)
136+
m.headerCache.SetDAIncluded(headerHash, uint64(1))
128137
// m.dataCache.SetDAIncluded(data.DACommitment().String()) // Not set
129138

130139
store.On("GetBlockData", mock.Anything, uint64(5)).Return(header, data, nil).Once()
@@ -272,12 +281,22 @@ func TestDAIncluderLoop_MultipleConsecutiveHeightsDAIncluded(t *testing.T) {
272281
headers[i], dataBlocks[i] = types.GetRandomBlock(height, numTxs, "testchain")
273282
headerHash := headers[i].Hash().String()
274283
dataHash := dataBlocks[i].DACommitment().String()
275-
m.headerCache.SetDAIncluded(headerHash)
276-
m.dataCache.SetDAIncluded(dataHash)
277-
store.On("GetBlockData", mock.Anything, height).Return(headers[i], dataBlocks[i], nil).Once()
284+
m.headerCache.SetDAIncluded(headerHash, uint64(i+1))
285+
m.dataCache.SetDAIncluded(dataHash, uint64(i+1))
286+
store.On("GetBlockData", mock.Anything, height).Return(headers[i], dataBlocks[i], nil).Times(2) // Called by IsDAIncluded and SetRollkitHeightToDAHeight
278287
}
279288
// Next height returns error
280289
store.On("GetBlockData", mock.Anything, startDAIncludedHeight+uint64(numConsecutive+1)).Return(nil, nil, assert.AnError).Once()
290+
// Mock expectations for SetRollkitHeightToDAHeight method calls
291+
for i := 0; i < numConsecutive; i++ {
292+
height := startDAIncludedHeight + uint64(i+1)
293+
headerHeightBytes := make([]byte, 8)
294+
binary.LittleEndian.PutUint64(headerHeightBytes, uint64(i+1))
295+
store.On("SetMetadata", mock.Anything, fmt.Sprintf("%s/%d/h", RollkitHeightToDAHeightKey, height), headerHeightBytes).Return(nil).Once()
296+
dataHeightBytes := make([]byte, 8)
297+
binary.LittleEndian.PutUint64(dataHeightBytes, uint64(i+1))
298+
store.On("SetMetadata", mock.Anything, fmt.Sprintf("%s/%d/d", RollkitHeightToDAHeightKey, height), dataHeightBytes).Return(nil).Once()
299+
}
281300
store.On("SetMetadata", mock.Anything, DAIncludedHeightKey, mock.Anything).Return(nil).Times(numConsecutive)
282301
exec.On("SetFinal", mock.Anything, mock.Anything).Return(nil).Times(numConsecutive)
283302

@@ -312,11 +331,25 @@ func TestDAIncluderLoop_AdvancesHeightWhenDataHashIsEmptyAndHeaderDAIncluded(t *
312331

313332
header, data := types.GetRandomBlock(5, 0, "testchain")
314333
headerHash := header.Hash().String()
315-
m.headerCache.SetDAIncluded(headerHash)
334+
m.headerCache.SetDAIncluded(headerHash, uint64(1))
316335
// Do NOT set data as DA-included
317336

318-
store.On("GetBlockData", mock.Anything, uint64(5)).Return(header, data, nil).Once()
337+
store.On("GetBlockData", mock.Anything, uint64(5)).Return(header, data, nil).Times(2) // Called by IsDAIncluded and SetRollkitHeightToDAHeight
319338
store.On("GetBlockData", mock.Anything, uint64(6)).Return(nil, nil, assert.AnError).Once()
339+
// Mock expectations for SetRollkitHeightToDAHeight method
340+
headerHeightBytes := make([]byte, 8)
341+
binary.LittleEndian.PutUint64(headerHeightBytes, uint64(1))
342+
store.On("SetMetadata", mock.Anything, fmt.Sprintf("%s/%d/h", RollkitHeightToDAHeightKey, uint64(5)), headerHeightBytes).Return(nil).Once()
343+
// Note: For empty data, data SetMetadata call should still be made but data won't be marked as DA-included in cache,
344+
// so SetRollkitHeightToDAHeight will fail when trying to get the DA height for data
345+
// Actually, let's check if this case is handled differently for empty txs
346+
// Let me check what happens with empty txs by adding the data cache entry as well
347+
dataHash := data.DACommitment().String()
348+
m.dataCache.SetDAIncluded(dataHash, uint64(1))
349+
dataHeightBytes := make([]byte, 8)
350+
binary.LittleEndian.PutUint64(dataHeightBytes, uint64(1))
351+
store.On("SetMetadata", mock.Anything, fmt.Sprintf("%s/%d/d", RollkitHeightToDAHeightKey, uint64(5)), dataHeightBytes).Return(nil).Once()
352+
// Mock expectations for incrementDAIncludedHeight method
320353
heightBytes := make([]byte, 8)
321354
binary.LittleEndian.PutUint64(heightBytes, expectedDAIncludedHeight)
322355
store.On("SetMetadata", mock.Anything, DAIncludedHeightKey, heightBytes).Return(nil).Once()

‎block/manager.go‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ const (
5555

5656
// LastBatchDataKey is the key used for persisting the last batch data in store.
5757
LastBatchDataKey = "l"
58+
59+
// RollkitHeightToDAHeightKey is the key used for persisting the mapping rollkit height to da height in store.
60+
RollkitHeightToDAHeightKey = "rhb"
5861
)
5962

6063
var (
@@ -486,6 +489,33 @@ func (m *Manager) IsDAIncluded(ctx context.Context, height uint64) (bool, error)
486489
return isIncluded, nil
487490
}
488491

492+
func (m *Manager) SetRollkitHeightToDAHeight(ctx context.Context, height uint64) error {
493+
header, data, err := m.store.GetBlockData(ctx, height)
494+
if err != nil {
495+
return err
496+
}
497+
headerHash, dataHash := header.Hash(), data.DACommitment()
498+
headerHeightBytes := make([]byte, 8)
499+
daHeightForHeader, ok := m.headerCache.GetDAIncludedHeight(headerHash.String())
500+
if !ok {
501+
return fmt.Errorf("header hash %s not found in cache", headerHash)
502+
}
503+
binary.LittleEndian.PutUint64(headerHeightBytes, daHeightForHeader)
504+
if err := m.store.SetMetadata(ctx, fmt.Sprintf("%s/%d/h", RollkitHeightToDAHeightKey, height), headerHeightBytes); err != nil {
505+
return err
506+
}
507+
dataHeightBytes := make([]byte, 8)
508+
daHeightForData, ok := m.dataCache.GetDAIncludedHeight(dataHash.String())
509+
if !ok {
510+
return fmt.Errorf("data hash %s not found in cache", dataHash.String())
511+
}
512+
binary.LittleEndian.PutUint64(dataHeightBytes, daHeightForData)
513+
if err := m.store.SetMetadata(ctx, fmt.Sprintf("%s/%d/d", RollkitHeightToDAHeightKey, height), dataHeightBytes); err != nil {
514+
return err
515+
}
516+
return nil
517+
}
518+
489519
// GetExecutor returns the executor used by the manager.
490520
//
491521
// Note: this is a temporary method to allow testing the manager.

‎block/manager_test.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,11 @@ func TestIsDAIncluded(t *testing.T) {
194194
require.False(m.IsDAIncluded(ctx, height))
195195

196196
// Set the hash as DAIncluded and verify IsDAIncluded returns true
197-
m.headerCache.SetDAIncluded(header.Hash().String())
197+
m.headerCache.SetDAIncluded(header.Hash().String(), uint64(1))
198198
require.False(m.IsDAIncluded(ctx, height))
199199

200200
// Set the data as DAIncluded and verify IsDAIncluded returns true
201-
m.dataCache.SetDAIncluded(data.DACommitment().String())
201+
m.dataCache.SetDAIncluded(data.DACommitment().String(), uint64(1))
202202
require.True(m.IsDAIncluded(ctx, height))
203203
}
204204

‎block/retriever.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ func (m *Manager) handlePotentialHeader(ctx context.Context, bz []byte, daHeight
133133
return true
134134
}
135135
headerHash := header.Hash().String()
136-
m.headerCache.SetDAIncluded(headerHash)
136+
m.headerCache.SetDAIncluded(headerHash, daHeight)
137137
m.sendNonBlockingSignalToDAIncluderCh()
138138
m.logger.Info("header marked as DA included", "headerHeight", header.Height(), "headerHash", headerHash)
139139
if !m.headerCache.IsSeen(headerHash) {
@@ -168,7 +168,7 @@ func (m *Manager) handlePotentialData(ctx context.Context, bz []byte, daHeight u
168168
}
169169

170170
dataHashStr := signedData.Data.DACommitment().String()
171-
m.dataCache.SetDAIncluded(dataHashStr)
171+
m.dataCache.SetDAIncluded(dataHashStr, daHeight)
172172
m.sendNonBlockingSignalToDAIncluderCh()
173173
m.logger.Info("signed data marked as DA included", "dataHash", dataHashStr, "daHeight", daHeight, "height", signedData.Height())
174174
if !m.dataCache.IsSeen(dataHashStr) {

‎block/retriever_test.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -528,9 +528,9 @@ func TestProcessNextDAHeader_HeaderAndDataAlreadySeen(t *testing.T) {
528528

529529
// Mark both header and data as seen and DA included
530530
headerCache.SetSeen(headerHash)
531-
headerCache.SetDAIncluded(headerHash)
531+
headerCache.SetDAIncluded(headerHash, uint64(10))
532532
dataCache.SetSeen(dataHash)
533-
dataCache.SetDAIncluded(dataHash)
533+
dataCache.SetDAIncluded(dataHash, uint64(10))
534534

535535
// Set up mocks with explicit logging
536536
mockDAClient.On("GetIDs", mock.Anything, daHeight, mock.Anything).Return(&coreda.GetIDsResult{

‎block/submitter.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ func (m *Manager) submitHeadersToDA(ctx context.Context, headersToSubmit []*type
172172
},
173173
func(submitted []*types.SignedHeader, res *coreda.ResultSubmit, gasPrice float64) {
174174
for _, header := range submitted {
175-
m.headerCache.SetDAIncluded(header.Hash().String())
175+
m.headerCache.SetDAIncluded(header.Hash().String(), res.Height)
176176
}
177177
lastSubmittedHeaderHeight := uint64(0)
178178
if l := len(submitted); l > 0 {
@@ -197,7 +197,7 @@ func (m *Manager) submitDataToDA(ctx context.Context, signedDataToSubmit []*type
197197
},
198198
func(submitted []*types.SignedData, res *coreda.ResultSubmit, gasPrice float64) {
199199
for _, signedData := range submitted {
200-
m.dataCache.SetDAIncluded(signedData.DACommitment().String())
200+
m.dataCache.SetDAIncluded(signedData.Data.DACommitment().String(), res.Height)
201201
}
202202
lastSubmittedDataHeight := uint64(0)
203203
if l := len(submitted); l > 0 {

‎block/submitter_test.go‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func TestSubmitDataToDA_Success(t *testing.T) {
9999
},
100100
mockDASetup: func(da *mocks.DA) {
101101
da.On("Submit", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
102-
Return([]coreda.ID{[]byte("id")}, nil)
102+
Return([]coreda.ID{getDummyID(1, []byte("commitment"))}, nil)
103103
},
104104
})
105105
}
@@ -118,7 +118,7 @@ func TestSubmitHeadersToDA_Success(t *testing.T) {
118118
},
119119
mockDASetup: func(da *mocks.DA) {
120120
da.On("Submit", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
121-
Return([]coreda.ID{[]byte("id")}, nil)
121+
Return([]coreda.ID{getDummyID(1, []byte("commitment"))}, nil)
122122
},
123123
})
124124
}
@@ -265,15 +265,15 @@ func runRetryPartialFailuresCase[T any](t *testing.T, tc retryPartialFailuresCas
265265
da.On("Submit", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
266266
Run(func(args mock.Arguments) {
267267
t.Logf("DA Submit call 1: args=%#v", args)
268-
}).Once().Return([]coreda.ID{[]byte("id2")}, nil)
268+
}).Once().Return([]coreda.ID{getDummyID(1, []byte("commitment2"))}, nil)
269269
da.On("Submit", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
270270
Run(func(args mock.Arguments) {
271271
t.Logf("DA Submit call 2: args=%#v", args)
272-
}).Once().Return([]coreda.ID{[]byte("id3")}, nil)
272+
}).Once().Return([]coreda.ID{getDummyID(1, []byte("commitment3"))}, nil)
273273
da.On("Submit", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
274274
Run(func(args mock.Arguments) {
275275
t.Logf("DA Submit call 3: args=%#v", args)
276-
}).Once().Return([]coreda.ID{[]byte("id4")}, nil)
276+
}).Once().Return([]coreda.ID{getDummyID(1, []byte("commitment4"))}, nil)
277277

278278
err = tc.submitToDA(m, ctx, items)
279279
assert.NoError(t, err)
@@ -554,3 +554,10 @@ func TestSubmitDataToDA_WithMetricsRecorder(t *testing.T) {
554554
// Verify that RecordMetrics was called
555555
mockSequencer.AssertExpectations(t)
556556
}
557+
558+
func getDummyID(height uint64, commitment []byte) coreda.ID {
559+
id := make([]byte, len(commitment)+8)
560+
binary.LittleEndian.PutUint64(id, height)
561+
copy(id[8:], commitment)
562+
return id
563+
}

‎pkg/cache/cache.go‎

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,21 @@ func (c *Cache[T]) SetSeen(hash string) {
6060

6161
// IsDAIncluded returns true if the hash has been DA-included
6262
func (c *Cache[T]) IsDAIncluded(hash string) bool {
63+
_, ok := c.daIncluded.Load(hash)
64+
return ok
65+
}
66+
67+
func (c *Cache[T]) GetDAIncludedHeight(hash string) (uint64, bool) {
6368
daIncluded, ok := c.daIncluded.Load(hash)
6469
if !ok {
65-
return false
70+
return 0, false
6671
}
67-
return daIncluded.(bool)
72+
return daIncluded.(uint64), true
6873
}
6974

70-
// SetDAIncluded sets the hash as DA-included
71-
func (c *Cache[T]) SetDAIncluded(hash string) {
72-
c.daIncluded.Store(hash, true)
75+
// SetDAIncluded sets the hash as DA-included with the given height
76+
func (c *Cache[T]) SetDAIncluded(hash string, height uint64) {
77+
c.daIncluded.Store(hash, height)
7378
}
7479

7580
const (
@@ -168,12 +173,12 @@ func (c *Cache[T]) SaveToDisk(folderPath string) error {
168173
}
169174

170175
// prepare daIncluded map
171-
daIncludedToSave := make(map[string]bool)
176+
daIncludedToSave := make(map[string]uint64)
172177
c.daIncluded.Range(func(k, v interface{}) bool {
173178
keyStr, okKey := k.(string)
174-
valBool, okVal := v.(bool)
179+
valUint64, okVal := v.(uint64)
175180
if okKey && okVal {
176-
daIncludedToSave[keyStr] = valBool
181+
daIncludedToSave[keyStr] = valUint64
177182
}
178183
return true
179184
})
@@ -213,7 +218,7 @@ func (c *Cache[T]) LoadFromDisk(folderPath string) error {
213218
}
214219

215220
// load daIncluded
216-
daIncludedMap, err := loadMapGob[string, bool](filepath.Join(folderPath, daIncludedFilename))
221+
daIncludedMap, err := loadMapGob[string, uint64](filepath.Join(folderPath, daIncludedFilename))
217222
if err != nil {
218223
return fmt.Errorf("failed to load daIncluded: %w", err)
219224
}

‎pkg/cache/cache_test.go‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func TestCacheDAIncludedOperations(t *testing.T) {
7777
}
7878

7979
// Test setting and checking DA-included status
80-
cache.SetDAIncluded(testHash)
80+
cache.SetDAIncluded(testHash, 1)
8181
if !cache.IsDAIncluded(testHash) {
8282
t.Error("Hash should be DA-included after SetDAIncluded")
8383
}
@@ -113,7 +113,7 @@ func TestCacheConcurrency(t *testing.T) {
113113
_ = cache.IsSeen(hash)
114114

115115
// Test concurrent DA-included operations
116-
cache.SetDAIncluded(hash)
116+
cache.SetDAIncluded(hash, 1)
117117
_ = cache.IsDAIncluded(hash)
118118
}
119119
}(i)
@@ -145,7 +145,7 @@ func TestCachePersistence(t *testing.T) {
145145
cache1.SetItem(100, &val1)
146146
cache1.SetItem(200, &val2)
147147
cache1.SetSeen(hash1)
148-
cache1.SetDAIncluded(hash2)
148+
cache1.SetDAIncluded(hash2, 1)
149149

150150
// save cache1 to disk
151151
err := cache1.SaveToDisk(tempDir)
@@ -227,7 +227,7 @@ func TestCachePersistence_Overwrite(t *testing.T) {
227227
cache2 := NewCache[int]()
228228
val2 := 456
229229
cache2.SetItem(2, &val2)
230-
cache2.SetDAIncluded("hash2")
230+
cache2.SetDAIncluded("hash2", 1)
231231
err = cache2.SaveToDisk(tempDir) // save to the same directory
232232
require.NoError(t, err)
233233

0 commit comments

Comments
 (0)