github.com/cosmos/cosmos-sdk@v0.50.10/x/group/internal/orm/sequence.go (about)

     1  package orm
     2  
     3  import (
     4  	"encoding/binary"
     5  
     6  	errorsmod "cosmossdk.io/errors"
     7  	"cosmossdk.io/store/prefix"
     8  	storetypes "cosmossdk.io/store/types"
     9  
    10  	"github.com/cosmos/cosmos-sdk/x/group/errors"
    11  )
    12  
    13  // sequenceStorageKey is a fix key to read/ write data on the storage layer
    14  var sequenceStorageKey = []byte{0x1}
    15  
    16  // sequence is a persistent unique key generator based on a counter.
    17  type Sequence struct {
    18  	prefix byte
    19  }
    20  
    21  func NewSequence(prefix byte) Sequence {
    22  	return Sequence{
    23  		prefix: prefix,
    24  	}
    25  }
    26  
    27  // NextVal increments and persists the counter by one and returns the value.
    28  func (s Sequence) NextVal(store storetypes.KVStore) uint64 {
    29  	pStore := prefix.NewStore(store, []byte{s.prefix})
    30  	v := pStore.Get(sequenceStorageKey)
    31  	seq := DecodeSequence(v)
    32  	seq++
    33  	pStore.Set(sequenceStorageKey, EncodeSequence(seq))
    34  	return seq
    35  }
    36  
    37  // CurVal returns the last value used. 0 if none.
    38  func (s Sequence) CurVal(store storetypes.KVStore) uint64 {
    39  	pStore := prefix.NewStore(store, []byte{s.prefix})
    40  	v := pStore.Get(sequenceStorageKey)
    41  	return DecodeSequence(v)
    42  }
    43  
    44  // PeekNextVal returns the CurVal + increment step. Not persistent.
    45  func (s Sequence) PeekNextVal(store storetypes.KVStore) uint64 {
    46  	pStore := prefix.NewStore(store, []byte{s.prefix})
    47  	v := pStore.Get(sequenceStorageKey)
    48  	return DecodeSequence(v) + 1
    49  }
    50  
    51  // InitVal sets the start value for the sequence. It must be called only once on an empty DB.
    52  // Otherwise an error is returned when the key exists. The given start value is stored as current
    53  // value.
    54  //
    55  // It is recommended to call this method only for a sequence start value other than `1` as the
    56  // method consumes unnecessary gas otherwise. A scenario would be an import from genesis.
    57  func (s Sequence) InitVal(store storetypes.KVStore, seq uint64) error {
    58  	pStore := prefix.NewStore(store, []byte{s.prefix})
    59  	if pStore.Has(sequenceStorageKey) {
    60  		return errorsmod.Wrap(errors.ErrORMUniqueConstraint, "already initialized")
    61  	}
    62  	pStore.Set(sequenceStorageKey, EncodeSequence(seq))
    63  	return nil
    64  }
    65  
    66  // DecodeSequence converts the binary representation into an Uint64 value.
    67  func DecodeSequence(bz []byte) uint64 {
    68  	if bz == nil {
    69  		return 0
    70  	}
    71  	val := binary.BigEndian.Uint64(bz)
    72  	return val
    73  }
    74  
    75  // EncodedSeqLength number of bytes used for the binary representation of a sequence value.
    76  const EncodedSeqLength = 8
    77  
    78  // EncodeSequence converts the sequence value into the binary representation.
    79  func EncodeSequence(val uint64) []byte {
    80  	bz := make([]byte, EncodedSeqLength)
    81  	binary.BigEndian.PutUint64(bz, val)
    82  	return bz
    83  }