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 }