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  }