github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/simulation/rand_util.go (about) 1 package simulation 2 3 import ( 4 "errors" 5 "math/big" 6 "math/rand" 7 "time" 8 9 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 10 ) 11 12 const ( 13 letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 14 letterIdxBits = 6 // 6 bits to represent a letter index 15 letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits 16 letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits 17 ) 18 19 // shamelessly copied from 20 // https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang#31832326 21 22 // RandStringOfLength generates a random string of a particular length 23 func RandStringOfLength(r *rand.Rand, n int) string { 24 b := make([]byte, n) 25 // A src.Int63() generates 63 random bits, enough for letterIdxMax characters! 26 for i, cache, remain := n-1, r.Int63(), letterIdxMax; i >= 0; { 27 if remain == 0 { 28 cache, remain = r.Int63(), letterIdxMax 29 } 30 if idx := int(cache & letterIdxMask); idx < len(letterBytes) { 31 b[i] = letterBytes[idx] 32 i-- 33 } 34 cache >>= letterIdxBits 35 remain-- 36 } 37 return string(b) 38 } 39 40 // RandPositiveInt get a rand positive sdk.Int 41 func RandPositiveInt(r *rand.Rand, max sdk.Dec) (sdk.Int, error) { 42 if !max.GTE(sdk.OneDec()) { 43 return sdk.Int{}, errors.New("max too small") 44 } 45 max = max.Sub(sdk.OneDec()) 46 return sdk.NewIntFromBigInt(new(big.Int).Rand(r, max.BigInt())).Add(sdk.OneInt()), nil 47 } 48 49 // RandomAmount generates a random amount 50 // Note: The range of RandomAmount includes max, and is, in fact, biased to return max as well as 0. 51 func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int { 52 var randInt = big.NewInt(0) 53 switch r.Intn(10) { 54 case 0: 55 // randInt = big.NewInt(0) 56 case 1: 57 randInt = max.BigInt() 58 default: // NOTE: there are 10 total cases. 59 randInt = big.NewInt(0).Rand(r, max.BigInt()) // up to max - 1 60 } 61 return sdk.NewIntFromBigInt(randInt) 62 } 63 64 // RandomDecAmount generates a random decimal amount 65 // Note: The range of RandomDecAmount includes max, and is, in fact, biased to return max as well as 0. 66 func RandomDecAmount(r *rand.Rand, max sdk.Dec) sdk.Dec { 67 var randInt = big.NewInt(0) 68 switch r.Intn(10) { 69 case 0: 70 // randInt = big.NewInt(0) 71 case 1: 72 randInt = max.Int // the underlying big int with all precision bits. 73 default: // NOTE: there are 10 total cases. 74 randInt = big.NewInt(0).Rand(r, max.Int) 75 } 76 return sdk.NewDecFromBigIntWithPrec(randInt, sdk.Precision) 77 } 78 79 // RandTimestamp generates a random timestamp 80 func RandTimestamp(r *rand.Rand) time.Time { 81 // json.Marshal breaks for timestamps greater with year greater than 9999 82 unixTime := r.Int63n(253373529600) 83 return time.Unix(unixTime, 0) 84 } 85 86 // RandIntBetween returns a random int between two numbers inclusively. 87 func RandIntBetween(r *rand.Rand, min, max int) int { 88 return r.Intn(max-min) + min 89 } 90 91 // returns random subset of the provided coins 92 // will return at least one coin unless coins argument is empty or malformed 93 // i.e. 0 amt in coins 94 func RandSubsetCoins(r *rand.Rand, coins sdk.Coins) sdk.Coins { 95 if len(coins) == 0 { 96 return sdk.Coins{} 97 } 98 // make sure at least one coin added 99 denomIdx := r.Intn(len(coins)) 100 coin := coins[denomIdx] 101 amt, err := RandPositiveInt(r, coin.Amount) 102 // malformed coin. 0 amt in coins 103 if err != nil { 104 return sdk.Coins{} 105 } 106 subset := sdk.Coins{sdk.NewCoin(coin.Denom, amt)} 107 for i, c := range coins { 108 // skip denom that we already chose earlier 109 if i == denomIdx { 110 continue 111 } 112 // coin flip if multiple coins 113 // if there is single coin then return random amount of it 114 if r.Intn(2) == 0 && len(coins) != 1 { 115 continue 116 } 117 118 amt, err := RandPositiveInt(r, c.Amount) 119 // ignore errors and try another denom 120 if err != nil { 121 continue 122 } 123 subset = append(subset, sdk.NewCoin(c.Denom, amt)) 124 } 125 return subset.Sort() 126 } 127 128 // DeriveRand derives a new Rand deterministically from another random source. 129 // Unlike rand.New(rand.NewSource(seed)), the result is "more random" 130 // depending on the source and state of r. 131 // 132 // NOTE: not crypto safe. 133 func DeriveRand(r *rand.Rand) *rand.Rand { 134 const num = 8 // TODO what's a good number? Too large is too slow. 135 ms := multiSource(make([]rand.Source, num)) 136 for i := 0; i < num; i++ { 137 ms[i] = rand.NewSource(r.Int63()) 138 } 139 return rand.New(ms) 140 } 141 142 type multiSource []rand.Source 143 144 func (ms multiSource) Int63() (r int64) { 145 for _, source := range ms { 146 r ^= source.Int63() 147 } 148 return r 149 } 150 151 func (ms multiSource) Seed(seed int64) { 152 panic("multiSource Seed should not be called") 153 }