@@ -38,10 +38,8 @@ func IndexClusterBlockHeight(lctx lockctx.Proof, rw storage.ReaderBatchWriter, c
3838 if existing != blockID {
3939 return fmt .Errorf ("cluster block height already indexed with different block ID: %s vs %s: %w" , existing , blockID , storage .ErrDataMismatch )
4040 }
41- // already indexed, nothing to do
42- return nil
43- }
44-
41+ return nil // for the specified height, the finalized block is already set to `blockID`
42+ // We do NOT want to continue with the WRITE UNLESS `storage.ErrNotFound` was received when checking for existing data.
4543 if ! errors .Is (err , storage .ErrNotFound ) {
4644 return fmt .Errorf ("failed to check existing cluster block height index: %w" , err )
4745 }
@@ -58,6 +56,16 @@ func LookupClusterBlockHeight(r storage.Reader, clusterID flow.ChainID, height u
5856 return RetrieveByKey (r , MakePrefix (codeFinalizedCluster , clusterID , height ), blockID )
5957}
6058
59+ // BootstrapClusterFinalizedHeight initializes the latest finalized cluster block height for the given cluster.
60+ //
61+ // CAUTION:
62+ // - This function is intended to be called during bootstrapping only. It expects that the height of the latest
63+ // known finalized cluster block has not yet been persisted.
64+ // - Confirming that no value is already stored and the subsequent write must be atomic to prevent data corruption.
65+ // Therefore, the caller must acquire the [storage.LockInsertOrFinalizeClusterBlock] and hold it until the database
66+ // write has been committed.
67+ //
68+ // No error returns expected during normal operations.
6169func BootstrapClusterFinalizedHeight (lctx lockctx.Proof , rw storage.ReaderBatchWriter , clusterID flow.ChainID , number uint64 ) error {
6270 if ! lctx .HoldsLock (storage .LockInsertOrFinalizeClusterBlock ) {
6371 return fmt .Errorf ("missing lock: %v" , storage .LockInsertOrFinalizeClusterBlock )
@@ -68,9 +76,10 @@ func BootstrapClusterFinalizedHeight(lctx lockctx.Proof, rw storage.ReaderBatchW
6876 var existing uint64
6977 err := RetrieveByKey (rw .GlobalReader (), key , & existing )
7078 if err == nil {
71- return fmt .Errorf ("finalized height already initialized: %d" , existing )
79+ return fmt .Errorf ("finalized height for cluster %v already initialized to %d" , clusterID , existing )
7280 }
7381
82+ // We do NOT want to continue with the WRITE UNLESS `storage.ErrNotFound` was received when checking for existing data.
7483 if ! errors .Is (err , storage .ErrNotFound ) {
7584 return fmt .Errorf ("failed to check existing finalized height: %w" , err )
7685 }
@@ -79,7 +88,17 @@ func BootstrapClusterFinalizedHeight(lctx lockctx.Proof, rw storage.ReaderBatchW
7988}
8089
8190// UpdateClusterFinalizedHeight updates (overwrites!) the latest finalized cluster block height for the given cluster.
82- func UpdateClusterFinalizedHeight (lctx lockctx.Proof , rw storage.ReaderBatchWriter , clusterID flow.ChainID , number uint64 ) error {
91+ //
92+ // CAUTION:
93+ // - This function is intended for normal operations after bootstrapping. It expects that the height of the
94+ // latest known finalized cluster block has already been persisted. This function guarantees that the height is updated
95+ // sequentially, i.e. the new height is equal to the old height plus one. Otherwise, an exception is returned.
96+ // - Reading the current height value, checking that it increases sequentially, and writing the new value must happen in one
97+ // atomic operation to prevent data corruption. Hence, the caller must acquire [storage.LockInsertOrFinalizeClusterBlock]
98+ // and hold it until the database write has been committed.
99+ //
100+ // No error returns expected during normal operations.
101+ func UpdateClusterFinalizedHeight (lctx lockctx.Proof , rw storage.ReaderBatchWriter , clusterID flow.ChainID , latestFinalizedHeight uint64 ) error {
83102 if ! lctx .HoldsLock (storage .LockInsertOrFinalizeClusterBlock ) {
84103 return fmt .Errorf ("missing lock: %v" , storage .LockInsertOrFinalizeClusterBlock )
85104 }
0 commit comments