192 lines
5.6 KiB
Go
192 lines
5.6 KiB
Go
package distribution_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
corestore "cosmossdk.io/core/store"
|
|
coretesting "cosmossdk.io/core/testing"
|
|
"cosmossdk.io/depinject"
|
|
"cosmossdk.io/log"
|
|
sdkmath "cosmossdk.io/math"
|
|
bankkeeper "cosmossdk.io/x/bank/keeper"
|
|
"cosmossdk.io/x/distribution/keeper"
|
|
"cosmossdk.io/x/distribution/types"
|
|
stakingkeeper "cosmossdk.io/x/staking/keeper"
|
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
"github.com/cosmos/cosmos-sdk/runtime"
|
|
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
_ "github.com/cosmos/cosmos-sdk/x/auth"
|
|
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
|
)
|
|
|
|
type ImportExportSuite struct {
|
|
suite.Suite
|
|
|
|
cdc codec.Codec
|
|
app *runtime.App
|
|
addrs []sdk.AccAddress
|
|
AccountKeeper authkeeper.AccountKeeper
|
|
BankKeeper bankkeeper.Keeper
|
|
DistributionKeeper keeper.Keeper
|
|
StakingKeeper *stakingkeeper.Keeper
|
|
appBuilder *runtime.AppBuilder
|
|
}
|
|
|
|
func TestDistributionImportExport(t *testing.T) {
|
|
suite.Run(t, new(ImportExportSuite))
|
|
}
|
|
|
|
func (s *ImportExportSuite) SetupTest() {
|
|
var err error
|
|
valTokens := sdk.TokensFromConsensusPower(42, sdk.DefaultPowerReduction)
|
|
s.app, err = simtestutil.SetupWithConfiguration(
|
|
depinject.Configs(
|
|
AppConfig,
|
|
depinject.Supply(log.NewNopLogger()),
|
|
),
|
|
simtestutil.DefaultStartUpConfig(),
|
|
&s.AccountKeeper, &s.BankKeeper, &s.DistributionKeeper, &s.StakingKeeper,
|
|
&s.cdc, &s.appBuilder,
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
ctx := s.app.BaseApp.NewContext(false)
|
|
s.addrs = simtestutil.AddTestAddrs(s.BankKeeper, s.StakingKeeper, ctx, 1, valTokens)
|
|
|
|
_, err = s.app.FinalizeBlock(&abci.FinalizeBlockRequest{
|
|
Height: s.app.LastBlockHeight() + 1,
|
|
})
|
|
s.Require().NoError(err)
|
|
}
|
|
|
|
func (s *ImportExportSuite) TestHappyPath() {
|
|
ctx := s.app.NewContext(true)
|
|
// Imagine a situation where rewards were, e.g. 100 / 3 = 33, but the fee collector sent 100 to the distribution module.
|
|
// There're 99 tokens in rewards, but 100 in the module; let's simulate a situation where there are 34 tokens left in the module,
|
|
// and a single validator has 33 tokens of rewards.
|
|
rewards := sdk.NewDecCoinsFromCoins(sdk.NewCoin("stake", sdkmath.NewInt(33)))
|
|
|
|
// We'll pretend s.addrs[0] is the fee collector module.
|
|
err := s.BankKeeper.SendCoinsFromAccountToModule(ctx, s.addrs[0], types.ModuleName, sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(34))))
|
|
s.Require().NoError(err)
|
|
|
|
validators, err := s.StakingKeeper.GetAllValidators(ctx)
|
|
s.Require().NoError(err)
|
|
val := validators[0]
|
|
|
|
err = s.DistributionKeeper.AllocateTokensToValidator(ctx, val, rewards)
|
|
s.Require().NoError(err)
|
|
|
|
_, err = s.app.FinalizeBlock(&abci.FinalizeBlockRequest{
|
|
Height: s.app.LastBlockHeight() + 1,
|
|
})
|
|
s.Require().NoError(err)
|
|
|
|
valBz, err := s.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator())
|
|
s.Require().NoError(err)
|
|
outstanding, err := s.DistributionKeeper.ValidatorOutstandingRewards.Get(ctx, valBz)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(rewards, outstanding.Rewards)
|
|
|
|
genesisState, err := s.app.ModuleManager.ExportGenesis(ctx)
|
|
s.Require().NoError(err)
|
|
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
|
s.Require().NoError(err)
|
|
|
|
db := coretesting.NewMemDB()
|
|
conf2 := simtestutil.DefaultStartUpConfig()
|
|
conf2.DB = db
|
|
app2, err := simtestutil.SetupWithConfiguration(
|
|
depinject.Configs(
|
|
AppConfig,
|
|
depinject.Supply(log.NewNopLogger()),
|
|
),
|
|
conf2,
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
s.clearDB(db)
|
|
err = app2.CommitMultiStore().LoadLatestVersion()
|
|
s.Require().NoError(err)
|
|
|
|
_, err = app2.InitChain(
|
|
&abci.InitChainRequest{
|
|
Validators: []abci.ValidatorUpdate{},
|
|
ConsensusParams: simtestutil.DefaultConsensusParams,
|
|
AppStateBytes: stateBytes,
|
|
},
|
|
)
|
|
s.Require().NoError(err)
|
|
}
|
|
|
|
func (s *ImportExportSuite) TestInsufficientFunds() {
|
|
ctx := s.app.NewContext(true)
|
|
rewards := sdk.NewCoin("stake", sdkmath.NewInt(35))
|
|
|
|
validators, err := s.StakingKeeper.GetAllValidators(ctx)
|
|
s.Require().NoError(err)
|
|
|
|
err = s.DistributionKeeper.AllocateTokensToValidator(ctx, validators[0], sdk.NewDecCoinsFromCoins(rewards))
|
|
s.Require().NoError(err)
|
|
|
|
// We'll pretend s.addrs[0] is the fee collector module.
|
|
err = s.BankKeeper.SendCoinsFromAccountToModule(ctx, s.addrs[0], types.ModuleName, sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(34))))
|
|
s.Require().NoError(err)
|
|
|
|
_, err = s.app.FinalizeBlock(&abci.FinalizeBlockRequest{
|
|
Height: s.app.LastBlockHeight() + 1,
|
|
})
|
|
s.Require().NoError(err)
|
|
|
|
genesisState, err := s.app.ModuleManager.ExportGenesis(ctx)
|
|
s.Require().NoError(err)
|
|
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
|
s.Require().NoError(err)
|
|
|
|
db := coretesting.NewMemDB()
|
|
conf2 := simtestutil.DefaultStartUpConfig()
|
|
conf2.DB = db
|
|
app2, err := simtestutil.SetupWithConfiguration(
|
|
depinject.Configs(
|
|
AppConfig,
|
|
depinject.Supply(log.NewNopLogger()),
|
|
),
|
|
conf2,
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
s.clearDB(db)
|
|
err = app2.CommitMultiStore().LoadLatestVersion()
|
|
s.Require().NoError(err)
|
|
|
|
_, err = app2.InitChain(
|
|
&abci.InitChainRequest{
|
|
Validators: []abci.ValidatorUpdate{},
|
|
ConsensusParams: simtestutil.DefaultConsensusParams,
|
|
AppStateBytes: stateBytes,
|
|
},
|
|
)
|
|
s.Require().ErrorContains(err, "distribution module balance is less than module holdings")
|
|
}
|
|
|
|
func (s *ImportExportSuite) clearDB(db corestore.KVStoreWithBatch) {
|
|
iter, err := db.Iterator(nil, nil)
|
|
s.Require().NoError(err)
|
|
defer iter.Close()
|
|
|
|
var keys [][]byte
|
|
for ; iter.Valid(); iter.Next() {
|
|
keys = append(keys, iter.Key())
|
|
}
|
|
|
|
for _, k := range keys {
|
|
s.Require().NoError(db.Delete(k))
|
|
}
|
|
}
|