Skip to content

Commit

Permalink
Merge PR cosmos#3656: Broken-Invar Tx - aka. Crisis module
Browse files Browse the repository at this point in the history
* beginning thinking on issue

* ...

* working

* working

* working fee pool distribution

* spek outline

* spec update

* gas refund calculations

* simulation saved to ~/.gaiad/simulations/

* lean simulation output

int

* cleanup bank simulation messages

* operation messges

int

* lint

* move simulation to its own module

* move simulation log code to log.go

* logger overhaul

int

* distribution comments

* fix compiling

* cleanup modifications to x/distribution/keeper/allocation.go

int

int

int

* gov bug

* result.IsOK() minimization

* importExport typo bug

* pending

* address @alexanderbez comments

* simple @cwgoes comments addressed

* event logging unified approach

* distr module name constant

* implementing

* compiles

* gaia integration

* proper constant fee removal

* crisis genesis

* go.sum update

* ...

* debugging

* fix sum errors

* missing err checks

* working implementing CLI

* remove query command

* crisis expected keepers in other modules

* crisis testing infrastructure

* working

* tests complete

* modify handler to still panic if not enough pool coins, docs working

* spec tags

* docs complete

* CL

* assert invariants on a blockly basis gaiad functionality

* gaiad CL

* transaction details in runtime invariance panic

* Apply suggestions from code review

Co-Authored-By: rigelrozanski <[email protected]>

* sender tags

* @mossid suggestions

int

* @cwgoes comments final

* Apply suggestions from code review

Co-Authored-By: rigelrozanski <[email protected]>

* bug seems fixed (cosmos#3998)

* delete unused line in zero height export bug
  • Loading branch information
rigelrozanski authored Mar 28, 2019
1 parent b9e6df3 commit df43941
Show file tree
Hide file tree
Showing 48 changed files with 820 additions and 120 deletions.
1 change: 1 addition & 0 deletions .pending/features/gaia/2935-optionally-asse
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#2935 Optionally assert invariants on a blockly basis using `gaiad --assert-invariants-blockly`
1 change: 1 addition & 0 deletions .pending/features/sdk/2935-New-module-Cris
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#2935 New module Crisis which can test broken invariant with messages
5 changes: 4 additions & 1 deletion client/lcd/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
privVal.Reset()

db := dbm.NewMemDB()
app := gapp.NewGaiaApp(logger, db, nil, true)
app := gapp.NewGaiaApp(logger, db, nil, true, false)
cdc = gapp.MakeCodec()

genesisFile := config.GenesisFile()
Expand Down Expand Up @@ -299,6 +299,9 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
genesisState.MintData.Minter.Inflation = inflationMin
genesisState.MintData.Params.InflationMin = inflationMin

// initialize crisis data
genesisState.CrisisData.ConstantFee = sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000)

