mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-26 08:15:19 +00:00
8d0bb5a5b0
* add genesis file invariant assertion command * fix: use correct cmd function name * update migration guide to add invariant check
264 lines
11 KiB
Go
264 lines
11 KiB
Go
package app
|
|
|
|
import (
|
|
"math/rand"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
tmdb "github.com/tendermint/tm-db"
|
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
"github.com/tendermint/tendermint/crypto"
|
|
"github.com/tendermint/tendermint/crypto/secp256k1"
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
|
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
|
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
|
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
|
"github.com/cosmos/cosmos-sdk/x/crisis"
|
|
"github.com/cosmos/cosmos-sdk/x/distribution"
|
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
|
"github.com/cosmos/cosmos-sdk/x/params"
|
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
|
"github.com/cosmos/cosmos-sdk/x/staking"
|
|
"github.com/cosmos/cosmos-sdk/x/supply"
|
|
"github.com/cosmos/cosmos-sdk/x/upgrade"
|
|
|
|
"github.com/kava-labs/kava/x/auction"
|
|
"github.com/kava-labs/kava/x/bep3"
|
|
"github.com/kava-labs/kava/x/cdp"
|
|
"github.com/kava-labs/kava/x/committee"
|
|
"github.com/kava-labs/kava/x/hard"
|
|
"github.com/kava-labs/kava/x/incentive"
|
|
"github.com/kava-labs/kava/x/issuance"
|
|
"github.com/kava-labs/kava/x/kavadist"
|
|
"github.com/kava-labs/kava/x/pricefeed"
|
|
"github.com/kava-labs/kava/x/swap"
|
|
validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
|
|
)
|
|
|
|
var (
|
|
emptyTime time.Time
|
|
emptyChainID string
|
|
)
|
|
|
|
// TestApp is a simple wrapper around an App. It exposes internal keepers for use in integration tests.
|
|
// This file also contains test helpers. Ideally they would be in separate package.
|
|
// Basic Usage:
|
|
// Create a test app with NewTestApp, then all keepers and their methods can be accessed for test setup and execution.
|
|
// Advanced Usage:
|
|
// Some tests call for an app to be initialized with some state. This can be achieved through keeper method calls (ie keeper.SetParams(...)).
|
|
// However this leads to a lot of duplicated logic similar to InitGenesis methods.
|
|
// So TestApp.InitializeFromGenesisStates() will call InitGenesis with the default genesis state.
|
|
// and TestApp.InitializeFromGenesisStates(authState, cdpState) will do the same but overwrite the auth and cdp sections of the default genesis state
|
|
// Creating the genesis states can be combersome, but helper methods can make it easier such as NewAuthGenStateFromAccounts below.
|
|
type TestApp struct {
|
|
App
|
|
}
|
|
|
|
func NewTestApp() TestApp {
|
|
config := sdk.GetConfig()
|
|
SetBech32AddressPrefixes(config)
|
|
SetBip44CoinType(config)
|
|
|
|
db := tmdb.NewMemDB()
|
|
app := NewApp(log.NewNopLogger(), db, nil, AppOptions{})
|
|
return TestApp{App: *app}
|
|
}
|
|
|
|
func NewTestAppFromSealed() TestApp {
|
|
db := tmdb.NewMemDB()
|
|
app := NewApp(log.NewNopLogger(), db, nil, AppOptions{})
|
|
return TestApp{App: *app}
|
|
}
|
|
|
|
// nolint
|
|
func (tApp TestApp) GetAccountKeeper() auth.AccountKeeper { return tApp.accountKeeper }
|
|
func (tApp TestApp) GetBankKeeper() bank.Keeper { return tApp.bankKeeper }
|
|
func (tApp TestApp) GetSupplyKeeper() supply.Keeper { return tApp.supplyKeeper }
|
|
func (tApp TestApp) GetStakingKeeper() staking.Keeper { return tApp.stakingKeeper }
|
|
func (tApp TestApp) GetSlashingKeeper() slashing.Keeper { return tApp.slashingKeeper }
|
|
func (tApp TestApp) GetMintKeeper() mint.Keeper { return tApp.mintKeeper }
|
|
func (tApp TestApp) GetDistrKeeper() distribution.Keeper { return tApp.distrKeeper }
|
|
func (tApp TestApp) GetGovKeeper() gov.Keeper { return tApp.govKeeper }
|
|
func (tApp TestApp) GetCrisisKeeper() crisis.Keeper { return tApp.crisisKeeper }
|
|
func (tApp TestApp) GetUpgradeKeeper() upgrade.Keeper { return tApp.upgradeKeeper }
|
|
func (tApp TestApp) GetParamsKeeper() params.Keeper { return tApp.paramsKeeper }
|
|
func (tApp TestApp) GetVVKeeper() validatorvesting.Keeper { return tApp.vvKeeper }
|
|
func (tApp TestApp) GetAuctionKeeper() auction.Keeper { return tApp.auctionKeeper }
|
|
func (tApp TestApp) GetCDPKeeper() cdp.Keeper { return tApp.cdpKeeper }
|
|
func (tApp TestApp) GetPriceFeedKeeper() pricefeed.Keeper { return tApp.pricefeedKeeper }
|
|
func (tApp TestApp) GetBep3Keeper() bep3.Keeper { return tApp.bep3Keeper }
|
|
func (tApp TestApp) GetKavadistKeeper() kavadist.Keeper { return tApp.kavadistKeeper }
|
|
func (tApp TestApp) GetIncentiveKeeper() incentive.Keeper { return tApp.incentiveKeeper }
|
|
func (tApp TestApp) GetHardKeeper() hard.Keeper { return tApp.hardKeeper }
|
|
func (tApp TestApp) GetCommitteeKeeper() committee.Keeper { return tApp.committeeKeeper }
|
|
func (tApp TestApp) GetIssuanceKeeper() issuance.Keeper { return tApp.issuanceKeeper }
|
|
func (tApp TestApp) GetSwapKeeper() swap.Keeper { return tApp.swapKeeper }
|
|
|
|
// InitializeFromGenesisStates calls InitChain on the app using the default genesis state, overwitten with any passed in genesis states
|
|
func (tApp TestApp) InitializeFromGenesisStates(genesisStates ...GenesisState) TestApp {
|
|
return tApp.InitializeFromGenesisStatesWithTimeAndChainID(emptyTime, emptyChainID, genesisStates...)
|
|
}
|
|
|
|
// InitializeFromGenesisStatesWithTime calls InitChain on the app using the default genesis state, overwitten with any passed in genesis states and genesis Time
|
|
func (tApp TestApp) InitializeFromGenesisStatesWithTime(genTime time.Time, genesisStates ...GenesisState) TestApp {
|
|
return tApp.InitializeFromGenesisStatesWithTimeAndChainID(genTime, emptyChainID, genesisStates...)
|
|
}
|
|
|
|
// InitializeFromGenesisStatesWithTimeAndChainID calls InitChain on the app using the default genesis state, overwitten with any passed in genesis states and genesis Time
|
|
func (tApp TestApp) InitializeFromGenesisStatesWithTimeAndChainID(genTime time.Time, chainID string, genesisStates ...GenesisState) TestApp {
|
|
// Create a default genesis state and overwrite with provided values
|
|
genesisState := NewDefaultGenesisState()
|
|
for _, state := range genesisStates {
|
|
for k, v := range state {
|
|
genesisState[k] = v
|
|
}
|
|
}
|
|
|
|
// Initialize the chain
|
|
stateBytes, err := codec.MarshalJSONIndent(tApp.cdc, genesisState)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
tApp.InitChain(
|
|
abci.RequestInitChain{
|
|
Time: genTime,
|
|
Validators: []abci.ValidatorUpdate{},
|
|
AppStateBytes: stateBytes,
|
|
ChainId: chainID,
|
|
},
|
|
)
|
|
tApp.Commit()
|
|
tApp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: tApp.LastBlockHeight() + 1, Time: genTime}})
|
|
return tApp
|
|
}
|
|
|
|
func (tApp TestApp) CheckBalance(t *testing.T, ctx sdk.Context, owner sdk.AccAddress, expectedCoins sdk.Coins) {
|
|
acc := tApp.GetAccountKeeper().GetAccount(ctx, owner)
|
|
require.NotNilf(t, acc, "account with address '%s' doesn't exist", owner)
|
|
require.Equal(t, expectedCoins, acc.GetCoins())
|
|
}
|
|
|
|
// GeneratePrivKeyAddressPairsFromRand generates (deterministically) a total of n secp256k1 private keys and addresses.
|
|
func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) {
|
|
r := rand.New(rand.NewSource(12345)) // make the generation deterministic
|
|
keys = make([]crypto.PrivKey, n)
|
|
addrs = make([]sdk.AccAddress, n)
|
|
for i := 0; i < n; i++ {
|
|
secret := make([]byte, 32)
|
|
_, err := r.Read(secret)
|
|
if err != nil {
|
|
panic("Could not read randomness")
|
|
}
|
|
keys[i] = secp256k1.GenPrivKeySecp256k1(secret)
|
|
addrs[i] = sdk.AccAddress(keys[i].PubKey().Address())
|
|
}
|
|
return
|
|
}
|
|
|
|
// Create a new auth genesis state from some addresses and coins. The state is returned marshalled into a map.
|
|
func NewAuthGenState(addresses []sdk.AccAddress, coins []sdk.Coins) GenesisState {
|
|
// Create GenAccounts
|
|
accounts := authexported.GenesisAccounts{}
|
|
for i := range addresses {
|
|
accounts = append(accounts, auth.NewBaseAccount(addresses[i], coins[i], nil, 0, 0))
|
|
}
|
|
// Create the auth genesis state
|
|
authGenesis := auth.NewGenesisState(auth.DefaultParams(), accounts)
|
|
return GenesisState{auth.ModuleName: auth.ModuleCdc.MustMarshalJSON(authGenesis)}
|
|
}
|
|
|
|
// AuthGenesisBuilder is a tool for creating an auth genesis state.
|
|
// Helper methods create basic accounts types and add them to a default genesis state.
|
|
// All methods are immutable and return updated copies of the builder.
|
|
// The builder inherits from auth.GenesisState, so fields can be accessed directly if a helper method doesn't exist.
|
|
//
|
|
// Example:
|
|
// // create a single account genesis state
|
|
// builder := NewAuthGenesisBuilder().WithSimpleAccount(testUserAddress, testCoins)
|
|
// genesisState := builder.Build()
|
|
//
|
|
type AuthGenesisBuilder struct {
|
|
auth.GenesisState
|
|
}
|
|
|
|
// NewAuthGenesisBuilder creates a AuthGenesisBuilder containing a default genesis state.
|
|
func NewAuthGenesisBuilder() AuthGenesisBuilder {
|
|
return AuthGenesisBuilder{
|
|
GenesisState: auth.DefaultGenesisState(),
|
|
}
|
|
}
|
|
|
|
// Build assembles and returns the final GenesisState
|
|
func (builder AuthGenesisBuilder) Build() auth.GenesisState {
|
|
return builder.GenesisState
|
|
}
|
|
|
|
// BuildMarshalled assembles the final GenesisState and json encodes it into a generic genesis type.
|
|
func (builder AuthGenesisBuilder) BuildMarshalled() GenesisState {
|
|
return GenesisState{
|
|
auth.ModuleName: auth.ModuleCdc.MustMarshalJSON(builder.Build()),
|
|
}
|
|
}
|
|
|
|
// WithAccounts adds accounts of any type to the genesis state.
|
|
func (builder AuthGenesisBuilder) WithAccounts(account ...authexported.GenesisAccount) AuthGenesisBuilder {
|
|
builder.Accounts = append(builder.Accounts, account...)
|
|
return builder
|
|
}
|
|
|
|
// WithSimpleAccount adds a standard account to the genesis state.
|
|
func (builder AuthGenesisBuilder) WithSimpleAccount(address sdk.AccAddress, balance sdk.Coins) AuthGenesisBuilder {
|
|
return builder.WithAccounts(auth.NewBaseAccount(address, balance, nil, 0, 0))
|
|
}
|
|
|
|
// WithSimpleModuleAccount adds a module account to the genesis state.
|
|
func (builder AuthGenesisBuilder) WithSimpleModuleAccount(moduleName string, balance sdk.Coins, permissions ...string) AuthGenesisBuilder {
|
|
account := supply.NewEmptyModuleAccount(moduleName, permissions...)
|
|
account.SetCoins(balance)
|
|
return builder.WithAccounts(account)
|
|
}
|
|
|
|
// WithSimplePeriodicVestingAccount adds a periodic vesting account to the genesis state.
|
|
func (builder AuthGenesisBuilder) WithSimplePeriodicVestingAccount(address sdk.AccAddress, balance sdk.Coins, periods vesting.Periods, firstPeriodStartTimestamp int64) AuthGenesisBuilder {
|
|
baseAccount := auth.NewBaseAccount(address, balance, nil, 0, 0)
|
|
|
|
originalVesting := sdk.NewCoins()
|
|
for _, p := range periods {
|
|
originalVesting = originalVesting.Add(p.Amount...)
|
|
}
|
|
|
|
var totalPeriods int64
|
|
for _, p := range periods {
|
|
totalPeriods += p.Length
|
|
}
|
|
endTime := firstPeriodStartTimestamp + totalPeriods
|
|
|
|
baseVestingAccount, err := vesting.NewBaseVestingAccount(baseAccount, originalVesting, endTime)
|
|
if err != nil {
|
|
panic(err.Error())
|
|
}
|
|
periodicVestingAccount := vesting.NewPeriodicVestingAccountRaw(baseVestingAccount, firstPeriodStartTimestamp, periods)
|
|
|
|
return builder.WithAccounts(periodicVestingAccount)
|
|
}
|
|
|
|
// WithEmptyValidatorVestingAccount adds a stub validator vesting account to the genesis state.
|
|
func (builder AuthGenesisBuilder) WithEmptyValidatorVestingAccount(address sdk.AccAddress) AuthGenesisBuilder {
|
|
// TODO create a validator vesting account builder and remove this method
|
|
bacc := auth.NewBaseAccount(address, nil, nil, 0, 0)
|
|
bva, err := vesting.NewBaseVestingAccount(bacc, nil, 1)
|
|
if err != nil {
|
|
panic(err.Error())
|
|
}
|
|
account := validatorvesting.NewValidatorVestingAccountRaw(bva, 0, nil, sdk.ConsAddress{}, nil, 90)
|
|
return builder.WithAccounts(account)
|
|
}
|