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