// double check inflation is set according to the minting boolean flag
if minting {
require.Equal(t, sdk.MustNewDecFromStr("15000.0"),
Expand Down
4 changes: 3 additions & 1 deletion client/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ func EnrichWithGas(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []s

// CalculateGas simulates the execution of a transaction and returns
// both the estimate obtained by the query and the adjusted amount.
func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *amino.Codec, txBytes []byte, adjustment float64) (estimate, adjusted uint64, err error) {
func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error),
cdc *amino.Codec, txBytes []byte, adjustment float64) (estimate, adjusted uint64, err error) {

// run a simulation (via /app/simulate query) to
// estimate gas and update TxBuilder accordingly
rawRes, err := queryFunc("/app/simulate", txBytes)
Expand Down
28 changes: 25 additions & 3 deletions cmd/gaia/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
Expand All @@ -44,6 +45,8 @@ type GaiaApp struct {
*bam.BaseApp
cdc *codec.Codec

assertInvariantsBlockly bool

// keys to access the substores
keyMain *sdk.KVStoreKey
keyAccount *sdk.KVStoreKey
Expand All @@ -67,11 +70,14 @@ type GaiaApp struct {
mintKeeper mint.Keeper
distrKeeper distr.Keeper
govKeeper gov.Keeper
crisisKeeper crisis.Keeper
paramsKeeper params.Keeper
}

// NewGaiaApp returns a reference to an initialized GaiaApp.
func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {
func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, assertInvariantsBlockly bool,
baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {

cdc := MakeCodec()

bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...)
Expand Down Expand Up @@ -143,6 +149,12 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakingKeeper,
gov.DefaultCodespace,
)
app.crisisKeeper = crisis.NewKeeper(
app.paramsKeeper.Subspace(crisis.DefaultParamspace),
app.distrKeeper,
app.bankKeeper,
app.feeCollectionKeeper,
)

// register the staking hooks
// NOTE: The stakingKeeper above is passed by reference, so that it can be
Expand All @@ -151,6 +163,11 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
NewStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()),
)

// register the crisis routes
bank.RegisterInvariants(&app.crisisKeeper, app.accountKeeper)
distr.RegisterInvariants(&app.crisisKeeper, app.distrKeeper, app.stakingKeeper)
staking.RegisterInvariants(&app.crisisKeeper, app.stakingKeeper, app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper)

// register message routes
//
// TODO: Use standard bank router once transfers are enabled.
Expand All @@ -159,7 +176,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper)).
AddRoute(distr.RouterKey, distr.NewHandler(app.distrKeeper)).
AddRoute(slashing.RouterKey, slashing.NewHandler(app.slashingKeeper)).
AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper))
AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper)).
AddRoute(crisis.RouterKey, crisis.NewHandler(app.crisisKeeper))

app.QueryRouter().
AddRoute(auth.QuerierRoute, auth.NewQuerier(app.accountKeeper)).
Expand Down Expand Up @@ -197,6 +215,7 @@ func MakeCodec() *codec.Codec {
slashing.RegisterCodec(cdc)
gov.RegisterCodec(cdc)
auth.RegisterCodec(cdc)
crisis.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
return cdc
Expand Down Expand Up @@ -229,7 +248,9 @@ func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.R
validatorUpdates, endBlockerTags := staking.EndBlocker(ctx, app.stakingKeeper)
tags = append(tags, endBlockerTags...)

app.assertRuntimeInvariants()
if app.assertInvariantsBlockly {
app.assertRuntimeInvariants()
}

return abci.ResponseEndBlock{
ValidatorUpdates: validatorUpdates,
Expand Down Expand Up @@ -262,6 +283,7 @@ func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisSt
bank.InitGenesis(ctx, app.bankKeeper, genesisState.BankData)
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakingData.Validators.ToSDKValidators())
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
crisis.InitGenesis(ctx, app.crisisKeeper, genesisState.CrisisData)
mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData)

// validate genesis state
Expand Down
6 changes: 4 additions & 2 deletions cmd/gaia/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"

"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/db"
Expand Down Expand Up @@ -35,6 +36,7 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
mint.DefaultGenesisState(),
distr.DefaultGenesisState(),
gov.DefaultGenesisState(),
crisis.DefaultGenesisState(),
slashing.DefaultGenesisState(),
)

Expand All @@ -53,11 +55,11 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {

func TestGaiadExport(t *testing.T) {
db := db.NewMemDB()
gapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true)
gapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, false)
setGenesis(gapp)

