github.com/KiraCore/sekai@v0.3.43/app/test_helpers.go (about) 1 package app 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "encoding/json" 7 "fmt" 8 "strconv" 9 "testing" 10 11 sdkmath "cosmossdk.io/math" 12 stakingtypes "github.com/KiraCore/sekai/x/staking/types" 13 cometbftdb "github.com/cometbft/cometbft-db" 14 abci "github.com/cometbft/cometbft/abci/types" 15 "github.com/cometbft/cometbft/crypto/secp256k1" 16 "github.com/cometbft/cometbft/libs/log" 17 tmproto "github.com/cometbft/cometbft/proto/tendermint/types" 18 tmtypes "github.com/cometbft/cometbft/types" 19 codectypes "github.com/cosmos/cosmos-sdk/codec/types" 20 cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" 21 "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" 22 cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" 23 "github.com/cosmos/cosmos-sdk/testutil/mock" 24 simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" 25 sdk "github.com/cosmos/cosmos-sdk/types" 26 "github.com/cosmos/cosmos-sdk/types/errors" 27 authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" 28 banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" 29 minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" 30 "github.com/stretchr/testify/require" 31 ) 32 33 // Initializes a new SekaiApp 34 func Setup(isCheckTx bool) *SekaiApp { 35 db := cometbftdb.NewMemDB() 36 app := NewInitApp( 37 log.NewNopLogger(), 38 db, 39 nil, 40 true, 41 map[int64]bool{}, 42 DefaultNodeHome, 43 5, 44 MakeEncodingConfig(), 45 simtestutil.EmptyAppOptions{}, 46 ) 47 if !isCheckTx { 48 genesisState := GenesisStateWithValSet(app) 49 stateBytes, err := json.MarshalIndent(genesisState, "", " ") 50 if err != nil { 51 panic(err) 52 } 53 54 app.InitChain( 55 abci.RequestInitChain{ 56 Validators: []abci.ValidatorUpdate{}, 57 ConsensusParams: simtestutil.DefaultConsensusParams, 58 AppStateBytes: stateBytes, 59 }, 60 ) 61 } 62 63 return app 64 } 65 66 func GenesisStateWithValSet(app *SekaiApp) GenesisState { 67 privVal := mock.NewPV() 68 pubKey, _ := privVal.GetPubKey() 69 validator := tmtypes.NewValidator(pubKey, 1) 70 valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) 71 72 // generate genesis account 73 senderPrivKey := secp256k1.GenPrivKey() 74 senderPrivKey.PubKey().Address() 75 acc := authtypes.NewBaseAccountWithAddress(senderPrivKey.PubKey().Address().Bytes()) 76 balance := banktypes.Balance{ 77 Address: acc.GetAddress().String(), 78 Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000000000))), 79 } 80 81 ////////////////////// 82 balances := []banktypes.Balance{balance} 83 genesisState := NewDefaultGenesisState() 84 genAccs := []authtypes.GenesisAccount{acc} 85 authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) 86 genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis) 87 88 validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) 89 90 initValPowers := []abci.ValidatorUpdate{} 91 92 for _, val := range valSet.Validators { 93 pk, _ := cryptocodec.FromTmPubKeyInterface(val.PubKey) 94 pkAny, _ := codectypes.NewAnyWithValue(pk) 95 validator := stakingtypes.Validator{ 96 ValKey: sdk.ValAddress(val.Address), 97 PubKey: pkAny, 98 Status: stakingtypes.Active, 99 Rank: 0, 100 Streak: 0, 101 } 102 validators = append(validators, validator) 103 104 // add initial validator powers so consumer InitGenesis runs correctly 105 pub, _ := val.ToProto() 106 initValPowers = append(initValPowers, abci.ValidatorUpdate{ 107 Power: val.VotingPower, 108 PubKey: pub.PubKey, 109 }) 110 } 111 // set validators and delegations 112 stakingGenesis := &stakingtypes.GenesisState{ 113 Validators: validators, 114 } 115 genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis) 116 117 totalSupply := sdk.NewCoins() 118 for _, b := range balances { 119 // add genesis acc tokens to total supply 120 totalSupply = totalSupply.Add(b.Coins...) 121 } 122 123 // update total supply 124 bankGenesis := banktypes.NewGenesisState( 125 banktypes.DefaultGenesisState().Params, 126 balances, 127 totalSupply, 128 []banktypes.Metadata{}, 129 []banktypes.SendEnabled{}, 130 ) 131 genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) 132 133 return genesisState 134 } 135 136 type GenerateAccountStrategy func(int) []sdk.AccAddress 137 138 // createRandomAccounts is a strategy used by addTestAddrs() in order to generated addresses in random order. 139 func createRandomAccounts(accNum int) []sdk.AccAddress { 140 testAddrs := make([]sdk.AccAddress, accNum) 141 for i := 0; i < accNum; i++ { 142 pk := ed25519.GenPrivKey().PubKey() 143 testAddrs[i] = sdk.AccAddress(pk.Address()) 144 } 145 146 return testAddrs 147 } 148 149 // createIncrementalAccounts is a strategy used by addTestAddrs() in order to generated addresses in ascending order. 150 func createIncrementalAccounts(accNum int) []sdk.AccAddress { 151 var addresses []sdk.AccAddress 152 var buffer bytes.Buffer 153 154 // start at 100 so we can make up to 999 test addresses with valid test addresses 155 for i := 100; i < (accNum + 100); i++ { 156 numString := strconv.Itoa(i) 157 buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") //base address string 158 159 buffer.WriteString(numString) //adding on final two digits to make addresses unique 160 res, _ := sdk.AccAddressFromHexUnsafe(buffer.String()) 161 bech := res.String() 162 addr, _ := TestAddr(buffer.String(), bech) 163 164 addresses = append(addresses, addr) 165 buffer.Reset() 166 } 167 168 return addresses 169 } 170 171 // AddTestAddrsFromPubKeys adds the addresses into the SimApp providing only the public keys. 172 func AddTestAddrsFromPubKeys(app *SekaiApp, ctx sdk.Context, pubKeys []cryptotypes.PubKey, accAmt sdk.Int) { 173 initCoins := sdk.NewCoins(sdk.NewCoin(app.CustomStakingKeeper.DefaultDenom(ctx), accAmt)) 174 175 // fill all the addresses with some coins, set the loose pool tokens simultaneously 176 for _, pubKey := range pubKeys { 177 saveAccount(app, ctx, sdk.AccAddress(pubKey.Address()), initCoins) 178 } 179 } 180 181 // AddTestAddrs constructs and returns accNum amount of accounts with an 182 // initial balance of accAmt in random order 183 func AddTestAddrs(app *SekaiApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { 184 return addTestAddrs(app, ctx, accNum, accAmt, createRandomAccounts) 185 } 186 187 // AddTestAddrs constructs and returns accNum amount of accounts with an 188 // initial balance of accAmt in random order 189 func AddTestAddrsIncremental(app *SekaiApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { 190 return addTestAddrs(app, ctx, accNum, accAmt, createIncrementalAccounts) 191 } 192 193 func addTestAddrs(app *SekaiApp, ctx sdk.Context, accNum int, accAmt sdk.Int, strategy GenerateAccountStrategy) []sdk.AccAddress { 194 testAddrs := strategy(accNum) 195 196 initCoins := sdk.NewCoins(sdk.NewCoin(app.CustomStakingKeeper.DefaultDenom(ctx), accAmt)) 197 198 // fill all the addresses with some coins, set the loose pool tokens simultaneously 199 for _, addr := range testAddrs { 200 saveAccount(app, ctx, addr, initCoins) 201 } 202 203 return testAddrs 204 } 205 206 // saveAccount saves the provided account into the simapp with balance based on initCoins. 207 func saveAccount(app *SekaiApp, ctx sdk.Context, addr sdk.AccAddress, initCoins sdk.Coins) { 208 acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) 209 app.AccountKeeper.SetAccount(ctx, acc) 210 err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, initCoins) 211 if err != nil { 212 panic(err) 213 } 214 err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, initCoins) 215 if err != nil { 216 panic(err) 217 } 218 } 219 220 // ConvertAddrsToValAddrs converts the provided addresses to ValAddress. 221 func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) []sdk.ValAddress { 222 valAddrs := make([]sdk.ValAddress, len(addrs)) 223 224 for i, addr := range addrs { 225 valAddrs[i] = sdk.ValAddress(addr) 226 } 227 228 return valAddrs 229 } 230 231 func TestAddr(addr string, bech string) (sdk.AccAddress, error) { 232 res, err := sdk.AccAddressFromHexUnsafe(addr) 233 if err != nil { 234 return nil, err 235 } 236 bechexpected := res.String() 237 if bech != bechexpected { 238 return nil, fmt.Errorf("bech encoding doesn't match reference") 239 } 240 241 bechres, err := sdk.AccAddressFromBech32(bech) 242 if err != nil { 243 return nil, err 244 } 245 if !bytes.Equal(bechres, res) { 246 return nil, err 247 } 248 249 return res, nil 250 } 251 252 // CheckBalance checks the balance of an account. 253 func CheckBalance(t *testing.T, app *SekaiApp, addr sdk.AccAddress, balances sdk.Coins) { 254 ctxCheck := app.BaseApp.NewContext(true, tmproto.Header{}) 255 require.True(t, balances.IsEqual(app.BankKeeper.GetAllBalances(ctxCheck, addr))) 256 } 257 258 func incrementAllSequenceNumbers(initSeqNums []uint64) { 259 for i := 0; i < len(initSeqNums); i++ { 260 initSeqNums[i]++ 261 } 262 } 263 264 // CreateTestPubKeys returns a total of numPubKeys public keys in ascending order. 265 func CreateTestPubKeys(numPubKeys int) []cryptotypes.PubKey { 266 var publicKeys []cryptotypes.PubKey 267 var buffer bytes.Buffer 268 269 // start at 10 to avoid changing 1 to 01, 2 to 02, etc 270 for i := 100; i < (numPubKeys + 100); i++ { 271 numString := strconv.Itoa(i) 272 buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") // base pubkey string 273 buffer.WriteString(numString) // adding on final two digits to make pubkeys unique 274 publicKeys = append(publicKeys, NewPubKeyFromHex(buffer.String())) 275 buffer.Reset() 276 } 277 278 return publicKeys 279 } 280 281 // NewPubKeyFromHex returns a PubKey from a hex string. 282 func NewPubKeyFromHex(pk string) (res cryptotypes.PubKey) { 283 pkBytes, err := hex.DecodeString(pk) 284 if err != nil { 285 panic(err) 286 } 287 if len(pkBytes) != ed25519.PubKeySize { 288 panic(errors.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size")) 289 } 290 return &ed25519.PubKey{Key: pkBytes} 291 } 292 293 // EmptyAppOptions is a stub implementing AppOptions 294 type EmptyAppOptions struct{} 295 296 // Get implements AppOptions 297 func (ao EmptyAppOptions) Get(o string) interface{} { 298 return nil 299 }