mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-26 00:05:18 +00:00
add simulation to validator vesting
This commit is contained in:
parent
b57b362062
commit
f6aec46343
@ -8,7 +8,7 @@ import (
|
||||
|
||||
// InitGenesis stores the account address of each ValidatorVestingAccount in the validator vesting keeper, for faster lookup.
|
||||
// CONTRACT: Accounts created by the account keeper must have already been initialized/created by AccountKeeper
|
||||
func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeeper, data GenesisState) {
|
||||
func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) {
|
||||
data.Accounts = auth.SanitizeGenesisAccounts(data.Accounts)
|
||||
for _, a := range data.Accounts {
|
||||
vv, ok := a.(ValidatorVestingAccount)
|
||||
@ -17,3 +17,8 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeep
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExportGenesis returns empty genesis state because auth exports all the genesis state we need.
|
||||
func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
||||
return types.DefaultGenesisState()
|
||||
}
|
||||
|
@ -34,3 +34,8 @@ func (data GenesisState) Equal(data2 GenesisState) bool {
|
||||
func (data GenesisState) IsEmpty() bool {
|
||||
return data.Equal(GenesisState{})
|
||||
}
|
||||
|
||||
// ValidateGenesis returns nil because accounts are validated by auth
|
||||
func ValidateGenesis(data GenesisState) error {
|
||||
return nil
|
||||
}
|
||||
|
146
x/validator-vesting/module.go
Normal file
146
x/validator-vesting/module.go
Normal file
@ -0,0 +1,146 @@
|
||||
package validatorvesting
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"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"
|
||||
sim "github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/validator-vesting/internal/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/validator-vesting/simulation"
|
||||
)
|
||||
|
||||
var (
|
||||
_ module.AppModule = AppModule{}
|
||||
_ module.AppModuleBasic = AppModuleBasic{}
|
||||
_ module.AppModuleSimulation = AppModuleSimulation{}
|
||||
)
|
||||
|
||||
// AppModuleBasic defines the basic application module used by the auth module.
|
||||
type AppModuleBasic struct{}
|
||||
|
||||
// Name returns the auth module's name.
|
||||
func (AppModuleBasic) Name() string {
|
||||
return types.ModuleName
|
||||
}
|
||||
|
||||
// RegisterCodec registers the auth module's types for the given codec.
|
||||
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
|
||||
types.RegisterCodec(cdc)
|
||||
}
|
||||
|
||||
// DefaultGenesis returns default genesis state as raw bytes for the validator-vesting
|
||||
// module.
|
||||
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
|
||||
return types.ModuleCdc.MustMarshalJSON(types.DefaultGenesisState())
|
||||
}
|
||||
|
||||
// ValidateGenesis performs genesis state validation for the validator-vesting module.
|
||||
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
|
||||
var data types.GenesisState
|
||||
if err := types.ModuleCdc.UnmarshalJSON(bz, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
return types.ValidateGenesis(data)
|
||||
}
|
||||
|
||||
// RegisterRESTRoutes registers no REST routes for the crisis module.
|
||||
func (AppModuleBasic) RegisterRESTRoutes(_ context.CLIContext, _ *mux.Router) {}
|
||||
|
||||
// GetTxCmd returns no root tx command for the validator-vesting module.
|
||||
func (AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil }
|
||||
|
||||
// GetQueryCmd returns no root query command for the validator-vesting module.
|
||||
func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil }
|
||||
|
||||
// AppModuleSimulation defines the module simulation functions used by the auth module.
|
||||
type AppModuleSimulation struct{}
|
||||
|
||||
// RegisterStoreDecoder registers a decoder for auth module's types
|
||||
func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
|
||||
sdr[StoreKey] = simulation.DecodeStore
|
||||
}
|
||||
|
||||
// GenerateGenesisState creates a randomized GenState of the auth module
|
||||
func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) {
|
||||
simulation.RandomizedGenState(simState)
|
||||
}
|
||||
|
||||
// RandomizedParams returns nil because validatorvesting has no params.
|
||||
func (AppModuleSimulation) RandomizedParams(_ *rand.Rand) []sim.ParamChange {
|
||||
return []sim.ParamChange{}
|
||||
}
|
||||
|
||||
// AppModule implements an application module for the validator-vesting module.
|
||||
type AppModule struct {
|
||||
AppModuleBasic
|
||||
AppModuleSimulation
|
||||
keeper Keeper
|
||||
}
|
||||
|
||||
// NewAppModule creates a new AppModule object
|
||||
func NewAppModule(keeper Keeper) AppModule {
|
||||
return AppModule{
|
||||
AppModuleBasic: AppModuleBasic{},
|
||||
AppModuleSimulation: AppModuleSimulation{},
|
||||
keeper: keeper,
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the auth module's name.
|
||||
func (AppModule) Name() string {
|
||||
return types.ModuleName
|
||||
}
|
||||
|
||||
// RegisterInvariants performs a no-op.
|
||||
func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
|
||||
|
||||
// Route returns the message routing key for the auth module.
|
||||
func (AppModule) Route() string { return "" }
|
||||
|
||||
// NewHandler returns an sdk.Handler for the auth module.
|
||||
func (AppModule) NewHandler() sdk.Handler { return nil }
|
||||
|
||||
// QuerierRoute returns the auth module's querier route name.
|
||||
func (AppModule) QuerierRoute() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// NewQuerierHandler returns the auth module sdk.Querier.
|
||||
func (am AppModule) NewQuerierHandler() sdk.Querier {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitGenesis performs genesis initialization for the auth module. It returns
|
||||
// no validator updates.
|
||||
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
|
||||
var genesisState GenesisState
|
||||
types.ModuleCdc.MustUnmarshalJSON(data, &genesisState)
|
||||
InitGenesis(ctx, am.keeper, genesisState)
|
||||
return []abci.ValidatorUpdate{}
|
||||
}
|
||||
|
||||
// ExportGenesis returns the exported genesis state as raw bytes for the auth
|
||||
// module.
|
||||
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
|
||||
gs := ExportGenesis(ctx, am.keeper)
|
||||
return types.ModuleCdc.MustMarshalJSON(gs)
|
||||
}
|
||||
|
||||
// BeginBlock returns the begin blocker for the auth module.
|
||||
func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
|
||||
BeginBlocker(ctx, req, am.keeper)
|
||||
}
|
||||
|
||||
// EndBlock returns the end blocker for the auth module. It returns no validator
|
||||
// updates.
|
||||
func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
|
||||
return []abci.ValidatorUpdate{}
|
||||
}
|
31
x/validator-vesting/simulation/decoder.go
Normal file
31
x/validator-vesting/simulation/decoder.go
Normal file
@ -0,0 +1,31 @@
|
||||
package simulation
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/validator-vesting/internal/types"
|
||||
)
|
||||
|
||||
// DecodeStore unmarshals the KVPair's Value to the corresponding auth type
|
||||
func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string {
|
||||
switch {
|
||||
case bytes.Equal(kvA.Key[:1], types.ValidatorVestingAccountPrefix):
|
||||
var accA, accB exported.Account
|
||||
cdc.MustUnmarshalBinaryBare(kvA.Value, &accA)
|
||||
cdc.MustUnmarshalBinaryBare(kvB.Value, &accB)
|
||||
return fmt.Sprintf("%v\n%v", accA, accB)
|
||||
case bytes.Equal(kvA.Key, types.BlocktimeKey):
|
||||
var btA, btB time.Time
|
||||
cdc.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &btA)
|
||||
cdc.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &btB)
|
||||
return fmt.Sprintf("%v\n%v", btA, btB)
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid account key %X", kvA.Key))
|
||||
}
|
||||
}
|
121
x/validator-vesting/simulation/genesis.go
Normal file
121
x/validator-vesting/simulation/genesis.go
Normal file
@ -0,0 +1,121 @@
|
||||
package simulation
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported"
|
||||
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/validator-vesting/internal/types"
|
||||
)
|
||||
|
||||
// RandomizedGenState generates a random GenesisState for validator-vesting
|
||||
func RandomizedGenState(simState *module.SimulationState) {
|
||||
var authGenState authtypes.GenesisState
|
||||
authSimState := simState.GenState[authtypes.ModuleName]
|
||||
simState.Cdc.MustUnmarshalJSON(authSimState, &authGenState)
|
||||
var newGenesisAccs authexported.GenesisAccounts
|
||||
for _, acc := range authGenState.Accounts {
|
||||
va, ok := acc.(vestexported.VestingAccount)
|
||||
if ok {
|
||||
// 50% of the time convert the vesting account
|
||||
|
||||
if simState.Rand.Intn(100) < 50 {
|
||||
bacc := authtypes.NewBaseAccountWithAddress(va.GetAddress())
|
||||
err := bacc.SetCoins(va.GetCoins())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
duration := va.GetEndTime() - va.GetStartTime()
|
||||
vestingPeriods := getRandomVestingPeriods(duration, simState.Rand, va.GetCoins())
|
||||
vestingCoins := getVestingCoins(vestingPeriods)
|
||||
bva := vestingtypes.NewBaseVestingAccount(&bacc, vestingCoins, va.GetEndTime())
|
||||
var gacc authexported.GenesisAccount
|
||||
if simState.Rand.Intn(100) < 50 {
|
||||
// convert to periodic vesting account 50%
|
||||
gacc = vestingtypes.NewPeriodicVestingAccountRaw(bva, va.GetStartTime(), vestingPeriods)
|
||||
err = gacc.Validate()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
consAdd := getRandomValidatorConsAddr(simState, simulation.RandIntBetween(simState.Rand, 0, int(simState.NumBonded)-1))
|
||||
// convert to validator vesting account 50%
|
||||
// set signing threshold to be anywhere between 1 and 100
|
||||
gacc = types.NewValidatorVestingAccountRaw(
|
||||
bva, va.GetStartTime(), vestingPeriods, consAdd, nil,
|
||||
int64(simulation.RandIntBetween(simState.Rand, 1, 100)),
|
||||
)
|
||||
err = gacc.Validate()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
newGenesisAccs = append(newGenesisAccs, gacc)
|
||||
} else {
|
||||
newGenesisAccs = append(newGenesisAccs, acc)
|
||||
}
|
||||
} else {
|
||||
newGenesisAccs = append(newGenesisAccs, acc)
|
||||
}
|
||||
}
|
||||
newAuthGenesis := authtypes.NewGenesisState(authGenState.Params, newGenesisAccs)
|
||||
simState.GenState[authtypes.ModuleName] = simState.Cdc.MustMarshalJSON(newAuthGenesis)
|
||||
}
|
||||
|
||||
func getRandomValidatorConsAddr(simState *module.SimulationState, rint int) sdk.ConsAddress {
|
||||
acc := simState.Accounts[rint]
|
||||
return sdk.ConsAddress(acc.PubKey.Address())
|
||||
}
|
||||
|
||||
func getRandomVestingPeriods(duration int64, r *rand.Rand, origCoins sdk.Coins) vestingtypes.Periods {
|
||||
maxPeriods := int64(50)
|
||||
if duration < maxPeriods {
|
||||
maxPeriods = duration
|
||||
}
|
||||
numPeriods := simulation.RandIntBetween(r, 1, int(maxPeriods))
|
||||
lenPeriod := duration / int64(numPeriods)
|
||||
periodLengths := make([]int64, numPeriods)
|
||||
totalLength := int64(0)
|
||||
for i := 0; i < numPeriods; i++ {
|
||||
periodLengths[i] = lenPeriod
|
||||
totalLength += lenPeriod
|
||||
}
|
||||
if duration-totalLength != 0 {
|
||||
periodLengths[len(periodLengths)-1] += (duration - totalLength)
|
||||
}
|
||||
|
||||
coinFraction := simulation.RandIntBetween(r, 1, 100)
|
||||
vestingCoins := sdk.NewCoins()
|
||||
for _, ic := range origCoins {
|
||||
amountVesting := ic.Amount.Int64() / int64(coinFraction)
|
||||
vestingCoins = vestingCoins.Add(sdk.NewCoins(sdk.NewInt64Coin(ic.Denom, amountVesting)))
|
||||
}
|
||||
periodCoins := sdk.NewCoins()
|
||||
for _, c := range vestingCoins {
|
||||
amountPeriod := c.Amount.Int64() / int64(numPeriods)
|
||||
periodCoins = periodCoins.Add(sdk.NewCoins(sdk.NewInt64Coin(c.Denom, amountPeriod)))
|
||||
}
|
||||
|
||||
vestingPeriods := make([]vestingtypes.Period, numPeriods)
|
||||
for i := 0; i < numPeriods; i++ {
|
||||
vestingPeriods[i] = vestingtypes.Period{Length: int64(periodLengths[i]), Amount: periodCoins}
|
||||
}
|
||||
|
||||
return vestingPeriods
|
||||
|
||||
}
|
||||
|
||||
func getVestingCoins(periods vestingtypes.Periods) sdk.Coins {
|
||||
vestingCoins := sdk.NewCoins()
|
||||
for _, p := range periods {
|
||||
vestingCoins = vestingCoins.Add(p.Amount)
|
||||
}
|
||||
return vestingCoins
|
||||
}
|
@ -122,9 +122,9 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper,
|
||||
|
||||
validators := staking.InitGenesis(ctx, stakingKeeper, mapp.AccountKeeper, supplyKeeper, stakingGenesis)
|
||||
if genState.IsEmpty() {
|
||||
InitGenesis(ctx, keeper, mapp.AccountKeeper, types.DefaultGenesisState())
|
||||
InitGenesis(ctx, keeper, types.DefaultGenesisState())
|
||||
} else {
|
||||
InitGenesis(ctx, keeper, mapp.AccountKeeper, genState)
|
||||
InitGenesis(ctx, keeper, genState)
|
||||
}
|
||||
return abci.ResponseInitChain{
|
||||
Validators: validators,
|
||||
|
Loading…
Reference in New Issue
Block a user