// Making a new app object with the db, so that initchain hasn't been called
newGapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true)
newGapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, false)
_, _, err := newGapp.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
}
3 changes: 3 additions & 0 deletions cmd/gaia/app/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
Expand Down Expand Up @@ -46,6 +47,7 @@ func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteLis
mint.ExportGenesis(ctx, app.mintKeeper),
distr.ExportGenesis(ctx, app.distrKeeper),
gov.ExportGenesis(ctx, app.govKeeper),
crisis.ExportGenesis(ctx, app.crisisKeeper),
slashing.ExportGenesis(ctx, app.slashingKeeper),
)
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
Expand Down Expand Up @@ -118,6 +120,7 @@ func (app *GaiaApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []st
// reinitialize all delegations
for _, del := range dels {
app.distrKeeper.Hooks().BeforeDelegationCreated(ctx, del.DelegatorAddress, del.ValidatorAddress)
app.distrKeeper.Hooks().AfterDelegationModified(ctx, del.DelegatorAddress, del.ValidatorAddress)
}

// reset context height
Expand Down
9 changes: 8 additions & 1 deletion cmd/gaia/app/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
Expand All @@ -39,14 +40,15 @@ type GenesisState struct {
MintData mint.GenesisState `json:"mint"`
DistrData distr.GenesisState `json:"distr"`
GovData gov.GenesisState `json:"gov"`
CrisisData crisis.GenesisState `json:"crisis"`
SlashingData slashing.GenesisState `json:"slashing"`
GenTxs []json.RawMessage `json:"gentxs"`
}

func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
bankData bank.GenesisState,
stakingData staking.GenesisState, mintData mint.GenesisState,
distrData distr.GenesisState, govData gov.GenesisState,
distrData distr.GenesisState, govData gov.GenesisState, crisisData crisis.GenesisState,
slashingData slashing.GenesisState) GenesisState {

return GenesisState{
Expand All @@ -57,6 +59,7 @@ func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
MintData: mintData,
DistrData: distrData,
GovData: govData,
CrisisData: crisisData,
SlashingData: slashingData,
}
}
Expand Down Expand Up @@ -209,6 +212,7 @@ func NewDefaultGenesisState() GenesisState {
MintData: mint.DefaultGenesisState(),
DistrData: distr.DefaultGenesisState(),
GovData: gov.DefaultGenesisState(),
CrisisData: crisis.DefaultGenesisState(),
SlashingData: slashing.DefaultGenesisState(),
GenTxs: nil,
}
Expand Down Expand Up @@ -246,6 +250,9 @@ func GaiaValidateGenesisState(genesisState GenesisState) error {
if err := gov.ValidateGenesis(genesisState.GovData); err != nil {
return err
}
if err := crisis.ValidateGenesis(genesisState.CrisisData); err != nil {
return err
}

return slashing.ValidateGenesis(genesisState.SlashingData)
}
Expand Down
22 changes: 6 additions & 16 deletions cmd/gaia/app/invariants.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,21 @@ import (
abci "github.com/tendermint/tendermint/abci/types"

sdk "github.com/cosmos/cosmos-sdk/types"
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
distrsim "github.com/cosmos/cosmos-sdk/x/distribution/simulation"
stakingsim "github.com/cosmos/cosmos-sdk/x/staking/simulation"
)

func (app *GaiaApp) runtimeInvariants() []sdk.Invariant {
return []sdk.Invariant{
banksim.NonnegativeBalanceInvariant(app.accountKeeper),
distrsim.NonNegativeOutstandingInvariant(app.distrKeeper),
stakingsim.SupplyInvariants(app.stakingKeeper, app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper),
stakingsim.NonNegativePowerInvariant(app.stakingKeeper),
}
}

func (app *GaiaApp) assertRuntimeInvariants() {
ctx := app.NewContext(false, abci.Header{Height: app.LastBlockHeight() + 1})
app.assertRuntimeInvariantsOnContext(ctx)
}

