github.com/Finschia/finschia-sdk@v0.48.1/x/token/class/keeper/id.go (about)

     1  package keeper
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"hash/fnv"
     7  	"math"
     8  
     9  	sdk "github.com/Finschia/finschia-sdk/types"
    10  )
    11  
    12  // NewID returns a brand new ID.
    13  func (k Keeper) NewID(ctx sdk.Context) string {
    14  	for nonce := k.getNonce(ctx); nonce.LTE(sdk.NewUint(math.MaxUint64)); nonce = nonce.Incr() {
    15  		encoded := nonceToID(nonce.Uint64())
    16  		if !k.HasID(ctx, encoded) {
    17  			k.addID(ctx, encoded)
    18  			k.setNonce(ctx, nonce.Incr())
    19  			return encoded
    20  		}
    21  	}
    22  	panic("contract id space exhausted: uint64")
    23  }
    24  
    25  func nonceToID(nonce uint64) string {
    26  	hash := fnv.New32()
    27  	bz := make([]byte, 8)
    28  	binary.LittleEndian.PutUint64(bz, nonce)
    29  	_, err := hash.Write(bz)
    30  	if err != nil {
    31  		panic("hash should not fail")
    32  	}
    33  	id := fmt.Sprintf("%x", hash.Sum32())
    34  	if len(id) < 8 {
    35  		id = "00000000"[len(id):] + id
    36  	}
    37  	return id
    38  }
    39  
    40  func (k Keeper) getNonce(ctx sdk.Context) sdk.Uint {
    41  	store := ctx.KVStore(k.storeKey)
    42  	bz := store.Get(nonceKey)
    43  	if bz == nil {
    44  		panic("next id must exist")
    45  	}
    46  	var nonce sdk.Uint
    47  	if err := nonce.Unmarshal(bz); err != nil {
    48  		panic(err)
    49  	}
    50  	return nonce
    51  }
    52  
    53  func (k Keeper) setNonce(ctx sdk.Context, nonce sdk.Uint) {
    54  	store := ctx.KVStore(k.storeKey)
    55  	bz, err := nonce.Marshal()
    56  	if err != nil {
    57  		panic(err)
    58  	}
    59  	store.Set(nonceKey, bz)
    60  }
    61  
    62  func (k Keeper) addID(ctx sdk.Context, id string) {
    63  	store := ctx.KVStore(k.storeKey)
    64  	store.Set(idKey(id), []byte{})
    65  }
    66  
    67  func (k Keeper) HasID(ctx sdk.Context, id string) bool {
    68  	store := ctx.KVStore(k.storeKey)
    69  	return store.Has(idKey(id))
    70  }
    71  
    72  func (k Keeper) DeleteID(ctx sdk.Context, id string) {
    73  	store := ctx.KVStore(k.storeKey)
    74  	store.Delete(idKey(id))
    75  }