github.com/ava-labs/avalanchego@v1.11.11/vms/proposervm/state/block_height_index.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package state 5 6 import ( 7 "github.com/ava-labs/avalanchego/cache" 8 "github.com/ava-labs/avalanchego/database" 9 "github.com/ava-labs/avalanchego/database/prefixdb" 10 "github.com/ava-labs/avalanchego/database/versiondb" 11 "github.com/ava-labs/avalanchego/ids" 12 ) 13 14 const cacheSize = 8192 // max cache entries 15 16 var ( 17 _ HeightIndex = (*heightIndex)(nil) 18 19 heightPrefix = []byte("height") 20 metadataPrefix = []byte("metadata") 21 22 forkKey = []byte("fork") 23 ) 24 25 type HeightIndexGetter interface { 26 // GetMinimumHeight return the smallest height of an indexed blockID. If 27 // there are no indexed blockIDs, ErrNotFound will be returned. 28 GetMinimumHeight() (uint64, error) 29 GetBlockIDAtHeight(height uint64) (ids.ID, error) 30 31 // Fork height is stored when the first post-fork block/option is accepted. 32 // Before that, fork height won't be found. 33 GetForkHeight() (uint64, error) 34 } 35 36 type HeightIndexWriter interface { 37 SetForkHeight(height uint64) error 38 SetBlockIDAtHeight(height uint64, blkID ids.ID) error 39 DeleteBlockIDAtHeight(height uint64) error 40 } 41 42 // HeightIndex contains mapping of blockHeights to accepted proposer block IDs 43 // along with some metadata (fork height and checkpoint). 44 type HeightIndex interface { 45 HeightIndexWriter 46 HeightIndexGetter 47 } 48 49 type heightIndex struct { 50 versiondb.Commitable 51 52 // Caches block height -> proposerVMBlockID. 53 heightsCache cache.Cacher[uint64, ids.ID] 54 55 heightDB database.Database 56 metadataDB database.Database 57 } 58 59 func NewHeightIndex(db database.Database, commitable versiondb.Commitable) HeightIndex { 60 return &heightIndex{ 61 Commitable: commitable, 62 63 heightsCache: &cache.LRU[uint64, ids.ID]{Size: cacheSize}, 64 heightDB: prefixdb.New(heightPrefix, db), 65 metadataDB: prefixdb.New(metadataPrefix, db), 66 } 67 } 68 69 func (hi *heightIndex) GetMinimumHeight() (uint64, error) { 70 it := hi.heightDB.NewIterator() 71 defer it.Release() 72 73 if !it.Next() { 74 return 0, database.ErrNotFound 75 } 76 77 height, err := database.ParseUInt64(it.Key()) 78 if err != nil { 79 return 0, err 80 } 81 return height, it.Error() 82 } 83 84 func (hi *heightIndex) GetBlockIDAtHeight(height uint64) (ids.ID, error) { 85 if blkID, found := hi.heightsCache.Get(height); found { 86 return blkID, nil 87 } 88 89 key := database.PackUInt64(height) 90 blkID, err := database.GetID(hi.heightDB, key) 91 if err != nil { 92 return ids.Empty, err 93 } 94 hi.heightsCache.Put(height, blkID) 95 return blkID, err 96 } 97 98 func (hi *heightIndex) SetBlockIDAtHeight(height uint64, blkID ids.ID) error { 99 hi.heightsCache.Put(height, blkID) 100 key := database.PackUInt64(height) 101 return database.PutID(hi.heightDB, key, blkID) 102 } 103 104 func (hi *heightIndex) DeleteBlockIDAtHeight(height uint64) error { 105 hi.heightsCache.Evict(height) 106 key := database.PackUInt64(height) 107 return hi.heightDB.Delete(key) 108 } 109 110 func (hi *heightIndex) GetForkHeight() (uint64, error) { 111 return database.GetUInt64(hi.metadataDB, forkKey) 112 } 113 114 func (hi *heightIndex) SetForkHeight(height uint64) error { 115 return database.PutUInt64(hi.metadataDB, forkKey, height) 116 }