Skip to content

Commit

Permalink
Merge PR cosmos#3428: Simulate from a genesis file
Browse files Browse the repository at this point in the history
  • Loading branch information
cwgoes authored Jan 29, 2019
1 parent 0ed6de0 commit 9320dbb
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 19 deletions.
20 changes: 17 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,15 @@ test_sim_gaia_nondeterminism:
@echo "Running nondeterminism test..."
@go test ./cmd/gaia/app -run TestAppStateDeterminism -SimulationEnabled=true -v -timeout 10m

test_sim_gaia_custom_genesis_fast:
@echo "Running custom genesis simulation..."
@echo "By default, ${HOME}/.gaiad/config/genesis.json will be used."
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationGenesis=${HOME}/.gaiad/config/genesis.json \
-SimulationEnabled=true -SimulationNumBlocks=100 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=99 -SimulationPeriod=5 -v -timeout 24h

test_sim_gaia_fast:
@echo "Running quick Gaia simulation. This may take several minutes..."
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=1000 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=99 -v -timeout 24h
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=100 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=99 -SimulationPeriod=5 -v -timeout 24h

test_sim_gaia_import_export:
@echo "Running Gaia import/export simulation. This may take several minutes..."
Expand All @@ -165,6 +171,11 @@ test_sim_gaia_simulation_after_import:
@echo "Running Gaia simulation-after-import. This may take several minutes..."
@bash scripts/multisim.sh 50 5 TestGaiaSimulationAfterImport

test_sim_gaia_custom_genesis_multi_seed:
@echo "Running multi-seed custom genesis simulation..."
@echo "By default, ${HOME}/.gaiad/config/genesis.json will be used."
@bash scripts/multisim.sh 400 5 TestFullGaiaSimulation ${HOME}/.gaiad/config/genesis.json

test_sim_gaia_multi_seed:
@echo "Running multi-seed Gaia simulation. This may take awhile!"
@bash scripts/multisim.sh 400 5 TestFullGaiaSimulation
Expand All @@ -174,11 +185,13 @@ SIM_BLOCK_SIZE ?= 200
SIM_COMMIT ?= true
test_sim_gaia_benchmark:
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@go test -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ -SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h
@go test -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ \
-SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h

test_sim_gaia_profile:
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@go test -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ -SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out
@go test -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ \
-SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out

test_cover:
@export VERSION=$(VERSION); bash tests/test_cover.sh
Expand Down Expand Up @@ -258,5 +271,6 @@ check_tools check_dev_tools get_vendor_deps draw_deps test test_cli test_unit \
test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update \
build-linux build-docker-gaiadnode localnet-start localnet-stop \
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast \
test_sim_gaia_custom_genesis_fast test_sim_gaia_custom_genesis_multi_seed \
test_sim_gaia_multi_seed test_sim_gaia_import_export update_tools update_dev_tools \
build-snap-edge
1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ FEATURES

* Gaia
- [\#3397](https://github.com/cosmos/cosmos-sdk/pull/3397) Implement genesis file sanitization to avoid failures at chain init.
* \#3428 Run the simulation from a particular genesis state loaded from a file

* SDK
* \#3270 [x/staking] limit number of ongoing unbonding delegations /redelegations per pair/trio
Expand Down
53 changes: 44 additions & 9 deletions cmd/gaia/app/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import (
"github.com/stretchr/testify/require"

abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/secp256k1"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"

"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -36,16 +38,18 @@ import (
)

var (
seed int64
numBlocks int
blockSize int
enabled bool
verbose bool
commit bool
period int
genesisFile string
seed int64
numBlocks int
blockSize int
enabled bool
verbose bool
commit bool
period int
)

func init() {
flag.StringVar(&genesisFile, "SimulationGenesis", "", "Custom simulation genesis file")
flag.Int64Var(&seed, "SimulationSeed", 42, "Simulation random seed")
flag.IntVar(&numBlocks, "SimulationNumBlocks", 500, "Number of blocks")
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "Operations per block")
Expand All @@ -55,7 +59,31 @@ func init() {
flag.IntVar(&period, "SimulationPeriod", 1, "Run slow invariants only once every period assertions")
}

func appStateFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) json.RawMessage {
func appStateFromGenesisFileFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {
var genesis tmtypes.GenesisDoc
cdc := MakeCodec()
bytes, err := ioutil.ReadFile(genesisFile)
if err != nil {
panic(err)
}
cdc.MustUnmarshalJSON(bytes, &genesis)
var appState GenesisState
cdc.MustUnmarshalJSON(genesis.AppState, &appState)
var newAccs []simulation.Account
for _, acc := range appState.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)
r.Read(privkeySeed)
privKey := secp256k1.GenPrivKeySecp256k1(privkeySeed)
newAccs = append(newAccs, simulation.Account{privKey, privKey.PubKey(), acc.Address})
}
return json.RawMessage(genesis.AppState), newAccs, genesis.ChainID
}

