2018-07-17 14:06:30 -07:00
package app
2018-07-11 15:14:37 -07:00
import (
2018-07-17 15:04:10 -07:00
"encoding/json"
2018-07-18 23:40:46 -07:00
"flag"
2018-09-01 19:04:44 -07:00
"fmt"
2018-10-29 16:10:39 -07:00
"io/ioutil"
2018-07-17 15:04:10 -07:00
"math/rand"
2018-08-30 11:43:56 -07:00
"os"
2018-07-11 15:14:37 -07:00
"testing"
2018-11-04 20:44:43 -08:00
"time"
2018-07-11 15:14:37 -07:00
"github.com/stretchr/testify/require"
2018-07-12 13:01:43 -07:00
2018-11-08 16:28:28 -08:00
abci "github.com/tendermint/tendermint/abci/types"
2019-01-29 14:53:42 -08:00
"github.com/tendermint/tendermint/crypto/secp256k1"
2018-07-12 13:01:43 -07:00
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
2019-01-29 14:53:42 -08:00
tmtypes "github.com/tendermint/tendermint/types"
2018-07-12 13:01:43 -07:00
2018-11-27 00:14:22 -08:00
"github.com/cosmos/cosmos-sdk/baseapp"
2018-07-17 15:04:10 -07:00
sdk "github.com/cosmos/cosmos-sdk/types"
2018-12-20 11:09:43 -08:00
"github.com/cosmos/cosmos-sdk/x/auth"
2018-10-22 21:53:06 -07:00
authsim "github.com/cosmos/cosmos-sdk/x/auth/simulation"
2019-01-28 19:06:48 -08:00
"github.com/cosmos/cosmos-sdk/x/bank"
2018-07-18 00:05:48 -07:00
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
2018-10-05 17:32:06 -07:00
distr "github.com/cosmos/cosmos-sdk/x/distribution"
2018-10-23 11:33:39 -07:00
distrsim "github.com/cosmos/cosmos-sdk/x/distribution/simulation"
2018-08-31 21:57:33 -07:00
"github.com/cosmos/cosmos-sdk/x/gov"
2018-08-16 08:36:15 -07:00
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
2018-10-19 11:36:00 -07:00
"github.com/cosmos/cosmos-sdk/x/mint"
2018-07-16 18:25:15 -07:00
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
2018-08-31 02:03:43 -07:00
"github.com/cosmos/cosmos-sdk/x/slashing"
2018-08-16 08:36:15 -07:00
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
2019-01-16 13:38:05 -08:00
"github.com/cosmos/cosmos-sdk/x/staking"
2019-01-11 12:08:01 -08:00
stakingsim "github.com/cosmos/cosmos-sdk/x/staking/simulation"
stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types"
2018-07-16 18:15:50 -07:00
)
2018-07-18 23:40:46 -07:00
var (
2019-01-29 14:53:42 -08:00
genesisFile string
seed int64
numBlocks int
blockSize int
enabled bool
verbose bool
commit bool
period int
2018-07-11 15:14:37 -07:00
)
2018-07-18 23:40:46 -07:00
func init ( ) {
2019-01-29 14:53:42 -08:00
flag . StringVar ( & genesisFile , "SimulationGenesis" , "" , "Custom simulation genesis file" )
2018-07-18 23:40:46 -07:00
flag . Int64Var ( & seed , "SimulationSeed" , 42 , "Simulation random seed" )
2018-08-16 08:36:15 -07:00
flag . IntVar ( & numBlocks , "SimulationNumBlocks" , 500 , "Number of blocks" )
flag . IntVar ( & blockSize , "SimulationBlockSize" , 200 , "Operations per block" )
2018-07-18 23:40:46 -07:00
flag . BoolVar ( & enabled , "SimulationEnabled" , false , "Enable the simulation" )
2018-08-16 08:36:15 -07:00
flag . BoolVar ( & verbose , "SimulationVerbose" , false , "Verbose log output" )
2018-08-30 11:47:32 -07:00
flag . BoolVar ( & commit , "SimulationCommit" , false , "Have the simulation commit" )
2018-12-08 07:44:18 -08:00
flag . IntVar ( & period , "SimulationPeriod" , 1 , "Run slow invariants only once every period assertions" )
2018-07-18 23:40:46 -07:00
}
2019-01-29 14:53:42 -08:00
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 } )
}
2019-02-04 15:35:12 -08:00
return genesis . AppState , newAccs , genesis . ChainID
2019-01-29 14:53:42 -08:00
}
func appStateRandomizedFn ( r * rand . Rand , accs [ ] simulation . Account , genesisTimestamp time . Time ) ( json . RawMessage , [ ] simulation . Account , string ) {
2018-07-17 15:04:10 -07:00
var genesisAccounts [ ] GenesisAccount
2018-07-17 11:33:53 -07:00
2018-11-04 20:44:43 -08:00
amount := int64 ( r . Intn ( 1e6 ) )
numInitiallyBonded := int64 ( r . Intn ( 250 ) )
numAccs := int64 ( len ( accs ) )
if numInitiallyBonded > numAccs {
numInitiallyBonded = numAccs
}
2018-11-26 04:13:47 -08:00
fmt . Printf ( "Selected randomly generated parameters for simulated genesis:\n" +
"\t{amount of steak per account: %v, initially bonded validators: %v}\n" ,
amount , numInitiallyBonded )
2018-10-23 09:24:06 -07:00
2019-01-17 08:15:13 -08:00
// randomly generate some genesis accounts
for i , acc := range accs {
2019-01-11 12:08:01 -08:00
coins := sdk . Coins { sdk . NewCoin ( stakingTypes . DefaultBondDenom , sdk . NewInt ( amount ) ) }
2019-01-17 08:15:13 -08:00
bacc := auth . NewBaseAccountWithAddress ( acc . Address )
bacc . SetCoins ( coins )
var gacc GenesisAccount
// Only consider making a vesting account once the initial bonded validator
// set is exhausted due to needing to track DelegatedVesting.
if int64 ( i ) > numInitiallyBonded && r . Intn ( 100 ) < 50 {
var (
vacc auth . VestingAccount
endTime int
)
startTime := genesisTimestamp . Unix ( )
// Allow for some vesting accounts to vest very quickly while others very
// slowly.
if r . Intn ( 100 ) < 50 {
endTime = randIntBetween ( r , int ( startTime ) , int ( startTime + ( 60 * 60 * 24 * 30 ) ) )
} else {
endTime = randIntBetween ( r , int ( startTime ) , int ( startTime + ( 60 * 60 * 12 ) ) )
}
if r . Intn ( 100 ) < 50 {
vacc = auth . NewContinuousVestingAccount ( & bacc , startTime , int64 ( endTime ) )
} else {
vacc = auth . NewDelayedVestingAccount ( & bacc , int64 ( endTime ) )
}
gacc = NewGenesisAccountI ( vacc )
} else {
gacc = NewGenesisAccount ( & bacc )
}
genesisAccounts = append ( genesisAccounts , gacc )
2018-07-17 15:04:10 -07:00
}
2018-10-05 17:32:06 -07:00
2018-12-20 11:09:43 -08:00
authGenesis := auth . GenesisState {
Params : auth . Params {
2019-02-04 15:35:12 -08:00
MaxMemoCharacters : uint64 ( randIntBetween ( r , 100 , 200 ) ) ,
2018-12-20 11:09:43 -08:00
TxSigLimit : uint64 ( r . Intn ( 7 ) + 1 ) ,
2019-02-04 15:35:12 -08:00
TxSizeCostPerByte : uint64 ( randIntBetween ( r , 5 , 15 ) ) ,
SigVerifyCostED25519 : uint64 ( randIntBetween ( r , 500 , 1000 ) ) ,
SigVerifyCostSecp256k1 : uint64 ( randIntBetween ( r , 500 , 1000 ) ) ,
2018-12-20 11:09:43 -08:00
} ,
}
fmt . Printf ( "Selected randomly generated auth parameters:\n\t%+v\n" , authGenesis )
2019-01-28 19:06:48 -08:00
bankGenesis := bank . NewGenesisState ( r . Int63n ( 2 ) == 0 )
fmt . Printf ( "Selected randomly generated bank parameters:\n\t%+v\n" , bankGenesis )
2018-11-04 20:44:43 -08:00
// Random genesis states
2018-12-11 11:05:49 -08:00
vp := time . Duration ( r . Intn ( 2 * 172800 ) ) * time . Second
2018-11-04 20:44:43 -08:00
govGenesis := gov . GenesisState {
2018-11-06 23:33:18 -08:00
StartingProposalID : uint64 ( r . Intn ( 100 ) ) ,
DepositParams : gov . DepositParams {
2019-01-11 12:08:01 -08:00
MinDeposit : sdk . Coins { sdk . NewInt64Coin ( stakingTypes . DefaultBondDenom , int64 ( r . Intn ( 1e3 ) ) ) } ,
2018-12-11 11:05:49 -08:00
MaxDepositPeriod : vp ,
2018-11-04 20:44:43 -08:00
} ,
2018-11-06 23:33:18 -08:00
VotingParams : gov . VotingParams {
2018-12-11 11:05:49 -08:00
VotingPeriod : vp ,
2018-11-04 20:44:43 -08:00
} ,
2018-11-06 23:33:18 -08:00
TallyParams : gov . TallyParams {
2018-12-17 10:56:45 -08:00
Threshold : sdk . NewDecWithPrec ( 5 , 1 ) ,
Veto : sdk . NewDecWithPrec ( 334 , 3 ) ,
GovernancePenalty : sdk . NewDecWithPrec ( 1 , 2 ) ,
2018-11-04 20:44:43 -08:00
} ,
}
2018-11-26 04:13:47 -08:00
fmt . Printf ( "Selected randomly generated governance parameters:\n\t%+v\n" , govGenesis )
2019-01-11 12:08:01 -08:00
stakingGenesis := staking . GenesisState {
Pool : staking . InitialPool ( ) ,
Params : staking . Params {
2018-12-19 09:03:16 -08:00
UnbondingTime : time . Duration ( randIntBetween ( r , 60 , 60 * 60 * 24 * 3 * 2 ) ) * time . Second ,
2018-11-04 20:44:43 -08:00
MaxValidators : uint16 ( r . Intn ( 250 ) ) ,
2019-01-11 12:08:01 -08:00
BondDenom : stakingTypes . DefaultBondDenom ,
2018-11-04 20:44:43 -08:00
} ,
}
2019-01-11 12:08:01 -08:00
fmt . Printf ( "Selected randomly generated staking parameters:\n\t%+v\n" , stakingGenesis )
2018-11-26 04:13:47 -08:00
2018-11-04 20:44:43 -08:00
slashingGenesis := slashing . GenesisState {
Params : slashing . Params {
2019-01-11 12:08:01 -08:00
MaxEvidenceAge : stakingGenesis . Params . UnbondingTime ,
2019-01-10 17:22:49 -08:00
SignedBlocksWindow : int64 ( randIntBetween ( r , 10 , 1000 ) ) ,
MinSignedPerWindow : sdk . NewDecWithPrec ( int64 ( r . Intn ( 10 ) ) , 1 ) ,
2019-01-16 13:38:05 -08:00
DowntimeJailDuration : time . Duration ( randIntBetween ( r , 60 , 60 * 60 * 24 ) ) * time . Second ,
2019-01-10 17:22:49 -08:00
SlashFractionDoubleSign : sdk . NewDec ( 1 ) . Quo ( sdk . NewDec ( int64 ( r . Intn ( 50 ) + 1 ) ) ) ,
SlashFractionDowntime : sdk . NewDec ( 1 ) . Quo ( sdk . NewDec ( int64 ( r . Intn ( 200 ) + 1 ) ) ) ,
2018-11-04 20:44:43 -08:00
} ,
}
2018-11-26 04:13:47 -08:00
fmt . Printf ( "Selected randomly generated slashing parameters:\n\t%+v\n" , slashingGenesis )
2018-11-04 20:44:43 -08:00
mintGenesis := mint . GenesisState {
2018-11-26 04:13:47 -08:00
Minter : mint . InitialMinter (
sdk . NewDecWithPrec ( int64 ( r . Intn ( 99 ) ) , 2 ) ) ,
Params : mint . NewParams (
2019-01-11 12:08:01 -08:00
stakingTypes . DefaultBondDenom ,
2018-11-26 04:13:47 -08:00
sdk . NewDecWithPrec ( int64 ( r . Intn ( 99 ) ) , 2 ) ,
sdk . NewDecWithPrec ( 20 , 2 ) ,
sdk . NewDecWithPrec ( 7 , 2 ) ,
sdk . NewDecWithPrec ( 67 , 2 ) ,
uint64 ( 60 * 60 * 8766 / 5 ) ) ,
2018-11-04 20:44:43 -08:00
}
2018-11-26 04:13:47 -08:00
fmt . Printf ( "Selected randomly generated minting parameters:\n\t%+v\n" , mintGenesis )
2019-01-11 12:08:01 -08:00
var validators [ ] staking . Validator
var delegations [ ] staking . Delegation
2018-10-05 17:32:06 -07:00
valAddrs := make ( [ ] sdk . ValAddress , numInitiallyBonded )
2018-08-16 08:36:15 -07:00
for i := 0 ; i < int ( numInitiallyBonded ) ; i ++ {
2018-10-05 17:32:06 -07:00
valAddr := sdk . ValAddress ( accs [ i ] . Address )
valAddrs [ i ] = valAddr
2019-01-11 12:08:01 -08:00
validator := staking . NewValidator ( valAddr , accs [ i ] . PubKey , staking . Description { } )
2019-01-02 12:29:47 -08:00
validator . Tokens = sdk . NewInt ( amount )
2018-11-04 20:44:43 -08:00
validator . DelegatorShares = sdk . NewDec ( amount )
2019-01-11 12:08:01 -08:00
delegation := staking . Delegation { accs [ i ] . Address , valAddr , sdk . NewDec ( amount ) }
2018-08-16 08:36:15 -07:00
validators = append ( validators , validator )
delegations = append ( delegations , delegation )
}
2019-01-17 08:15:13 -08:00
2019-01-21 16:52:03 -08:00
stakingGenesis . Pool . NotBondedTokens = sdk . NewInt ( ( amount * numAccs ) + ( numInitiallyBonded * amount ) )
2019-01-11 12:08:01 -08:00
stakingGenesis . Validators = validators
stakingGenesis . Bonds = delegations
2018-10-05 17:32:06 -07:00
2019-01-16 13:38:05 -08:00
distrGenesis := distr . GenesisState {
FeePool : distr . InitialFeePool ( ) ,
CommunityTax : sdk . NewDecWithPrec ( 1 , 2 ) . Add ( sdk . NewDecWithPrec ( int64 ( r . Intn ( 30 ) ) , 2 ) ) ,
BaseProposerReward : sdk . NewDecWithPrec ( 1 , 2 ) . Add ( sdk . NewDecWithPrec ( int64 ( r . Intn ( 30 ) ) , 2 ) ) ,
BonusProposerReward : sdk . NewDecWithPrec ( 1 , 2 ) . Add ( sdk . NewDecWithPrec ( int64 ( r . Intn ( 30 ) ) , 2 ) ) ,
}
fmt . Printf ( "Selected randomly generated distribution parameters:\n\t%+v\n" , distrGenesis )
2018-07-17 14:06:30 -07:00
genesis := GenesisState {
2018-08-31 02:03:43 -07:00
Accounts : genesisAccounts ,
2018-12-20 11:09:43 -08:00
AuthData : authGenesis ,
2019-01-28 19:06:48 -08:00
BankData : bankGenesis ,
2019-01-15 07:34:48 -08:00
StakingData : stakingGenesis ,
2018-10-19 11:36:00 -07:00
MintData : mintGenesis ,
2019-01-16 13:38:05 -08:00
DistrData : distrGenesis ,
2018-10-06 09:08:49 -07:00
SlashingData : slashingGenesis ,
2018-08-31 02:03:43 -07:00
GovData : govGenesis ,
2018-07-17 11:33:53 -07:00
}
// Marshal genesis
2018-07-17 14:06:30 -07:00
appState , err := MakeCodec ( ) . MarshalJSON ( genesis )
2018-07-17 11:33:53 -07:00
if err != nil {
panic ( err )
}
2019-01-29 14:53:42 -08:00
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 )
2018-07-17 15:04:10 -07:00
}
2018-12-19 09:03:16 -08:00
func randIntBetween ( r * rand . Rand , min , max int ) int {
return r . Intn ( max - min ) + min
}
2018-09-12 00:16:52 -07:00
func testAndRunTxs ( app * GaiaApp ) [ ] simulation . WeightedOperation {
return [ ] simulation . WeightedOperation {
2018-10-23 08:54:58 -07:00
{ 5 , authsim . SimulateDeductFee ( app . accountKeeper , app . feeCollectionKeeper ) } ,
2019-02-04 15:58:02 -08:00
{ 100 , banksim . SendMsg ( app . accountKeeper , app . bankKeeper ) } ,
{ 10 , banksim . SingleInputMsgMultiSend ( app . accountKeeper , app . bankKeeper ) } ,
2018-10-23 11:33:39 -07:00
{ 50 , distrsim . SimulateMsgSetWithdrawAddress ( app . accountKeeper , app . distrKeeper ) } ,
{ 50 , distrsim . SimulateMsgWithdrawDelegatorReward ( app . accountKeeper , app . distrKeeper ) } ,
2019-01-16 13:38:05 -08:00
{ 50 , distrsim . SimulateMsgWithdrawValidatorCommission ( app . accountKeeper , app . distrKeeper ) } ,
2019-01-11 12:08:01 -08:00
{ 5 , govsim . SimulateSubmittingVotingAndSlashingForProposal ( app . govKeeper , app . stakingKeeper ) } ,
2018-11-06 23:33:18 -08:00
{ 100 , govsim . SimulateMsgDeposit ( app . govKeeper ) } ,
2019-01-11 12:08:01 -08:00
{ 100 , stakingsim . SimulateMsgCreateValidator ( app . accountKeeper , app . stakingKeeper ) } ,
{ 5 , stakingsim . SimulateMsgEditValidator ( app . stakingKeeper ) } ,
{ 100 , stakingsim . SimulateMsgDelegate ( app . accountKeeper , app . stakingKeeper ) } ,
2019-01-17 09:53:22 -08:00
{ 100 , stakingsim . SimulateMsgUndelegate ( app . accountKeeper , app . stakingKeeper ) } ,
2019-01-11 12:08:01 -08:00
{ 100 , stakingsim . SimulateMsgBeginRedelegate ( app . accountKeeper , app . stakingKeeper ) } ,
2018-09-12 00:16:52 -07:00
{ 100 , slashingsim . SimulateMsgUnjail ( app . slashingKeeper ) } ,
2018-08-17 07:19:33 -07:00
}
}
func invariants ( app * GaiaApp ) [ ] simulation . Invariant {
return [ ] simulation . Invariant {
2018-11-29 07:17:10 -08:00
simulation . PeriodicInvariant ( banksim . NonnegativeBalanceInvariant ( app . accountKeeper ) , period , 0 ) ,
simulation . PeriodicInvariant ( govsim . AllInvariants ( ) , period , 0 ) ,
2019-01-11 12:08:01 -08:00
simulation . PeriodicInvariant ( distrsim . AllInvariants ( app . distrKeeper , app . stakingKeeper ) , period , 0 ) ,
simulation . PeriodicInvariant ( stakingsim . AllInvariants ( app . bankKeeper , app . stakingKeeper ,
2018-11-29 07:17:10 -08:00
app . feeCollectionKeeper , app . distrKeeper , app . accountKeeper ) , period , 0 ) ,
simulation . PeriodicInvariant ( slashingsim . AllInvariants ( ) , period , 0 ) ,
2018-08-17 07:19:33 -07:00
}
}
2018-11-27 00:14:22 -08:00
// Pass this in as an option to use a dbStoreAdapter instead of an IAVLStore for simulation speed.
func fauxMerkleModeOpt ( bapp * baseapp . BaseApp ) {
bapp . SetFauxMerkleMode ( )
}
2018-08-29 23:02:15 -07:00
// Profile with:
2018-09-01 19:04:44 -07:00
// /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$ -SimulationCommit=true -cpuprofile cpu.out
2018-08-29 23:02:15 -07:00
func BenchmarkFullGaiaSimulation ( b * testing . B ) {
// Setup Gaia application
var logger log . Logger
logger = log . NewNopLogger ( )
2018-08-30 11:43:56 -07:00
var db dbm . DB
2018-10-29 16:10:39 -07:00
dir , _ := ioutil . TempDir ( "" , "goleveldb-gaia-sim" )
2018-09-01 12:32:24 -07:00
db , _ = dbm . NewGoLevelDB ( "Simulation" , dir )
defer func ( ) {
db . Close ( )
os . RemoveAll ( dir )
} ( )
2018-12-18 08:17:50 -08:00
app := NewGaiaApp ( logger , db , nil , true )
2018-08-29 23:02:15 -07:00
// Run randomized simulation
// TODO parameterize numbers, save for a later PR
2018-11-26 04:21:23 -08:00
_ , err := simulation . SimulateFromSeed (
2018-08-29 23:02:15 -07:00
b , app . BaseApp , appStateFn , seed ,
testAndRunTxs ( app ) ,
2018-08-30 00:13:31 -07:00
invariants ( app ) , // these shouldn't get ran
2018-09-01 19:04:44 -07:00
numBlocks ,
2018-08-31 21:57:33 -07:00
blockSize ,
2018-08-30 11:47:32 -07:00
commit ,
2018-08-29 23:02:15 -07:00
)
2018-09-11 02:18:58 -07:00
if err != nil {
fmt . Println ( err )
b . Fail ( )
}
2018-09-01 19:04:44 -07:00
if commit {
fmt . Println ( "GoLevelDB Stats" )
fmt . Println ( db . Stats ( ) [ "leveldb.stats" ] )
fmt . Println ( "GoLevelDB cached block size" , db . Stats ( ) [ "leveldb.cachedblock" ] )
}
2018-08-29 23:02:15 -07:00
}
2018-07-17 15:04:10 -07:00
func TestFullGaiaSimulation ( t * testing . T ) {
2018-07-18 23:40:46 -07:00
if ! enabled {
2018-07-17 15:04:10 -07:00
t . Skip ( "Skipping Gaia simulation" )
}
// Setup Gaia application
2018-08-16 08:36:15 -07:00
var logger log . Logger
if verbose {
logger = log . TestingLogger ( )
} else {
logger = log . NewNopLogger ( )
}
2018-10-29 16:10:39 -07:00
var db dbm . DB
dir , _ := ioutil . TempDir ( "" , "goleveldb-gaia-sim" )
db , _ = dbm . NewGoLevelDB ( "Simulation" , dir )
defer func ( ) {
db . Close ( )
os . RemoveAll ( dir )
} ( )
2018-12-18 08:17:50 -08:00
app := NewGaiaApp ( logger , db , nil , true , fauxMerkleModeOpt )
2018-07-17 15:04:10 -07:00
require . Equal ( t , "GaiaApp" , app . Name ( ) )
2018-07-16 18:15:50 -07:00
// Run randomized simulation
2018-11-26 04:21:23 -08:00
_ , err := simulation . SimulateFromSeed (
2018-07-17 22:37:38 -07:00
t , app . BaseApp , appStateFn , seed ,
2018-08-17 07:19:33 -07:00
testAndRunTxs ( app ) ,
invariants ( app ) ,
2018-07-18 23:40:46 -07:00
numBlocks ,
2018-07-18 00:54:41 -07:00
blockSize ,
2018-08-30 11:47:32 -07:00
commit ,
2018-07-16 18:15:50 -07:00
)
2018-09-01 19:04:44 -07:00
if commit {
2018-10-29 16:10:39 -07:00
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
fmt . Println ( "GoLevelDB Stats" )
fmt . Println ( db . Stats ( ) [ "leveldb.stats" ] )
fmt . Println ( "GoLevelDB cached block size" , db . Stats ( ) [ "leveldb.cachedblock" ] )
2018-09-01 19:04:44 -07:00
}
2018-09-11 02:18:58 -07:00
require . Nil ( t , err )
2018-07-11 15:14:37 -07:00
}
2018-08-16 08:36:15 -07:00
2018-11-08 16:28:28 -08:00
func TestGaiaImportExport ( t * testing . T ) {
if ! enabled {
t . Skip ( "Skipping Gaia import/export simulation" )
}
// Setup Gaia application
var logger log . Logger
if verbose {
logger = log . TestingLogger ( )
} else {
logger = log . NewNopLogger ( )
}
var db dbm . DB
dir , _ := ioutil . TempDir ( "" , "goleveldb-gaia-sim" )
db , _ = dbm . NewGoLevelDB ( "Simulation" , dir )
defer func ( ) {
db . Close ( )
os . RemoveAll ( dir )
} ( )
2018-12-18 08:17:50 -08:00
app := NewGaiaApp ( logger , db , nil , true , fauxMerkleModeOpt )
2018-11-08 16:28:28 -08:00
require . Equal ( t , "GaiaApp" , app . Name ( ) )
// Run randomized simulation
2018-11-26 04:21:23 -08:00
_ , err := simulation . SimulateFromSeed (
2018-11-08 16:28:28 -08:00
t , app . BaseApp , appStateFn , seed ,
testAndRunTxs ( app ) ,
invariants ( app ) ,
numBlocks ,
blockSize ,
commit ,
)
if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
fmt . Println ( "GoLevelDB Stats" )
fmt . Println ( db . Stats ( ) [ "leveldb.stats" ] )
fmt . Println ( "GoLevelDB cached block size" , db . Stats ( ) [ "leveldb.cachedblock" ] )
}
require . Nil ( t , err )
fmt . Printf ( "Exporting genesis...\n" )
2019-02-04 08:42:48 -08:00
appState , _ , err := app . ExportAppStateAndValidators ( false , [ ] string { } )
2018-11-08 16:28:28 -08:00
if err != nil {
panic ( err )
}
fmt . Printf ( "Importing genesis...\n" )
newDir , _ := ioutil . TempDir ( "" , "goleveldb-gaia-sim-2" )
newDB , _ := dbm . NewGoLevelDB ( "Simulation-2" , dir )
defer func ( ) {
newDB . Close ( )
os . RemoveAll ( newDir )
} ( )
2018-12-18 08:17:50 -08:00
newApp := NewGaiaApp ( log . NewNopLogger ( ) , newDB , nil , true , fauxMerkleModeOpt )
2018-11-08 16:28:28 -08:00
require . Equal ( t , "GaiaApp" , newApp . Name ( ) )
2018-11-26 04:21:23 -08:00
var genesisState GenesisState
err = app . cdc . UnmarshalJSON ( appState , & genesisState )
if err != nil {
panic ( err )
2018-11-08 16:28:28 -08:00
}
2018-11-26 04:21:23 -08:00
ctxB := newApp . NewContext ( true , abci . Header { } )
newApp . initFromGenesisState ( ctxB , genesisState )
2018-11-08 16:28:28 -08:00
fmt . Printf ( "Comparing stores...\n" )
ctxA := app . NewContext ( true , abci . Header { } )
type StoreKeysPrefixes struct {
A sdk . StoreKey
B sdk . StoreKey
Prefixes [ ] [ ] byte
}
storeKeysPrefixes := [ ] StoreKeysPrefixes {
{ app . keyMain , newApp . keyMain , [ ] [ ] byte { } } ,
{ app . keyAccount , newApp . keyAccount , [ ] [ ] byte { } } ,
2019-01-11 12:08:01 -08:00
{ app . keyStaking , newApp . keyStaking , [ ] [ ] byte { staking . UnbondingQueueKey , staking . RedelegationQueueKey , staking . ValidatorQueueKey } } , // ordering may change but it doesn't matter
2018-11-08 16:28:28 -08:00
{ app . keySlashing , newApp . keySlashing , [ ] [ ] byte { } } ,
{ app . keyMint , newApp . keyMint , [ ] [ ] byte { } } ,
{ app . keyDistr , newApp . keyDistr , [ ] [ ] byte { } } ,
{ app . keyFeeCollection , newApp . keyFeeCollection , [ ] [ ] byte { } } ,
{ app . keyParams , newApp . keyParams , [ ] [ ] byte { } } ,
{ app . keyGov , newApp . keyGov , [ ] [ ] byte { } } ,
}
for _ , storeKeysPrefix := range storeKeysPrefixes {
storeKeyA := storeKeysPrefix . A
storeKeyB := storeKeysPrefix . B
prefixes := storeKeysPrefix . Prefixes
storeA := ctxA . KVStore ( storeKeyA )
storeB := ctxB . KVStore ( storeKeyB )
kvA , kvB , count , equal := sdk . DiffKVStores ( storeA , storeB , prefixes )
fmt . Printf ( "Compared %d key/value pairs between %s and %s\n" , count , storeKeyA , storeKeyB )
2019-01-24 13:01:32 -08:00
require . True ( t , equal ,
"unequal stores: %s / %s:\nstore A %X => %X\nstore B %X => %X" ,
storeKeyA , storeKeyB , kvA . Key , kvA . Value , kvB . Key , kvB . Value ,
)
2018-11-08 16:28:28 -08:00
}
}
2018-11-26 04:21:23 -08:00
func TestGaiaSimulationAfterImport ( t * testing . T ) {
if ! enabled {
t . Skip ( "Skipping Gaia simulation after import" )
}
// Setup Gaia application
var logger log . Logger
if verbose {
logger = log . TestingLogger ( )
} else {
logger = log . NewNopLogger ( )
}
dir , _ := ioutil . TempDir ( "" , "goleveldb-gaia-sim" )
db , _ := dbm . NewGoLevelDB ( "Simulation" , dir )
defer func ( ) {
db . Close ( )
os . RemoveAll ( dir )
} ( )
2018-12-18 08:17:50 -08:00
app := NewGaiaApp ( logger , db , nil , true , fauxMerkleModeOpt )
2018-11-26 04:21:23 -08:00
require . Equal ( t , "GaiaApp" , app . Name ( ) )
// Run randomized simulation
stopEarly , err := simulation . SimulateFromSeed (
t , app . BaseApp , appStateFn , seed ,
testAndRunTxs ( app ) ,
invariants ( app ) ,
numBlocks ,
blockSize ,
commit ,
)
if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
fmt . Println ( "GoLevelDB Stats" )
fmt . Println ( db . Stats ( ) [ "leveldb.stats" ] )
fmt . Println ( "GoLevelDB cached block size" , db . Stats ( ) [ "leveldb.cachedblock" ] )
}
require . Nil ( t , err )
if stopEarly {
// we can't export or import a zero-validator genesis
fmt . Printf ( "We can't export or import a zero-validator genesis, exiting test...\n" )
return
}
fmt . Printf ( "Exporting genesis...\n" )
2019-02-04 08:42:48 -08:00
appState , _ , err := app . ExportAppStateAndValidators ( true , [ ] string { } )
2018-11-26 04:21:23 -08:00
if err != nil {
panic ( err )
}
fmt . Printf ( "Importing genesis...\n" )
newDir , _ := ioutil . TempDir ( "" , "goleveldb-gaia-sim-2" )
newDB , _ := dbm . NewGoLevelDB ( "Simulation-2" , dir )
defer func ( ) {
newDB . Close ( )
os . RemoveAll ( newDir )
} ( )
2018-12-18 08:17:50 -08:00
newApp := NewGaiaApp ( log . NewNopLogger ( ) , newDB , nil , true , fauxMerkleModeOpt )
2018-11-26 04:21:23 -08:00
require . Equal ( t , "GaiaApp" , newApp . Name ( ) )
newApp . InitChain ( abci . RequestInitChain {
AppStateBytes : appState ,
} )
// Run randomized simulation on imported app
_ , err = simulation . SimulateFromSeed (
t , newApp . BaseApp , appStateFn , seed ,
testAndRunTxs ( newApp ) ,
invariants ( newApp ) ,
numBlocks ,
blockSize ,
commit ,
)
require . Nil ( t , err )
}
2018-08-16 14:45:07 -07:00
// TODO: Make another test for the fuzzer itself, which just has noOp txs
// and doesn't depend on gaia
2018-08-16 08:36:15 -07:00
func TestAppStateDeterminism ( t * testing . T ) {
2018-08-17 07:19:33 -07:00
if ! enabled {
t . Skip ( "Skipping Gaia simulation" )
2018-08-16 08:36:15 -07:00
}
2018-08-17 07:19:33 -07:00
2018-09-03 19:13:08 -07:00
numSeeds := 3
2018-08-17 07:19:33 -07:00
numTimesToRunPerSeed := 5
appHashList := make ( [ ] json . RawMessage , numTimesToRunPerSeed )
for i := 0 ; i < numSeeds ; i ++ {
seed := rand . Int63 ( )
for j := 0 ; j < numTimesToRunPerSeed ; j ++ {
logger := log . NewNopLogger ( )
db := dbm . NewMemDB ( )
2018-12-18 08:17:50 -08:00
app := NewGaiaApp ( logger , db , nil , true )
2018-08-17 07:19:33 -07:00
// Run randomized simulation
simulation . SimulateFromSeed (
t , app . BaseApp , appStateFn , seed ,
testAndRunTxs ( app ) ,
[ ] simulation . Invariant { } ,
2018-09-03 19:13:08 -07:00
50 ,
100 ,
2018-09-12 21:53:55 -07:00
true ,
2018-08-17 07:19:33 -07:00
)
appHash := app . LastCommitID ( ) . Hash
appHashList [ j ] = appHash
}
for k := 1 ; k < numTimesToRunPerSeed ; k ++ {
2018-08-27 14:27:00 -07:00
require . Equal ( t , appHashList [ 0 ] , appHashList [ k ] , "appHash list: %v" , appHashList )
2018-08-17 07:19:33 -07:00
}
2018-08-16 08:36:15 -07:00
}
}