x/evidence: StoreDecoder simulation (#6035)

* x/evidence: simulations

* update app

* evidence store decoder

* add evidence to sim import export

* fix test

* prevent zero values on randomized genesis

* return empty evidences for genesis state

* address comments from review
This commit is contained in:
Federico Kunze 2020-04-23 10:51:03 -04:00 committed by GitHub
parent f6e9ee7623
commit 8c736bb72f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 184 additions and 9 deletions

View File

@ -219,6 +219,7 @@ functionality that requires an online connection.
* (client) [\#5895](https://github.com/cosmos/cosmos-sdk/issues/5895) show config options in the config command's help screen.
* (types/rest) [\#5900](https://github.com/cosmos/cosmos-sdk/pull/5900) Add Check*Error function family to spare developers from replicating tons of boilerplate code.
* (x/evidence) [\#5952](https://github.com/cosmos/cosmos-sdk/pull/5952) Tendermint Consensus parameters can now be changed via parameter change proposals through `x/gov`.
* (x/evidence) [\#5961](https://github.com/cosmos/cosmos-sdk/issues/5961) Add `StoreDecoder` simulation for evidence module.
* (x/auth/ante) [\#6040](https://github.com/cosmos/cosmos-sdk/pull/6040) `AccountKeeper` interface used for `NewAnteHandler` and handler's decorators to add support of using custom `AccountKeeper` implementations.
* (simulation) [\#6002](https://github.com/cosmos/cosmos-sdk/pull/6002) Add randomized consensus params into simulation.

View File

@ -271,7 +271,7 @@ func NewSimApp(
distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
upgrade.NewAppModule(app.UpgradeKeeper),
evidence.NewAppModule(app.EvidenceKeeper),
evidence.NewAppModule(appCodec, app.EvidenceKeeper),
ibc.NewAppModule(app.IBCKeeper),
params.NewAppModule(app.ParamsKeeper),
transferModule,
@ -313,6 +313,7 @@ func NewSimApp(
distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
params.NewAppModule(app.ParamsKeeper),
evidence.NewAppModule(appCodec, app.EvidenceKeeper),
)
app.sm.RegisterStoreDecoders()

View File

@ -20,6 +20,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/evidence"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
@ -156,6 +157,7 @@ func TestAppImportExport(t *testing.T) {
{app.keys[bank.StoreKey], newApp.keys[bank.StoreKey], [][]byte{bank.BalancesPrefix}},
{app.keys[paramtypes.StoreKey], newApp.keys[paramtypes.StoreKey], [][]byte{}},
{app.keys[gov.StoreKey], newApp.keys[gov.StoreKey], [][]byte{}},
{app.keys[evidence.StoreKey], newApp.keys[evidence.StoreKey], [][]byte{}},
}
for _, skp := range storeKeysPrefixes {

View File

@ -3,14 +3,17 @@ package evidence
import (
"encoding/json"
"fmt"
"math/rand"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/evidence/client"
"github.com/cosmos/cosmos-sdk/x/evidence/client/cli"
"github.com/cosmos/cosmos-sdk/x/evidence/client/rest"
"github.com/cosmos/cosmos-sdk/x/evidence/simulation"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -18,11 +21,9 @@ import (
)
var (
_ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{}
// TODO: Enable simulation once concrete types are defined.
// _ module.AppModuleSimulation = AppModuleSimulation{}
_ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{}
_ module.AppModuleSimulation = AppModule{}
)
// ----------------------------------------------------------------------------
@ -31,9 +32,11 @@ var (
// AppModuleBasic implements the AppModuleBasic interface for the evidence module.
type AppModuleBasic struct {
cdc Codec
evidenceHandlers []client.EvidenceHandler // client evidence submission handlers
}
// NewAppModuleBasic crates a AppModuleBasic without the codec.
func NewAppModuleBasic(evidenceHandlers ...client.EvidenceHandler) AppModuleBasic {
return AppModuleBasic{
evidenceHandlers: evidenceHandlers,
@ -103,9 +106,9 @@ type AppModule struct {
keeper Keeper
}
func NewAppModule(keeper Keeper) AppModule {
func NewAppModule(cdc Codec, keeper Keeper) AppModule {
return AppModule{
AppModuleBasic: NewAppModuleBasic(),
AppModuleBasic: AppModuleBasic{cdc: cdc},
keeper: keeper,
}
}
@ -166,3 +169,33 @@ func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{}
}
//____________________________________________________________________________
// AppModuleSimulation functions
// GenerateGenesisState creates a randomized GenState of the evidence module.
func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
}
// ProposalContents returns all the evidence content functions used to
// simulate governance proposals.
func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent {
return nil
}
// RandomizedParams creates randomized evidence param changes for the simulator.
func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
return nil
}
// RegisterStoreDecoder registers a decoder for evidence module's types
func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[StoreKey] = simulation.NewDecodeStore(am.cdc)
}
// WeightedOperations returns the all the gov module operations with their respective weights.
func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
return nil
}

View File

@ -0,0 +1,32 @@
package simulation
import (
"bytes"
"fmt"
tmkv "github.com/tendermint/tendermint/libs/kv"
"github.com/cosmos/cosmos-sdk/x/evidence/types"
)
// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
// Value to the corresponding evidence type.
func NewDecodeStore(cdc types.Codec) func(kvA, kvB tmkv.Pair) string {
return func(kvA, kvB tmkv.Pair) string {
switch {
case bytes.Equal(kvA.Key[:1], types.KeyPrefixEvidence):
evidenceA, err := cdc.UnmarshalEvidence(kvA.Value)
if err != nil {
panic(fmt.Sprintf("cannot unmarshal evidence: %s", err.Error()))
}
evidenceB, err := cdc.UnmarshalEvidence(kvB.Value)
if err != nil {
panic(fmt.Sprintf("cannot unmarshal evidence: %s", err.Error()))
}
return fmt.Sprintf("%v\n%v", evidenceA, evidenceB)
default:
panic(fmt.Sprintf("invalid %s key prefix %X", types.ModuleName, kvA.Key[:1]))
}
}
}

View File

@ -0,0 +1,64 @@
package simulation_test
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/ed25519"
tmkv "github.com/tendermint/tendermint/libs/kv"
codecstd "github.com/cosmos/cosmos-sdk/codec/std"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/evidence/simulation"
"github.com/cosmos/cosmos-sdk/x/evidence/types"
)
func TestDecodeStore(t *testing.T) {
cdc := codecstd.NewAppCodec(codecstd.MakeCodec(simapp.ModuleBasics))
dec := simulation.NewDecodeStore(cdc)
delPk1 := ed25519.GenPrivKey().PubKey()
ev := types.Equivocation{
Height: 10,
Time: time.Now().UTC(),
Power: 1000,
ConsensusAddress: sdk.ConsAddress(delPk1.Address()),
}
evBz, err := cdc.MarshalEvidence(&ev)
require.NoError(t, err)
kvPairs := tmkv.Pairs{
tmkv.Pair{
Key: types.KeyPrefixEvidence,
Value: evBz,
},
tmkv.Pair{
Key: []byte{0x99},
Value: []byte{0x99},
},
}
tests := []struct {
name string
expectedLog string
}{
{"Evidence", fmt.Sprintf("%v\n%v", ev, ev)},
{"other", ""},
}
for i, tt := range tests {
i, tt := i, tt
t.Run(tt.name, func(t *testing.T) {
switch i {
case len(tests) - 1:
require.Panics(t, func() { dec(kvPairs[i], kvPairs[i]) }, tt.name)
default:
require.Equal(t, tt.expectedLog, dec(kvPairs[i], kvPairs[i]), tt.name)
}
})
}
}

View File

@ -0,0 +1,37 @@
package simulation
// DONTCOVER
import (
"fmt"
"math/rand"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/evidence/exported"
"github.com/cosmos/cosmos-sdk/x/evidence/types"
)
// Simulation parameter constants
const evidence = "evidence"
// GenEvidences returns an empty slice of evidences.
func GenEvidences(_ *rand.Rand, _ []simtypes.Account) []exported.Evidence {
return []exported.Evidence{}
}
// RandomizedGenState generates a random GenesisState for evidence
func RandomizedGenState(simState *module.SimulationState) {
var ev []exported.Evidence
simState.AppParams.GetOrGenerate(
simState.Cdc, evidence, &ev, simState.Rand,
func(r *rand.Rand) { ev = GenEvidences(r, simState.Accounts) },
)
evidenceGenesis := types.GenesisState{Evidence: ev}
fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, evidenceGenesis))
simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(evidenceGenesis)
}

View File

@ -1,6 +1,8 @@
package types
import (
"fmt"
"github.com/cosmos/cosmos-sdk/x/evidence/exported"
)
@ -27,7 +29,10 @@ func DefaultGenesisState() GenesisState {
// Validate performs basic gensis state validation returning an error upon any
// failure.
func (gs GenesisState) Validate() error {
for _, e := range gs.Evidence {
for i, e := range gs.Evidence {
if e == nil {
return fmt.Errorf("evidence %d cannot be nil", i)
}
if err := e.ValidateBasic(); err != nil {
return err
}