github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/testing/simapp/test_helpers.go (about) 1 package simapp 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "encoding/json" 7 "fmt" 8 "math/big" 9 "strconv" 10 "testing" 11 "time" 12 13 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client" 14 ibcmsg "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/ibc-adapter" 15 16 abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types" 17 tmproto "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types" 18 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 19 tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types" 20 dbm "github.com/fibonacci-chain/fbc/libs/tm-db" 21 "github.com/stretchr/testify/require" 22 23 bam "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/baseapp" 24 cryptotypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/types" 25 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 26 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 27 authtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth" 28 authexported "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/exported" 29 minttypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/mint" 30 "github.com/fibonacci-chain/fbc/libs/ibc-go/testing/simapp/helpers" 31 cryptotypes2 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto" 32 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto/ed25519" 33 ) 34 35 // DefaultConsensusParams defines the default Tendermint consensus params used in 36 // SimApp testing. 37 var DefaultConsensusParams = &abci.ConsensusParams{ 38 Block: &abci.BlockParams{ 39 MaxBytes: 200000, 40 MaxGas: 2000000, 41 }, 42 Evidence: &tmproto.EvidenceParams{ 43 MaxAgeNumBlocks: 302400, 44 MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration 45 //MaxBytes: 10000, 46 }, 47 Validator: &tmproto.ValidatorParams{ 48 PubKeyTypes: []string{ 49 tmtypes.ABCIPubKeyTypeEd25519, 50 }, 51 }, 52 } 53 54 func setup(withGenesis bool, invCheckPeriod uint) (*SimApp, GenesisState) { 55 db := dbm.NewMemDB() 56 app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, invCheckPeriod) 57 if withGenesis { 58 return app, NewDefaultGenesisState() 59 } 60 return app, GenesisState{} 61 } 62 63 // Setup initializes a new SimApp. A Nop logger is set in SimApp. 64 func Setup(isCheckTx bool) *SimApp { 65 app, genesisState := setup(!isCheckTx, 5) 66 if !isCheckTx { 67 // init chain must be called to stop deliverState from being nil 68 stateBytes, err := json.MarshalIndent(genesisState, "", " ") 69 if err != nil { 70 panic(err) 71 } 72 73 // Initialize the chain 74 app.InitChain( 75 abci.RequestInitChain{ 76 Validators: []abci.ValidatorUpdate{}, 77 ConsensusParams: DefaultConsensusParams, 78 AppStateBytes: stateBytes, 79 }, 80 ) 81 } 82 83 return app 84 } 85 86 // SetupWithGenesisAccounts initializes a new SimApp with the provided genesis 87 // accounts and possible balances. 88 func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount, balances sdk.Coins) *SimApp { 89 app, genesisState := setup(true, 0) 90 authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) 91 genesisState[authtypes.ModuleName] = app.AppCodec().GetCdc().MustMarshalJSON(authGenesis) 92 93 totalSupply := sdk.NewCoins() 94 for _, b := range balances { 95 totalSupply = totalSupply.Add(b) 96 } 97 98 stateBytes, err := json.MarshalIndent(genesisState, "", " ") 99 if err != nil { 100 panic(err) 101 } 102 103 app.InitChain( 104 abci.RequestInitChain{ 105 Validators: []abci.ValidatorUpdate{}, 106 ConsensusParams: DefaultConsensusParams, 107 AppStateBytes: stateBytes, 108 }, 109 ) 110 111 app.Commit(tmproto.RequestCommit{}) 112 app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1}}) 113 114 return app 115 } 116 117 type GenerateAccountStrategy func(int) []sdk.AccAddress 118 119 // createRandomAccounts is a strategy used by addTestAddrs() in order to generated addresses in random order. 120 func createRandomAccounts(accNum int) []sdk.AccAddress { 121 testAddrs := make([]sdk.AccAddress, accNum) 122 for i := 0; i < accNum; i++ { 123 pk := ed25519.GenPrivKey().PubKey() 124 testAddrs[i] = sdk.AccAddress(pk.Address()) 125 } 126 127 return testAddrs 128 } 129 130 // createIncrementalAccounts is a strategy used by addTestAddrs() in order to generated addresses in ascending order. 131 func createIncrementalAccounts(accNum int) []sdk.AccAddress { 132 var addresses []sdk.AccAddress 133 var buffer bytes.Buffer 134 135 // start at 100 so we can make up to 999 test addresses with valid test addresses 136 for i := 100; i < (accNum + 100); i++ { 137 numString := strconv.Itoa(i) 138 buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") // base address string 139 140 buffer.WriteString(numString) // adding on final two digits to make addresses unique 141 res, _ := sdk.AccAddressFromHex(buffer.String()) 142 bech := res.String() 143 addr, _ := TestAddr(buffer.String(), bech) 144 145 addresses = append(addresses, addr) 146 buffer.Reset() 147 } 148 149 return addresses 150 } 151 152 // AddTestAddrsFromPubKeys adds the addresses into the SimApp providing only the public keys. 153 func AddTestAddrsFromPubKeys(app *SimApp, ctx sdk.Context, pubKeys []cryptotypes.PubKey, accAmt sdk.Int) { 154 initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt)) 155 156 for _, pk := range pubKeys { 157 initAccountWithCoins(app, ctx, sdk.AccAddress(pk.Address()), initCoins) 158 } 159 } 160 161 // AddTestAddrs constructs and returns accNum amount of accounts with an 162 // initial balance of accAmt in random order 163 func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { 164 return addTestAddrs(app, ctx, accNum, accAmt, createRandomAccounts) 165 } 166 167 // AddTestAddrs constructs and returns accNum amount of accounts with an 168 // initial balance of accAmt in random order 169 func AddTestAddrsIncremental(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress { 170 return addTestAddrs(app, ctx, accNum, accAmt, createIncrementalAccounts) 171 } 172 173 func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, strategy GenerateAccountStrategy) []sdk.AccAddress { 174 testAddrs := strategy(accNum) 175 176 initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt)) 177 178 for _, addr := range testAddrs { 179 initAccountWithCoins(app, ctx, addr, initCoins) 180 } 181 182 return testAddrs 183 } 184 185 func initAccountWithCoins(app *SimApp, ctx sdk.Context, addr sdk.AccAddress, coins sdk.Coins) { 186 err := app.SupplyKeeper.MintCoins(ctx, minttypes.ModuleName, coins) 187 if err != nil { 188 panic(err) 189 } 190 191 err = app.SupplyKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, coins) 192 if err != nil { 193 panic(err) 194 } 195 } 196 197 // ConvertAddrsToValAddrs converts the provided addresses to ValAddress. 198 func ConvertAddrsToValAddrs(addrs []sdk.AccAddress) []sdk.ValAddress { 199 valAddrs := make([]sdk.ValAddress, len(addrs)) 200 201 for i, addr := range addrs { 202 valAddrs[i] = sdk.ValAddress(addr) 203 } 204 205 return valAddrs 206 } 207 208 func TestAddr(addr string, bech string) (sdk.AccAddress, error) { 209 res, err := sdk.AccAddressFromHex(addr) 210 if err != nil { 211 return nil, err 212 } 213 bechexpected := res.String() 214 if bech != bechexpected { 215 return nil, fmt.Errorf("bech encoding doesn't match reference") 216 } 217 218 bechres, err := sdk.AccAddressFromBech32(bech) 219 if err != nil { 220 return nil, err 221 } 222 if !bytes.Equal(bechres, res) { 223 return nil, err 224 } 225 226 return res, nil 227 } 228 229 // CheckBalance checks the balance of an account. 230 func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, balances sdk.Coins) { 231 ctxCheck := app.BaseApp.NewContext(true, tmproto.Header{}) 232 require.True(t, balances.IsEqual(app.BankKeeper.GetCoins(ctxCheck, addr))) 233 } 234 235 // SignAndDeliver signs and delivers a transaction. No simulation occurs as the 236 // ibc testing package causes checkState and deliverState to diverge in block time. 237 func SignAndDeliver( 238 t *testing.T, txCfg client.TxConfig, app *bam.BaseApp, header tmproto.Header, msgs []ibcmsg.Msg, 239 chainID string, accNums, accSeqs []uint64, expSimPass, expPass bool, priv ...cryptotypes2.PrivKey, 240 ) (sdk.GasInfo, *sdk.Result, error) { 241 242 tx, err := helpers.GenTx( 243 txCfg, 244 msgs, 245 //sdk.CoinAdapters{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}, 246 sdk.CoinAdapters{sdk.NewCoinAdapter(sdk.DefaultIbcWei, sdk.NewIntFromBigInt(big.NewInt(0)))}, 247 helpers.DefaultGenTxGas, 248 chainID, 249 accNums, 250 accSeqs, 251 1, 252 priv..., 253 ) 254 require.NoError(t, err) 255 256 // Simulate a sending a transaction and committing a block 257 app.BeginBlock(abci.RequestBeginBlock{Header: header}) 258 //convert tx to ibctx 259 gInfo, res, err := app.Deliver(tx) 260 261 if expPass { 262 require.NoError(t, err) 263 require.NotNil(t, res) 264 } else { 265 require.Error(t, err) 266 require.Nil(t, res) 267 } 268 269 app.EndBlock(abci.RequestEndBlock{}) 270 app.Commit(abci.RequestCommit{}) 271 272 return gInfo, res, err 273 } 274 275 // GenSequenceOfTxs generates a set of signed transactions of messages, such 276 // that they differ only by having the sequence numbers incremented between 277 // every transaction. 278 func GenSequenceOfTxs(txGen client.TxConfig, msgs []ibcmsg.Msg, accNums []uint64, initSeqNums []uint64, numToGenerate int, priv ...cryptotypes2.PrivKey) ([]sdk.Tx, error) { 279 txs := make([]sdk.Tx, numToGenerate) 280 var err error 281 for i := 0; i < numToGenerate; i++ { 282 txs[i], err = helpers.GenTx( 283 txGen, 284 msgs, 285 //sdk.CoinAdapters{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}, 286 sdk.CoinAdapters{sdk.NewCoinAdapter(sdk.DefaultBondDenom, sdk.NewIntFromBigInt(big.NewInt(0)))}, 287 helpers.DefaultGenTxGas, 288 "", 289 accNums, 290 initSeqNums, 291 1, 292 priv..., 293 ) 294 if err != nil { 295 break 296 } 297 incrementAllSequenceNumbers(initSeqNums) 298 } 299 300 return txs, err 301 } 302 303 func incrementAllSequenceNumbers(initSeqNums []uint64) { 304 for i := 0; i < len(initSeqNums); i++ { 305 initSeqNums[i]++ 306 } 307 } 308 309 // CreateTestPubKeys returns a total of numPubKeys public keys in ascending order. 310 func CreateTestPubKeys(numPubKeys int) []cryptotypes2.PubKey { 311 var publicKeys []cryptotypes2.PubKey 312 var buffer bytes.Buffer 313 314 // start at 10 to avoid changing 1 to 01, 2 to 02, etc 315 for i := 100; i < (numPubKeys + 100); i++ { 316 numString := strconv.Itoa(i) 317 buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") // base pubkey string 318 buffer.WriteString(numString) // adding on final two digits to make pubkeys unique 319 publicKeys = append(publicKeys, NewPubKeyFromHex(buffer.String())) 320 buffer.Reset() 321 } 322 323 return publicKeys 324 } 325 326 // NewPubKeyFromHex returns a PubKey from a hex string. 327 func NewPubKeyFromHex(pk string) (res cryptotypes2.PubKey) { 328 pkBytes, err := hex.DecodeString(pk) 329 if err != nil { 330 panic(err) 331 } 332 333 if len(pkBytes) != ed25519.PubKeyEd25519Size { 334 panic(errors.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size")) 335 } 336 key := ed25519.PubKeyEd25519{} 337 copy(key[:], pkBytes) 338 339 return key 340 } 341 342 // EmptyAppOptions is a stub implementing AppOptions 343 type EmptyAppOptions struct{} 344 345 // Get implements AppOptions 346 func (ao EmptyAppOptions) Get(o string) interface{} { 347 return nil 348 } 349 350 // FundAccount is a utility function that funds an account by minting and sending the coins to the address 351 // TODO(fdymylja): instead of using the mint module account, which has the permission of minting, create a "faucet" account 352 func FundAccount(app *SimApp, ctx sdk.Context, addr sdk.AccAddress, amounts sdk.Coins) error { 353 err := app.SupplyKeeper.MintCoins(ctx, minttypes.ModuleName, amounts) 354 if err != nil { 355 return err 356 } 357 return app.SupplyKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, amounts) 358 }