mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-27 00:35: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.
|
// 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
|
// 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)
|
data.Accounts = auth.SanitizeGenesisAccounts(data.Accounts)
|
||||||
for _, a := range data.Accounts {
|
for _, a := range data.Accounts {
|
||||||
vv, ok := a.(ValidatorVestingAccount)
|
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 {
|
func (data GenesisState) IsEmpty() bool {
|
||||||
return data.Equal(GenesisState{})
|
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)
|
validators := staking.InitGenesis(ctx, stakingKeeper, mapp.AccountKeeper, supplyKeeper, stakingGenesis)
|
||||||
if genState.IsEmpty() {
|
if genState.IsEmpty() {
|
||||||
InitGenesis(ctx, keeper, mapp.AccountKeeper, types.DefaultGenesisState())
|
InitGenesis(ctx, keeper, types.DefaultGenesisState())
|
||||||
} else {
|
} else {
|
||||||
InitGenesis(ctx, keeper, mapp.AccountKeeper, genState)
|
InitGenesis(ctx, keeper, genState)
|
||||||
}
|
}
|
||||||
return abci.ResponseInitChain{
|
return abci.ResponseInitChain{
|
||||||
Validators: validators,
|
Validators: validators,
|
||||||
|
Loading…
Reference in New Issue
Block a user