github.com/MetalBlockchain/metalgo@v1.11.9/snow/engine/snowman/bootstrap/interval/state.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package interval 5 6 import ( 7 "errors" 8 9 "github.com/MetalBlockchain/metalgo/database" 10 ) 11 12 const ( 13 intervalPrefixByte byte = iota 14 blockPrefixByte 15 16 prefixLen = 1 17 ) 18 19 var ( 20 intervalPrefix = []byte{intervalPrefixByte} 21 blockPrefix = []byte{blockPrefixByte} 22 23 errInvalidKeyLength = errors.New("invalid key length") 24 ) 25 26 func GetIntervals(db database.Iteratee) ([]*Interval, error) { 27 it := db.NewIteratorWithPrefix(intervalPrefix) 28 defer it.Release() 29 30 var intervals []*Interval 31 for it.Next() { 32 dbKey := it.Key() 33 if len(dbKey) < prefixLen { 34 return nil, errInvalidKeyLength 35 } 36 37 intervalKey := dbKey[prefixLen:] 38 upperBound, err := database.ParseUInt64(intervalKey) 39 if err != nil { 40 return nil, err 41 } 42 43 value := it.Value() 44 lowerBound, err := database.ParseUInt64(value) 45 if err != nil { 46 return nil, err 47 } 48 49 intervals = append(intervals, &Interval{ 50 LowerBound: lowerBound, 51 UpperBound: upperBound, 52 }) 53 } 54 return intervals, it.Error() 55 } 56 57 func PutInterval(db database.KeyValueWriter, upperBound uint64, lowerBound uint64) error { 58 return database.PutUInt64(db, makeIntervalKey(upperBound), lowerBound) 59 } 60 61 func DeleteInterval(db database.KeyValueDeleter, upperBound uint64) error { 62 return db.Delete(makeIntervalKey(upperBound)) 63 } 64 65 // makeIntervalKey uses the upperBound rather than the lowerBound because blocks 66 // are fetched from tip towards genesis. This means that it is more common for 67 // the lowerBound to change than the upperBound. Modifying the lowerBound only 68 // requires a single write rather than a write and a delete when modifying the 69 // upperBound. 70 func makeIntervalKey(upperBound uint64) []byte { 71 intervalKey := database.PackUInt64(upperBound) 72 return append(intervalPrefix, intervalKey...) 73 } 74 75 // GetBlockIterator returns a block iterator that will produce values 76 // corresponding to persisted blocks in order of increasing height. 77 func GetBlockIterator(db database.Iteratee) database.Iterator { 78 return db.NewIteratorWithPrefix(blockPrefix) 79 } 80 81 // GetBlockIteratorWithStart returns a block iterator that will produce values 82 // corresponding to persisted blocks in order of increasing height starting at 83 // [height]. 84 func GetBlockIteratorWithStart(db database.Iteratee, height uint64) database.Iterator { 85 return db.NewIteratorWithStartAndPrefix( 86 makeBlockKey(height), 87 blockPrefix, 88 ) 89 } 90 91 func GetBlock(db database.KeyValueReader, height uint64) ([]byte, error) { 92 return db.Get(makeBlockKey(height)) 93 } 94 95 func PutBlock(db database.KeyValueWriter, height uint64, bytes []byte) error { 96 return db.Put(makeBlockKey(height), bytes) 97 } 98 99 func DeleteBlock(db database.KeyValueDeleter, height uint64) error { 100 return db.Delete(makeBlockKey(height)) 101 } 102 103 // makeBlockKey ensures that the returned key maintains the same sorted order as 104 // the height. This ensures that database iteration of block keys will iterate 105 // from lower height to higher height. 106 func makeBlockKey(height uint64) []byte { 107 blockKey := database.PackUInt64(height) 108 return append(blockPrefix, blockKey...) 109 }