func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {

var genesisAccounts []GenesisAccount

amount := int64(r.Intn(1e6))
Expand Down Expand Up @@ -221,7 +249,14 @@ func appStateFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.T
panic(err)
}

return appState
return appState, accs, "simulation"
}

func appStateFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {
if genesisFile != "" {
return appStateFromGenesisFileFn(r, accs, genesisTimestamp)
}
return appStateRandomizedFn(r, accs, genesisTimestamp)
}

func randIntBetween(r *rand.Rand, min, max int) int {
Expand Down
4 changes: 3 additions & 1 deletion scripts/multisim.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ seeds=(1 2 4 7 9 20 32 123 124 582 1893 2989 3012 4728 37827 981928 87821 891823
blocks=$1
period=$2
testname=$3
genesis=$4

echo "Running multi-seed simulation with seeds ${seeds[@]}"
echo "Running $blocks blocks per seed"
echo "Running test $testname"
echo "Using genesis file $genesis"
echo "Edit scripts/multisim.sh to add new seeds. Keeping parameters in the file makes failures easy to reproduce."
echo "This script will kill all sub-simulations on SIGINT/SIGTERM (i.e. Ctrl-C)."

Expand All @@ -22,7 +24,7 @@ sim() {
echo "Running Gaia simulation with seed $seed. This may take awhile!"
file="$tmpdir/gaia-simulation-seed-$seed-date-$(date -u +"%Y-%m-%dT%H:%M:%S+00:00").stdout"
echo "Writing stdout to $file..."
go test ./cmd/gaia/app -run $testname -SimulationEnabled=true -SimulationNumBlocks=$blocks \
go test ./cmd/gaia/app -run $testname -SimulationEnabled=true -SimulationNumBlocks=$blocks -SimulationGenesis=$genesis \
-SimulationVerbose=true -SimulationCommit=true -SimulationSeed=$seed -SimulationPeriod=$period -v -timeout 24h > $file
}

Expand Down
19 changes: 13 additions & 6 deletions x/mock/simulation/simulate.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

// AppStateFn returns the app state json bytes
type AppStateFn func(r *rand.Rand, accs []Account, genesisTimestamp time.Time) json.RawMessage
// AppStateFn returns the app state json bytes, the genesis accounts, and the chain identifier
type AppStateFn func(r *rand.Rand, accs []Account, genesisTimestamp time.Time) (appState json.RawMessage, accounts []Account, chainId string)

// Simulate tests application by sending random messages.
func Simulate(t *testing.T, app *baseapp.BaseApp,
Expand All @@ -35,15 +35,18 @@ func Simulate(t *testing.T, app *baseapp.BaseApp,
func initChain(
r *rand.Rand, params Params, accounts []Account,
app *baseapp.BaseApp, appStateFn AppStateFn, genesisTimestamp time.Time,
) mockValidators {
) (mockValidators, []Account) {

appState, accounts, chainID := appStateFn(r, accounts, genesisTimestamp)

req := abci.RequestInitChain{
AppStateBytes: appStateFn(r, accounts, genesisTimestamp),
AppStateBytes: appState,
ChainId: chainID,
}
res := app.InitChain(req)
validators := newMockValidators(r, res.Validators, params)

return validators
return validators, accounts
}

// SimulateFromSeed tests an application by running the provided
Expand Down Expand Up @@ -73,7 +76,11 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,

// Second variable to keep pending validator set (delayed one block since
// TM 0.24) Initially this is the same as the initial validator set
validators := initChain(r, params, accs, app, appStateFn, genesisTimestamp)
validators, accs := initChain(r, params, accs, app, appStateFn, genesisTimestamp)
if len(accs) == 0 {
return true, fmt.Errorf("must have greater than zero genesis accounts")
}

nextValidators := validators

header := abci.Header{
Expand Down

0 comments on commit 9320dbb

Please sign in to comment.