Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem: not make use of sim utils from sdk #1117

Merged
merged 7 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/sims.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
member:
name: Check whether it is triggered by team members with issue_comment or push or pull_request
runs-on: ubuntu-latest
timeout-minutes: 120
permissions:
pull-requests: write
if: >-
Expand Down
6 changes: 6 additions & 0 deletions app/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ import (
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
ibcfeetypes "github.com/cosmos/ibc-go/v6/modules/apps/29-fee/types"
ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
ibchost "github.com/cosmos/ibc-go/v6/modules/core/24-host"
cronosmoduletypes "github.com/crypto-org-chain/cronos/v2/x/cronos/types"
)

Expand Down Expand Up @@ -238,6 +241,9 @@ func TestAppImportExport(t *testing.T) {
{app.keys[authzkeeper.StoreKey], newApp.keys[authzkeeper.StoreKey], [][]byte{authzkeeper.GrantKey, authzkeeper.GrantQueuePrefix}},
{app.keys[evmtypes.StoreKey], newApp.keys[evmtypes.StoreKey], [][]byte{}},
{app.keys[cronosmoduletypes.StoreKey], newApp.keys[cronosmoduletypes.StoreKey], [][]byte{}},
{app.keys[ibchost.StoreKey], newApp.keys[ibchost.StoreKey], [][]byte{}},
{app.keys[ibctransfertypes.StoreKey], newApp.keys[ibctransfertypes.StoreKey], [][]byte{}},
{app.keys[ibcfeetypes.StoreKey], newApp.keys[ibcfeetypes.StoreKey], [][]byte{}},
}

