@@ -35,7 +35,7 @@ func TestClusterHeights(t *testing.T) {
3535 t .Run ("insert/retrieve" , func (t * testing.T ) {
3636 err := unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
3737 return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
38- return operation .IndexClusterBlockHeight (lctx , rw . Writer () , clusterID , height , expected )
38+ return operation .IndexClusterBlockHeight (lctx , rw , clusterID , height , expected )
3939 })
4040 })
4141 require .NoError (t , err )
@@ -46,6 +46,32 @@ func TestClusterHeights(t *testing.T) {
4646 assert .Equal (t , expected , actual )
4747 })
4848
49+ t .Run ("data mismatch error" , func (t * testing.T ) {
50+ // Use a different cluster ID and height to avoid conflicts with other tests
51+ testClusterID := flow .ChainID ("test-cluster" )
52+ testHeight := uint64 (999 )
53+
54+ // First index a block ID for the cluster and height
55+ firstBlockID := unittest .IdentifierFixture ()
56+ err := unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
57+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
58+ return operation .IndexClusterBlockHeight (lctx , rw , testClusterID , testHeight , firstBlockID )
59+ })
60+ })
61+ require .NoError (t , err )
62+
63+ // Try to index a different block ID for the same cluster and height
64+ differentBlockID := unittest .IdentifierFixture ()
65+ err = unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
66+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
67+ return operation .IndexClusterBlockHeight (lctx , rw , testClusterID , testHeight , differentBlockID )
68+ })
69+ })
70+
71+ require .Error (t , err )
72+ assert .ErrorIs (t , err , storage .ErrDataMismatch )
73+ })
74+
4975 t .Run ("multiple chain IDs" , func (t * testing.T ) {
5076 // use different cluster ID but same block height
5177 // - we first index *all* three blocks from different clusters for the same height
@@ -61,7 +87,7 @@ func TestClusterHeights(t *testing.T) {
6187
6288 err := unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
6389 return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
64- return operation .IndexClusterBlockHeight (lctx , rw . Writer () , clusterIDs [i ], height , clusterBlockIDs [i ])
90+ return operation .IndexClusterBlockHeight (lctx , rw , clusterIDs [i ], height , clusterBlockIDs [i ])
6591 })
6692 })
6793 require .NoError (t , err )
@@ -81,11 +107,10 @@ func Test_RetrieveClusterFinalizedHeight(t *testing.T) {
81107 lockManager := storage .NewTestingLockManager ()
82108 var (
83109 clusterID flow.ChainID = "cluster"
84- expected uint64 = 42
85110 err error
86111 )
87112
88- t .Run ("retrieve non-existant " , func (t * testing.T ) {
113+ t .Run ("retrieve non-existent " , func (t * testing.T ) {
89114 var actual uint64
90115 err = operation .RetrieveClusterFinalizedHeight (db .Reader (), clusterID , & actual )
91116 t .Log (err )
@@ -96,22 +121,29 @@ func Test_RetrieveClusterFinalizedHeight(t *testing.T) {
96121
97122 err := unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
98123 return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
99- return operation .UpsertClusterFinalizedHeight (lctx , rw .Writer (), clusterID , 21 )
124+ return operation .BootstrapClusterFinalizedHeight (lctx , rw , clusterID , 20 )
125+ })
126+ })
127+ require .NoError (t , err )
128+
129+ err = unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
130+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
131+ return operation .UpdateClusterFinalizedHeight (lctx , rw , clusterID , 21 )
100132 })
101133 })
102134 require .NoError (t , err )
103135
104136 err = unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
105137 return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
106- return operation .UpsertClusterFinalizedHeight (lctx , rw . Writer () , clusterID , expected )
138+ return operation .UpdateClusterFinalizedHeight (lctx , rw , clusterID , 22 )
107139 })
108140 })
109141 require .NoError (t , err )
110142
111143 var actual uint64
112144 err = operation .RetrieveClusterFinalizedHeight (db .Reader (), clusterID , & actual )
113145 assert .NoError (t , err )
114- assert .Equal (t , expected , actual )
146+ assert .Equal (t , uint64 ( 22 ) , actual )
115147 })
116148
117149 t .Run ("multiple chain IDs" , func (t * testing.T ) {
@@ -129,7 +161,7 @@ func Test_RetrieveClusterFinalizedHeight(t *testing.T) {
129161
130162 err := unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
131163 return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
132- return operation .UpsertClusterFinalizedHeight (lctx , rw . Writer () , clusterIDs [i ], clusterFinalizedHeights [i ])
164+ return operation .BootstrapClusterFinalizedHeight (lctx , rw , clusterIDs [i ], clusterFinalizedHeights [i ])
133165 })
134166 })
135167 require .NoError (t , err )
@@ -140,6 +172,51 @@ func Test_RetrieveClusterFinalizedHeight(t *testing.T) {
140172 assert .Equal (t , clusterFinalizedHeights [i ], actual )
141173 }
142174 })
175+
176+ t .Run ("update to non-sequential finalized height returns error" , func (t * testing.T ) {
177+ // Use a different cluster ID to avoid conflicts with other tests
178+ testClusterID := flow .ChainID ("test-cluster-non-sequential" )
179+
180+ // First bootstrap a cluster with height 20
181+ err := unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
182+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
183+ return operation .BootstrapClusterFinalizedHeight (lctx , rw , testClusterID , 20 )
184+ })
185+ })
186+ require .NoError (t , err )
187+
188+ // Try to update to a non-sequential height (should fail)
189+ err = unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
190+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
191+ return operation .UpdateClusterFinalizedHeight (lctx , rw , testClusterID , 25 ) // Should be 21, not 25
192+ })
193+ })
194+ require .Error (t , err )
195+ assert .Contains (t , err .Error (), "finalization isn't sequential" )
196+ })
197+
198+ t .Run ("bootstrap on non-empty key returns error" , func (t * testing.T ) {
199+ // Use a different cluster ID to avoid conflicts with other tests
200+ testClusterID := flow .ChainID ("test-cluster-bootstrap-error" )
201+
202+ // First bootstrap a cluster with height 30
203+ err := unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
204+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
205+ return operation .BootstrapClusterFinalizedHeight (lctx , rw , testClusterID , 30 )
206+ })
207+ })
208+ require .NoError (t , err )
209+
210+ // Try to bootstrap again (should fail)
211+ err = unittest .WithLock (t , lockManager , storage .LockInsertOrFinalizeClusterBlock , func (lctx lockctx.Context ) error {
212+ return db .WithReaderBatchWriter (func (rw storage.ReaderBatchWriter ) error {
213+ return operation .BootstrapClusterFinalizedHeight (lctx , rw , testClusterID , 35 )
214+ })
215+ })
216+ require .Error (t , err )
217+ assert .Contains (t , err .Error (), "finalized height for cluster" )
218+ assert .Contains (t , err .Error (), "already initialized" )
219+ })
143220 })
144221}
145222
0 commit comments