func (app *GaiaApp) assertRuntimeInvariantsOnContext(ctx sdk.Context) {
start := time.Now()
invariants := app.runtimeInvariants()
for _, inv := range invariants {
if err := inv(ctx); err != nil {
panic(fmt.Errorf("invariant broken: %s", err))
invarRoutes := app.crisisKeeper.Routes()
for _, ir := range invarRoutes {
if err := ir.Invar(ctx); err != nil {
panic(fmt.Errorf("invariant broken: %s\n"+
"\tCRITICAL please submit the following transaction:\n"+
"\t\t gaiacli tx crisis invariant-broken %v %v", err, ir.ModuleName, ir.Route))
}
}
end := time.Now()
Expand Down
22 changes: 10 additions & 12 deletions cmd/gaia/app/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,10 @@ func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {

func invariants(app *GaiaApp) []sdk.Invariant {
return []sdk.Invariant{
simulation.PeriodicInvariant(banksim.NonnegativeBalanceInvariant(app.accountKeeper), period, 0),
simulation.PeriodicInvariant(govsim.AllInvariants(), period, 0),
simulation.PeriodicInvariant(distrsim.AllInvariants(app.distrKeeper, app.stakingKeeper), period, 0),
simulation.PeriodicInvariant(stakingsim.AllInvariants(app.stakingKeeper, app.feeCollectionKeeper,
simulation.PeriodicInvariant(bank.NonnegativeBalanceInvariant(app.accountKeeper), period, 0),
simulation.PeriodicInvariant(distr.AllInvariants(app.distrKeeper, app.stakingKeeper), period, 0),
simulation.PeriodicInvariant(staking.AllInvariants(app.stakingKeeper, app.feeCollectionKeeper,
app.distrKeeper, app.accountKeeper), period, 0),
simulation.PeriodicInvariant(slashingsim.AllInvariants(), period, 0),
}
}

Expand All @@ -321,7 +319,7 @@ func BenchmarkFullGaiaSimulation(b *testing.B) {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true)
app := NewGaiaApp(logger, db, nil, true, false)

// Run randomized simulation
// TODO parameterize numbers, save for a later PR
Expand Down Expand Up @@ -356,7 +354,7 @@ func TestFullGaiaSimulation(t *testing.T) {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true, fauxMerkleModeOpt)
app := NewGaiaApp(logger, db, nil, true, false, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", app.Name())

// Run randomized simulation
Expand Down Expand Up @@ -390,7 +388,7 @@ func TestGaiaImportExport(t *testing.T) {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true, fauxMerkleModeOpt)
app := NewGaiaApp(logger, db, nil, true, false, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", app.Name())

// Run randomized simulation
Expand All @@ -417,7 +415,7 @@ func TestGaiaImportExport(t *testing.T) {
newDB.Close()
os.RemoveAll(newDir)
}()
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, true, fauxMerkleModeOpt)
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, true, false, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", newApp.Name())
var genesisState GenesisState
err = app.cdc.UnmarshalJSON(appState, &genesisState)
Expand Down Expand Up @@ -480,7 +478,7 @@ func TestGaiaSimulationAfterImport(t *testing.T) {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true, fauxMerkleModeOpt)
app := NewGaiaApp(logger, db, nil, true, false, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", app.Name())

// Run randomized simulation
Expand Down Expand Up @@ -516,7 +514,7 @@ func TestGaiaSimulationAfterImport(t *testing.T) {
newDB.Close()
os.RemoveAll(newDir)
}()
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, true, fauxMerkleModeOpt)
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, true, false, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", newApp.Name())
newApp.InitChain(abci.RequestInitChain{
AppStateBytes: appState,
Expand Down Expand Up @@ -544,7 +542,7 @@ func TestAppStateDeterminism(t *testing.T) {
for j := 0; j < numTimesToRunPerSeed; j++ {
logger := log.NewNopLogger()
db := dbm.NewMemDB()
app := NewGaiaApp(logger, db, nil, true)
app := NewGaiaApp(logger, db, nil, true, false)

// Run randomized simulation
simulation.SimulateFromSeed(
Expand Down
7 changes: 6 additions & 1 deletion cmd/gaia/cmd/gaiacli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (

authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
crisisclient "github.com/cosmos/cosmos-sdk/x/crisis/client"
distcmd "github.com/cosmos/cosmos-sdk/x/distribution"
distClient "github.com/cosmos/cosmos-sdk/x/distribution/client"
govClient "github.com/cosmos/cosmos-sdk/x/gov/client"
Expand Down Expand Up @@ -69,6 +70,7 @@ func main() {
distClient.NewModuleClient(distcmd.StoreKey, cdc),
stakingClient.NewModuleClient(st.StoreKey, cdc),
slashingClient.NewModuleClient(sl.StoreKey, cdc),
crisisclient.NewModuleClient(sl.StoreKey, cdc),
}

rootCmd := &cobra.Command{
Expand Down Expand Up @@ -124,7 +126,10 @@ func queryCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
)

for _, m := range mc {
queryCmd.AddCommand(m.GetQueryCmd())
mQueryCmd := m.GetQueryCmd()
if mQueryCmd != nil {
queryCmd.AddCommand(mQueryCmd)
}
}

return queryCmd
Expand Down
Loading

0 comments on commit df43941

Please sign in to comment.