for _, skp := range storeKeysPrefixes {
Expand Down
261 changes: 21 additions & 240 deletions app/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,11 @@ package app

import (
"encoding/json"
"fmt"
"io"
"math/rand"
"os"
"time"

sdkmath "cosmossdk.io/math"
tmjson "github.com/tendermint/tendermint/libs/json"
tmtypes "github.com/tendermint/tendermint/types"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/simapp"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

evmtypes "github.com/evmos/ethermint/x/evm/types"
Expand All @@ -30,236 +16,31 @@ import (
// It panics if the user provides files for both of them.
// If a file is not given for the genesis or the sim params, it creates a randomized one.
func StateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simtypes.AppStateFn {
return func(r *rand.Rand, accs []simtypes.Account, config simtypes.Config,
) (appState json.RawMessage, simAccs []simtypes.Account, chainID string, genesisTimestamp time.Time) {
if simapp.FlagGenesisTimeValue == 0 {
genesisTimestamp = simtypes.RandTimestamp(r)
} else {
genesisTimestamp = time.Unix(simapp.FlagGenesisTimeValue, 0)
}

chainID = config.ChainID
switch {
case config.ParamsFile != "" && config.GenesisFile != "":
panic("cannot provide both a genesis file and a params file")

case config.GenesisFile != "":
// override the default chain-id from simapp to set it later to the config
genesisDoc, accounts := StateFromGenesisFileFn(r, cdc, config.GenesisFile)

if simapp.FlagGenesisTimeValue == 0 {
// use genesis timestamp if no custom timestamp is provided (i.e no random timestamp)
genesisTimestamp = genesisDoc.GenesisTime
var bondDenom string
return simapp.AppStateFnWithExtendedCbs(
cdc,
simManager,
NewDefaultGenesisState(cdc),
func(moduleName string, genesisState interface{}) {
if moduleName == stakingtypes.ModuleName {
stakingState := genesisState.(*stakingtypes.GenesisState)
bondDenom = stakingState.Params.BondDenom
}

appState = genesisDoc.AppState
chainID = genesisDoc.ChainID
simAccs = accounts

case config.ParamsFile != "":
appParams := make(simtypes.AppParams)
bz, err := os.ReadFile(config.ParamsFile)
if err != nil {
panic(err)
},
func(rawState map[string]json.RawMessage) {
evmStateBz, ok := rawState[evmtypes.ModuleName]
if !ok {
panic("evm genesis state is missing")
}

err = json.Unmarshal(bz, &appParams)
if err != nil {
panic(err)
}
appState, simAccs = StateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams)

default:
appParams := make(simtypes.AppParams)
appState, simAccs = StateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams)
}

rawState := make(map[string]json.RawMessage)
err := json.Unmarshal(appState, &rawState)
if err != nil {
panic(err)
}

stakingStateBz, ok := rawState[stakingtypes.ModuleName]
if !ok {
panic("staking genesis state is missing")
}

stakingState := new(stakingtypes.GenesisState)
err = cdc.UnmarshalJSON(stakingStateBz, stakingState)
if err != nil {
panic(err)
}
// compute not bonded balance
notBondedTokens := sdk.ZeroInt()
for _, val := range stakingState.Validators {
if val.Status != stakingtypes.Unbonded {
continue
}
notBondedTokens = notBondedTokens.Add(val.GetTokens())
}
notBondedCoins := sdk.NewCoin(stakingState.Params.BondDenom, notBondedTokens)
// edit bank state to make it have the not bonded pool tokens
bankStateBz, ok := rawState[banktypes.ModuleName]
// TODO(fdymylja/jonathan): should we panic in this case
if !ok {
panic("bank genesis state is missing")
}
bankState := new(banktypes.GenesisState)
err = cdc.UnmarshalJSON(bankStateBz, bankState)
if err != nil {
panic(err)
}

stakingAddr := authtypes.NewModuleAddress(stakingtypes.NotBondedPoolName).String()
var found bool
for _, balance := range bankState.Balances {
if balance.Address == stakingAddr {
found = true
break
}
}
if !found {
bankState.Balances = append(bankState.Balances, banktypes.Balance{
Address: stakingAddr,
Coins: sdk.NewCoins(notBondedCoins),
})
}

// we should get the BondDenom and make it the evmdenom.
// thus simulation accounts could have positive amount of gas token.
bondDenom := stakingState.Params.BondDenom

evmStateBz, ok := rawState[evmtypes.ModuleName]
if !ok {
panic("evm genesis state is missing")
}

evmState := new(evmtypes.GenesisState)
cdc.MustUnmarshalJSON(evmStateBz, evmState)

// we should replace the EvmDenom with BondDenom
evmState.Params.EvmDenom = bondDenom

// change appState back
rawState[stakingtypes.ModuleName] = cdc.MustMarshalJSON(stakingState)
rawState[banktypes.ModuleName] = cdc.MustMarshalJSON(bankState)
rawState[evmtypes.ModuleName] = cdc.MustMarshalJSON(evmState)

// replace appstate
appState, err = json.Marshal(rawState)
if err != nil {
panic(err)
}
return appState, simAccs, chainID, genesisTimestamp
}
}
evmState := new(evmtypes.GenesisState)
cdc.MustUnmarshalJSON(evmStateBz, evmState)

// StateRandomizedFn creates calls each module's GenesisState generator function
// and creates the simulation params
func StateRandomizedFn(
simManager *module.SimulationManager, r *rand.Rand, cdc codec.JSONCodec,
accs []simtypes.Account, genesisTimestamp time.Time, appParams simtypes.AppParams,
) (json.RawMessage, []simtypes.Account) {
numAccs := int64(len(accs))
genesisState := NewDefaultGenesisState(cdc)
// we should replace the EvmDenom with BondDenom
evmState.Params.EvmDenom = bondDenom

// generate a random amount of initial stake coins and a random initial
// number of bonded accounts
var (
numInitiallyBonded int64
initialStake sdkmath.Int
// change appState back
rawState[evmtypes.ModuleName] = cdc.MustMarshalJSON(evmState)
},
)
appParams.GetOrGenerate(
cdc, simappparams.StakePerAccount, &initialStake, r,
func(r *rand.Rand) { initialStake = sdkmath.NewInt(r.Int63n(1e12)) },
)
appParams.GetOrGenerate(
cdc, simappparams.InitiallyBondedValidators, &numInitiallyBonded, r,
func(r *rand.Rand) { numInitiallyBonded = int64(r.Intn(300)) },
)

if numInitiallyBonded > numAccs {
numInitiallyBonded = numAccs
}

fmt.Printf(
`Selected randomly generated parameters for simulated genesis:
{
stake_per_account: "%d",
initially_bonded_validators: "%d"
}
`, initialStake, numInitiallyBonded,
)

simState := &module.SimulationState{
AppParams: appParams,
Cdc: cdc,
Rand: r,
GenState: genesisState,
Accounts: accs,
InitialStake: initialStake,
NumBonded: numInitiallyBonded,
GenTimestamp: genesisTimestamp,
}

simManager.GenerateGenesisStates(simState)

appState, err := json.Marshal(genesisState)
if err != nil {
panic(err)
}

return appState, accs
}

// StateFromGenesisFileFn util function to generate the genesis AppState
// from a genesis.json file.
func StateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile string) (tmtypes.GenesisDoc, []simtypes.Account) {
bytes, err := os.ReadFile(genesisFile)
if err != nil {
panic(err)
}

var genesis tmtypes.GenesisDoc
// NOTE: Tendermint uses a custom JSON decoder for GenesisDoc
err = tmjson.Unmarshal(bytes, &genesis)
if err != nil {
panic(err)
}

var appState GenesisState
err = json.Unmarshal(genesis.AppState, &appState)
if err != nil {
panic(err)
}

var authGenesis authtypes.GenesisState
if appState[authtypes.ModuleName] != nil {
cdc.MustUnmarshalJSON(appState[authtypes.ModuleName], &authGenesis)
}

newAccs := make([]simtypes.Account, len(authGenesis.Accounts))
for i, acc := range authGenesis.Accounts {
// Pick a random private key, since we don't know the actual key
// This should be fine as it's only used for mock Tendermint validators
// and these keys are never actually used to sign by mock Tendermint.
privkeySeed := make([]byte, 15)
if _, err := r.Read(privkeySeed); err != nil {
panic(err)
}

privKey := secp256k1.GenPrivKeyFromSecret(privkeySeed)

a, ok := acc.GetCachedValue().(authtypes.AccountI)
if !ok {
panic("expected account")
}

// create simulator accounts
simAcc := simtypes.Account{PrivKey: privKey, PubKey: privKey.PubKey(), Address: a.GetAddress()}
newAccs[i] = simAcc
}

return genesis, newAccs
}