Merge PR #4255: Supply Module
This commit is contained in:
parent
4a0fbb3d6e
commit
352678438c
|
@ -0,0 +1,9 @@
|
|||
#4255 Add supply module that passively tracks the supplies of a chain
|
||||
- Introduce `ModuleAccount` type, which tracks the flow of coins held within a module
|
||||
- Replaced `FeeCollectorKeeper` for a `ModuleAccount`
|
||||
- Replaced the staking `Pool`, which coins are now held by the `BondedPool` and `NotBonded` module accounts
|
||||
- The `NotBonded` module account now only keeps track of the not bonded tokens within staking, instead of the whole chain
|
||||
- #3628 Replaced governance's burn and deposit accounts for a `ModuleAccount`
|
||||
- Added a `ModuleAccount` for the distribution module
|
||||
- Added a `ModuleAccount` for the mint module
|
||||
#4472 validation for crisis genesis
|
120
simapp/app.go
120
simapp/app.go
|
@ -15,11 +15,11 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/crisis"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
distrclient "github.com/cosmos/cosmos-sdk/x/distribution/client"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
|
@ -27,6 +27,7 @@ import (
|
|||
paramsclient "github.com/cosmos/cosmos-sdk/x/params/client"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
const appName = "SimApp"
|
||||
|
@ -53,6 +54,7 @@ var (
|
|||
params.AppModuleBasic{},
|
||||
crisis.AppModuleBasic{},
|
||||
slashing.AppModuleBasic{},
|
||||
supply.AppModuleBasic{},
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -73,30 +75,30 @@ type SimApp struct {
|
|||
invCheckPeriod uint
|
||||
|
||||
// keys to access the substores
|
||||
keyMain *sdk.KVStoreKey
|
||||
keyAccount *sdk.KVStoreKey
|
||||
keyStaking *sdk.KVStoreKey
|
||||
tkeyStaking *sdk.TransientStoreKey
|
||||
keySlashing *sdk.KVStoreKey
|
||||
keyMint *sdk.KVStoreKey
|
||||
keyDistr *sdk.KVStoreKey
|
||||
tkeyDistr *sdk.TransientStoreKey
|
||||
keyGov *sdk.KVStoreKey
|
||||
keyFeeCollection *sdk.KVStoreKey
|
||||
keyParams *sdk.KVStoreKey
|
||||
tkeyParams *sdk.TransientStoreKey
|
||||
keyMain *sdk.KVStoreKey
|
||||
keyAccount *sdk.KVStoreKey
|
||||
keySupply *sdk.KVStoreKey
|
||||
keyStaking *sdk.KVStoreKey
|
||||
tkeyStaking *sdk.TransientStoreKey
|
||||
keySlashing *sdk.KVStoreKey
|
||||
keyMint *sdk.KVStoreKey
|
||||
keyDistr *sdk.KVStoreKey
|
||||
tkeyDistr *sdk.TransientStoreKey
|
||||
keyGov *sdk.KVStoreKey
|
||||
keyParams *sdk.KVStoreKey
|
||||
tkeyParams *sdk.TransientStoreKey
|
||||
|
||||
// keepers
|
||||
accountKeeper auth.AccountKeeper
|
||||
feeCollectionKeeper auth.FeeCollectionKeeper
|
||||
bankKeeper bank.Keeper
|
||||
stakingKeeper staking.Keeper
|
||||
slashingKeeper slashing.Keeper
|
||||
mintKeeper mint.Keeper
|
||||
distrKeeper distr.Keeper
|
||||
govKeeper gov.Keeper
|
||||
crisisKeeper crisis.Keeper
|
||||
paramsKeeper params.Keeper
|
||||
accountKeeper auth.AccountKeeper
|
||||
bankKeeper bank.Keeper
|
||||
supplyKeeper supply.Keeper
|
||||
stakingKeeper staking.Keeper
|
||||
slashingKeeper slashing.Keeper
|
||||
mintKeeper mint.Keeper
|
||||
distrKeeper distr.Keeper
|
||||
govKeeper gov.Keeper
|
||||
crisisKeeper crisis.Keeper
|
||||
paramsKeeper params.Keeper
|
||||
|
||||
// the module manager
|
||||
mm *module.Manager
|
||||
|
@ -113,21 +115,21 @@ func NewSimApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bo
|
|||
bApp.SetAppVersion(version.Version)
|
||||
|
||||
var app = &SimApp{
|
||||
BaseApp: bApp,
|
||||
cdc: cdc,
|
||||
invCheckPeriod: invCheckPeriod,
|
||||
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
|
||||
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
|
||||
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
|
||||
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
|
||||
keyMint: sdk.NewKVStoreKey(mint.StoreKey),
|
||||
keyDistr: sdk.NewKVStoreKey(distr.StoreKey),
|
||||
tkeyDistr: sdk.NewTransientStoreKey(distr.TStoreKey),
|
||||
keySlashing: sdk.NewKVStoreKey(slashing.StoreKey),
|
||||
keyGov: sdk.NewKVStoreKey(gov.StoreKey),
|
||||
keyFeeCollection: sdk.NewKVStoreKey(auth.FeeStoreKey),
|
||||
keyParams: sdk.NewKVStoreKey(params.StoreKey),
|
||||
tkeyParams: sdk.NewTransientStoreKey(params.TStoreKey),
|
||||
BaseApp: bApp,
|
||||
cdc: cdc,
|
||||
invCheckPeriod: invCheckPeriod,
|
||||
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
|
||||
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
|
||||
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
|
||||
keySupply: sdk.NewKVStoreKey(supply.StoreKey),
|
||||
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
|
||||
keyMint: sdk.NewKVStoreKey(mint.StoreKey),
|
||||
keyDistr: sdk.NewKVStoreKey(distr.StoreKey),
|
||||
tkeyDistr: sdk.NewTransientStoreKey(distr.TStoreKey),
|
||||
keySlashing: sdk.NewKVStoreKey(slashing.StoreKey),
|
||||
keyGov: sdk.NewKVStoreKey(gov.StoreKey),
|
||||
keyParams: sdk.NewKVStoreKey(params.StoreKey),
|
||||
tkeyParams: sdk.NewTransientStoreKey(params.TStoreKey),
|
||||
}
|
||||
|
||||
// init params keeper and subspaces
|
||||
|
@ -141,19 +143,24 @@ func NewSimApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bo
|
|||
govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace)
|
||||
crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace)
|
||||
|
||||
// account permissions
|
||||
basicModuleAccs := []string{auth.FeeCollectorName, distr.ModuleName}
|
||||
minterModuleAccs := []string{mint.ModuleName}
|
||||
burnerModuleAccs := []string{staking.BondedPoolName, staking.NotBondedPoolName, gov.ModuleName}
|
||||
|
||||
// add keepers
|
||||
app.accountKeeper = auth.NewAccountKeeper(app.cdc, app.keyAccount, authSubspace, auth.ProtoBaseAccount)
|
||||
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, bankSubspace, bank.DefaultCodespace)
|
||||
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(app.cdc, app.keyFeeCollection)
|
||||
stakingKeeper := staking.NewKeeper(app.cdc, app.keyStaking, app.tkeyStaking, app.bankKeeper,
|
||||
stakingSubspace, staking.DefaultCodespace)
|
||||
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint, mintSubspace, &stakingKeeper, app.feeCollectionKeeper)
|
||||
app.distrKeeper = distr.NewKeeper(app.cdc, app.keyDistr, distrSubspace, app.bankKeeper, &stakingKeeper,
|
||||
app.feeCollectionKeeper, distr.DefaultCodespace)
|
||||
app.supplyKeeper = supply.NewKeeper(app.cdc, app.keySupply, app.accountKeeper,
|
||||
app.bankKeeper, supply.DefaultCodespace, basicModuleAccs, minterModuleAccs, burnerModuleAccs)
|
||||
stakingKeeper := staking.NewKeeper(app.cdc, app.keyStaking, app.tkeyStaking,
|
||||
app.supplyKeeper, stakingSubspace, staking.DefaultCodespace)
|
||||
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint, mintSubspace, &stakingKeeper, app.supplyKeeper, auth.FeeCollectorName)
|
||||
app.distrKeeper = distr.NewKeeper(app.cdc, app.keyDistr, distrSubspace, &stakingKeeper,
|
||||
app.supplyKeeper, distr.DefaultCodespace, auth.FeeCollectorName)
|
||||
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, &stakingKeeper,
|
||||
slashingSubspace, slashing.DefaultCodespace)
|
||||
app.crisisKeeper = crisis.NewKeeper(crisisSubspace, invCheckPeriod, app.distrKeeper,
|
||||
app.bankKeeper, app.feeCollectionKeeper)
|
||||
app.crisisKeeper = crisis.NewKeeper(crisisSubspace, invCheckPeriod, app.supplyKeeper, auth.FeeCollectorName)
|
||||
|
||||
// register the proposal types
|
||||
govRouter := gov.NewRouter()
|
||||
|
@ -161,7 +168,7 @@ func NewSimApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bo
|
|||
AddRoute(params.RouterKey, params.NewParamChangeProposalHandler(app.paramsKeeper)).
|
||||
AddRoute(distr.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.distrKeeper))
|
||||
app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper, govSubspace,
|
||||
app.bankKeeper, &stakingKeeper, gov.DefaultCodespace, govRouter)
|
||||
app.supplyKeeper, &stakingKeeper, gov.DefaultCodespace, govRouter)
|
||||
|
||||
// register the staking hooks
|
||||
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
|
||||
|
@ -171,14 +178,15 @@ func NewSimApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bo
|
|||
app.mm = module.NewManager(
|
||||
genaccounts.NewAppModule(app.accountKeeper),
|
||||
genutil.NewAppModule(app.accountKeeper, app.stakingKeeper, app.BaseApp.DeliverTx),
|
||||
auth.NewAppModule(app.accountKeeper, app.feeCollectionKeeper),
|
||||
auth.NewAppModule(app.accountKeeper),
|
||||
bank.NewAppModule(app.bankKeeper, app.accountKeeper),
|
||||
crisis.NewAppModule(app.crisisKeeper),
|
||||
distr.NewAppModule(app.distrKeeper),
|
||||
gov.NewAppModule(app.govKeeper),
|
||||
supply.NewAppModule(app.supplyKeeper, app.accountKeeper),
|
||||
distr.NewAppModule(app.distrKeeper, app.supplyKeeper),
|
||||
gov.NewAppModule(app.govKeeper, app.supplyKeeper),
|
||||
mint.NewAppModule(app.mintKeeper),
|
||||
slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper),
|
||||
staking.NewAppModule(app.stakingKeeper, app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper),
|
||||
staking.NewAppModule(app.stakingKeeper, app.distrKeeper, app.accountKeeper, app.supplyKeeper),
|
||||
)
|
||||
|
||||
// During begin block slashing happens after distr.BeginBlocker so that
|
||||
|
@ -190,7 +198,7 @@ func NewSimApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bo
|
|||
|
||||
// genutils must occur after staking so that pools are properly
|
||||
// initialized with tokens from genesis accounts.
|
||||
app.mm.SetOrderInitGenesis(genaccounts.ModuleName, distr.ModuleName,
|
||||
app.mm.SetOrderInitGenesis(genaccounts.ModuleName, supply.ModuleName, distr.ModuleName,
|
||||
staking.ModuleName, auth.ModuleName, bank.ModuleName, slashing.ModuleName,
|
||||
gov.ModuleName, mint.ModuleName, crisis.ModuleName, genutil.ModuleName)
|
||||
|
||||
|
@ -198,14 +206,14 @@ func NewSimApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bo
|
|||
app.mm.RegisterRoutes(app.Router(), app.QueryRouter())
|
||||
|
||||
// initialize stores
|
||||
app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keyMint,
|
||||
app.keyDistr, app.keySlashing, app.keyGov, app.keyFeeCollection,
|
||||
app.keyParams, app.tkeyParams, app.tkeyStaking, app.tkeyDistr)
|
||||
app.MountStores(app.keyMain, app.keyAccount, app.keySupply, app.keyStaking,
|
||||
app.keyMint, app.keyDistr, app.keySlashing, app.keyGov, app.keyParams,
|
||||
app.tkeyParams, app.tkeyStaking, app.tkeyDistr)
|
||||
|
||||
// initialize BaseApp
|
||||
app.SetInitChainer(app.InitChainer)
|
||||
app.SetBeginBlocker(app.BeginBlocker)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper, auth.DefaultSigVerificationGasConsumer))
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.supplyKeeper, auth.DefaultSigVerificationGasConsumer))
|
||||
app.SetEndBlocker(app.EndBlocker)
|
||||
|
||||
if loadLatest {
|
||||
|
|
|
@ -23,11 +23,11 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
|
||||
authsim "github.com/cosmos/cosmos-sdk/x/auth/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
distrsim "github.com/cosmos/cosmos-sdk/x/distribution/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
|
@ -37,6 +37,7 @@ import (
|
|||
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
stakingsim "github.com/cosmos/cosmos-sdk/x/staking/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -145,6 +146,7 @@ func appStateRandomizedFn(
|
|||
genGenesisAccounts(cdc, r, accs, genesisTimestamp, amount, numInitiallyBonded, genesisState)
|
||||
genAuthGenesisState(cdc, r, appParams, genesisState)
|
||||
genBankGenesisState(cdc, r, appParams, genesisState)
|
||||
genSupplyGenesisState(cdc, amount, numInitiallyBonded, int64(len(accs)), genesisState)
|
||||
genGovGenesisState(cdc, r, appParams, genesisState)
|
||||
genMintGenesisState(cdc, r, appParams, genesisState)
|
||||
genDistrGenesisState(cdc, r, appParams, genesisState)
|
||||
|
@ -192,7 +194,6 @@ func appStateFn(
|
|||
|
||||
func genAuthGenesisState(cdc *codec.Codec, r *rand.Rand, ap simulation.AppParams, genesisState map[string]json.RawMessage) {
|
||||
authGenesis := auth.NewGenesisState(
|
||||
nil,
|
||||
auth.NewParams(
|
||||
func(r *rand.Rand) uint64 {
|
||||
var v uint64
|
||||
|
@ -257,6 +258,16 @@ func genBankGenesisState(cdc *codec.Codec, r *rand.Rand, ap simulation.AppParams
|
|||
genesisState[bank.ModuleName] = cdc.MustMarshalJSON(bankGenesis)
|
||||
}
|
||||
|
||||
func genSupplyGenesisState(cdc *codec.Codec, amount, numInitiallyBonded, numAccs int64, genesisState map[string]json.RawMessage) {
|
||||
totalSupply := sdk.NewInt(amount * (numAccs + numInitiallyBonded))
|
||||
supplyGenesis := supply.NewGenesisState(
|
||||
supply.NewSupply(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, totalSupply))),
|
||||
)
|
||||
|
||||
fmt.Printf("Generated supply parameters:\n%s\n", codec.MustMarshalJSONIndent(cdc, supplyGenesis))
|
||||
genesisState[supply.ModuleName] = cdc.MustMarshalJSON(supplyGenesis)
|
||||
}
|
||||
|
||||
func genGenesisAccounts(
|
||||
cdc *codec.Codec, r *rand.Rand, accs []simulation.Account,
|
||||
genesisTimestamp time.Time, amount, numInitiallyBonded int64,
|
||||
|
@ -517,7 +528,6 @@ func genStakingGenesisState(
|
|||
) staking.GenesisState {
|
||||
|
||||
stakingGenesis := staking.NewGenesisState(
|
||||
staking.InitialPool(),
|
||||
staking.NewParams(
|
||||
func(r *rand.Rand) time.Duration {
|
||||
var v time.Duration
|
||||
|
@ -560,7 +570,6 @@ func genStakingGenesisState(
|
|||
delegations = append(delegations, delegation)
|
||||
}
|
||||
|
||||
stakingGenesis.Pool.NotBondedTokens = sdk.NewInt((amount * numAccs) + (numInitiallyBonded * amount))
|
||||
stakingGenesis.Validators = validators
|
||||
stakingGenesis.Delegations = delegations
|
||||
|
||||
|
@ -593,7 +602,7 @@ func testAndRunTxs(app *SimApp) []simulation.WeightedOperation {
|
|||
})
|
||||
return v
|
||||
}(nil),
|
||||
authsim.SimulateDeductFee(app.accountKeeper, app.feeCollectionKeeper),
|
||||
authsim.SimulateDeductFee(app.accountKeeper, app.supplyKeeper),
|
||||
},
|
||||
{
|
||||
func(_ *rand.Rand) int {
|
||||
|
@ -764,6 +773,11 @@ func testAndRunTxs(app *SimApp) []simulation.WeightedOperation {
|
|||
}
|
||||
|
||||
func invariants(app *SimApp) []sdk.Invariant {
|
||||
// TODO: fix PeriodicInvariants, it doesn't seem to call individual invariants for a period of 1
|
||||
// Ref: https://github.com/cosmos/cosmos-sdk/issues/4631
|
||||
if period == 1 {
|
||||
return app.crisisKeeper.Invariants()
|
||||
}
|
||||
return simulation.PeriodicInvariants(app.crisisKeeper.Invariants(), period, 0)
|
||||
}
|
||||
|
||||
|
@ -896,6 +910,7 @@ func TestAppImportExport(t *testing.T) {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("debug genesisState: %s\n", genesisState)
|
||||
|
||||
ctxB := newApp.NewContext(true, abci.Header{})
|
||||
newApp.mm.InitGenesis(ctxB, genesisState)
|
||||
|
@ -917,7 +932,7 @@ func TestAppImportExport(t *testing.T) {
|
|||
{app.keySlashing, newApp.keySlashing, [][]byte{}},
|
||||
{app.keyMint, newApp.keyMint, [][]byte{}},
|
||||
{app.keyDistr, newApp.keyDistr, [][]byte{}},
|
||||
{app.keyFeeCollection, newApp.keyFeeCollection, [][]byte{}},
|
||||
{app.keySupply, newApp.keySupply, [][]byte{}},
|
||||
{app.keyParams, newApp.keyParams, [][]byte{}},
|
||||
{app.keyGov, newApp.keyGov, [][]byte{}},
|
||||
}
|
||||
|
@ -1074,7 +1089,7 @@ func BenchmarkInvariants(b *testing.B) {
|
|||
for _, cr := range app.crisisKeeper.Routes() {
|
||||
b.Run(fmt.Sprintf("%s/%s", cr.ModuleName, cr.Route), func(b *testing.B) {
|
||||
if err := cr.Invar(ctx); err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Printf("broken invariant at block %d of %d\n%s", ctx.BlockHeight()-1, numBlocks, err)
|
||||
b.FailNow()
|
||||
}
|
||||
})
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
// NewSimAppUNSAFE is used for debugging purposes only.
|
||||
|
@ -57,6 +58,8 @@ func getSimulationLog(storeName string, cdcA, cdcB *codec.Codec, kvA, kvB cmn.KV
|
|||
return decodeGovStore(cdcA, cdcB, kvA, kvB)
|
||||
case distribution.StoreKey:
|
||||
return decodeDistributionStore(cdcA, cdcB, kvA, kvB)
|
||||
case supply.StoreKey:
|
||||
return decodeSupplyStore(cdcA, cdcB, kvA, kvB)
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
@ -254,3 +257,15 @@ func decodeGovStore(cdcA, cdcB *codec.Codec, kvA, kvB cmn.KVPair) string {
|
|||
panic(fmt.Sprintf("invalid governance key prefix %X", kvA.Key[:1]))
|
||||
}
|
||||
}
|
||||
|
||||
func decodeSupplyStore(cdcA, cdcB *codec.Codec, kvA, kvB cmn.KVPair) string {
|
||||
switch {
|
||||
case bytes.Equal(kvA.Key[:1], supply.SupplyKey):
|
||||
var supplyA, supplyB supply.Supply
|
||||
cdcA.MustUnmarshalBinaryLengthPrefixed(kvA.Value, &supplyA)
|
||||
cdcB.MustUnmarshalBinaryLengthPrefixed(kvB.Value, &supplyB)
|
||||
return fmt.Sprintf("%v\n%v", supplyB, supplyB)
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid supply key %X", kvA.Key))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
@ -55,6 +56,7 @@ func TestGetSimulationLog(t *testing.T) {
|
|||
{gov.StoreKey, cmn.KVPair{Key: gov.VoteKey(1, delAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(gov.Vote{})}},
|
||||
{distribution.StoreKey, cmn.KVPair{Key: distr.ProposerKey, Value: consAddr1.Bytes()}},
|
||||
{slashing.StoreKey, cmn.KVPair{Key: slashing.GetValidatorMissedBlockBitArrayKey(consAddr1, 6), Value: cdc.MustMarshalBinaryLengthPrefixed(true)}},
|
||||
{supply.StoreKey, cmn.KVPair{Key: supply.SupplyKey, Value: cdc.MustMarshalBinaryLengthPrefixed(supply.NewSupply(sdk.Coins{}))}},
|
||||
{"Empty", cmn.KVPair{}},
|
||||
{"OtherStore", cmn.KVPair{Key: []byte("key"), Value: []byte("value")}},
|
||||
}
|
||||
|
@ -183,14 +185,12 @@ func TestDecodeStakingStore(t *testing.T) {
|
|||
|
||||
bondTime := time.Now().UTC()
|
||||
|
||||
pool := staking.InitialPool()
|
||||
val := staking.NewValidator(valAddr1, delPk1, staking.NewDescription("test", "test", "test", "test"))
|
||||
del := staking.NewDelegation(delAddr1, valAddr1, sdk.OneDec())
|
||||
ubd := staking.NewUnbondingDelegation(delAddr1, valAddr1, 15, bondTime, sdk.OneInt())
|
||||
red := staking.NewRedelegation(delAddr1, valAddr1, valAddr1, 12, bondTime, sdk.OneInt(), sdk.OneDec())
|
||||
|
||||
kvPairs := cmn.KVPairs{
|
||||
cmn.KVPair{Key: staking.PoolKey, Value: cdc.MustMarshalBinaryLengthPrefixed(pool)},
|
||||
cmn.KVPair{Key: staking.LastTotalPowerKey, Value: cdc.MustMarshalBinaryLengthPrefixed(sdk.OneInt())},
|
||||
cmn.KVPair{Key: staking.GetValidatorKey(valAddr1), Value: cdc.MustMarshalBinaryLengthPrefixed(val)},
|
||||
cmn.KVPair{Key: staking.LastValidatorPowerKey, Value: valAddr1.Bytes()},
|
||||
|
@ -204,7 +204,6 @@ func TestDecodeStakingStore(t *testing.T) {
|
|||
name string
|
||||
expectedLog string
|
||||
}{
|
||||
{"Pool", fmt.Sprintf("%v\n%v", pool, pool)},
|
||||
{"LastTotalPower", fmt.Sprintf("%v\n%v", sdk.OneInt(), sdk.OneInt())},
|
||||
{"Validator", fmt.Sprintf("%v\n%v", val, val)},
|
||||
{"LastValidatorPower/ValidatorsByConsAddr/ValidatorsByPowerIndex", fmt.Sprintf("%v\n%v", valAddr1, valAddr1)},
|
||||
|
@ -302,3 +301,33 @@ func TestDecodeGovStore(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeSupplyStore(t *testing.T) {
|
||||
cdc := makeTestCodec()
|
||||
|
||||
totalSupply := supply.NewSupply(sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000)))
|
||||
|
||||
kvPairs := cmn.KVPairs{
|
||||
cmn.KVPair{Key: supply.SupplyKey, Value: cdc.MustMarshalBinaryLengthPrefixed(totalSupply)},
|
||||
cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expectedLog string
|
||||
}{
|
||||
{"Supply", fmt.Sprintf("%v\n%v", totalSupply, totalSupply)},
|
||||
{"other", ""},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
switch i {
|
||||
case len(tests) - 1:
|
||||
require.Panics(t, func() { decodeSupplyStore(cdc, cdc, kvPairs[i], kvPairs[i]) }, tt.name)
|
||||
default:
|
||||
require.Equal(t, tt.expectedLog, decodeSupplyStore(cdc, cdc, kvPairs[i], kvPairs[i]), tt.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
const (
|
||||
ModuleName = types.ModuleName
|
||||
StoreKey = types.StoreKey
|
||||
FeeStoreKey = types.FeeStoreKey
|
||||
FeeCollectorName = types.FeeCollectorName
|
||||
QuerierRoute = types.QuerierRoute
|
||||
DefaultParamspace = types.DefaultParamspace
|
||||
DefaultMaxMemoCharacters = types.DefaultMaxMemoCharacters
|
||||
|
@ -34,8 +34,6 @@ var (
|
|||
NewDelayedVestingAccountRaw = types.NewDelayedVestingAccountRaw
|
||||
NewDelayedVestingAccount = types.NewDelayedVestingAccount
|
||||
RegisterCodec = types.RegisterCodec
|
||||
RegisterBaseAccount = types.RegisterBaseAccount
|
||||
NewFeeCollectionKeeper = types.NewFeeCollectionKeeper
|
||||
NewGenesisState = types.NewGenesisState
|
||||
DefaultGenesisState = types.DefaultGenesisState
|
||||
ValidateGenesis = types.ValidateGenesis
|
||||
|
@ -43,6 +41,7 @@ var (
|
|||
NewParams = types.NewParams
|
||||
ParamKeyTable = types.ParamKeyTable
|
||||
DefaultParams = types.DefaultParams
|
||||
NewQueryAccountParams = types.NewQueryAccountParams
|
||||
NewStdTx = types.NewStdTx
|
||||
CountSubKeys = types.CountSubKeys
|
||||
NewStdFee = types.NewStdFee
|
||||
|
@ -72,9 +71,9 @@ type (
|
|||
BaseVestingAccount = types.BaseVestingAccount
|
||||
ContinuousVestingAccount = types.ContinuousVestingAccount
|
||||
DelayedVestingAccount = types.DelayedVestingAccount
|
||||
FeeCollectionKeeper = types.FeeCollectionKeeper
|
||||
GenesisState = types.GenesisState
|
||||
Params = types.Params
|
||||
QueryAccountParams = types.QueryAccountParams
|
||||
StdSignMsg = types.StdSignMsg
|
||||
StdTx = types.StdTx
|
||||
StdFee = types.StdFee
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
||||
|
@ -14,6 +13,7 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -35,11 +35,15 @@ type SignatureVerificationGasConsumer = func(meter sdk.GasMeter, sig []byte, pub
|
|||
// NewAnteHandler returns an AnteHandler that checks and increments sequence
|
||||
// numbers, checks signatures & account numbers, and deducts fees from the first
|
||||
// signer.
|
||||
func NewAnteHandler(ak AccountKeeper, fck FeeCollectionKeeper, sigGasConsumer SignatureVerificationGasConsumer) sdk.AnteHandler {
|
||||
func NewAnteHandler(ak AccountKeeper, supplyKeeper types.SupplyKeeper, sigGasConsumer SignatureVerificationGasConsumer) sdk.AnteHandler {
|
||||
return func(
|
||||
ctx sdk.Context, tx sdk.Tx, simulate bool,
|
||||
) (newCtx sdk.Context, res sdk.Result, abort bool) {
|
||||
|
||||
if addr := supplyKeeper.GetModuleAddress(types.FeeCollectorName); addr == nil {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.FeeCollectorName))
|
||||
}
|
||||
|
||||
// all transactions must be of type auth.StdTx
|
||||
stdTx, ok := tx.(StdTx)
|
||||
if !ok {
|
||||
|
@ -112,13 +116,15 @@ func NewAnteHandler(ak AccountKeeper, fck FeeCollectionKeeper, sigGasConsumer Si
|
|||
return newCtx, res, true
|
||||
}
|
||||
|
||||
// deduct the fees
|
||||
if !stdTx.Fee.Amount.IsZero() {
|
||||
signerAccs[0], res = DeductFees(ctx.BlockHeader().Time, signerAccs[0], stdTx.Fee)
|
||||
res = DeductFees(supplyKeeper, newCtx, signerAccs[0], stdTx.Fee.Amount)
|
||||
if !res.IsOK() {
|
||||
return newCtx, res, true
|
||||
}
|
||||
|
||||
fck.AddCollectedFees(newCtx, stdTx.Fee.Amount)
|
||||
// reload the account as fees have been deducted
|
||||
signerAccs[0] = ak.GetAccount(newCtx, signerAccs[0].GetAddress())
|
||||
}
|
||||
|
||||
// stdSigs contains the sequence number, account number, and signatures.
|
||||
|
@ -327,36 +333,37 @@ func consumeMultisignatureVerificationGas(meter sdk.GasMeter,
|
|||
//
|
||||
// NOTE: We could use the CoinKeeper (in addition to the AccountKeeper, because
|
||||
// the CoinKeeper doesn't give us accounts), but it seems easier to do this.
|
||||
func DeductFees(blockTime time.Time, acc Account, fee StdFee) (Account, sdk.Result) {
|
||||
func DeductFees(supplyKeeper types.SupplyKeeper, ctx sdk.Context, acc Account, fees sdk.Coins) sdk.Result {
|
||||
blockTime := ctx.BlockHeader().Time
|
||||
coins := acc.GetCoins()
|
||||
feeAmount := fee.Amount
|
||||
|
||||
if !feeAmount.IsValid() {
|
||||
return nil, sdk.ErrInsufficientFee(fmt.Sprintf("invalid fee amount: %s", feeAmount)).Result()
|
||||
if !fees.IsValid() {
|
||||
return sdk.ErrInsufficientFee(fmt.Sprintf("invalid fee amount: %s", fees)).Result()
|
||||
}
|
||||
|
||||
// get the resulting coins deducting the fees
|
||||
newCoins, ok := coins.SafeSub(feeAmount)
|
||||
if ok {
|
||||
return nil, sdk.ErrInsufficientFunds(
|
||||
fmt.Sprintf("insufficient funds to pay for fees; %s < %s", coins, feeAmount),
|
||||
// verify the account has enough funds to pay for fees
|
||||
_, hasNeg := coins.SafeSub(fees)
|
||||
if hasNeg {
|
||||
return sdk.ErrInsufficientFunds(
|
||||
fmt.Sprintf("insufficient funds to pay for fees; %s < %s", coins, fees),
|
||||
).Result()
|
||||
}
|
||||
|
||||
// Validate the account has enough "spendable" coins as this will cover cases
|
||||
// such as vesting accounts.
|
||||
spendableCoins := acc.SpendableCoins(blockTime)
|
||||
if _, hasNeg := spendableCoins.SafeSub(feeAmount); hasNeg {
|
||||
return nil, sdk.ErrInsufficientFunds(
|
||||
fmt.Sprintf("insufficient funds to pay for fees; %s < %s", spendableCoins, feeAmount),
|
||||
if _, hasNeg := spendableCoins.SafeSub(fees); hasNeg {
|
||||
return sdk.ErrInsufficientFunds(
|
||||
fmt.Sprintf("insufficient funds to pay for fees; %s < %s", spendableCoins, fees),
|
||||
).Result()
|
||||
}
|
||||
|
||||
if err := acc.SetCoins(newCoins); err != nil {
|
||||
return nil, sdk.ErrInternal(err.Error()).Result()
|
||||
err := supplyKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
return acc, sdk.Result{}
|
||||
return sdk.Result{}
|
||||
}
|
||||
|
||||
// EnsureSufficientMempoolFees verifies that the given transaction has supplied
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
// run the tx through the anteHandler and ensure its valid
|
||||
func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, simulate bool) {
|
||||
_, result, abort := anteHandler(ctx, tx, simulate)
|
||||
require.Equal(t, "", result.Log)
|
||||
require.False(t, abort)
|
||||
require.Equal(t, sdk.CodeOK, result.Code)
|
||||
require.True(t, result.IsOK())
|
||||
|
@ -48,7 +49,7 @@ func TestAnteHandlerSigErrors(t *testing.T) {
|
|||
// setup
|
||||
input := setupTestInput()
|
||||
ctx := input.ctx
|
||||
anteHandler := NewAnteHandler(input.ak, input.fck, DefaultSigVerificationGasConsumer)
|
||||
anteHandler := NewAnteHandler(input.ak, input.sk, DefaultSigVerificationGasConsumer)
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := types.KeyTestPubAddr()
|
||||
|
@ -96,7 +97,7 @@ func TestAnteHandlerSigErrors(t *testing.T) {
|
|||
func TestAnteHandlerAccountNumbers(t *testing.T) {
|
||||
// setup
|
||||
input := setupTestInput()
|
||||
anteHandler := NewAnteHandler(input.ak, input.fck, DefaultSigVerificationGasConsumer)
|
||||
anteHandler := NewAnteHandler(input.ak, input.sk, DefaultSigVerificationGasConsumer)
|
||||
ctx := input.ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
|
@ -106,9 +107,11 @@ func TestAnteHandlerAccountNumbers(t *testing.T) {
|
|||
// set the accounts
|
||||
acc1 := input.ak.NewAccountWithAddress(ctx, addr1)
|
||||
acc1.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc1.SetAccountNumber(0))
|
||||
input.ak.SetAccount(ctx, acc1)
|
||||
acc2 := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
acc2.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc2.SetAccountNumber(1))
|
||||
input.ak.SetAccount(ctx, acc2)
|
||||
|
||||
// msg and signatures
|
||||
|
@ -151,19 +154,20 @@ func TestAnteHandlerAccountNumbers(t *testing.T) {
|
|||
func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) {
|
||||
// setup
|
||||
input := setupTestInput()
|
||||
anteHandler := NewAnteHandler(input.ak, input.fck, DefaultSigVerificationGasConsumer)
|
||||
anteHandler := NewAnteHandler(input.ak, input.sk, DefaultSigVerificationGasConsumer)
|
||||
ctx := input.ctx.WithBlockHeight(0)
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := types.KeyTestPubAddr()
|
||||
priv2, _, addr2 := types.KeyTestPubAddr()
|
||||
|
||||
// set the accounts
|
||||
// set the accounts, we don't need the acc numbers as it is in the genesis block
|
||||
acc1 := input.ak.NewAccountWithAddress(ctx, addr1)
|
||||
acc1.SetCoins(types.NewTestCoins())
|
||||
input.ak.SetAccount(ctx, acc1)
|
||||
acc2 := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
acc2.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc2.SetAccountNumber(1))
|
||||
input.ak.SetAccount(ctx, acc2)
|
||||
|
||||
// msg and signatures
|
||||
|
@ -206,7 +210,7 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) {
|
|||
func TestAnteHandlerSequences(t *testing.T) {
|
||||
// setup
|
||||
input := setupTestInput()
|
||||
anteHandler := NewAnteHandler(input.ak, input.fck, DefaultSigVerificationGasConsumer)
|
||||
anteHandler := NewAnteHandler(input.ak, input.sk, DefaultSigVerificationGasConsumer)
|
||||
ctx := input.ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
|
@ -217,12 +221,15 @@ func TestAnteHandlerSequences(t *testing.T) {
|
|||
// set the accounts
|
||||
acc1 := input.ak.NewAccountWithAddress(ctx, addr1)
|
||||
acc1.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc1.SetAccountNumber(0))
|
||||
input.ak.SetAccount(ctx, acc1)
|
||||
acc2 := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
acc2.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc2.SetAccountNumber(1))
|
||||
input.ak.SetAccount(ctx, acc2)
|
||||
acc3 := input.ak.NewAccountWithAddress(ctx, addr3)
|
||||
acc3.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc3.SetAccountNumber(2))
|
||||
input.ak.SetAccount(ctx, acc3)
|
||||
|
||||
// msg and signatures
|
||||
|
@ -281,7 +288,7 @@ func TestAnteHandlerFees(t *testing.T) {
|
|||
// setup
|
||||
input := setupTestInput()
|
||||
ctx := input.ctx
|
||||
anteHandler := NewAnteHandler(input.ak, input.fck, DefaultSigVerificationGasConsumer)
|
||||
anteHandler := NewAnteHandler(input.ak, input.sk, DefaultSigVerificationGasConsumer)
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := types.KeyTestPubAddr()
|
||||
|
@ -305,23 +312,22 @@ func TestAnteHandlerFees(t *testing.T) {
|
|||
input.ak.SetAccount(ctx, acc1)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInsufficientFunds)
|
||||
|
||||
emptyCoins := sdk.NewCoins()
|
||||
require.True(t, input.fck.GetCollectedFees(ctx).IsEqual(emptyCoins))
|
||||
require.True(t, input.ak.GetAccount(ctx, addr1).GetCoins().AmountOf("atom").Equal(sdk.NewInt(149)))
|
||||
require.True(t, input.sk.GetModuleAccount(ctx, types.FeeCollectorName).GetCoins().Empty())
|
||||
require.True(sdk.IntEq(t, input.ak.GetAccount(ctx, addr1).GetCoins().AmountOf("atom"), sdk.NewInt(149)))
|
||||
|
||||
acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 150)))
|
||||
input.ak.SetAccount(ctx, acc1)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
require.True(t, input.fck.GetCollectedFees(ctx).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("atom", 150))))
|
||||
require.True(t, input.ak.GetAccount(ctx, addr1).GetCoins().AmountOf("atom").Equal(sdk.NewInt(0)))
|
||||
require.True(sdk.IntEq(t, input.sk.GetModuleAccount(ctx, types.FeeCollectorName).GetCoins().AmountOf("atom"), sdk.NewInt(150)))
|
||||
require.True(sdk.IntEq(t, input.ak.GetAccount(ctx, addr1).GetCoins().AmountOf("atom"), sdk.NewInt(0)))
|
||||
}
|
||||
|
||||
// Test logic around memo gas consumption.
|
||||
func TestAnteHandlerMemoGas(t *testing.T) {
|
||||
// setup
|
||||
input := setupTestInput()
|
||||
anteHandler := NewAnteHandler(input.ak, input.fck, DefaultSigVerificationGasConsumer)
|
||||
anteHandler := NewAnteHandler(input.ak, input.sk, DefaultSigVerificationGasConsumer)
|
||||
ctx := input.ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
|
@ -329,6 +335,7 @@ func TestAnteHandlerMemoGas(t *testing.T) {
|
|||
|
||||
// set the accounts
|
||||
acc1 := input.ak.NewAccountWithAddress(ctx, addr1)
|
||||
require.NoError(t, acc1.SetAccountNumber(0))
|
||||
input.ak.SetAccount(ctx, acc1)
|
||||
|
||||
// msg and signatures
|
||||
|
@ -360,7 +367,7 @@ func TestAnteHandlerMemoGas(t *testing.T) {
|
|||
func TestAnteHandlerMultiSigner(t *testing.T) {
|
||||
// setup
|
||||
input := setupTestInput()
|
||||
anteHandler := NewAnteHandler(input.ak, input.fck, DefaultSigVerificationGasConsumer)
|
||||
anteHandler := NewAnteHandler(input.ak, input.sk, DefaultSigVerificationGasConsumer)
|
||||
ctx := input.ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
|
@ -371,12 +378,15 @@ func TestAnteHandlerMultiSigner(t *testing.T) {
|
|||
// set the accounts
|
||||
acc1 := input.ak.NewAccountWithAddress(ctx, addr1)
|
||||
acc1.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc1.SetAccountNumber(0))
|
||||
input.ak.SetAccount(ctx, acc1)
|
||||
acc2 := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
acc2.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc2.SetAccountNumber(1))
|
||||
input.ak.SetAccount(ctx, acc2)
|
||||
acc3 := input.ak.NewAccountWithAddress(ctx, addr3)
|
||||
acc3.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc3.SetAccountNumber(2))
|
||||
input.ak.SetAccount(ctx, acc3)
|
||||
|
||||
// set up msgs and fee
|
||||
|
@ -407,7 +417,7 @@ func TestAnteHandlerMultiSigner(t *testing.T) {
|
|||
func TestAnteHandlerBadSignBytes(t *testing.T) {
|
||||
// setup
|
||||
input := setupTestInput()
|
||||
anteHandler := NewAnteHandler(input.ak, input.fck, DefaultSigVerificationGasConsumer)
|
||||
anteHandler := NewAnteHandler(input.ak, input.sk, DefaultSigVerificationGasConsumer)
|
||||
ctx := input.ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
|
@ -417,9 +427,11 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
|||
// set the accounts
|
||||
acc1 := input.ak.NewAccountWithAddress(ctx, addr1)
|
||||
acc1.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc1.SetAccountNumber(0))
|
||||
input.ak.SetAccount(ctx, acc1)
|
||||
acc2 := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
acc2.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc2.SetAccountNumber(1))
|
||||
input.ak.SetAccount(ctx, acc2)
|
||||
|
||||
var tx sdk.Tx
|
||||
|
@ -482,7 +494,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
|||
func TestAnteHandlerSetPubKey(t *testing.T) {
|
||||
// setup
|
||||
input := setupTestInput()
|
||||
anteHandler := NewAnteHandler(input.ak, input.fck, DefaultSigVerificationGasConsumer)
|
||||
anteHandler := NewAnteHandler(input.ak, input.sk, DefaultSigVerificationGasConsumer)
|
||||
ctx := input.ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
|
@ -492,9 +504,11 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
|||
// set the accounts
|
||||
acc1 := input.ak.NewAccountWithAddress(ctx, addr1)
|
||||
acc1.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc1.SetAccountNumber(0))
|
||||
input.ak.SetAccount(ctx, acc1)
|
||||
acc2 := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
acc2.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc2.SetAccountNumber(1))
|
||||
input.ak.SetAccount(ctx, acc2)
|
||||
|
||||
var tx sdk.Tx
|
||||
|
@ -676,7 +690,7 @@ func TestCountSubkeys(t *testing.T) {
|
|||
func TestAnteHandlerSigLimitExceeded(t *testing.T) {
|
||||
// setup
|
||||
input := setupTestInput()
|
||||
anteHandler := NewAnteHandler(input.ak, input.fck, DefaultSigVerificationGasConsumer)
|
||||
anteHandler := NewAnteHandler(input.ak, input.sk, DefaultSigVerificationGasConsumer)
|
||||
ctx := input.ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
|
@ -695,6 +709,7 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) {
|
|||
input.ak.SetAccount(ctx, acc1)
|
||||
acc2 := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
acc2.SetCoins(types.NewTestCoins())
|
||||
require.NoError(t, acc2.SetAccountNumber(1))
|
||||
input.ak.SetAccount(ctx, acc2)
|
||||
|
||||
var tx sdk.Tx
|
||||
|
@ -765,7 +780,7 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) {
|
|||
// setup
|
||||
input := setupTestInput()
|
||||
// setup an ante handler that only accepts PubKeyEd25519
|
||||
anteHandler := NewAnteHandler(input.ak, input.fck, func(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params Params) sdk.Result {
|
||||
anteHandler := NewAnteHandler(input.ak, input.sk, func(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params Params) sdk.Result {
|
||||
switch pubkey := pubkey.(type) {
|
||||
case ed25519.PubKeyEd25519:
|
||||
meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519")
|
||||
|
@ -781,6 +796,7 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) {
|
|||
acc1 := input.ak.NewAccountWithAddress(ctx, addr1)
|
||||
_ = acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 150)))
|
||||
input.ak.SetAccount(ctx, acc1)
|
||||
|
||||
var tx sdk.Tx
|
||||
msg := types.NewTestMsg(addr1)
|
||||
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||
|
@ -794,7 +810,8 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) {
|
|||
pub2 := priv2.PubKey()
|
||||
addr2 := sdk.AccAddress(pub2.Address())
|
||||
acc2 := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
_ = acc2.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 150)))
|
||||
require.NoError(t, acc2.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 150))))
|
||||
require.NoError(t, acc2.SetAccountNumber(1))
|
||||
input.ak.SetAccount(ctx, acc2)
|
||||
msg = types.NewTestMsg(addr2)
|
||||
privs, accnums, seqs = []crypto.PrivKey{priv2}, []uint64{1}, []uint64{0}
|
||||
|
|
|
@ -2,19 +2,18 @@ package auth
|
|||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
// InitGenesis - Init store state from genesis data
|
||||
func InitGenesis(ctx sdk.Context, ak AccountKeeper, fck types.FeeCollectionKeeper, data types.GenesisState) {
|
||||
//
|
||||
// CONTRACT: old coins from the FeeCollectionKeeper need to be transferred through
|
||||
// a genesis port script to the new fee collector account
|
||||
func InitGenesis(ctx sdk.Context, ak AccountKeeper, data GenesisState) {
|
||||
ak.SetParams(ctx, data.Params)
|
||||
fck.AddCollectedFees(ctx, data.CollectedFees)
|
||||
}
|
||||
|
||||
// ExportGenesis returns a GenesisState for a given context and keeper
|
||||
func ExportGenesis(ctx sdk.Context, ak AccountKeeper, fck types.FeeCollectionKeeper) types.GenesisState {
|
||||
collectedFees := fck.GetCollectedFees(ctx)
|
||||
func ExportGenesis(ctx sdk.Context, ak AccountKeeper) GenesisState {
|
||||
params := ak.GetParams(ctx)
|
||||
|
||||
return types.NewGenesisState(collectedFees, params)
|
||||
return NewGenesisState(params)
|
||||
}
|
||||
|
|
|
@ -68,17 +68,14 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command {
|
|||
// app module object
|
||||
type AppModule struct {
|
||||
AppModuleBasic
|
||||
accountKeeper AccountKeeper
|
||||
feeCollectionKeeper types.FeeCollectionKeeper
|
||||
accountKeeper AccountKeeper
|
||||
}
|
||||
|
||||
// NewAppModule creates a new AppModule object
|
||||
func NewAppModule(accountKeeper AccountKeeper,
|
||||
feeCollectionKeeper types.FeeCollectionKeeper) AppModule {
|
||||
func NewAppModule(accountKeeper AccountKeeper) AppModule {
|
||||
return AppModule{
|
||||
AppModuleBasic: AppModuleBasic{},
|
||||
accountKeeper: accountKeeper,
|
||||
feeCollectionKeeper: feeCollectionKeeper,
|
||||
AppModuleBasic: AppModuleBasic{},
|
||||
accountKeeper: accountKeeper,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,15 +105,15 @@ func (am AppModule) NewQuerierHandler() sdk.Querier {
|
|||
|
||||
// module init-genesis
|
||||
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
|
||||
var genesisState types.GenesisState
|
||||
var genesisState GenesisState
|
||||
types.ModuleCdc.MustUnmarshalJSON(data, &genesisState)
|
||||
InitGenesis(ctx, am.accountKeeper, am.feeCollectionKeeper, genesisState)
|
||||
InitGenesis(ctx, am.accountKeeper, genesisState)
|
||||
return []abci.ValidatorUpdate{}
|
||||
}
|
||||
|
||||
// module export genesis
|
||||
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
|
||||
gs := ExportGenesis(ctx, am.accountKeeper, am.feeCollectionKeeper)
|
||||
gs := ExportGenesis(ctx, am.accountKeeper)
|
||||
return types.ModuleCdc.MustMarshalJSON(gs)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,25 +2,32 @@ package simulation
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
)
|
||||
|
||||
// SimulateDeductFee
|
||||
func SimulateDeductFee(m auth.AccountKeeper, f auth.FeeCollectionKeeper) simulation.Operation {
|
||||
func SimulateDeductFee(ak auth.AccountKeeper, supplyKeeper types.SupplyKeeper) simulation.Operation {
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accs []simulation.Account) (
|
||||
opMsg simulation.OperationMsg, fOps []simulation.FutureOperation, err error) {
|
||||
|
||||
account := simulation.RandomAcc(r, accs)
|
||||
stored := m.GetAccount(ctx, account.Address)
|
||||
stored := ak.GetAccount(ctx, account.Address)
|
||||
initCoins := stored.GetCoins()
|
||||
opMsg = simulation.NewOperationMsgBasic(auth.ModuleName, "deduct_fee", "", false, nil)
|
||||
opMsg = simulation.NewOperationMsgBasic(types.ModuleName, "deduct_fee", "", false, nil)
|
||||
|
||||
feeCollector := ak.GetAccount(ctx, supplyKeeper.GetModuleAddress(types.FeeCollectorName))
|
||||
if feeCollector == nil {
|
||||
panic(fmt.Errorf("fee collector account hasn't been set"))
|
||||
}
|
||||
|
||||
if len(initCoins) == 0 {
|
||||
return opMsg, nil, nil
|
||||
|
@ -36,25 +43,23 @@ func SimulateDeductFee(m auth.AccountKeeper, f auth.FeeCollectionKeeper) simulat
|
|||
|
||||
// Create a random fee and verify the fees are within the account's spendable
|
||||
// balance.
|
||||
fees := sdk.Coins{sdk.NewCoin(randCoin.Denom, amt)}
|
||||
fees := sdk.NewCoins(sdk.NewCoin(randCoin.Denom, amt))
|
||||
spendableCoins := stored.SpendableCoins(ctx.BlockHeader().Time)
|
||||
if _, hasNeg := spendableCoins.SafeSub(fees); hasNeg {
|
||||
return opMsg, nil, nil
|
||||
}
|
||||
|
||||
// get the new account balance
|
||||
newCoins, hasNeg := initCoins.SafeSub(fees)
|
||||
_, hasNeg := initCoins.SafeSub(fees)
|
||||
if hasNeg {
|
||||
return opMsg, nil, nil
|
||||
}
|
||||
|
||||
if err := stored.SetCoins(newCoins); err != nil {
|
||||
err = supplyKeeper.SendCoinsFromAccountToModule(ctx, stored.GetAddress(), types.FeeCollectorName, fees)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
m.SetAccount(ctx, stored)
|
||||
f.AddCollectedFees(ctx, fees)
|
||||
|
||||
opMsg.OK = true
|
||||
return opMsg, nil, nil
|
||||
}
|
||||
|
|
|
@ -11,39 +11,104 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/params/subspace"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
supplytypes "github.com/cosmos/cosmos-sdk/x/supply/types"
|
||||
)
|
||||
|
||||
type testInput struct {
|
||||
cdc *codec.Codec
|
||||
ctx sdk.Context
|
||||
ak AccountKeeper
|
||||
fck types.FeeCollectionKeeper
|
||||
sk types.SupplyKeeper
|
||||
}
|
||||
|
||||
func setupTestInput() testInput {
|
||||
db := dbm.NewMemDB()
|
||||
|
||||
cdc := codec.New()
|
||||
types.RegisterBaseAccount(cdc)
|
||||
types.RegisterCodec(cdc)
|
||||
supplytypes.RegisterCodec(cdc)
|
||||
codec.RegisterCrypto(cdc)
|
||||
|
||||
authCapKey := sdk.NewKVStoreKey("authCapKey")
|
||||
fckCapKey := sdk.NewKVStoreKey("fckCapKey")
|
||||
keyParams := sdk.NewKVStoreKey("subspace")
|
||||
tkeyParams := sdk.NewTransientStoreKey("transient_subspace")
|
||||
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(authCapKey, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(fckCapKey, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
|
||||
ms.LoadLatestVersion()
|
||||
|
||||
ps := subspace.NewSubspace(cdc, keyParams, tkeyParams, types.DefaultParamspace)
|
||||
ak := NewAccountKeeper(cdc, authCapKey, ps, types.ProtoBaseAccount)
|
||||
fck := types.NewFeeCollectionKeeper(cdc, fckCapKey)
|
||||
sk := NewDummySupplyKeeper(ak)
|
||||
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "test-chain-id"}, false, log.NewNopLogger())
|
||||
|
||||
ak.SetParams(ctx, types.DefaultParams())
|
||||
|
||||
return testInput{cdc: cdc, ctx: ctx, ak: ak, fck: fck}
|
||||
return testInput{cdc: cdc, ctx: ctx, ak: ak, sk: sk}
|
||||
}
|
||||
|
||||
// DummySupplyKeeper defines a supply keeper used only for testing to avoid
|
||||
// circle dependencies
|
||||
type DummySupplyKeeper struct {
|
||||
ak AccountKeeper
|
||||
}
|
||||
|
||||
// NewDummySupplyKeeper creates a DummySupplyKeeper instance
|
||||
func NewDummySupplyKeeper(ak AccountKeeper) DummySupplyKeeper {
|
||||
return DummySupplyKeeper{ak}
|
||||
}
|
||||
|
||||
// SendCoinsFromAccountToModule for the dummy supply keeper
|
||||
func (sk DummySupplyKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, fromAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error {
|
||||
|
||||
fromAcc := sk.ak.GetAccount(ctx, fromAddr)
|
||||
moduleAcc := sk.GetModuleAccount(ctx, recipientModule)
|
||||
|
||||
newFromCoins, hasNeg := fromAcc.GetCoins().SafeSub(amt)
|
||||
if hasNeg {
|
||||
return sdk.ErrInsufficientCoins(fromAcc.GetCoins().String())
|
||||
}
|
||||
|
||||
newToCoins := moduleAcc.GetCoins().Add(amt)
|
||||
|
||||
if err := fromAcc.SetCoins(newFromCoins); err != nil {
|
||||
return sdk.ErrInternal(err.Error())
|
||||
}
|
||||
|
||||
if err := moduleAcc.SetCoins(newToCoins); err != nil {
|
||||
return sdk.ErrInternal(err.Error())
|
||||
}
|
||||
|
||||
sk.ak.SetAccount(ctx, fromAcc)
|
||||
sk.ak.SetAccount(ctx, moduleAcc)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetModuleAccount for dummy supply keeper
|
||||
func (sk DummySupplyKeeper) GetModuleAccount(ctx sdk.Context, moduleName string) exported.ModuleAccountI {
|
||||
addr := sk.GetModuleAddress(moduleName)
|
||||
|
||||
acc := sk.ak.GetAccount(ctx, addr)
|
||||
if acc != nil {
|
||||
macc, ok := acc.(exported.ModuleAccountI)
|
||||
if ok {
|
||||
return macc
|
||||
}
|
||||
}
|
||||
|
||||
// create a new module account
|
||||
macc := supplytypes.NewEmptyModuleAccount(moduleName, "basic")
|
||||
maccI := (sk.ak.NewAccount(ctx, macc)).(exported.ModuleAccountI)
|
||||
sk.ak.SetAccount(ctx, maccI)
|
||||
return maccI
|
||||
}
|
||||
|
||||
// GetModuleAddress for dummy supply keeper
|
||||
func (sk DummySupplyKeeper) GetModuleAddress(moduleName string) sdk.AccAddress {
|
||||
return supplytypes.NewModuleAddress(moduleName)
|
||||
}
|
||||
|
|
|
@ -8,23 +8,12 @@ import (
|
|||
// RegisterCodec registers concrete types on the codec
|
||||
func RegisterCodec(cdc *codec.Codec) {
|
||||
cdc.RegisterInterface((*exported.Account)(nil), nil)
|
||||
cdc.RegisterConcrete(&BaseAccount{}, "cosmos-sdk/Account", nil)
|
||||
cdc.RegisterInterface((*exported.VestingAccount)(nil), nil)
|
||||
cdc.RegisterConcrete(&BaseAccount{}, "auth/Account", nil)
|
||||
cdc.RegisterConcrete(&BaseVestingAccount{}, "auth/BaseVestingAccount", nil)
|
||||
cdc.RegisterConcrete(&ContinuousVestingAccount{}, "auth/ContinuousVestingAccount", nil)
|
||||
cdc.RegisterConcrete(&DelayedVestingAccount{}, "auth/DelayedVestingAccount", nil)
|
||||
cdc.RegisterConcrete(StdTx{}, "auth/StdTx", nil)
|
||||
}
|
||||
|
||||
// RegisterBaseAccount most users shouldn't use this, but this comes in handy for tests.
|
||||
func RegisterBaseAccount(cdc *codec.Codec) {
|
||||
cdc.RegisterInterface((*exported.Account)(nil), nil)
|
||||
cdc.RegisterInterface((*exported.VestingAccount)(nil), nil)
|
||||
cdc.RegisterConcrete(&BaseAccount{}, "cosmos-sdk/BaseAccount", nil)
|
||||
cdc.RegisterConcrete(&BaseVestingAccount{}, "cosmos-sdk/BaseVestingAccount", nil)
|
||||
cdc.RegisterConcrete(&ContinuousVestingAccount{}, "cosmos-sdk/ContinuousVestingAccount", nil)
|
||||
cdc.RegisterConcrete(&DelayedVestingAccount{}, "cosmos-sdk/DelayedVestingAccount", nil)
|
||||
codec.RegisterCrypto(cdc)
|
||||
cdc.RegisterConcrete(StdTx{}, "cosmos-sdk/StdTx", nil)
|
||||
}
|
||||
|
||||
// module wide codec
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
)
|
||||
|
||||
// SupplyKeeper defines the expected supply Keeper (noalias)
|
||||
type SupplyKeeper interface {
|
||||
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error
|
||||
GetModuleAccount(ctx sdk.Context, moduleName string) exported.ModuleAccountI
|
||||
GetModuleAddress(moduleName string) sdk.AccAddress
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
codec "github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
var (
|
||||
collectedFeesKey = []byte("collectedFees")
|
||||
)
|
||||
|
||||
// FeeCollectionKeeper handles collection of fees in the anteHandler
|
||||
// and setting of MinFees for different fee tokens
|
||||
type FeeCollectionKeeper struct {
|
||||
|
||||
// The (unexposed) key used to access the fee store from the Context.
|
||||
key sdk.StoreKey
|
||||
|
||||
// The codec codec for binary encoding/decoding of accounts.
|
||||
cdc *codec.Codec
|
||||
}
|
||||
|
||||
// NewFeeCollectionKeeper returns a new FeeCollectionKeeper
|
||||
func NewFeeCollectionKeeper(cdc *codec.Codec, key sdk.StoreKey) FeeCollectionKeeper {
|
||||
return FeeCollectionKeeper{
|
||||
key: key,
|
||||
cdc: cdc,
|
||||
}
|
||||
}
|
||||
|
||||
// GetCollectedFees - retrieves the collected fee pool
|
||||
func (fck FeeCollectionKeeper) GetCollectedFees(ctx sdk.Context) sdk.Coins {
|
||||
store := ctx.KVStore(fck.key)
|
||||
bz := store.Get(collectedFeesKey)
|
||||
if bz == nil {
|
||||
return sdk.NewCoins()
|
||||
}
|
||||
|
||||
emptyFees := sdk.NewCoins()
|
||||
feePool := &emptyFees
|
||||
fck.cdc.MustUnmarshalBinaryLengthPrefixed(bz, feePool)
|
||||
return *feePool
|
||||
}
|
||||
|
||||
func (fck FeeCollectionKeeper) setCollectedFees(ctx sdk.Context, coins sdk.Coins) {
|
||||
bz := fck.cdc.MustMarshalBinaryLengthPrefixed(coins)
|
||||
store := ctx.KVStore(fck.key)
|
||||
store.Set(collectedFeesKey, bz)
|
||||
}
|
||||
|
||||
// AddCollectedFees - add to the fee pool
|
||||
func (fck FeeCollectionKeeper) AddCollectedFees(ctx sdk.Context, coins sdk.Coins) sdk.Coins {
|
||||
newCoins := fck.GetCollectedFees(ctx).Add(coins)
|
||||
fck.setCollectedFees(ctx, newCoins)
|
||||
|
||||
return newCoins
|
||||
}
|
||||
|
||||
// ClearCollectedFees - clear the fee pool
|
||||
func (fck FeeCollectionKeeper) ClearCollectedFees(ctx sdk.Context) {
|
||||
fck.setCollectedFees(ctx, sdk.NewCoins())
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
var (
|
||||
emptyCoins = sdk.NewCoins()
|
||||
oneCoin = sdk.NewCoins(sdk.NewInt64Coin("foocoin", 1))
|
||||
twoCoins = sdk.NewCoins(sdk.NewInt64Coin("foocoin", 2))
|
||||
)
|
||||
|
||||
func TestFeeCollectionKeeperGetSet(t *testing.T) {
|
||||
input := setupTestInput()
|
||||
ctx := input.ctx
|
||||
|
||||
// no coins initially
|
||||
currFees := input.fck.GetCollectedFees(ctx)
|
||||
require.True(t, currFees.IsEqual(emptyCoins))
|
||||
|
||||
// set feeCollection to oneCoin
|
||||
input.fck.setCollectedFees(ctx, oneCoin)
|
||||
|
||||
// check that it is equal to oneCoin
|
||||
require.True(t, input.fck.GetCollectedFees(ctx).IsEqual(oneCoin))
|
||||
}
|
||||
|
||||
func TestFeeCollectionKeeperAdd(t *testing.T) {
|
||||
input := setupTestInput()
|
||||
ctx := input.ctx
|
||||
|
||||
// no coins initially
|
||||
require.True(t, input.fck.GetCollectedFees(ctx).IsEqual(emptyCoins))
|
||||
|
||||
// add oneCoin and check that pool is now oneCoin
|
||||
input.fck.AddCollectedFees(ctx, oneCoin)
|
||||
require.True(t, input.fck.GetCollectedFees(ctx).IsEqual(oneCoin))
|
||||
|
||||
// add oneCoin again and check that pool is now twoCoins
|
||||
input.fck.AddCollectedFees(ctx, oneCoin)
|
||||
require.True(t, input.fck.GetCollectedFees(ctx).IsEqual(twoCoins))
|
||||
}
|
||||
|
||||
func TestFeeCollectionKeeperClear(t *testing.T) {
|
||||
input := setupTestInput()
|
||||
ctx := input.ctx
|
||||
|
||||
// set coins initially
|
||||
input.fck.setCollectedFees(ctx, twoCoins)
|
||||
require.True(t, input.fck.GetCollectedFees(ctx).IsEqual(twoCoins))
|
||||
|
||||
// clear fees and see that pool is now empty
|
||||
input.fck.ClearCollectedFees(ctx)
|
||||
require.True(t, input.fck.GetCollectedFees(ctx).IsEqual(emptyCoins))
|
||||
}
|
|
@ -2,27 +2,21 @@ package types
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// GenesisState - all auth state that must be provided at genesis
|
||||
type GenesisState struct {
|
||||
CollectedFees sdk.Coins `json:"collected_fees"`
|
||||
Params Params `json:"params"`
|
||||
Params Params `json:"params"`
|
||||
}
|
||||
|
||||
// NewGenesisState - Create a new genesis state
|
||||
func NewGenesisState(collectedFees sdk.Coins, params Params) GenesisState {
|
||||
return GenesisState{
|
||||
CollectedFees: collectedFees,
|
||||
Params: params,
|
||||
}
|
||||
func NewGenesisState(params Params) GenesisState {
|
||||
return GenesisState{params}
|
||||
}
|
||||
|
||||
// DefaultGenesisState - Return a default genesis state
|
||||
func DefaultGenesisState() GenesisState {
|
||||
return NewGenesisState(sdk.NewCoins(), DefaultParams())
|
||||
return NewGenesisState(DefaultParams())
|
||||
}
|
||||
|
||||
// ValidateGenesis performs basic validation of auth genesis data returning an
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package types
|
||||
|
||||
import sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// module name
|
||||
|
@ -9,8 +11,8 @@ const (
|
|||
// StoreKey is string representation of the store key for auth
|
||||
StoreKey = "acc"
|
||||
|
||||
// FeeStoreKey is a string representation of the store key for fees
|
||||
FeeStoreKey = "fee"
|
||||
// FeeCollectorName the root string for the fee collector account address
|
||||
FeeCollectorName = "FeeCollector"
|
||||
|
||||
// QuerierRoute is the querier route for acc
|
||||
QuerierRoute = StoreKey
|
||||
|
|
|
@ -2,49 +2,12 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
//DONTCOVER
|
||||
|
||||
type testInput struct {
|
||||
cdc *codec.Codec
|
||||
ctx sdk.Context
|
||||
fck FeeCollectionKeeper
|
||||
}
|
||||
|
||||
func setupTestInput() testInput {
|
||||
db := dbm.NewMemDB()
|
||||
|
||||
cdc := codec.New()
|
||||
RegisterBaseAccount(cdc)
|
||||
|
||||
authCapKey := sdk.NewKVStoreKey("authCapKey")
|
||||
fckCapKey := sdk.NewKVStoreKey("fckCapKey")
|
||||
keyParams := sdk.NewKVStoreKey("subspace")
|
||||
tkeyParams := sdk.NewTransientStoreKey("transient_subspace")
|
||||
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(authCapKey, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(fckCapKey, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
|
||||
ms.LoadLatestVersion()
|
||||
|
||||
fck := NewFeeCollectionKeeper(cdc, fckCapKey)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "test-chain-id"}, false, log.NewNopLogger())
|
||||
|
||||
return testInput{cdc: cdc, ctx: ctx, fck: fck}
|
||||
}
|
||||
|
||||
func NewTestMsg(addrs ...sdk.AccAddress) *sdk.TestMsg {
|
||||
return sdk.NewTestMsg(addrs...)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/bank/internal/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/internal/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
supplytypes "github.com/cosmos/cosmos-sdk/x/supply/types"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
|
@ -92,6 +93,7 @@ var (
|
|||
// initialize the mock application for this module
|
||||
func getMockApp(t *testing.T) *mock.App {
|
||||
mapp, err := getBenchmarkMockApp()
|
||||
supplytypes.RegisterCodec(mapp.Cdc)
|
||||
require.NoError(t, err)
|
||||
return mapp
|
||||
}
|
||||
|
@ -274,12 +276,14 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) {
|
|||
func TestMsgMultiSendDependent(t *testing.T) {
|
||||
mapp := getMockApp(t)
|
||||
|
||||
acc1 := &auth.BaseAccount{
|
||||
Address: addr1,
|
||||
Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)},
|
||||
}
|
||||
acc1 := auth.NewBaseAccountWithAddress(addr1)
|
||||
acc2 := auth.NewBaseAccountWithAddress(addr2)
|
||||
err := acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42)))
|
||||
require.NoError(t, err)
|
||||
err = acc2.SetAccountNumber(1)
|
||||
require.NoError(t, err)
|
||||
|
||||
mock.SetGenesis(mapp, []auth.Account{acc1})
|
||||
mock.SetGenesis(mapp, []auth.Account{&acc1, &acc2})
|
||||
|
||||
testCases := []appTestCase{
|
||||
{
|
||||
|
|
|
@ -24,8 +24,8 @@ type Keeper interface {
|
|||
AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error)
|
||||
InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) sdk.Error
|
||||
|
||||
DelegateCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error
|
||||
UndelegateCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error
|
||||
DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) sdk.Error
|
||||
UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) sdk.Error
|
||||
}
|
||||
|
||||
// BaseKeeper manages transfers between accounts. It implements the Keeper interface.
|
||||
|
@ -53,10 +53,6 @@ func NewBaseKeeper(ak types.AccountKeeper,
|
|||
func (keeper BaseKeeper) SetCoins(
|
||||
ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins,
|
||||
) sdk.Error {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
return setCoins(ctx, keeper.ak, addr, amt)
|
||||
}
|
||||
|
||||
|
@ -64,10 +60,6 @@ func (keeper BaseKeeper) SetCoins(
|
|||
func (keeper BaseKeeper) SubtractCoins(
|
||||
ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins,
|
||||
) (sdk.Coins, sdk.Error) {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
return subtractCoins(ctx, keeper.ak, addr, amt)
|
||||
}
|
||||
|
||||
|
@ -75,10 +67,6 @@ func (keeper BaseKeeper) SubtractCoins(
|
|||
func (keeper BaseKeeper) AddCoins(
|
||||
ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins,
|
||||
) (sdk.Coins, sdk.Error) {
|
||||
|
||||
if !amt.IsValid() {
|
||||
return nil, sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
return addCoins(ctx, keeper.ak, addr, amt)
|
||||
}
|
||||
|
||||
|
@ -90,22 +78,95 @@ func (keeper BaseKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input,
|
|||
// DelegateCoins performs delegation by deducting amt coins from an account with
|
||||
// address addr. For vesting accounts, delegations amounts are tracked for both
|
||||
// vesting and vested coins.
|
||||
func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error {
|
||||
// The coins are then transferred from the delegator address to a ModuleAccount address.
|
||||
// If any of the delegation amounts are negative, an error is returned.
|
||||
func (keeper BaseKeeper) DelegateCoins(
|
||||
ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins,
|
||||
) sdk.Error {
|
||||
|
||||
delegatorAcc := getAccount(ctx, keeper.ak, delegatorAddr)
|
||||
if delegatorAcc == nil {
|
||||
return sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", delegatorAddr))
|
||||
}
|
||||
|
||||
moduleAcc := getAccount(ctx, keeper.ak, moduleAccAddr)
|
||||
if moduleAcc == nil {
|
||||
return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", moduleAccAddr))
|
||||
}
|
||||
|
||||
if !amt.IsValid() {
|
||||
return sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
return delegateCoins(ctx, keeper.ak, addr, amt)
|
||||
|
||||
oldCoins := delegatorAcc.GetCoins()
|
||||
|
||||
_, hasNeg := oldCoins.SafeSub(amt)
|
||||
if hasNeg {
|
||||
return sdk.ErrInsufficientCoins(
|
||||
fmt.Sprintf("insufficient account funds; %s < %s", oldCoins, amt),
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: return error on account.TrackDelegation
|
||||
if err := trackDelegation(delegatorAcc, ctx.BlockHeader().Time, amt); err != nil {
|
||||
return sdk.ErrInternal(fmt.Sprintf("failed to track delegation: %v", err))
|
||||
}
|
||||
|
||||
setAccount(ctx, keeper.ak, delegatorAcc)
|
||||
|
||||
_, err := addCoins(ctx, keeper.ak, moduleAccAddr, amt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UndelegateCoins performs undelegation by crediting amt coins to an account with
|
||||
// address addr. For vesting accounts, undelegation amounts are tracked for both
|
||||
// vesting and vested coins.
|
||||
// The coins are then transferred from a ModuleAccount address to the delegator address.
|
||||
// If any of the undelegation amounts are negative, an error is returned.
|
||||
func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error {
|
||||
func (keeper BaseKeeper) UndelegateCoins(
|
||||
ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins,
|
||||
) sdk.Error {
|
||||
|
||||
delegatorAcc := getAccount(ctx, keeper.ak, delegatorAddr)
|
||||
if delegatorAcc == nil {
|
||||
return sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", delegatorAddr))
|
||||
}
|
||||
|
||||
moduleAcc := getAccount(ctx, keeper.ak, moduleAccAddr)
|
||||
if moduleAcc == nil {
|
||||
return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", moduleAccAddr))
|
||||
}
|
||||
|
||||
if !amt.IsValid() {
|
||||
return sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
return undelegateCoins(ctx, keeper.ak, addr, amt)
|
||||
|
||||
oldCoins := moduleAcc.GetCoins()
|
||||
|
||||
newCoins, hasNeg := oldCoins.SafeSub(amt)
|
||||
if hasNeg {
|
||||
return sdk.ErrInsufficientCoins(
|
||||
fmt.Sprintf("insufficient account funds; %s < %s", oldCoins, amt),
|
||||
)
|
||||
}
|
||||
|
||||
err := setCoins(ctx, keeper.ak, moduleAccAddr, newCoins)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: return error on account.TrackUndelegation
|
||||
if err := trackUndelegation(delegatorAcc, amt); err != nil {
|
||||
return sdk.ErrInternal(fmt.Sprintf("failed to track undelegation: %v", err))
|
||||
}
|
||||
|
||||
setAccount(ctx, keeper.ak, delegatorAcc)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendKeeper defines a module interface that facilitates the transfer of coins
|
||||
|
@ -141,6 +202,7 @@ func NewBaseSendKeeper(ak types.AccountKeeper,
|
|||
}
|
||||
}
|
||||
|
||||
// TODO combine with sendCoins
|
||||
// SendCoins moves coins from one account to another
|
||||
func (keeper BaseSendKeeper) SendCoins(
|
||||
ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins,
|
||||
|
@ -199,6 +261,11 @@ func NewBaseViewKeeper(ak types.AccountKeeper, codespace sdk.CodespaceType) Base
|
|||
return BaseViewKeeper{ak: ak, codespace: codespace}
|
||||
}
|
||||
|
||||
// Logger returns a module-specific logger.
|
||||
func (keeper BaseViewKeeper) Logger(ctx sdk.Context) log.Logger {
|
||||
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
|
||||
}
|
||||
|
||||
// GetCoins returns the coins at the addr.
|
||||
func (keeper BaseViewKeeper) GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins {
|
||||
return getCoins(ctx, keeper.ak, addr)
|
||||
|
@ -214,13 +281,9 @@ func (keeper BaseViewKeeper) Codespace() sdk.CodespaceType {
|
|||
return keeper.codespace
|
||||
}
|
||||
|
||||
// Logger returns a module-specific logger.
|
||||
func (keeper BaseViewKeeper) Logger(ctx sdk.Context) log.Logger {
|
||||
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
|
||||
}
|
||||
|
||||
func getCoins(ctx sdk.Context, ak types.AccountKeeper, addr sdk.AccAddress) sdk.Coins {
|
||||
acc := ak.GetAccount(ctx, addr)
|
||||
// getCoins returns the account coins
|
||||
func getCoins(ctx sdk.Context, am types.AccountKeeper, addr sdk.AccAddress) sdk.Coins {
|
||||
acc := am.GetAccount(ctx, addr)
|
||||
if acc == nil {
|
||||
return sdk.NewCoins()
|
||||
}
|
||||
|
@ -252,10 +315,12 @@ func hasCoins(ctx sdk.Context, ak types.AccountKeeper, addr sdk.AccAddress, amt
|
|||
return getCoins(ctx, ak, addr).IsAllGTE(amt)
|
||||
}
|
||||
|
||||
// getAccount implements AccountKeeper
|
||||
func getAccount(ctx sdk.Context, ak types.AccountKeeper, addr sdk.AccAddress) exported.Account {
|
||||
return ak.GetAccount(ctx, addr)
|
||||
}
|
||||
|
||||
// setAccount implements AccountKeeper
|
||||
func setAccount(ctx sdk.Context, ak types.AccountKeeper, acc exported.Account) {
|
||||
ak.SetAccount(ctx, acc)
|
||||
}
|
||||
|
@ -313,11 +378,7 @@ func addCoins(ctx sdk.Context, ak types.AccountKeeper, addr sdk.AccAddress, amt
|
|||
|
||||
// SendCoins moves coins from one account to another
|
||||
// Returns ErrInvalidCoins if amt is invalid.
|
||||
func sendCoins(ctx sdk.Context, ak types.AccountKeeper, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error {
|
||||
// Safety check ensuring that when sending coins the keeper must maintain the
|
||||
if !amt.IsValid() {
|
||||
return sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
func sendCoins(ctx sdk.Context, ak types.AccountKeeper, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error {
|
||||
|
||||
_, err := subtractCoins(ctx, ak, fromAddr, amt)
|
||||
if err != nil {
|
||||
|
@ -372,51 +433,6 @@ func inputOutputCoins(ctx sdk.Context, ak types.AccountKeeper, inputs []types.In
|
|||
return nil
|
||||
}
|
||||
|
||||
func delegateCoins(ctx sdk.Context, ak types.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins) sdk.Error {
|
||||
if !amt.IsValid() {
|
||||
return sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
|
||||
acc := getAccount(ctx, ak, addr)
|
||||
if acc == nil {
|
||||
return sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr))
|
||||
}
|
||||
|
||||
oldCoins := acc.GetCoins()
|
||||
|
||||
_, hasNeg := oldCoins.SafeSub(amt)
|
||||
if hasNeg {
|
||||
return sdk.ErrInsufficientCoins(
|
||||
fmt.Sprintf("insufficient account funds; %s < %s", oldCoins, amt),
|
||||
)
|
||||
}
|
||||
|
||||
if err := trackDelegation(acc, ctx.BlockHeader().Time, amt); err != nil {
|
||||
return sdk.ErrInternal(fmt.Sprintf("failed to track delegation: %v", err))
|
||||
}
|
||||
|
||||
setAccount(ctx, ak, acc)
|
||||
return nil
|
||||
}
|
||||
|
||||
func undelegateCoins(ctx sdk.Context, ak types.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins) sdk.Error {
|
||||
if !amt.IsValid() {
|
||||
return sdk.ErrInvalidCoins(amt.String())
|
||||
}
|
||||
|
||||
acc := getAccount(ctx, ak, addr)
|
||||
if acc == nil {
|
||||
return sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr))
|
||||
}
|
||||
|
||||
if err := trackUndelegation(acc, amt); err != nil {
|
||||
return sdk.ErrInternal(fmt.Sprintf("failed to track undelegation: %v", err))
|
||||
}
|
||||
|
||||
setAccount(ctx, ak, acc)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CONTRACT: assumes that amt is valid.
|
||||
func trackDelegation(acc exported.Account, blockTime time.Time, amt sdk.Coins) error {
|
||||
vacc, ok := acc.(exported.VestingAccount)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
@ -30,16 +31,15 @@ func setupTestInput() testInput {
|
|||
db := dbm.NewMemDB()
|
||||
|
||||
cdc := codec.New()
|
||||
auth.RegisterBaseAccount(cdc)
|
||||
auth.RegisterCodec(cdc)
|
||||
codec.RegisterCrypto(cdc)
|
||||
|
||||
authCapKey := sdk.NewKVStoreKey("authCapKey")
|
||||
fckCapKey := sdk.NewKVStoreKey("fckCapKey")
|
||||
keyParams := sdk.NewKVStoreKey("params")
|
||||
tkeyParams := sdk.NewTransientStoreKey("transient_params")
|
||||
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(authCapKey, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(fckCapKey, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
|
||||
ms.LoadLatestVersion()
|
||||
|
@ -283,25 +283,30 @@ func TestDelegateCoins(t *testing.T) {
|
|||
|
||||
addr1 := sdk.AccAddress([]byte("addr1"))
|
||||
addr2 := sdk.AccAddress([]byte("addr2"))
|
||||
addrModule := sdk.AccAddress([]byte("moduleAcc"))
|
||||
|
||||
bacc := auth.NewBaseAccountWithAddress(addr1)
|
||||
bacc.SetCoins(origCoins)
|
||||
macc := input.ak.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing
|
||||
vacc := auth.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix())
|
||||
acc := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
input.ak.SetAccount(ctx, vacc)
|
||||
input.ak.SetAccount(ctx, acc)
|
||||
input.ak.SetAccount(ctx, macc)
|
||||
input.k.SetCoins(ctx, addr2, origCoins)
|
||||
|
||||
ctx = ctx.WithBlockTime(now.Add(12 * time.Hour))
|
||||
|
||||
// require the ability for a non-vesting account to delegate
|
||||
err := input.k.DelegateCoins(ctx, addr2, delCoins)
|
||||
err := input.k.DelegateCoins(ctx, addr2, addrModule, delCoins)
|
||||
acc = input.ak.GetAccount(ctx, addr2)
|
||||
macc = input.ak.GetAccount(ctx, addrModule)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, delCoins, acc.GetCoins())
|
||||
require.Equal(t, origCoins.Sub(delCoins), acc.GetCoins())
|
||||
require.Equal(t, delCoins, macc.GetCoins())
|
||||
|
||||
// require the ability for a vesting account to delegate
|
||||
err = input.k.DelegateCoins(ctx, addr1, delCoins)
|
||||
err = input.k.DelegateCoins(ctx, addr1, addrModule, delCoins)
|
||||
vacc = input.ak.GetAccount(ctx, addr1).(*auth.ContinuousVestingAccount)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, delCoins, vacc.GetCoins())
|
||||
|
@ -318,36 +323,53 @@ func TestUndelegateCoins(t *testing.T) {
|
|||
|
||||
addr1 := sdk.AccAddress([]byte("addr1"))
|
||||
addr2 := sdk.AccAddress([]byte("addr2"))
|
||||
addrModule := sdk.AccAddress([]byte("moduleAcc"))
|
||||
|
||||
bacc := auth.NewBaseAccountWithAddress(addr1)
|
||||
bacc.SetCoins(origCoins)
|
||||
macc := input.ak.NewAccountWithAddress(ctx, addrModule) // we don't need to define an actual module account bc we just need the address for testing
|
||||
vacc := auth.NewContinuousVestingAccount(&bacc, ctx.BlockHeader().Time.Unix(), endTime.Unix())
|
||||
acc := input.ak.NewAccountWithAddress(ctx, addr2)
|
||||
input.ak.SetAccount(ctx, vacc)
|
||||
input.ak.SetAccount(ctx, acc)
|
||||
input.ak.SetAccount(ctx, macc)
|
||||
input.k.SetCoins(ctx, addr2, origCoins)
|
||||
|
||||
ctx = ctx.WithBlockTime(now.Add(12 * time.Hour))
|
||||
|
||||
// require the ability for a non-vesting account to delegate
|
||||
err := input.k.DelegateCoins(ctx, addr2, delCoins)
|
||||
require.NoError(t, err)
|
||||
|
||||
// require the ability for a non-vesting account to undelegate
|
||||
err = input.k.UndelegateCoins(ctx, addr2, delCoins)
|
||||
err := input.k.DelegateCoins(ctx, addr2, addrModule, delCoins)
|
||||
require.NoError(t, err)
|
||||
|
||||
acc = input.ak.GetAccount(ctx, addr2)
|
||||
require.Equal(t, origCoins, acc.GetCoins())
|
||||
macc = input.ak.GetAccount(ctx, addrModule)
|
||||
require.Equal(t, origCoins.Sub(delCoins), acc.GetCoins())
|
||||
require.Equal(t, delCoins, macc.GetCoins())
|
||||
|
||||
// require the ability for a vesting account to delegate
|
||||
err = input.k.DelegateCoins(ctx, addr1, delCoins)
|
||||
// require the ability for a non-vesting account to undelegate
|
||||
err = input.k.UndelegateCoins(ctx, addrModule, addr2, delCoins)
|
||||
require.NoError(t, err)
|
||||
|
||||
// require the ability for a vesting account to undelegate
|
||||
err = input.k.UndelegateCoins(ctx, addr1, delCoins)
|
||||
acc = input.ak.GetAccount(ctx, addr2)
|
||||
macc = input.ak.GetAccount(ctx, addrModule)
|
||||
require.Equal(t, origCoins, acc.GetCoins())
|
||||
require.True(t, macc.GetCoins().Empty())
|
||||
|
||||
// require the ability for a vesting account to delegate
|
||||
err = input.k.DelegateCoins(ctx, addr1, addrModule, delCoins)
|
||||
require.NoError(t, err)
|
||||
|
||||
vacc = input.ak.GetAccount(ctx, addr1).(*auth.ContinuousVestingAccount)
|
||||
macc = input.ak.GetAccount(ctx, addrModule)
|
||||
require.Equal(t, origCoins.Sub(delCoins), vacc.GetCoins())
|
||||
require.Equal(t, delCoins, macc.GetCoins())
|
||||
|
||||
// require the ability for a vesting account to undelegate
|
||||
err = input.k.UndelegateCoins(ctx, addrModule, addr1, delCoins)
|
||||
require.NoError(t, err)
|
||||
|
||||
vacc = input.ak.GetAccount(ctx, addr1).(*auth.ContinuousVestingAccount)
|
||||
macc = input.ak.GetAccount(ctx, addrModule)
|
||||
require.Equal(t, origCoins, vacc.GetCoins())
|
||||
require.True(t, macc.GetCoins().Empty())
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
// query balance path
|
||||
QueryBalance = "balances"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
package crisis
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// expected bank keeper
|
||||
type DistrKeeper interface {
|
||||
DistributeFeePool(ctx sdk.Context, amount sdk.Coins, receiveAddr sdk.AccAddress) sdk.Error
|
||||
}
|
||||
|
||||
// expected fee collection keeper
|
||||
type FeeCollectionKeeper interface {
|
||||
AddCollectedFees(ctx sdk.Context, coins sdk.Coins) sdk.Coins
|
||||
}
|
||||
|
||||
// expected bank keeper
|
||||
type BankKeeper interface {
|
||||
SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error)
|
||||
}
|
|
@ -29,13 +29,11 @@ func handleMsgVerifyInvariant(ctx sdk.Context, msg types.MsgVerifyInvariant, k K
|
|||
// remove the constant fee
|
||||
constantFee := sdk.NewCoins(k.GetConstantFee(ctx))
|
||||
|
||||
_, err := k.bankKeeper.SubtractCoins(ctx, msg.Sender, constantFee)
|
||||
err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, msg.Sender, k.feeCollectorName, constantFee)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
_ = k.feeCollectionKeeper.AddCollectedFees(ctx, constantFee)
|
||||
|
||||
// use a cached context to avoid gas costs during invariants
|
||||
cacheCtx, _ := ctx.CacheContext()
|
||||
|
||||
|
@ -62,7 +60,7 @@ func handleMsgVerifyInvariant(ctx sdk.Context, msg types.MsgVerifyInvariant, k K
|
|||
|
||||
// TODO uncomment the following code block with implementation of the circuit breaker
|
||||
//// refund constant fee
|
||||
//err := k.distrKeeper.DistributeFeePool(ctx, constantFee, msg.Sender)
|
||||
//err := k.distrKeeper.DistributeFromFeePool(ctx, constantFee, msg.Sender)
|
||||
//if err != nil {
|
||||
//// if there are insufficient coins to refund, log the error,
|
||||
//// but still halt the chain.
|
||||
|
|
|
@ -24,11 +24,11 @@ var (
|
|||
func CreateTestInput(t *testing.T) (sdk.Context, Keeper, auth.AccountKeeper, distr.Keeper) {
|
||||
|
||||
communityTax := sdk.NewDecWithPrec(2, 2)
|
||||
ctx, accKeeper, bankKeeper, distrKeeper, _, feeCollectionKeeper, paramsKeeper :=
|
||||
ctx, accKeeper, _, distrKeeper, _, paramsKeeper, supplyKeeper :=
|
||||
distr.CreateTestInputAdvanced(t, false, 10, communityTax)
|
||||
|
||||
paramSpace := paramsKeeper.Subspace(DefaultParamspace)
|
||||
crisisKeeper := NewKeeper(paramSpace, 1, distrKeeper, bankKeeper, feeCollectionKeeper)
|
||||
crisisKeeper := NewKeeper(paramSpace, 1, supplyKeeper, auth.FeeCollectorName)
|
||||
constantFee := sdk.NewInt64Coin("stake", 10000000)
|
||||
crisisKeeper.SetConstantFee(ctx, constantFee)
|
||||
|
||||
|
|
|
@ -17,23 +17,21 @@ type Keeper struct {
|
|||
paramSpace params.Subspace
|
||||
invCheckPeriod uint
|
||||
|
||||
distrKeeper DistrKeeper
|
||||
bankKeeper BankKeeper
|
||||
feeCollectionKeeper FeeCollectionKeeper
|
||||
supplyKeeper types.SupplyKeeper
|
||||
|
||||
feeCollectorName string // name of the FeeCollector ModuleAccount
|
||||
}
|
||||
|
||||
// NewKeeper creates a new Keeper object
|
||||
func NewKeeper(paramSpace params.Subspace, invCheckPeriod uint,
|
||||
distrKeeper DistrKeeper, bankKeeper BankKeeper,
|
||||
feeCollectionKeeper FeeCollectionKeeper) Keeper {
|
||||
supplyKeeper types.SupplyKeeper, feeCollectorName string) Keeper {
|
||||
|
||||
return Keeper{
|
||||
routes: []types.InvarRoute{},
|
||||
paramSpace: paramSpace.WithKeyTable(types.ParamKeyTable()),
|
||||
invCheckPeriod: invCheckPeriod,
|
||||
distrKeeper: distrKeeper,
|
||||
bankKeeper: bankKeeper,
|
||||
feeCollectionKeeper: feeCollectionKeeper,
|
||||
routes: []types.InvarRoute{},
|
||||
paramSpace: paramSpace.WithKeyTable(types.ParamKeyTable()),
|
||||
invCheckPeriod: invCheckPeriod,
|
||||
supplyKeeper: supplyKeeper,
|
||||
feeCollectorName: feeCollectorName,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +40,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
|
|||
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
|
||||
}
|
||||
|
||||
// register routes for the
|
||||
// RegisterRoute register the routes for each of the invariants
|
||||
func (k *Keeper) RegisterRoute(moduleName, route string, invar sdk.Invariant) {
|
||||
invarRoute := types.NewInvarRoute(moduleName, route, invar)
|
||||
k.routes = append(k.routes, invarRoute)
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/x/crisis/client/cli"
|
||||
"github.com/cosmos/cosmos-sdk/x/crisis/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -37,13 +38,16 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
|
|||
|
||||
// default genesis state
|
||||
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
|
||||
return ModuleCdc.MustMarshalJSON(DefaultGenesisState())
|
||||
return types.ModuleCdc.MustMarshalJSON(DefaultGenesisState())
|
||||
}
|
||||
|
||||
// module validate genesis
|
||||
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
|
||||
// TODO
|
||||
return nil
|
||||
var data types.GenesisState
|
||||
if err := types.ModuleCdc.UnmarshalJSON(bz, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
return types.ValidateGenesis(data)
|
||||
}
|
||||
|
||||
// register rest routes
|
||||
|
@ -99,7 +103,7 @@ func (AppModule) NewQuerierHandler() sdk.Querier { return nil }
|
|||
// module init-genesis
|
||||
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
|
||||
var genesisState GenesisState
|
||||
ModuleCdc.MustUnmarshalJSON(data, &genesisState)
|
||||
types.ModuleCdc.MustUnmarshalJSON(data, &genesisState)
|
||||
InitGenesis(ctx, am.keeper, genesisState)
|
||||
|
||||
am.keeper.AssertInvariants(ctx)
|
||||
|
@ -109,7 +113,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.Va
|
|||
// module export genesis
|
||||
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
|
||||
gs := ExportGenesis(ctx, am.keeper)
|
||||
return ModuleCdc.MustMarshalJSON(gs)
|
||||
return types.ModuleCdc.MustMarshalJSON(gs)
|
||||
}
|
||||
|
||||
// module begin-block
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// SupplyKeeper defines the expected supply keeper (noalias)
|
||||
type SupplyKeeper interface {
|
||||
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
|
@ -22,3 +24,11 @@ func DefaultGenesisState() GenesisState {
|
|||
ConstantFee: sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)),
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateGenesis - validate crisis genesis data
|
||||
func ValidateGenesis(data GenesisState) error {
|
||||
if !data.ConstantFee.IsPositive() {
|
||||
return fmt.Errorf("constant fee must be positive: %s", data.ConstantFee)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ var (
|
|||
NonNegativeOutstandingInvariant = keeper.NonNegativeOutstandingInvariant
|
||||
CanWithdrawInvariant = keeper.CanWithdrawInvariant
|
||||
ReferenceCountInvariant = keeper.ReferenceCountInvariant
|
||||
ModuleAccountInvariant = keeper.ModuleAccountInvariant
|
||||
NewKeeper = keeper.NewKeeper
|
||||
GetValidatorOutstandingRewardsAddress = keeper.GetValidatorOutstandingRewardsAddress
|
||||
GetDelegatorWithdrawInfoAddress = keeper.GetDelegatorWithdrawInfoAddress
|
||||
|
@ -127,13 +128,8 @@ var (
|
|||
type (
|
||||
Hooks = keeper.Hooks
|
||||
Keeper = keeper.Keeper
|
||||
DummyFeeCollectionKeeper = keeper.DummyFeeCollectionKeeper
|
||||
DelegatorStartingInfo = types.DelegatorStartingInfo
|
||||
CodeType = types.CodeType
|
||||
StakingKeeper = types.StakingKeeper
|
||||
StakingHooks = types.StakingHooks
|
||||
BankKeeper = types.BankKeeper
|
||||
FeeCollectionKeeper = types.FeeCollectionKeeper
|
||||
FeePool = types.FeePool
|
||||
DelegatorWithdrawInfo = types.DelegatorWithdrawInfo
|
||||
ValidatorOutstandingRewardsRecord = types.ValidatorOutstandingRewardsRecord
|
||||
|
|
|
@ -1,23 +1,29 @@
|
|||
package distribution
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
// InitGenesis sets distribution information for genesis
|
||||
func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
|
||||
func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper, data types.GenesisState) {
|
||||
var moduleHoldings sdk.DecCoins
|
||||
|
||||
keeper.SetFeePool(ctx, data.FeePool)
|
||||
keeper.SetCommunityTax(ctx, data.CommunityTax)
|
||||
keeper.SetBaseProposerReward(ctx, data.BaseProposerReward)
|
||||
keeper.SetBonusProposerReward(ctx, data.BonusProposerReward)
|
||||
keeper.SetWithdrawAddrEnabled(ctx, data.WithdrawAddrEnabled)
|
||||
|
||||
for _, dwi := range data.DelegatorWithdrawInfos {
|
||||
keeper.SetDelegatorWithdrawAddr(ctx, dwi.DelegatorAddress, dwi.WithdrawAddress)
|
||||
}
|
||||
keeper.SetPreviousProposerConsAddr(ctx, data.PreviousProposer)
|
||||
for _, rew := range data.OutstandingRewards {
|
||||
keeper.SetValidatorOutstandingRewards(ctx, rew.ValidatorAddress, rew.OutstandingRewards)
|
||||
moduleHoldings = moduleHoldings.Add(rew.OutstandingRewards)
|
||||
}
|
||||
for _, acc := range data.ValidatorAccumulatedCommissions {
|
||||
keeper.SetValidatorAccumulatedCommission(ctx, acc.ValidatorAddress, acc.Accumulated)
|
||||
|
@ -34,6 +40,22 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
|
|||
for _, evt := range data.ValidatorSlashEvents {
|
||||
keeper.SetValidatorSlashEvent(ctx, evt.ValidatorAddress, evt.Height, evt.Event)
|
||||
}
|
||||
|
||||
moduleHoldings = moduleHoldings.Add(data.FeePool.CommunityPool)
|
||||
moduleHoldingsInt, _ := moduleHoldings.TruncateDecimal()
|
||||
|
||||
// check if the module account exists
|
||||
moduleAcc := keeper.GetDistributionAccount(ctx)
|
||||
if moduleAcc == nil {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
|
||||
}
|
||||
|
||||
if moduleAcc.GetCoins().IsZero() {
|
||||
if err := moduleAcc.SetCoins(moduleHoldingsInt); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
supplyKeeper.SetModuleAccount(ctx, moduleAcc)
|
||||
}
|
||||
}
|
||||
|
||||
// ExportGenesis returns a GenesisState for a given context and keeper.
|
||||
|
|
|
@ -2,6 +2,8 @@ package keeper
|
|||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
)
|
||||
|
||||
// get outstanding rewards
|
||||
|
@ -13,3 +15,8 @@ func (k Keeper) GetValidatorOutstandingRewardsCoins(ctx sdk.Context, val sdk.Val
|
|||
func (k Keeper) GetFeePoolCommunityCoins(ctx sdk.Context) sdk.DecCoins {
|
||||
return k.GetFeePool(ctx).CommunityPool
|
||||
}
|
||||
|
||||
// GetDistributionAccount returns the distribution ModuleAccount
|
||||
func (k Keeper) GetDistributionAccount(ctx sdk.Context) exported.ModuleAccountI {
|
||||
return k.supplyKeeper.GetModuleAccount(ctx, types.ModuleName)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/staking/exported"
|
||||
)
|
||||
|
||||
// allocate fees handles distribution of the collected fees
|
||||
// AllocateTokens handles distribution of the collected fees
|
||||
func (k Keeper) AllocateTokens(
|
||||
ctx sdk.Context, sumPreviousPrecommitPower, totalPreviousPower int64,
|
||||
previousProposer sdk.ConsAddress, previousVotes []abci.VoteInfo,
|
||||
|
@ -21,9 +21,15 @@ func (k Keeper) AllocateTokens(
|
|||
// fetch and clear the collected fees for distribution, since this is
|
||||
// called in BeginBlock, collected fees will be from the previous block
|
||||
// (and distributed to the previous proposer)
|
||||
feesCollectedInt := k.feeCollectionKeeper.GetCollectedFees(ctx)
|
||||
feeCollector := k.supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName)
|
||||
feesCollectedInt := feeCollector.GetCoins()
|
||||
feesCollected := sdk.NewDecCoins(feesCollectedInt)
|
||||
k.feeCollectionKeeper.ClearCollectedFees(ctx)
|
||||
|
||||
// transfer collected fees to the distribution module account
|
||||
err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, k.feeCollectorName, types.ModuleName, feesCollectedInt)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// temporary workaround to keep CanWithdrawInvariant happy
|
||||
// general discussions here: https://github.com/cosmos/cosmos-sdk/issues/2906#issuecomment-441867634
|
||||
|
|
|
@ -38,7 +38,7 @@ func TestAllocateTokensToValidatorWithCommission(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAllocateTokensToManyValidators(t *testing.T) {
|
||||
ctx, _, k, sk, fck := CreateTestInputDefault(t, false, 1000)
|
||||
ctx, ak, k, sk, supplyKeeper := CreateTestInputDefault(t, false, 1000)
|
||||
sh := staking.NewHandler(sk)
|
||||
|
||||
// create validator with 50% commission
|
||||
|
@ -72,10 +72,14 @@ func TestAllocateTokensToManyValidators(t *testing.T) {
|
|||
require.True(t, k.GetValidatorCurrentRewards(ctx, valOpAddr2).Rewards.IsZero())
|
||||
|
||||
// allocate tokens as if both had voted and second was proposer
|
||||
fees := sdk.Coins{
|
||||
{sdk.DefaultBondDenom, sdk.NewInt(100)},
|
||||
}
|
||||
fck.SetCollectedFees(fees)
|
||||
fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)))
|
||||
feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName)
|
||||
require.NotNil(t, feeCollector)
|
||||
|
||||
err := feeCollector.SetCoins(fees)
|
||||
require.NoError(t, err)
|
||||
ak.SetAccount(ctx, feeCollector)
|
||||
|
||||
votes := []abci.VoteInfo{
|
||||
{
|
||||
Validator: abciValA,
|
||||
|
@ -105,7 +109,7 @@ func TestAllocateTokensToManyValidators(t *testing.T) {
|
|||
|
||||
func TestAllocateTokensTruncation(t *testing.T) {
|
||||
communityTax := sdk.NewDec(0)
|
||||
ctx, _, _, k, sk, fck, _ := CreateTestInputAdvanced(t, false, 1000000, communityTax)
|
||||
ctx, ak, _, k, sk, _, supplyKeeper := CreateTestInputAdvanced(t, false, 1000000, communityTax)
|
||||
sh := staking.NewHandler(sk)
|
||||
|
||||
// create validator with 10% commission
|
||||
|
@ -150,10 +154,16 @@ func TestAllocateTokensTruncation(t *testing.T) {
|
|||
require.True(t, k.GetValidatorCurrentRewards(ctx, valOpAddr2).Rewards.IsZero())
|
||||
|
||||
// allocate tokens as if both had voted and second was proposer
|
||||
fees := sdk.Coins{
|
||||
sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(634195840)),
|
||||
}
|
||||
fck.SetCollectedFees(fees)
|
||||
fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(634195840)))
|
||||
|
||||
feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName)
|
||||
require.NotNil(t, feeCollector)
|
||||
|
||||
err := feeCollector.SetCoins(fees)
|
||||
require.NoError(t, err)
|
||||
|
||||
ak.SetAccount(ctx, feeCollector)
|
||||
|
||||
votes := []abci.VoteInfo{
|
||||
{
|
||||
Validator: abciValA,
|
||||
|
|
|
@ -173,7 +173,8 @@ func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val exported.Validato
|
|||
// add coins to user account
|
||||
if !coins.IsZero() {
|
||||
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, del.GetDelegatorAddr())
|
||||
if _, err := k.bankKeeper.AddCoins(ctx, withdrawAddr, coins); err != nil {
|
||||
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, withdrawAddr, coins)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -266,6 +266,11 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) {
|
|||
ctx, ak, k, sk, _ := CreateTestInputDefault(t, false, balancePower)
|
||||
sh := staking.NewHandler(sk)
|
||||
|
||||
// set module account coins
|
||||
distrAcc := k.GetDistributionAccount(ctx)
|
||||
distrAcc.SetCoins(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens)))
|
||||
k.supplyKeeper.SetModuleAccount(ctx, distrAcc)
|
||||
|
||||
// create validator with 50% commission
|
||||
power := int64(100)
|
||||
valTokens := sdk.TokensFromConsensusPower(power)
|
||||
|
@ -473,8 +478,13 @@ func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) {
|
|||
func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) {
|
||||
ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000)
|
||||
sh := staking.NewHandler(sk)
|
||||
|
||||
initial := int64(20)
|
||||
|
||||
// set module account coins
|
||||
distrAcc := k.GetDistributionAccount(ctx)
|
||||
distrAcc.SetCoins(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000))))
|
||||
k.supplyKeeper.SetModuleAccount(ctx, distrAcc)
|
||||
|
||||
totalRewards := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDec(initial*2))}
|
||||
tokens := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDec(initial))}
|
||||
|
||||
|
|
|
@ -5,17 +5,21 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
// DistributeFeePool distributes funds from the the community pool to a receiver address
|
||||
func (k Keeper) DistributeFeePool(ctx sdk.Context, amount sdk.Coins, receiveAddr sdk.AccAddress) sdk.Error {
|
||||
// DistributeFromFeePool distributes funds from the distribution module account to
|
||||
// a receiver address while updating the community pool
|
||||
func (k Keeper) DistributeFromFeePool(ctx sdk.Context, amount sdk.Coins, receiveAddr sdk.AccAddress) sdk.Error {
|
||||
feePool := k.GetFeePool(ctx)
|
||||
|
||||
poolTruncated, _ := feePool.CommunityPool.TruncateDecimal()
|
||||
if !poolTruncated.IsAllGTE(amount) {
|
||||
// NOTE the community pool isn't a module account, however its coins
|
||||
// are held in the distribution module account. Thus the community pool
|
||||
// must be reduced separately from the SendCoinsFromModuleToAccount call
|
||||
newPool, negative := feePool.CommunityPool.SafeSub(sdk.NewDecCoins(amount))
|
||||
if negative {
|
||||
return types.ErrBadDistribution(k.codespace)
|
||||
}
|
||||
feePool.CommunityPool = newPool
|
||||
|
||||
feePool.CommunityPool.Sub(sdk.NewDecCoins(amount))
|
||||
_, err := k.bankKeeper.AddCoins(ctx, receiveAddr, amount)
|
||||
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, receiveAddr, amount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@ package keeper
|
|||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
)
|
||||
|
||||
// Wrapper struct
|
||||
|
@ -10,7 +11,7 @@ type Hooks struct {
|
|||
k Keeper
|
||||
}
|
||||
|
||||
var _ types.StakingHooks = Hooks{}
|
||||
var _ stakingtypes.StakingHooks = Hooks{}
|
||||
|
||||
// Create new distribution hooks
|
||||
func (k Keeper) Hooks() Hooks { return Hooks{k} }
|
||||
|
@ -46,8 +47,8 @@ func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr
|
|||
|
||||
accAddr := sdk.AccAddress(valAddr)
|
||||
withdrawAddr := h.k.GetDelegatorWithdrawAddr(ctx, accAddr)
|
||||
|
||||
if _, err := h.k.bankKeeper.AddCoins(ctx, withdrawAddr, coins); err != nil {
|
||||
err := h.k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, withdrawAddr, coins)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
|
|||
CanWithdrawInvariant(k))
|
||||
ir.RegisterRoute(types.ModuleName, "reference-count",
|
||||
ReferenceCountInvariant(k))
|
||||
ir.RegisterRoute(types.ModuleName, "module-account",
|
||||
ModuleAccountInvariant(k))
|
||||
}
|
||||
|
||||
// AllInvariants runs all invariants of the distribution module
|
||||
|
@ -33,7 +35,7 @@ func AllInvariants(k Keeper) sdk.Invariant {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return ModuleAccountInvariant(k)(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,3 +137,29 @@ func ReferenceCountInvariant(k Keeper) sdk.Invariant {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ModuleAccountInvariant checks that the coins held by the distr ModuleAccount
|
||||
// is consistent with the sum of validator outstanding rewards
|
||||
func ModuleAccountInvariant(k Keeper) sdk.Invariant {
|
||||
return func(ctx sdk.Context) error {
|
||||
|
||||
var expectedCoins sdk.DecCoins
|
||||
k.IterateValidatorOutstandingRewards(ctx, func(_ sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) {
|
||||
expectedCoins = expectedCoins.Add(rewards)
|
||||
return false
|
||||
})
|
||||
|
||||
communityPool := k.GetFeePoolCommunityCoins(ctx)
|
||||
expectedInt, _ := expectedCoins.Add(communityPool).TruncateDecimal()
|
||||
|
||||
macc := k.GetDistributionAccount(ctx)
|
||||
|
||||
if !macc.GetCoins().IsEqual(expectedInt) {
|
||||
return fmt.Errorf("distribution ModuleAccount coins invariance:\n"+
|
||||
"\texpected ModuleAccount coins: %s\n"+
|
||||
"\tdistribution ModuleAccount coins : %s", expectedInt, macc.GetCoins())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,32 +11,39 @@ import (
|
|||
"github.com/tendermint/tendermint/libs/log"
|
||||
)
|
||||
|
||||
// keeper of the staking store
|
||||
// Keeper of the distribution store
|
||||
type Keeper struct {
|
||||
storeKey sdk.StoreKey
|
||||
cdc *codec.Codec
|
||||
paramSpace params.Subspace
|
||||
bankKeeper types.BankKeeper
|
||||
stakingKeeper types.StakingKeeper
|
||||
feeCollectionKeeper types.FeeCollectionKeeper
|
||||
storeKey sdk.StoreKey
|
||||
cdc *codec.Codec
|
||||
paramSpace params.Subspace
|
||||
stakingKeeper types.StakingKeeper
|
||||
supplyKeeper types.SupplyKeeper
|
||||
|
||||
// codespace
|
||||
codespace sdk.CodespaceType
|
||||
|
||||
feeCollectorName string // name of the FeeCollector ModuleAccount
|
||||
}
|
||||
|
||||
// create a new keeper
|
||||
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, ck types.BankKeeper,
|
||||
sk types.StakingKeeper, fck types.FeeCollectionKeeper, codespace sdk.CodespaceType) Keeper {
|
||||
keeper := Keeper{
|
||||
storeKey: key,
|
||||
cdc: cdc,
|
||||
paramSpace: paramSpace.WithKeyTable(ParamKeyTable()),
|
||||
bankKeeper: ck,
|
||||
stakingKeeper: sk,
|
||||
feeCollectionKeeper: fck,
|
||||
codespace: codespace,
|
||||
// NewKeeper creates a new distribution Keeper instance
|
||||
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace,
|
||||
sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, codespace sdk.CodespaceType,
|
||||
feeCollectorName string) Keeper {
|
||||
|
||||
// ensure distribution module account is set
|
||||
if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
|
||||
}
|
||||
|
||||
return Keeper{
|
||||
storeKey: key,
|
||||
cdc: cdc,
|
||||
paramSpace: paramSpace.WithKeyTable(ParamKeyTable()),
|
||||
stakingKeeper: sk,
|
||||
supplyKeeper: supplyKeeper,
|
||||
codespace: codespace,
|
||||
feeCollectorName: feeCollectorName,
|
||||
}
|
||||
return keeper
|
||||
}
|
||||
|
||||
// Logger returns a module-specific logger.
|
||||
|
@ -110,8 +117,8 @@ func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddr
|
|||
if !commission.IsZero() {
|
||||
accAddr := sdk.AccAddress(valAddr)
|
||||
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, accAddr)
|
||||
|
||||
if _, err := k.bankKeeper.AddCoins(ctx, withdrawAddr, commission); err != nil {
|
||||
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, withdrawAddr, commission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -125,3 +132,14 @@ func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddr
|
|||
|
||||
return commission, nil
|
||||
}
|
||||
|
||||
// GetTotalRewards returns the total amount of fee distribution rewards held in the store
|
||||
func (k Keeper) GetTotalRewards(ctx sdk.Context) (totalRewards sdk.DecCoins) {
|
||||
k.IterateValidatorOutstandingRewards(ctx,
|
||||
func(_ sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) {
|
||||
totalRewards = totalRewards.Add(rewards)
|
||||
return false
|
||||
},
|
||||
)
|
||||
return totalRewards
|
||||
}
|
||||
|
|
|
@ -30,12 +30,19 @@ func TestWithdrawValidatorCommission(t *testing.T) {
|
|||
sdk.NewDecCoinFromDec("stake", sdk.NewDec(3).Quo(sdk.NewDec(2))),
|
||||
}
|
||||
|
||||
// set module account coins
|
||||
distrAcc := keeper.GetDistributionAccount(ctx)
|
||||
distrAcc.SetCoins(sdk.NewCoins(
|
||||
sdk.NewCoin("mytoken", sdk.NewInt(2)),
|
||||
sdk.NewCoin("stake", sdk.NewInt(2)),
|
||||
))
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, distrAcc)
|
||||
|
||||
// check initial balance
|
||||
balance := ak.GetAccount(ctx, sdk.AccAddress(valOpAddr3)).GetCoins()
|
||||
expTokens := sdk.TokensFromConsensusPower(1000)
|
||||
require.Equal(t, sdk.Coins{
|
||||
sdk.NewCoin("stake", sdk.TokensFromConsensusPower(1000)),
|
||||
}, balance)
|
||||
expCoins := sdk.NewCoins(sdk.NewCoin("stake", expTokens))
|
||||
require.Equal(t, expCoins, balance)
|
||||
|
||||
// set outstanding rewards
|
||||
keeper.SetValidatorOutstandingRewards(ctx, valOpAddr3, valCommission)
|
||||
|
@ -48,10 +55,10 @@ func TestWithdrawValidatorCommission(t *testing.T) {
|
|||
|
||||
// check balance increase
|
||||
balance = ak.GetAccount(ctx, sdk.AccAddress(valOpAddr3)).GetCoins()
|
||||
require.Equal(t, sdk.Coins{
|
||||
require.Equal(t, sdk.NewCoins(
|
||||
sdk.NewCoin("mytoken", sdk.NewInt(1)),
|
||||
sdk.NewCoin("stake", expTokens.AddRaw(1)),
|
||||
}, balance)
|
||||
), balance)
|
||||
|
||||
// check remainder
|
||||
remainder := keeper.GetValidatorAccumulatedCommission(ctx, valOpAddr3)
|
||||
|
@ -62,3 +69,20 @@ func TestWithdrawValidatorCommission(t *testing.T) {
|
|||
|
||||
require.True(t, true)
|
||||
}
|
||||
|
||||
func TestGetTotalRewards(t *testing.T) {
|
||||
ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 1000)
|
||||
|
||||
valCommission := sdk.DecCoins{
|
||||
sdk.NewDecCoinFromDec("mytoken", sdk.NewDec(5).Quo(sdk.NewDec(4))),
|
||||
sdk.NewDecCoinFromDec("stake", sdk.NewDec(3).Quo(sdk.NewDec(2))),
|
||||
}
|
||||
|
||||
keeper.SetValidatorOutstandingRewards(ctx, valOpAddr1, valCommission)
|
||||
keeper.SetValidatorOutstandingRewards(ctx, valOpAddr2, valCommission)
|
||||
|
||||
expectedRewards := valCommission.MulDec(sdk.NewDec(2))
|
||||
totalRewards := keeper.GetTotalRewards(ctx)
|
||||
|
||||
require.Equal(t, expectedRewards, totalRewards)
|
||||
}
|
||||
|
|
|
@ -7,20 +7,14 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
// Handler for executing a passed community spend proposal
|
||||
// HandleCommunityPoolSpendProposal is a handler for executing a passed community spend proposal
|
||||
func HandleCommunityPoolSpendProposal(ctx sdk.Context, k Keeper, p types.CommunityPoolSpendProposal) sdk.Error {
|
||||
feePool := k.GetFeePool(ctx)
|
||||
newPool, negative := feePool.CommunityPool.SafeSub(sdk.NewDecCoins(p.Amount))
|
||||
if negative {
|
||||
return types.ErrBadDistribution(k.codespace)
|
||||
}
|
||||
feePool.CommunityPool = newPool
|
||||
k.SetFeePool(ctx, feePool)
|
||||
_, err := k.bankKeeper.AddCoins(ctx, p.Recipient, p.Amount)
|
||||
err := k.DistributeFromFeePool(ctx, p.Amount, p.Recipient)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger := k.Logger(ctx)
|
||||
logger.Info(fmt.Sprintf("Spent %s coins from the community pool to recipient %s", p.Amount, p.Recipient))
|
||||
logger.Info(fmt.Sprintf("transferred %s from the community pool to recipient %s", p.Amount, p.Recipient))
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
const custom = "custom"
|
||||
|
@ -138,6 +139,7 @@ func getQueriedCommunityPool(t *testing.T, ctx sdk.Context, cdc *codec.Codec, qu
|
|||
func TestQueries(t *testing.T) {
|
||||
cdc := codec.New()
|
||||
types.RegisterCodec(cdc)
|
||||
supply.RegisterCodec(cdc)
|
||||
ctx, _, keeper, sk, _ := CreateTestInputDefault(t, false, 100)
|
||||
querier := NewQuerier(keeper)
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
@ -66,6 +67,7 @@ func MakeTestCodec() *codec.Codec {
|
|||
bank.RegisterCodec(cdc)
|
||||
staking.RegisterCodec(cdc)
|
||||
auth.RegisterCodec(cdc)
|
||||
supply.RegisterCodec(cdc)
|
||||
sdk.RegisterCodec(cdc)
|
||||
codec.RegisterCrypto(cdc)
|
||||
|
||||
|
@ -75,26 +77,26 @@ func MakeTestCodec() *codec.Codec {
|
|||
|
||||
// test input with default values
|
||||
func CreateTestInputDefault(t *testing.T, isCheckTx bool, initPower int64) (
|
||||
sdk.Context, auth.AccountKeeper, Keeper, staking.Keeper, DummyFeeCollectionKeeper) {
|
||||
sdk.Context, auth.AccountKeeper, Keeper, staking.Keeper, types.SupplyKeeper) {
|
||||
|
||||
communityTax := sdk.NewDecWithPrec(2, 2)
|
||||
|
||||
ctx, ak, _, dk, sk, fck, _ := CreateTestInputAdvanced(t, isCheckTx, initPower, communityTax)
|
||||
return ctx, ak, dk, sk, fck
|
||||
ctx, ak, _, dk, sk, _, supplyKeeper := CreateTestInputAdvanced(t, isCheckTx, initPower, communityTax)
|
||||
return ctx, ak, dk, sk, supplyKeeper
|
||||
}
|
||||
|
||||
// hogpodge of all sorts of input required for testing
|
||||
func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64,
|
||||
communityTax sdk.Dec) (sdk.Context, auth.AccountKeeper, bank.Keeper,
|
||||
Keeper, staking.Keeper, DummyFeeCollectionKeeper, params.Keeper) {
|
||||
Keeper, staking.Keeper, params.Keeper, types.SupplyKeeper) {
|
||||
|
||||
initCoins := sdk.TokensFromConsensusPower(initPower)
|
||||
initTokens := sdk.TokensFromConsensusPower(initPower)
|
||||
|
||||
keyDistr := sdk.NewKVStoreKey(types.StoreKey)
|
||||
keyStaking := sdk.NewKVStoreKey(staking.StoreKey)
|
||||
tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey)
|
||||
keyAcc := sdk.NewKVStoreKey(auth.StoreKey)
|
||||
keyFeeCollection := sdk.NewKVStoreKey(auth.FeeStoreKey)
|
||||
keySupply := sdk.NewKVStoreKey(supply.StoreKey)
|
||||
keyParams := sdk.NewKVStoreKey(params.StoreKey)
|
||||
tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey)
|
||||
|
||||
|
@ -104,8 +106,8 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64,
|
|||
ms.MountStoreWithDB(keyDistr, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyStaking, sdk.StoreTypeTransient, nil)
|
||||
ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyFeeCollection, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
|
||||
|
||||
|
@ -118,23 +120,34 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64,
|
|||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger())
|
||||
accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount)
|
||||
bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace)
|
||||
sk := staking.NewKeeper(cdc, keyStaking, tkeyStaking, bankKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
|
||||
sk.SetPool(ctx, staking.InitialPool())
|
||||
supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, supply.DefaultCodespace,
|
||||
[]string{auth.FeeCollectorName, types.ModuleName}, []string{}, []string{staking.NotBondedPoolName, staking.BondedPoolName})
|
||||
|
||||
sk := staking.NewKeeper(cdc, keyStaking, tkeyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
|
||||
sk.SetParams(ctx, staking.DefaultParams())
|
||||
|
||||
keeper := NewKeeper(cdc, keyDistr, pk.Subspace(DefaultParamspace), sk, supplyKeeper, types.DefaultCodespace, auth.FeeCollectorName)
|
||||
|
||||
initCoins := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens))
|
||||
totalSupply := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens.MulRaw(int64(len(TestAddrs)))))
|
||||
supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply))
|
||||
|
||||
// fill all the addresses with some coins, set the loose pool tokens simultaneously
|
||||
for _, addr := range TestAddrs {
|
||||
pool := sk.GetPool(ctx)
|
||||
_, err := bankKeeper.AddCoins(ctx, addr, sdk.Coins{
|
||||
sdk.NewCoin(sk.GetParams(ctx).BondDenom, initCoins),
|
||||
})
|
||||
_, err := bankKeeper.AddCoins(ctx, addr, initCoins)
|
||||
require.Nil(t, err)
|
||||
pool.NotBondedTokens = pool.NotBondedTokens.Add(initCoins)
|
||||
sk.SetPool(ctx, pool)
|
||||
}
|
||||
|
||||
fck := DummyFeeCollectionKeeper{}
|
||||
keeper := NewKeeper(cdc, keyDistr, pk.Subspace(DefaultParamspace), bankKeeper, sk, fck, types.DefaultCodespace)
|
||||
// create module accounts
|
||||
feeCollectorAcc := supply.NewEmptyModuleAccount(auth.FeeCollectorName, supply.Basic)
|
||||
notBondedPool := supply.NewEmptyModuleAccount(staking.NotBondedPoolName, supply.Burner)
|
||||
bondPool := supply.NewEmptyModuleAccount(staking.BondedPoolName, supply.Burner)
|
||||
distrAcc := supply.NewEmptyModuleAccount(types.ModuleName, supply.Basic)
|
||||
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, bondPool)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, distrAcc)
|
||||
|
||||
// set the distribution hooks on staking
|
||||
sk.SetHooks(keeper.Hooks())
|
||||
|
@ -145,27 +158,5 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64,
|
|||
keeper.SetBaseProposerReward(ctx, sdk.NewDecWithPrec(1, 2))
|
||||
keeper.SetBonusProposerReward(ctx, sdk.NewDecWithPrec(4, 2))
|
||||
|
||||
return ctx, accountKeeper, bankKeeper, keeper, sk, fck, pk
|
||||
}
|
||||
|
||||
//__________________________________________________________________________________
|
||||
// fee collection keeper used only for testing
|
||||
type DummyFeeCollectionKeeper struct{}
|
||||
|
||||
var heldFees sdk.Coins
|
||||
var _ types.FeeCollectionKeeper = DummyFeeCollectionKeeper{}
|
||||
|
||||
// nolint
|
||||
func (fck DummyFeeCollectionKeeper) AddCollectedFees(_ sdk.Context, in sdk.Coins) sdk.Coins {
|
||||
fck.SetCollectedFees(heldFees.Add(in))
|
||||
return heldFees
|
||||
}
|
||||
func (fck DummyFeeCollectionKeeper) GetCollectedFees(_ sdk.Context) sdk.Coins {
|
||||
return heldFees
|
||||
}
|
||||
func (fck DummyFeeCollectionKeeper) SetCollectedFees(in sdk.Coins) {
|
||||
heldFees = in
|
||||
}
|
||||
func (fck DummyFeeCollectionKeeper) ClearCollectedFees(_ sdk.Context) {
|
||||
heldFees = sdk.NewCoins()
|
||||
return ctx, accountKeeper, bankKeeper, keeper, sk, pk, supplyKeeper
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/client/cli"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -67,14 +68,16 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command {
|
|||
// app module
|
||||
type AppModule struct {
|
||||
AppModuleBasic
|
||||
keeper Keeper
|
||||
keeper Keeper
|
||||
supplyKeeper types.SupplyKeeper
|
||||
}
|
||||
|
||||
// NewAppModule creates a new AppModule object
|
||||
func NewAppModule(keeper Keeper) AppModule {
|
||||
func NewAppModule(keeper Keeper, supplyKeeper types.SupplyKeeper) AppModule {
|
||||
return AppModule{
|
||||
AppModuleBasic: AppModuleBasic{},
|
||||
keeper: keeper,
|
||||
supplyKeeper: supplyKeeper,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +115,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier {
|
|||
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
|
||||
var genesisState GenesisState
|
||||
ModuleCdc.MustUnmarshalJSON(data, &genesisState)
|
||||
InitGenesis(ctx, am.keeper, genesisState)
|
||||
InitGenesis(ctx, am.keeper, am.supplyKeeper, genesisState)
|
||||
return []abci.ValidatorUpdate{}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ import (
|
|||
var (
|
||||
delPk1 = ed25519.GenPrivKey().PubKey()
|
||||
delAddr1 = sdk.AccAddress(delPk1.Address())
|
||||
|
||||
amount = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1)))
|
||||
)
|
||||
|
||||
func testProposal(recipient sdk.AccAddress, amount sdk.Coins) types.CommunityPoolSpendProposal {
|
||||
|
@ -25,34 +27,39 @@ func testProposal(recipient sdk.AccAddress, amount sdk.Coins) types.CommunityPoo
|
|||
}
|
||||
|
||||
func TestProposalHandlerPassed(t *testing.T) {
|
||||
ctx, accountKeeper, keeper, _, _ := CreateTestInputDefault(t, false, 10)
|
||||
ctx, accountKeeper, keeper, _, supplyKeeper := CreateTestInputDefault(t, false, 10)
|
||||
recipient := delAddr1
|
||||
amount := sdk.NewCoin("stake", sdk.NewInt(1))
|
||||
|
||||
// add coins to the module account
|
||||
macc := keeper.GetDistributionAccount(ctx)
|
||||
err := macc.SetCoins(macc.GetCoins().Add(amount))
|
||||
require.NoError(t, err)
|
||||
|
||||
supplyKeeper.SetModuleAccount(ctx, macc)
|
||||
|
||||
account := accountKeeper.NewAccountWithAddress(ctx, recipient)
|
||||
require.True(t, account.GetCoins().IsZero())
|
||||
accountKeeper.SetAccount(ctx, account)
|
||||
|
||||
feePool := keeper.GetFeePool(ctx)
|
||||
feePool.CommunityPool = sdk.DecCoins{sdk.NewDecCoinFromCoin(amount)}
|
||||
feePool.CommunityPool = sdk.NewDecCoins(amount)
|
||||
keeper.SetFeePool(ctx, feePool)
|
||||
|
||||
tp := testProposal(recipient, sdk.NewCoins(amount))
|
||||
tp := testProposal(recipient, amount)
|
||||
hdlr := NewCommunityPoolSpendProposalHandler(keeper)
|
||||
require.NoError(t, hdlr(ctx, tp))
|
||||
require.Equal(t, accountKeeper.GetAccount(ctx, recipient).GetCoins(), sdk.NewCoins(amount))
|
||||
require.Equal(t, accountKeeper.GetAccount(ctx, recipient).GetCoins(), amount)
|
||||
}
|
||||
|
||||
func TestProposalHandlerFailed(t *testing.T) {
|
||||
ctx, accountKeeper, keeper, _, _ := CreateTestInputDefault(t, false, 10)
|
||||
recipient := delAddr1
|
||||
amount := sdk.NewCoin("stake", sdk.NewInt(1))
|
||||
|
||||
account := accountKeeper.NewAccountWithAddress(ctx, recipient)
|
||||
require.True(t, account.GetCoins().IsZero())
|
||||
accountKeeper.SetAccount(ctx, account)
|
||||
|
||||
tp := testProposal(recipient, sdk.NewCoins(amount))
|
||||
tp := testProposal(recipient, amount)
|
||||
hdlr := NewCommunityPoolSpendProposalHandler(keeper)
|
||||
require.Error(t, hdlr(ctx, tp))
|
||||
require.True(t, accountKeeper.GetAccount(ctx, recipient).GetCoins().IsZero())
|
||||
|
|
|
@ -3,27 +3,26 @@ package types
|
|||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking/exported"
|
||||
stakingexported "github.com/cosmos/cosmos-sdk/x/staking/exported"
|
||||
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
)
|
||||
|
||||
// StakingKeeper expected staking keeper
|
||||
// StakingKeeper expected staking keeper (noalias)
|
||||
type StakingKeeper interface {
|
||||
// iterate through validators by operator address, execute func for each validator
|
||||
IterateValidators(sdk.Context,
|
||||
func(index int64, validator exported.ValidatorI) (stop bool))
|
||||
func(index int64, validator stakingexported.ValidatorI) (stop bool))
|
||||
|
||||
// iterate through bonded validators by operator address, execute func for each validator
|
||||
IterateBondedValidatorsByPower(sdk.Context,
|
||||
func(index int64, validator exported.ValidatorI) (stop bool))
|
||||
func(index int64, validator stakingexported.ValidatorI) (stop bool))
|
||||
|
||||
// iterate through the consensus validator set of the last block by operator address, execute func for each validator
|
||||
IterateLastValidators(sdk.Context,
|
||||
func(index int64, validator exported.ValidatorI) (stop bool))
|
||||
func(index int64, validator stakingexported.ValidatorI) (stop bool))
|
||||
|
||||
Validator(sdk.Context, sdk.ValAddress) exported.ValidatorI // get a particular validator by operator address
|
||||
ValidatorByConsAddr(sdk.Context, sdk.ConsAddress) exported.ValidatorI // get a particular validator by consensus address
|
||||
TotalBondedTokens(sdk.Context) sdk.Int // total bonded tokens within the validator set
|
||||
TotalTokens(sdk.Context) sdk.Int // total token supply
|
||||
Validator(sdk.Context, sdk.ValAddress) stakingexported.ValidatorI // get a particular validator by operator address
|
||||
ValidatorByConsAddr(sdk.Context, sdk.ConsAddress) stakingexported.ValidatorI // get a particular validator by consensus address
|
||||
|
||||
// slash the validator and delegators of the validator, specifying offence height, offence power, and slash fraction
|
||||
Slash(sdk.Context, sdk.ConsAddress, int64, int64, sdk.Dec)
|
||||
|
@ -32,13 +31,13 @@ type StakingKeeper interface {
|
|||
|
||||
// Delegation allows for getting a particular delegation for a given validator
|
||||
// and delegator outside the scope of the staking module.
|
||||
Delegation(sdk.Context, sdk.AccAddress, sdk.ValAddress) exported.DelegationI
|
||||
Delegation(sdk.Context, sdk.AccAddress, sdk.ValAddress) stakingexported.DelegationI
|
||||
|
||||
// MaxValidators returns the maximum amount of bonded validators
|
||||
MaxValidators(sdk.Context) uint16
|
||||
|
||||
IterateDelegations(ctx sdk.Context, delegator sdk.AccAddress,
|
||||
fn func(index int64, delegation exported.DelegationI) (stop bool))
|
||||
fn func(index int64, delegation stakingexported.DelegationI) (stop bool))
|
||||
|
||||
GetLastTotalPower(ctx sdk.Context) sdk.Int
|
||||
GetLastValidatorPower(ctx sdk.Context, valAddr sdk.ValAddress) int64
|
||||
|
@ -46,7 +45,7 @@ type StakingKeeper interface {
|
|||
GetAllSDKDelegations(ctx sdk.Context) []staking.Delegation
|
||||
}
|
||||
|
||||
// StakingHooks event hooks for staking validator object
|
||||
// StakingHooks event hooks for staking validator object (noalias)
|
||||
type StakingHooks interface {
|
||||
AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) // Must be called when a validator is created
|
||||
AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) // Must be called when a validator is deleted
|
||||
|
@ -57,13 +56,15 @@ type StakingHooks interface {
|
|||
BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec)
|
||||
}
|
||||
|
||||
// expected coin keeper
|
||||
type BankKeeper interface {
|
||||
AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error)
|
||||
}
|
||||
// SupplyKeeper defines the expected supply Keeper (noalias)
|
||||
type SupplyKeeper interface {
|
||||
GetModuleAddress(name string) sdk.AccAddress
|
||||
GetModuleAccount(ctx sdk.Context, name string) supplyexported.ModuleAccountI
|
||||
|
||||
// expected fee collection keeper
|
||||
type FeeCollectionKeeper interface {
|
||||
GetCollectedFees(ctx sdk.Context) sdk.Coins
|
||||
ClearCollectedFees(ctx sdk.Context)
|
||||
// TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862
|
||||
SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI)
|
||||
|
||||
SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) sdk.Error
|
||||
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error
|
||||
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package types
|
|||
|
||||
const (
|
||||
// ModuleName is the module name constant used in many places
|
||||
ModuleName = "distr"
|
||||
ModuleName = "distribution"
|
||||
|
||||
// StoreKey is the store key string for distribution
|
||||
StoreKey = ModuleName
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
)
|
||||
|
||||
|
@ -60,7 +60,7 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec,
|
|||
return err
|
||||
}
|
||||
|
||||
genAcc := genaccounts.NewGenesisAccountRaw(addr, coins, vestingAmt, vestingStart, vestingEnd)
|
||||
genAcc := genaccounts.NewGenesisAccountRaw(addr, coins, vestingAmt, vestingStart, vestingEnd, "", "")
|
||||
if err := genAcc.Validate(); err != nil {
|
||||
return err
|
||||
}
|
|
@ -3,9 +3,13 @@ package genaccounts
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
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/supply"
|
||||
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
)
|
||||
|
||||
// GenesisAccount is a struct for account initialization used exclusively during genesis
|
||||
|
@ -21,9 +25,13 @@ type GenesisAccount struct {
|
|||
DelegatedVesting sdk.Coins `json:"delegated_vesting"` // delegated vesting coins at time of delegation
|
||||
StartTime int64 `json:"start_time"` // vesting start time (UNIX Epoch time)
|
||||
EndTime int64 `json:"end_time"` // vesting end time (UNIX Epoch time)
|
||||
|
||||
// module account fields
|
||||
ModuleName string `json:"module_name"` // name of the module account
|
||||
ModulePermission string `json:"module_permission"` // permission of module account
|
||||
}
|
||||
|
||||
// validate the the VestingAccount parameters are possible
|
||||
// Validate checks for errors on the vesting and module account parameters
|
||||
func (ga GenesisAccount) Validate() error {
|
||||
if !ga.OriginalVesting.IsZero() {
|
||||
if ga.OriginalVesting.IsAnyGT(ga.Coins) {
|
||||
|
@ -33,12 +41,19 @@ func (ga GenesisAccount) Validate() error {
|
|||
return errors.New("vesting start-time cannot be before end-time")
|
||||
}
|
||||
}
|
||||
|
||||
// don't allow blank (i.e just whitespaces) on the module name
|
||||
if ga.ModuleName != "" && strings.TrimSpace(ga.ModuleName) == "" {
|
||||
return errors.New("module account name cannot be blank")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewGenesisAccount creates a new GenesisAccount object
|
||||
// NewGenesisAccountRaw creates a new GenesisAccount object
|
||||
func NewGenesisAccountRaw(address sdk.AccAddress, coins,
|
||||
vestingAmount sdk.Coins, vestingStartTime, vestingEndTime int64) GenesisAccount {
|
||||
vestingAmount sdk.Coins, vestingStartTime, vestingEndTime int64,
|
||||
module, permission string) GenesisAccount {
|
||||
|
||||
return GenesisAccount{
|
||||
Address: address,
|
||||
|
@ -50,9 +65,12 @@ func NewGenesisAccountRaw(address sdk.AccAddress, coins,
|
|||
DelegatedVesting: sdk.Coins{}, // ignored
|
||||
StartTime: vestingStartTime,
|
||||
EndTime: vestingEndTime,
|
||||
ModuleName: module,
|
||||
ModulePermission: permission,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGenesisAccount creates a GenesisAccount instance from a BaseAccount.
|
||||
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
||||
return GenesisAccount{
|
||||
Address: acc.Address,
|
||||
|
@ -62,7 +80,8 @@ func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
|||
}
|
||||
}
|
||||
|
||||
func NewGenesisAccountI(acc auth.Account) (GenesisAccount, error) {
|
||||
// NewGenesisAccountI creates a GenesisAccount instance from an Account interface.
|
||||
func NewGenesisAccountI(acc authexported.Account) (GenesisAccount, error) {
|
||||
gacc := GenesisAccount{
|
||||
Address: acc.GetAddress(),
|
||||
Coins: acc.GetCoins(),
|
||||
|
@ -74,22 +93,26 @@ func NewGenesisAccountI(acc auth.Account) (GenesisAccount, error) {
|
|||
return gacc, err
|
||||
}
|
||||
|
||||
vacc, ok := acc.(auth.VestingAccount)
|
||||
if ok {
|
||||
gacc.OriginalVesting = vacc.GetOriginalVesting()
|
||||
gacc.DelegatedFree = vacc.GetDelegatedFree()
|
||||
gacc.DelegatedVesting = vacc.GetDelegatedVesting()
|
||||
gacc.StartTime = vacc.GetStartTime()
|
||||
gacc.EndTime = vacc.GetEndTime()
|
||||
switch acc := acc.(type) {
|
||||
case authexported.VestingAccount:
|
||||
gacc.OriginalVesting = acc.GetOriginalVesting()
|
||||
gacc.DelegatedFree = acc.GetDelegatedFree()
|
||||
gacc.DelegatedVesting = acc.GetDelegatedVesting()
|
||||
gacc.StartTime = acc.GetStartTime()
|
||||
gacc.EndTime = acc.GetEndTime()
|
||||
case supplyexported.ModuleAccountI:
|
||||
gacc.ModuleName = acc.GetName()
|
||||
gacc.ModulePermission = acc.GetPermission()
|
||||
}
|
||||
|
||||
return gacc, nil
|
||||
}
|
||||
|
||||
// convert GenesisAccount to auth.Account
|
||||
// ToAccount converts a GenesisAccount to an Account interface
|
||||
func (ga *GenesisAccount) ToAccount() auth.Account {
|
||||
bacc := auth.NewBaseAccount(ga.Address, ga.Coins.Sort(), nil, ga.AccountNumber, ga.Sequence)
|
||||
|
||||
// vesting accounts
|
||||
if !ga.OriginalVesting.IsZero() {
|
||||
baseVestingAcc := auth.NewBaseVestingAccount(
|
||||
bacc, ga.OriginalVesting, ga.DelegatedFree,
|
||||
|
@ -106,6 +129,11 @@ func (ga *GenesisAccount) ToAccount() auth.Account {
|
|||
}
|
||||
}
|
||||
|
||||
// module accounts
|
||||
if ga.ModuleName != "" {
|
||||
return supply.NewModuleAccount(bacc, ga.ModuleName, ga.ModulePermission)
|
||||
}
|
||||
|
||||
return bacc
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
supplytypes "github.com/cosmos/cosmos-sdk/x/supply/types"
|
||||
)
|
||||
|
||||
func TestGenesisAccountValidate(t *testing.T) {
|
||||
|
@ -22,13 +23,18 @@ func TestGenesisAccountValidate(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
"valid account",
|
||||
NewGenesisAccountRaw(addr, sdk.NewCoins(), sdk.NewCoins(), 0, 0),
|
||||
NewGenesisAccountRaw(addr, sdk.NewCoins(), sdk.NewCoins(), 0, 0, "", ""),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid module account",
|
||||
NewGenesisAccountRaw(addr, sdk.NewCoins(), sdk.NewCoins(), 0, 0, "mint", supplytypes.Minter),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"invalid vesting amount",
|
||||
NewGenesisAccountRaw(addr, sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
|
||||
sdk.NewCoins(sdk.NewInt64Coin("stake", 100)), 0, 0),
|
||||
sdk.NewCoins(sdk.NewInt64Coin("stake", 100)), 0, 0, "", ""),
|
||||
errors.New("vesting amount cannot be greater than total amount"),
|
||||
},
|
||||
{
|
||||
|
@ -36,15 +42,20 @@ func TestGenesisAccountValidate(t *testing.T) {
|
|||
NewGenesisAccountRaw(addr,
|
||||
sdk.NewCoins(sdk.NewInt64Coin("uatom", 50), sdk.NewInt64Coin("eth", 50)),
|
||||
sdk.NewCoins(sdk.NewInt64Coin("uatom", 100), sdk.NewInt64Coin("eth", 20)),
|
||||
0, 0),
|
||||
0, 0, "", ""),
|
||||
errors.New("vesting amount cannot be greater than total amount"),
|
||||
},
|
||||
{
|
||||
"invalid vesting times",
|
||||
NewGenesisAccountRaw(addr, sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
|
||||
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)), 1654668078, 1554668078),
|
||||
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)), 1654668078, 1554668078, "", ""),
|
||||
errors.New("vesting start-time cannot be before end-time"),
|
||||
},
|
||||
{
|
||||
"invalid module account name",
|
||||
NewGenesisAccountRaw(addr, sdk.NewCoins(), sdk.NewCoins(), 0, 0, " ", ""),
|
||||
errors.New("module account name cannot be blank"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -57,6 +68,8 @@ func TestGenesisAccountValidate(t *testing.T) {
|
|||
func TestToAccount(t *testing.T) {
|
||||
priv := ed25519.GenPrivKey()
|
||||
addr := sdk.AccAddress(priv.PubKey().Address())
|
||||
|
||||
// base account
|
||||
authAcc := auth.NewBaseAccountWithAddress(addr)
|
||||
authAcc.SetCoins(sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)))
|
||||
genAcc := NewGenesisAccount(&authAcc)
|
||||
|
@ -64,6 +77,7 @@ func TestToAccount(t *testing.T) {
|
|||
require.IsType(t, &auth.BaseAccount{}, acc)
|
||||
require.Equal(t, &authAcc, acc.(*auth.BaseAccount))
|
||||
|
||||
// vesting account
|
||||
vacc := auth.NewContinuousVestingAccount(
|
||||
&authAcc, time.Now().Unix(), time.Now().Add(24*time.Hour).Unix(),
|
||||
)
|
||||
|
@ -72,4 +86,12 @@ func TestToAccount(t *testing.T) {
|
|||
acc = genAcc.ToAccount()
|
||||
require.IsType(t, &auth.ContinuousVestingAccount{}, acc)
|
||||
require.Equal(t, vacc, acc.(*auth.ContinuousVestingAccount))
|
||||
|
||||
// module account
|
||||
macc := supplytypes.NewEmptyModuleAccount("mint", supplytypes.Minter)
|
||||
genAcc, err = NewGenesisAccountI(macc)
|
||||
require.NoError(t, err)
|
||||
acc = genAcc.ToAccount()
|
||||
require.IsType(t, &supplytypes.ModuleAccount{}, acc)
|
||||
require.Equal(t, macc, acc.(*supplytypes.ModuleAccount))
|
||||
}
|
|
@ -39,9 +39,8 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd
|
|||
return ErrAlreadyFinishedProposal(keeper.codespace, proposalID), false
|
||||
}
|
||||
|
||||
// Send coins from depositor's account to DepositedCoinsAccAddr account
|
||||
// TODO: Don't use an account for this purpose; it's clumsy and prone to misuse.
|
||||
err := keeper.ck.SendCoins(ctx, depositorAddr, DepositedCoinsAccAddr, depositAmount)
|
||||
// update the governance module's account coins pool
|
||||
err := keeper.supplyKeeper.SendCoinsFromAccountToModule(ctx, depositorAddr, types.ModuleName, depositAmount)
|
||||
if err != nil {
|
||||
return err, false
|
||||
}
|
||||
|
@ -105,11 +104,12 @@ func (keeper Keeper) GetDepositsIterator(ctx sdk.Context, proposalID uint64) sdk
|
|||
func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) {
|
||||
store := ctx.KVStore(keeper.storeKey)
|
||||
|
||||
keeper.IterateDeposits(ctx, proposalID, func(deposit Deposit) bool {
|
||||
err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, deposit.Depositor, deposit.Amount)
|
||||
keeper.IterateDeposits(ctx, proposalID, func(deposit types.Deposit) bool {
|
||||
err := keeper.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, deposit.Depositor, deposit.Amount)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
store.Delete(DepositKey(proposalID, deposit.Depositor))
|
||||
return false
|
||||
})
|
||||
|
@ -119,8 +119,8 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) {
|
|||
func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) {
|
||||
store := ctx.KVStore(keeper.storeKey)
|
||||
|
||||
keeper.IterateDeposits(ctx, proposalID, func(deposit Deposit) bool {
|
||||
err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, BurnedDepositCoinsAccAddr, deposit.Amount)
|
||||
keeper.IterateDeposits(ctx, proposalID, func(deposit types.Deposit) bool {
|
||||
err := keeper.supplyKeeper.BurnCoins(ctx, types.ModuleName, deposit.Amount)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ func TestTickExpiredDepositPeriod(t *testing.T) {
|
|||
input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := input.mApp.BaseApp.NewContext(false, abci.Header{})
|
||||
input.keeper.ck.SetSendEnabled(ctx, true)
|
||||
govHandler := NewHandler(input.keeper)
|
||||
|
||||
inactiveQueue := input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
|
||||
|
@ -69,7 +68,6 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
|
|||
input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := input.mApp.BaseApp.NewContext(false, abci.Header{})
|
||||
input.keeper.ck.SetSendEnabled(ctx, true)
|
||||
govHandler := NewHandler(input.keeper)
|
||||
|
||||
inactiveQueue := input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
|
||||
|
@ -138,7 +136,6 @@ func TestTickPassedDepositPeriod(t *testing.T) {
|
|||
input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := input.mApp.BaseApp.NewContext(false, abci.Header{})
|
||||
input.keeper.ck.SetSendEnabled(ctx, true)
|
||||
govHandler := NewHandler(input.keeper)
|
||||
|
||||
inactiveQueue := input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
|
||||
|
@ -188,7 +185,6 @@ func TestTickPassedVotingPeriod(t *testing.T) {
|
|||
input.mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := input.mApp.BaseApp.NewContext(false, abci.Header{})
|
||||
input.keeper.ck.SetSendEnabled(ctx, true)
|
||||
govHandler := NewHandler(input.keeper)
|
||||
|
||||
inactiveQueue := input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
|
||||
|
@ -256,10 +252,13 @@ func TestProposalPassedEndblocker(t *testing.T) {
|
|||
|
||||
valAddr := sdk.ValAddress(input.addrs[0])
|
||||
|
||||
input.keeper.ck.SetSendEnabled(ctx, true)
|
||||
createValidators(t, stakingHandler, ctx, []sdk.ValAddress{valAddr}, []int64{10})
|
||||
staking.EndBlocker(ctx, input.sk)
|
||||
|
||||
macc := input.keeper.GetGovernanceAccount(ctx)
|
||||
require.NotNil(t, macc)
|
||||
initialModuleAccCoins := macc.GetCoins()
|
||||
|
||||
proposal, err := input.keeper.SubmitProposal(ctx, testProposal())
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -268,6 +267,13 @@ func TestProposalPassedEndblocker(t *testing.T) {
|
|||
res := handler(ctx, newDepositMsg)
|
||||
require.True(t, res.IsOK())
|
||||
|
||||
macc = input.keeper.GetGovernanceAccount(ctx)
|
||||
require.NotNil(t, macc)
|
||||
moduleAccCoins := macc.GetCoins()
|
||||
|
||||
deposits := initialModuleAccCoins.Add(proposal.TotalDeposit).Add(proposalCoins)
|
||||
require.True(t, moduleAccCoins.IsEqual(deposits))
|
||||
|
||||
err = input.keeper.AddVote(ctx, proposal.ProposalID, input.addrs[0], OptionYes)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -276,6 +282,10 @@ func TestProposalPassedEndblocker(t *testing.T) {
|
|||
ctx = ctx.WithBlockHeader(newHeader)
|
||||
|
||||
EndBlocker(ctx, input.keeper)
|
||||
|
||||
macc = input.keeper.GetGovernanceAccount(ctx)
|
||||
require.NotNil(t, macc)
|
||||
require.True(t, macc.GetCoins().IsEqual(initialModuleAccCoins))
|
||||
}
|
||||
|
||||
func TestEndBlockerProposalHandlerFailed(t *testing.T) {
|
||||
|
@ -294,7 +304,6 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) {
|
|||
|
||||
valAddr := sdk.ValAddress(input.addrs[0])
|
||||
|
||||
input.keeper.ck.SetSendEnabled(ctx, true)
|
||||
createValidators(t, stakingHandler, ctx, []sdk.ValAddress{valAddr}, []int64{10})
|
||||
staking.EndBlocker(ctx, input.sk)
|
||||
|
||||
|
|
|
@ -2,26 +2,31 @@ package gov
|
|||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking/exported"
|
||||
stakingexported "github.com/cosmos/cosmos-sdk/x/staking/exported"
|
||||
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
)
|
||||
|
||||
// expected bank keeper
|
||||
type BankKeeper interface {
|
||||
GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
|
||||
// SupplyKeeper defines the supply Keeper for module accounts
|
||||
type SupplyKeeper interface {
|
||||
GetModuleAddress(name string) sdk.AccAddress
|
||||
GetModuleAccount(ctx sdk.Context, name string) supplyexported.ModuleAccountI
|
||||
|
||||
// TODO remove once governance doesn't require use of accounts
|
||||
SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error
|
||||
SetSendEnabled(ctx sdk.Context, enabled bool)
|
||||
// TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862
|
||||
SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI)
|
||||
|
||||
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error
|
||||
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error
|
||||
BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error
|
||||
}
|
||||
|
||||
// StakingKeeper expected staking keeper (Validator and Delegator sets)
|
||||
type StakingKeeper interface {
|
||||
// iterate through bonded validators by operator address, execute func for each validator
|
||||
IterateBondedValidatorsByPower(sdk.Context,
|
||||
func(index int64, validator exported.ValidatorI) (stop bool))
|
||||
func(index int64, validator stakingexported.ValidatorI) (stop bool))
|
||||
|
||||
TotalBondedTokens(sdk.Context) sdk.Int // total bonded tokens within the validator set
|
||||
|
||||
IterateDelegations(ctx sdk.Context, delegator sdk.AccAddress,
|
||||
fn func(index int64, delegation exported.DelegationI) (stop bool))
|
||||
fn func(index int64, delegation stakingexported.DelegationI) (stop bool))
|
||||
}
|
||||
|
|
|
@ -91,18 +91,29 @@ func ValidateGenesis(data GenesisState) error {
|
|||
}
|
||||
|
||||
// InitGenesis - store genesis parameters
|
||||
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
||||
func InitGenesis(ctx sdk.Context, k Keeper, supplyKeeper SupplyKeeper, data GenesisState) {
|
||||
|
||||
k.setProposalID(ctx, data.StartingProposalID)
|
||||
k.setDepositParams(ctx, data.DepositParams)
|
||||
k.setVotingParams(ctx, data.VotingParams)
|
||||
k.setTallyParams(ctx, data.TallyParams)
|
||||
|
||||
// check if the deposits pool account exists
|
||||
moduleAcc := k.GetGovernanceAccount(ctx)
|
||||
if moduleAcc == nil {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
|
||||
}
|
||||
|
||||
var totalDeposits sdk.Coins
|
||||
for _, deposit := range data.Deposits {
|
||||
k.setDeposit(ctx, deposit.ProposalID, deposit.Depositor, deposit)
|
||||
totalDeposits = totalDeposits.Add(deposit.Amount)
|
||||
}
|
||||
|
||||
for _, vote := range data.Votes {
|
||||
k.setVote(ctx, vote.ProposalID, vote.Voter, vote)
|
||||
}
|
||||
|
||||
for _, proposal := range data.Proposals {
|
||||
switch proposal.Status {
|
||||
case StatusDepositPeriod:
|
||||
|
@ -112,6 +123,14 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
|||
}
|
||||
k.SetProposal(ctx, proposal)
|
||||
}
|
||||
|
||||
// add coins if not provided on genesis
|
||||
if moduleAcc.GetCoins().IsZero() {
|
||||
if err := moduleAcc.SetCoins(totalDeposits); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
supplyKeeper.SetModuleAccount(ctx, moduleAcc)
|
||||
}
|
||||
}
|
||||
|
||||
// ExportGenesis - output genesis parameters
|
||||
|
|
|
@ -85,7 +85,8 @@ func TestImportExportQueues(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
proposalID2 := proposal2.ProposalID
|
||||
|
||||
_, votingStarted := input.keeper.AddDeposit(ctx, proposalID2, input.addrs[0], input.keeper.GetDepositParams(ctx).MinDeposit)
|
||||
err, votingStarted := input.keeper.AddDeposit(ctx, proposalID2, input.addrs[0], input.keeper.GetDepositParams(ctx).MinDeposit)
|
||||
require.NoError(t, err)
|
||||
require.True(t, votingStarted)
|
||||
|
||||
proposal1, ok := input.keeper.GetProposal(ctx, proposalID1)
|
||||
|
@ -117,7 +118,9 @@ func TestImportExportQueues(t *testing.T) {
|
|||
require.True(t, proposal1.Status == StatusDepositPeriod)
|
||||
require.True(t, proposal2.Status == StatusVotingPeriod)
|
||||
|
||||
// Run the endblocker. Check to make sure that proposal1 is removed from state, and proposal2 is finished VotingPeriod.
|
||||
require.Equal(t, input2.keeper.GetDepositParams(ctx2).MinDeposit, input2.keeper.GetGovernanceAccount(ctx2).GetCoins())
|
||||
|
||||
// Run the endblocker. Check to make sure that proposal1 is removed from state, and proposal2 is finished VotingPeriod.
|
||||
EndBlocker(ctx2, input2.keeper)
|
||||
|
||||
proposal1, ok = input2.keeper.GetProposal(ctx2, proposalID1)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package gov
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
)
|
||||
|
||||
// RegisterInvariants registers all governance invariants
|
||||
func RegisterInvariants(ir sdk.InvariantRegistry, keeper Keeper) {
|
||||
ir.RegisterRoute(types.ModuleName, "module-account", ModuleAccountInvariant(keeper))
|
||||
}
|
||||
|
||||
// AllInvariants runs all invariants of the governance module
|
||||
func AllInvariants(keeper Keeper) sdk.Invariant {
|
||||
return func(ctx sdk.Context) error {
|
||||
return ModuleAccountInvariant(keeper)(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// ModuleAccountInvariant checks that the module account coins reflects the sum of
|
||||
// deposit amounts held on store
|
||||
func ModuleAccountInvariant(keeper Keeper) sdk.Invariant {
|
||||
return func(ctx sdk.Context) error {
|
||||
var expectedDeposits sdk.Coins
|
||||
|
||||
keeper.IterateAllDeposits(ctx, func(deposit types.Deposit) bool {
|
||||
expectedDeposits = expectedDeposits.Add(deposit.Amount)
|
||||
return false
|
||||
})
|
||||
|
||||
macc := keeper.GetGovernanceAccount(ctx)
|
||||
if !macc.GetCoins().IsEqual(expectedDeposits) {
|
||||
return fmt.Errorf("deposits invariance:\n"+
|
||||
"\tgov ModuleAccount coins: %s\n"+
|
||||
"\tsum of deposit amounts: %s", macc.GetCoins(), expectedDeposits)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -8,18 +8,11 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
)
|
||||
|
||||
// special governance addresses
|
||||
var (
|
||||
// TODO: Find another way to implement this without using accounts, or find a cleaner way to implement it using accounts.
|
||||
DepositedCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govDepositedCoins")))
|
||||
BurnedDepositCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govBurnedDepositCoins")))
|
||||
)
|
||||
|
||||
// Governance Keeper
|
||||
type Keeper struct {
|
||||
// The reference to the Param Keeper to get and set Global Params
|
||||
|
@ -28,8 +21,8 @@ type Keeper struct {
|
|||
// The reference to the Paramstore to get and set gov specific params
|
||||
paramSpace params.Subspace
|
||||
|
||||
// The reference to the CoinKeeper to modify balances
|
||||
ck BankKeeper
|
||||
// The SupplyKeeper to reduce the supply of the network
|
||||
supplyKeeper SupplyKeeper
|
||||
|
||||
// The reference to the DelegationSet and ValidatorSet to get information about validators and delegators
|
||||
sk StakingKeeper
|
||||
|
@ -54,9 +47,14 @@ type Keeper struct {
|
|||
// - and tallying the result of the vote.
|
||||
func NewKeeper(
|
||||
cdc *codec.Codec, key sdk.StoreKey, paramsKeeper params.Keeper, paramSpace params.Subspace,
|
||||
ck BankKeeper, sk StakingKeeper, codespace sdk.CodespaceType, rtr Router,
|
||||
supplyKeeper SupplyKeeper, sk StakingKeeper, codespace sdk.CodespaceType, rtr Router,
|
||||
) Keeper {
|
||||
|
||||
// ensure governance module account is set
|
||||
if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
|
||||
}
|
||||
|
||||
// It is vital to seal the governance proposal router here as to not allow
|
||||
// further handlers to be registered after the keeper is created since this
|
||||
// could create invalid or non-deterministic behavior.
|
||||
|
@ -66,7 +64,7 @@ func NewKeeper(
|
|||
storeKey: key,
|
||||
paramsKeeper: paramsKeeper,
|
||||
paramSpace: paramSpace.WithKeyTable(ParamKeyTable()),
|
||||
ck: ck,
|
||||
supplyKeeper: supplyKeeper,
|
||||
sk: sk,
|
||||
cdc: cdc,
|
||||
codespace: codespace,
|
||||
|
@ -79,6 +77,11 @@ func (keeper Keeper) Logger(ctx sdk.Context) log.Logger {
|
|||
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
|
||||
}
|
||||
|
||||
// GetGovernanceAccount returns the governance ModuleAccount
|
||||
func (keeper Keeper) GetGovernanceAccount(ctx sdk.Context) exported.ModuleAccountI {
|
||||
return keeper.supplyKeeper.GetModuleAccount(ctx, types.ModuleName)
|
||||
}
|
||||
|
||||
// Params
|
||||
|
||||
// Returns the current DepositParams from the global param store
|
||||
|
|
|
@ -83,6 +83,7 @@ func TestActivateVotingPeriod(t *testing.T) {
|
|||
|
||||
func TestDeposits(t *testing.T) {
|
||||
input := getMockApp(t, 2, GenesisState{}, nil)
|
||||
|
||||
SortAddresses(input.addrs)
|
||||
|
||||
header := abci.Header{Height: input.mApp.LastBlockHeight() + 1}
|
||||
|
@ -98,8 +99,8 @@ func TestDeposits(t *testing.T) {
|
|||
fourStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4)))
|
||||
fiveStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5)))
|
||||
|
||||
addr0Initial := input.keeper.ck.GetCoins(ctx, input.addrs[0])
|
||||
addr1Initial := input.keeper.ck.GetCoins(ctx, input.addrs[1])
|
||||
addr0Initial := input.mApp.AccountKeeper.GetAccount(ctx, input.addrs[0]).GetCoins()
|
||||
addr1Initial := input.mApp.AccountKeeper.GetAccount(ctx, input.addrs[1]).GetCoins()
|
||||
|
||||
expTokens := sdk.TokensFromConsensusPower(42)
|
||||
require.Equal(t, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, expTokens)), addr0Initial)
|
||||
|
@ -123,7 +124,7 @@ func TestDeposits(t *testing.T) {
|
|||
proposal, ok = input.keeper.GetProposal(ctx, proposalID)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, fourStake, proposal.TotalDeposit)
|
||||
require.Equal(t, addr0Initial.Sub(fourStake), input.keeper.ck.GetCoins(ctx, input.addrs[0]))
|
||||
require.Equal(t, addr0Initial.Sub(fourStake), input.mApp.AccountKeeper.GetAccount(ctx, input.addrs[0]).GetCoins())
|
||||
|
||||
// Check a second deposit from same address
|
||||
err, votingStarted = input.keeper.AddDeposit(ctx, proposalID, input.addrs[0], fiveStake)
|
||||
|
@ -136,7 +137,7 @@ func TestDeposits(t *testing.T) {
|
|||
proposal, ok = input.keeper.GetProposal(ctx, proposalID)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, fourStake.Add(fiveStake), proposal.TotalDeposit)
|
||||
require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), input.keeper.ck.GetCoins(ctx, input.addrs[0]))
|
||||
require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), input.mApp.AccountKeeper.GetAccount(ctx, input.addrs[0]).GetCoins())
|
||||
|
||||
// Check third deposit from a new address
|
||||
err, votingStarted = input.keeper.AddDeposit(ctx, proposalID, input.addrs[1], fourStake)
|
||||
|
@ -149,7 +150,7 @@ func TestDeposits(t *testing.T) {
|
|||
proposal, ok = input.keeper.GetProposal(ctx, proposalID)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, fourStake.Add(fiveStake).Add(fourStake), proposal.TotalDeposit)
|
||||
require.Equal(t, addr1Initial.Sub(fourStake), input.keeper.ck.GetCoins(ctx, input.addrs[1]))
|
||||
require.Equal(t, addr1Initial.Sub(fourStake), input.mApp.AccountKeeper.GetAccount(ctx, input.addrs[1]).GetCoins())
|
||||
|
||||
// Check that proposal moved to voting period
|
||||
proposal, ok = input.keeper.GetProposal(ctx, proposalID)
|
||||
|
@ -177,8 +178,8 @@ func TestDeposits(t *testing.T) {
|
|||
input.keeper.RefundDeposits(ctx, proposalID)
|
||||
deposit, found = input.keeper.GetDeposit(ctx, proposalID, input.addrs[1])
|
||||
require.False(t, found)
|
||||
require.Equal(t, addr0Initial, input.keeper.ck.GetCoins(ctx, input.addrs[0]))
|
||||
require.Equal(t, addr1Initial, input.keeper.ck.GetCoins(ctx, input.addrs[1]))
|
||||
require.Equal(t, addr0Initial, input.mApp.AccountKeeper.GetAccount(ctx, input.addrs[0]).GetCoins())
|
||||
require.Equal(t, addr1Initial, input.mApp.AccountKeeper.GetAccount(ctx, input.addrs[1]).GetCoins())
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -92,14 +92,16 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command {
|
|||
// app module
|
||||
type AppModule struct {
|
||||
AppModuleBasic
|
||||
keeper Keeper
|
||||
keeper Keeper
|
||||
supplyKeeper SupplyKeeper
|
||||
}
|
||||
|
||||
// NewAppModule creates a new AppModule object
|
||||
func NewAppModule(keeper Keeper) AppModule {
|
||||
func NewAppModule(keeper Keeper, supplyKeeper SupplyKeeper) AppModule {
|
||||
return AppModule{
|
||||
AppModuleBasic: AppModuleBasic{},
|
||||
keeper: keeper,
|
||||
supplyKeeper: supplyKeeper,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +111,9 @@ func (AppModule) Name() string {
|
|||
}
|
||||
|
||||
// register invariants
|
||||
func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
|
||||
func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
|
||||
RegisterInvariants(ir, am.keeper)
|
||||
}
|
||||
|
||||
// module message route name
|
||||
func (AppModule) Route() string {
|
||||
|
@ -135,7 +139,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier {
|
|||
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)
|
||||
InitGenesis(ctx, am.keeper, am.supplyKeeper, genesisState)
|
||||
return []abci.ValidatorUpdate{}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,14 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
var (
|
||||
valTokens = sdk.TokensFromConsensusPower(42)
|
||||
initTokens = sdk.TokensFromConsensusPower(100000)
|
||||
valCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, valTokens))
|
||||
initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))
|
||||
)
|
||||
|
||||
type testInput struct {
|
||||
|
@ -36,30 +44,34 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a
|
|||
mApp := mock.NewApp()
|
||||
|
||||
staking.RegisterCodec(mApp.Cdc)
|
||||
RegisterCodec(mApp.Cdc)
|
||||
types.RegisterCodec(mApp.Cdc)
|
||||
supply.RegisterCodec(mApp.Cdc)
|
||||
|
||||
keyStaking := sdk.NewKVStoreKey(staking.StoreKey)
|
||||
tKeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey)
|
||||
keyGov := sdk.NewKVStoreKey(StoreKey)
|
||||
keySupply := sdk.NewKVStoreKey(supply.StoreKey)
|
||||
|
||||
pk := mApp.ParamsKeeper
|
||||
|
||||
rtr := NewRouter().
|
||||
AddRoute(RouterKey, ProposalHandler)
|
||||
|
||||
ck := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace)
|
||||
sk := staking.NewKeeper(mApp.Cdc, keyStaking, tKeyStaking, ck, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
|
||||
keeper := NewKeeper(mApp.Cdc, keyGov, pk, pk.Subspace("testgov"), ck, sk, DefaultCodespace, rtr)
|
||||
bk := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace)
|
||||
|
||||
supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bk, supply.DefaultCodespace,
|
||||
[]string{}, []string{}, []string{types.ModuleName, staking.NotBondedPoolName, staking.BondedPoolName})
|
||||
sk := staking.NewKeeper(mApp.Cdc, keyStaking, tKeyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
|
||||
|
||||
keeper := NewKeeper(mApp.Cdc, keyGov, pk, pk.Subspace("testgov"), supplyKeeper, sk, DefaultCodespace, rtr)
|
||||
|
||||
mApp.Router().AddRoute(RouterKey, NewHandler(keeper))
|
||||
mApp.QueryRouter().AddRoute(QuerierRoute, NewQuerier(keeper))
|
||||
|
||||
mApp.SetEndBlocker(getEndBlocker(keeper))
|
||||
mApp.SetInitChainer(getInitChainer(mApp, keeper, sk, mApp.AccountKeeper, genState))
|
||||
mApp.SetInitChainer(getInitChainer(mApp, keeper, sk, supplyKeeper, genAccs, genState))
|
||||
|
||||
require.NoError(t, mApp.CompleteSetup(keyStaking, tKeyStaking, keyGov))
|
||||
|
||||
valTokens := sdk.TokensFromConsensusPower(42)
|
||||
require.NoError(t, mApp.CompleteSetup(keyStaking, tKeyStaking, keyGov, keySupply))
|
||||
|
||||
var (
|
||||
addrs []sdk.AccAddress
|
||||
|
@ -68,8 +80,7 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a
|
|||
)
|
||||
|
||||
if genAccs == nil || len(genAccs) == 0 {
|
||||
genAccs, addrs, pubKeys, privKeys = mock.CreateGenAccounts(numGenAccs,
|
||||
sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, valTokens)})
|
||||
genAccs, addrs, pubKeys, privKeys = mock.CreateGenAccounts(numGenAccs, valCoins)
|
||||
}
|
||||
|
||||
mock.SetGenesis(mApp, genAccs)
|
||||
|
@ -86,21 +97,29 @@ func getEndBlocker(keeper Keeper) sdk.EndBlocker {
|
|||
}
|
||||
|
||||
// gov and staking initchainer
|
||||
func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper,
|
||||
accountKeeper staking.AccountKeeper, genState GenesisState) sdk.InitChainer {
|
||||
|
||||
func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, supplyKeeper supply.Keeper, accs []auth.Account, genState GenesisState) sdk.InitChainer {
|
||||
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
mapp.InitChainer(ctx, req)
|
||||
|
||||
stakingGenesis := staking.DefaultGenesisState()
|
||||
tokens := sdk.TokensFromConsensusPower(100000)
|
||||
stakingGenesis.Pool.NotBondedTokens = tokens
|
||||
|
||||
validators := staking.InitGenesis(ctx, stakingKeeper, accountKeeper, stakingGenesis)
|
||||
totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens.MulRaw(int64(len(mapp.GenesisAccounts)))))
|
||||
supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply))
|
||||
|
||||
// set module accounts
|
||||
govAcc := supply.NewEmptyModuleAccount(types.ModuleName, supply.Burner)
|
||||
notBondedPool := supply.NewEmptyModuleAccount(staking.NotBondedPoolName, supply.Burner)
|
||||
bondPool := supply.NewEmptyModuleAccount(staking.BondedPoolName, supply.Burner)
|
||||
|
||||
supplyKeeper.SetModuleAccount(ctx, govAcc)
|
||||
supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
supplyKeeper.SetModuleAccount(ctx, bondPool)
|
||||
|
||||
validators := staking.InitGenesis(ctx, stakingKeeper, mapp.AccountKeeper, supplyKeeper, stakingGenesis)
|
||||
if genState.IsEmpty() {
|
||||
InitGenesis(ctx, keeper, DefaultGenesisState())
|
||||
InitGenesis(ctx, keeper, supplyKeeper, DefaultGenesisState())
|
||||
} else {
|
||||
InitGenesis(ctx, keeper, genState)
|
||||
InitGenesis(ctx, keeper, supplyKeeper, genState)
|
||||
}
|
||||
return abci.ResponseInitChain{
|
||||
Validators: validators,
|
||||
|
|
|
@ -27,6 +27,9 @@ func (v Vote) String() string {
|
|||
type Votes []Vote
|
||||
|
||||
func (v Votes) String() string {
|
||||
if len(v) == 0 {
|
||||
return "[]"
|
||||
}
|
||||
out := fmt.Sprintf("Votes for Proposal %d:", v[0].ProposalID)
|
||||
for _, vot := range v {
|
||||
out += fmt.Sprintf("\n %s: %s", vot.Voter, vot.Option)
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
supplytypes "github.com/cosmos/cosmos-sdk/x/supply/types"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
|
@ -19,6 +20,8 @@ func getMockApp(t *testing.T) *mock.App {
|
|||
mapp := mock.NewApp()
|
||||
|
||||
RegisterCodec(mapp.Cdc)
|
||||
supplytypes.RegisterCodec(mapp.Cdc)
|
||||
|
||||
keyIBC := sdk.NewKVStoreKey("ibc")
|
||||
ibcMapper := NewMapper(mapp.Cdc, keyIBC, DefaultCodespace)
|
||||
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper,
|
||||
|
|
|
@ -12,16 +12,26 @@ func BeginBlocker(ctx sdk.Context, k Keeper) {
|
|||
params := k.GetParams(ctx)
|
||||
|
||||
// recalculate inflation rate
|
||||
totalSupply := k.TotalTokens(ctx)
|
||||
totalStakingSupply := k.StakingTokenSupply(ctx)
|
||||
bondedRatio := k.BondedRatio(ctx)
|
||||
minter.Inflation = minter.NextInflationRate(params, bondedRatio)
|
||||
minter.AnnualProvisions = minter.NextAnnualProvisions(params, totalSupply)
|
||||
minter.AnnualProvisions = minter.NextAnnualProvisions(params, totalStakingSupply)
|
||||
k.SetMinter(ctx, minter)
|
||||
|
||||
// mint coins, add to collected fees, update supply
|
||||
// mint coins, update supply
|
||||
mintedCoin := minter.BlockProvision(params)
|
||||
k.AddCollectedFees(ctx, sdk.Coins{mintedCoin})
|
||||
k.InflateSupply(ctx, mintedCoin.Amount)
|
||||
mintedCoins := sdk.NewCoins(mintedCoin)
|
||||
|
||||
err := k.MintCoins(ctx, mintedCoins)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// send the minted coins to the fee collector account
|
||||
err = k.AddCollectedFees(ctx, mintedCoins)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
|
|
|
@ -26,7 +26,7 @@ func DefaultGenesisState() GenesisState {
|
|||
}
|
||||
}
|
||||
|
||||
// new mint genesis
|
||||
// InitGenesis new mint genesis
|
||||
func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) {
|
||||
keeper.SetMinter(ctx, data.Minter)
|
||||
keeper.SetParams(ctx, data.Params)
|
||||
|
|
|
@ -11,28 +11,34 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
)
|
||||
|
||||
// keeper of the staking store
|
||||
// Keeper of the mint store
|
||||
type Keeper struct {
|
||||
storeKey sdk.StoreKey
|
||||
cdc *codec.Codec
|
||||
paramSpace params.Subspace
|
||||
sk types.StakingKeeper
|
||||
fck types.FeeCollectionKeeper
|
||||
cdc *codec.Codec
|
||||
storeKey sdk.StoreKey
|
||||
paramSpace params.Subspace
|
||||
sk types.StakingKeeper
|
||||
supplyKeeper types.SupplyKeeper
|
||||
feeCollectorName string
|
||||
}
|
||||
|
||||
// NewKeeper creates a new mint Keeper instance
|
||||
func NewKeeper(
|
||||
cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace,
|
||||
sk types.StakingKeeper, fck types.FeeCollectionKeeper,
|
||||
) Keeper {
|
||||
sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string) Keeper {
|
||||
|
||||
keeper := Keeper{
|
||||
storeKey: key,
|
||||
cdc: cdc,
|
||||
paramSpace: paramSpace.WithKeyTable(types.ParamKeyTable()),
|
||||
sk: sk,
|
||||
fck: fck,
|
||||
// ensure mint module account is set
|
||||
if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil {
|
||||
panic("the mint module account has not been set")
|
||||
}
|
||||
|
||||
return Keeper{
|
||||
cdc: cdc,
|
||||
storeKey: key,
|
||||
paramSpace: paramSpace.WithKeyTable(types.ParamKeyTable()),
|
||||
sk: sk,
|
||||
supplyKeeper: supplyKeeper,
|
||||
feeCollectorName: feeCollectorName,
|
||||
}
|
||||
return keeper
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
@ -61,30 +67,6 @@ func (k Keeper) SetMinter(ctx sdk.Context, minter types.Minter) {
|
|||
store.Set(types.MinterKey, b)
|
||||
}
|
||||
|
||||
// TotalTokens implements an alias call to the underlying staking keeper's
|
||||
// TotalTokens to be used in BeginBlocker.
|
||||
func (k Keeper) TotalTokens(ctx sdk.Context) sdk.Int {
|
||||
return k.sk.TotalTokens(ctx)
|
||||
}
|
||||
|
||||
// BondedRatio implements an alias call to the underlying staking keeper's
|
||||
// BondedRatio to be used in BeginBlocker.
|
||||
func (k Keeper) BondedRatio(ctx sdk.Context) sdk.Dec {
|
||||
return k.sk.BondedRatio(ctx)
|
||||
}
|
||||
|
||||
// InflateSupply implements an alias call to the underlying staking keeper's
|
||||
// InflateSupply to be used in BeginBlocker.
|
||||
func (k Keeper) InflateSupply(ctx sdk.Context, newTokens sdk.Int) {
|
||||
k.sk.InflateSupply(ctx, newTokens)
|
||||
}
|
||||
|
||||
// AddCollectedFees implements an alias call to the underlying staking keeper's
|
||||
// AddCollectedFees to be used in BeginBlocker.
|
||||
func (k Keeper) AddCollectedFees(ctx sdk.Context, fees sdk.Coins) sdk.Coins {
|
||||
return k.fck.AddCollectedFees(ctx, fees)
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// GetParams returns the total set of minting parameters.
|
||||
|
@ -97,3 +79,29 @@ func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
|
|||
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
|
||||
k.paramSpace.SetParamSet(ctx, ¶ms)
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// StakingTokenSupply implements an alias call to the underlying staking keeper's
|
||||
// StakingTokenSupply to be used in BeginBlocker.
|
||||
func (k Keeper) StakingTokenSupply(ctx sdk.Context) sdk.Int {
|
||||
return k.sk.StakingTokenSupply(ctx)
|
||||
}
|
||||
|
||||
// BondedRatio implements an alias call to the underlying staking keeper's
|
||||
// BondedRatio to be used in BeginBlocker.
|
||||
func (k Keeper) BondedRatio(ctx sdk.Context) sdk.Dec {
|
||||
return k.sk.BondedRatio(ctx)
|
||||
}
|
||||
|
||||
// MintCoins implements an alias call to the underlying supply keeper's
|
||||
// MintCoins to be used in BeginBlocker.
|
||||
func (k Keeper) MintCoins(ctx sdk.Context, newCoins sdk.Coins) sdk.Error {
|
||||
return k.supplyKeeper.MintCoins(ctx, types.ModuleName, newCoins)
|
||||
}
|
||||
|
||||
// AddCollectedFees implements an alias call to the underlying supply keeper's
|
||||
// AddCollectedFees to be used in BeginBlocker.
|
||||
func (k Keeper) AddCollectedFees(ctx sdk.Context, fees sdk.Coins) sdk.Error {
|
||||
return k.supplyKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, k.feeCollectorName, fees)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/mint/internal/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
type testInput struct {
|
||||
|
@ -33,36 +34,48 @@ func newTestInput(t *testing.T) testInput {
|
|||
db := dbm.NewMemDB()
|
||||
|
||||
keyAcc := sdk.NewKVStoreKey(auth.StoreKey)
|
||||
keySupply := sdk.NewKVStoreKey(supply.StoreKey)
|
||||
keyStaking := sdk.NewKVStoreKey(staking.StoreKey)
|
||||
tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey)
|
||||
keyParams := sdk.NewKVStoreKey(params.StoreKey)
|
||||
tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey)
|
||||
keyFeeCollection := sdk.NewKVStoreKey(auth.FeeStoreKey)
|
||||
keyMint := sdk.NewKVStoreKey(types.StoreKey)
|
||||
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyStaking, sdk.StoreTypeTransient, nil)
|
||||
ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyFeeCollection, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyMint, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
|
||||
err := ms.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
|
||||
ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout))
|
||||
|
||||
paramsKeeper := params.NewKeeper(types.ModuleCdc, keyParams, tkeyParams, params.DefaultCodespace)
|
||||
feeCollectionKeeper := auth.NewFeeCollectionKeeper(types.ModuleCdc, keyFeeCollection)
|
||||
accountKeeper := auth.NewAccountKeeper(types.ModuleCdc, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount)
|
||||
bankKeeper := bank.NewBaseKeeper(accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace)
|
||||
stakingKeeper := staking.NewKeeper(
|
||||
types.ModuleCdc, keyStaking, tkeyStaking, bankKeeper, paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace,
|
||||
)
|
||||
mintKeeper := NewKeeper(
|
||||
types.ModuleCdc, keyMint, paramsKeeper.Subspace(types.DefaultParamspace), &stakingKeeper, feeCollectionKeeper,
|
||||
)
|
||||
supplyKeeper := supply.NewKeeper(types.ModuleCdc, keySupply, accountKeeper, bankKeeper, supply.DefaultCodespace,
|
||||
[]string{auth.FeeCollectorName}, []string{types.ModuleName}, []string{staking.NotBondedPoolName, staking.BondedPoolName})
|
||||
supplyKeeper.SetSupply(ctx, supply.NewSupply(sdk.Coins{}))
|
||||
|
||||
ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout))
|
||||
stakingKeeper := staking.NewKeeper(
|
||||
types.ModuleCdc, keyStaking, tkeyStaking, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace,
|
||||
)
|
||||
mintKeeper := NewKeeper(types.ModuleCdc, keyMint, paramsKeeper.Subspace(types.DefaultParamspace), &stakingKeeper, supplyKeeper, auth.FeeCollectorName)
|
||||
|
||||
// set module accounts
|
||||
feeCollectorAcc := supply.NewEmptyModuleAccount(auth.FeeCollectorName, supply.Basic)
|
||||
minterAcc := supply.NewEmptyModuleAccount(types.ModuleName, supply.Minter)
|
||||
notBondedPool := supply.NewEmptyModuleAccount(staking.NotBondedPoolName, supply.Burner)
|
||||
bondPool := supply.NewEmptyModuleAccount(staking.BondedPoolName, supply.Burner)
|
||||
|
||||
supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc)
|
||||
supplyKeeper.SetModuleAccount(ctx, minterAcc)
|
||||
supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
supplyKeeper.SetModuleAccount(ctx, bondPool)
|
||||
|
||||
mintKeeper.SetParams(ctx, types.DefaultParams())
|
||||
mintKeeper.SetMinter(ctx, types.DefaultInitialMinter())
|
||||
|
|
|
@ -2,16 +2,23 @@ package types // noalias
|
|||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
)
|
||||
|
||||
// expected staking keeper
|
||||
// StakingKeeper defines the expected staking keeper
|
||||
type StakingKeeper interface {
|
||||
TotalTokens(ctx sdk.Context) sdk.Int
|
||||
StakingTokenSupply(ctx sdk.Context) sdk.Int
|
||||
BondedRatio(ctx sdk.Context) sdk.Dec
|
||||
InflateSupply(ctx sdk.Context, newTokens sdk.Int)
|
||||
}
|
||||
|
||||
// expected fee collection keeper interface
|
||||
type FeeCollectionKeeper interface {
|
||||
AddCollectedFees(sdk.Context, sdk.Coins) sdk.Coins
|
||||
// SupplyKeeper defines the expected supply keeper
|
||||
type SupplyKeeper interface {
|
||||
GetModuleAddress(name string) sdk.AccAddress
|
||||
|
||||
// TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862
|
||||
SetModuleAccount(sdk.Context, exported.ModuleAccountI)
|
||||
|
||||
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error
|
||||
SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) sdk.Error
|
||||
MintCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error
|
||||
}
|
||||
|
|
|
@ -28,17 +28,15 @@ const chainID = ""
|
|||
// capabilities aren't needed for testing.
|
||||
type App struct {
|
||||
*bam.BaseApp
|
||||
Cdc *codec.Codec // Cdc is public since the codec is passed into the module anyways
|
||||
KeyMain *sdk.KVStoreKey
|
||||
KeyAccount *sdk.KVStoreKey
|
||||
KeyFeeCollection *sdk.KVStoreKey
|
||||
KeyParams *sdk.KVStoreKey
|
||||
TKeyParams *sdk.TransientStoreKey
|
||||
Cdc *codec.Codec // Cdc is public since the codec is passed into the module anyways
|
||||
KeyMain *sdk.KVStoreKey
|
||||
KeyAccount *sdk.KVStoreKey
|
||||
KeyParams *sdk.KVStoreKey
|
||||
TKeyParams *sdk.TransientStoreKey
|
||||
|
||||
// TODO: Abstract this out from not needing to be auth specifically
|
||||
AccountKeeper auth.AccountKeeper
|
||||
FeeCollectionKeeper auth.FeeCollectionKeeper
|
||||
ParamsKeeper params.Keeper
|
||||
AccountKeeper auth.AccountKeeper
|
||||
ParamsKeeper params.Keeper
|
||||
|
||||
GenesisAccounts []auth.Account
|
||||
TotalCoinsSupply sdk.Coins
|
||||
|
@ -59,30 +57,27 @@ func NewApp() *App {
|
|||
Cdc: cdc,
|
||||
KeyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
|
||||
KeyAccount: sdk.NewKVStoreKey(auth.StoreKey),
|
||||
KeyFeeCollection: sdk.NewKVStoreKey("fee"),
|
||||
KeyParams: sdk.NewKVStoreKey("params"),
|
||||
TKeyParams: sdk.NewTransientStoreKey("transient_params"),
|
||||
TotalCoinsSupply: sdk.NewCoins(),
|
||||
}
|
||||
|
||||
// define keepers
|
||||
app.ParamsKeeper = params.NewKeeper(app.Cdc, app.KeyParams, app.TKeyParams, params.DefaultCodespace)
|
||||
|
||||
// Define the accountKeeper
|
||||
app.AccountKeeper = auth.NewAccountKeeper(
|
||||
app.Cdc,
|
||||
app.KeyAccount,
|
||||
app.ParamsKeeper.Subspace(auth.DefaultParamspace),
|
||||
auth.ProtoBaseAccount,
|
||||
)
|
||||
app.FeeCollectionKeeper = auth.NewFeeCollectionKeeper(
|
||||
app.Cdc,
|
||||
app.KeyFeeCollection,
|
||||
)
|
||||
|
||||
supplyKeeper := auth.NewDummySupplyKeeper(app.AccountKeeper)
|
||||
|
||||
// Initialize the app. The chainers and blockers can be overwritten before
|
||||
// calling complete setup.
|
||||
app.SetInitChainer(app.InitChainer)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.AccountKeeper, app.FeeCollectionKeeper, auth.DefaultSigVerificationGasConsumer))
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.AccountKeeper, supplyKeeper, auth.DefaultSigVerificationGasConsumer))
|
||||
|
||||
// Not sealing for custom extension
|
||||
|
||||
|
@ -94,7 +89,7 @@ func NewApp() *App {
|
|||
func (app *App) CompleteSetup(newKeys ...sdk.StoreKey) error {
|
||||
newKeys = append(
|
||||
newKeys,
|
||||
app.KeyMain, app.KeyAccount, app.KeyParams, app.TKeyParams, app.KeyFeeCollection,
|
||||
app.KeyMain, app.KeyAccount, app.KeyParams, app.TKeyParams,
|
||||
)
|
||||
|
||||
for _, key := range newKeys {
|
||||
|
@ -116,6 +111,7 @@ func (app *App) CompleteSetup(newKeys ...sdk.StoreKey) error {
|
|||
// InitChainer performs custom logic for initialization.
|
||||
// nolint: errcheck
|
||||
func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain {
|
||||
|
||||
// Load the genesis accounts
|
||||
for _, genacc := range app.GenesisAccounts {
|
||||
acc := app.AccountKeeper.NewAccountWithAddress(ctx, genacc.GetAddress())
|
||||
|
@ -123,7 +119,7 @@ func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.Respo
|
|||
app.AccountKeeper.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
auth.InitGenesis(ctx, app.AccountKeeper, app.FeeCollectionKeeper, auth.DefaultGenesisState())
|
||||
auth.InitGenesis(ctx, app.AccountKeeper, auth.DefaultGenesisState())
|
||||
|
||||
return abci.ResponseInitChain{}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
supplytypes "github.com/cosmos/cosmos-sdk/x/supply/types"
|
||||
)
|
||||
|
||||
const msgRoute = "testMsg"
|
||||
|
@ -51,6 +52,7 @@ func getMockApp(t *testing.T) *App {
|
|||
func TestCheckAndDeliverGenTx(t *testing.T) {
|
||||
mApp := getMockApp(t)
|
||||
mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil)
|
||||
supplytypes.RegisterCodec(mApp.Cdc)
|
||||
|
||||
SetGenesis(mApp, accs)
|
||||
ctxCheck := mApp.BaseApp.NewContext(true, abci.Header{})
|
||||
|
@ -90,6 +92,7 @@ func TestCheckAndDeliverGenTx(t *testing.T) {
|
|||
func TestCheckGenTx(t *testing.T) {
|
||||
mApp := getMockApp(t)
|
||||
mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil)
|
||||
supplytypes.RegisterCodec(mApp.Cdc)
|
||||
|
||||
SetGenesis(mApp, accs)
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// nolint
|
||||
const (
|
||||
// Minimum time per block
|
||||
minTimePerBlock int64 = 10000 / 2
|
||||
|
@ -148,6 +149,7 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
// TODO add description
|
||||
type (
|
||||
AppParams map[string]json.RawMessage
|
||||
ParamSimulator func(r *rand.Rand)
|
||||
|
|
|
@ -36,6 +36,7 @@ func RandStringOfLength(r *rand.Rand, n int) string {
|
|||
return string(b)
|
||||
}
|
||||
|
||||
// get a rand positive sdk.Int
|
||||
func RandPositiveInt(r *rand.Rand, max sdk.Int) (sdk.Int, error) {
|
||||
if !max.GT(sdk.OneInt()) {
|
||||
return sdk.Int{}, errors.New("max too small")
|
||||
|
|
|
@ -63,7 +63,7 @@ func getBlockSize(r *rand.Rand, params Params,
|
|||
|
||||
// PeriodicInvariants returns an array of wrapped Invariants. Where each
|
||||
// invariant function is only executed periodically defined by period and offset.
|
||||
func PeriodicInvariants(invariants []sdk.Invariant, period int, offset int) []sdk.Invariant {
|
||||
func PeriodicInvariants(invariants []sdk.Invariant, period, offset int) []sdk.Invariant {
|
||||
var outInvariants []sdk.Invariant
|
||||
for _, invariant := range invariants {
|
||||
outInvariant := func(ctx sdk.Context) error {
|
||||
|
|
|
@ -24,7 +24,7 @@ func TestBeginBlocker(t *testing.T) {
|
|||
staking.EndBlocker(ctx, sk)
|
||||
require.Equal(
|
||||
t, ck.GetCoins(ctx, sdk.AccAddress(addr)),
|
||||
sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, initCoins.Sub(amt))},
|
||||
sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, initTokens.Sub(amt))),
|
||||
)
|
||||
require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens())
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -27,21 +28,25 @@ func getMockApp(t *testing.T) (*mock.App, staking.Keeper, Keeper) {
|
|||
|
||||
RegisterCodec(mapp.Cdc)
|
||||
staking.RegisterCodec(mapp.Cdc)
|
||||
supply.RegisterCodec(mapp.Cdc)
|
||||
|
||||
keyStaking := sdk.NewKVStoreKey(staking.StoreKey)
|
||||
tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey)
|
||||
keySlashing := sdk.NewKVStoreKey(StoreKey)
|
||||
keySupply := sdk.NewKVStoreKey(supply.StoreKey)
|
||||
|
||||
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace)
|
||||
stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, tkeyStaking, bankKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
|
||||
supplyKeeper := supply.NewKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, bankKeeper, supply.DefaultCodespace,
|
||||
[]string{auth.FeeCollectorName}, []string{}, []string{staking.NotBondedPoolName, staking.BondedPoolName})
|
||||
stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, tkeyStaking, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
|
||||
keeper := NewKeeper(mapp.Cdc, keySlashing, stakingKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace)
|
||||
mapp.Router().AddRoute(staking.RouterKey, staking.NewHandler(stakingKeeper))
|
||||
mapp.Router().AddRoute(RouterKey, NewHandler(keeper))
|
||||
|
||||
mapp.SetEndBlocker(getEndBlocker(stakingKeeper))
|
||||
mapp.SetInitChainer(getInitChainer(mapp, stakingKeeper, mapp.AccountKeeper))
|
||||
mapp.SetInitChainer(getInitChainer(mapp, stakingKeeper, mapp.AccountKeeper, supplyKeeper))
|
||||
|
||||
require.NoError(t, mapp.CompleteSetup(keyStaking, tkeyStaking, keySlashing))
|
||||
require.NoError(t, mapp.CompleteSetup(keyStaking, tkeyStaking, keySupply, keySlashing))
|
||||
|
||||
return mapp, stakingKeeper, keeper
|
||||
}
|
||||
|
@ -57,13 +62,20 @@ func getEndBlocker(keeper staking.Keeper) sdk.EndBlocker {
|
|||
}
|
||||
|
||||
// overwrite the mock init chainer
|
||||
func getInitChainer(mapp *mock.App, keeper staking.Keeper, accountKeeper types.AccountKeeper) sdk.InitChainer {
|
||||
func getInitChainer(mapp *mock.App, keeper staking.Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper) sdk.InitChainer {
|
||||
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
// set module accounts
|
||||
feeCollector := supply.NewEmptyModuleAccount(auth.FeeCollectorName, supply.Basic)
|
||||
notBondedPool := supply.NewEmptyModuleAccount(types.NotBondedPoolName, supply.Burner)
|
||||
bondPool := supply.NewEmptyModuleAccount(types.BondedPoolName, supply.Burner)
|
||||
|
||||
supplyKeeper.SetModuleAccount(ctx, feeCollector)
|
||||
supplyKeeper.SetModuleAccount(ctx, bondPool)
|
||||
supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
mapp.InitChainer(ctx, req)
|
||||
stakingGenesis := staking.DefaultGenesisState()
|
||||
tokens := sdk.TokensFromConsensusPower(100000)
|
||||
stakingGenesis.Pool.NotBondedTokens = tokens
|
||||
validators := staking.InitGenesis(ctx, keeper, accountKeeper, stakingGenesis)
|
||||
validators := staking.InitGenesis(ctx, keeper, accountKeeper, supplyKeeper, stakingGenesis)
|
||||
return abci.ResponseInitChain{
|
||||
Validators: validators,
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ func TestCannotUnjailUnlessJailed(t *testing.T) {
|
|||
|
||||
require.Equal(
|
||||
t, ck.GetCoins(ctx, sdk.AccAddress(addr)),
|
||||
sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, initCoins.Sub(amt))},
|
||||
sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, initTokens.Sub(amt))},
|
||||
)
|
||||
require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens())
|
||||
|
||||
|
@ -50,7 +50,7 @@ func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) {
|
|||
|
||||
require.Equal(
|
||||
t, ck.GetCoins(ctx, sdk.AccAddress(addr)),
|
||||
sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, initCoins.Sub(amt))},
|
||||
sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, initTokens.Sub(amt))},
|
||||
)
|
||||
|
||||
unbondAmt := sdk.NewCoin(sk.GetParams(ctx).BondDenom, sdk.OneInt())
|
||||
|
|
|
@ -69,7 +69,7 @@ func (k Keeper) HandleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio
|
|||
// Reject evidence if the double-sign is too old
|
||||
if age > k.MaxEvidenceAge(ctx) {
|
||||
logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d",
|
||||
pubkey.Address(), infractionHeight, age, k.MaxEvidenceAge(ctx)))
|
||||
sdk.ConsAddress(pubkey.Address()), infractionHeight, age, k.MaxEvidenceAge(ctx)))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -90,12 +90,12 @@ func (k Keeper) HandleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio
|
|||
|
||||
// validator is already tombstoned
|
||||
if signInfo.Tombstoned {
|
||||
logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, validator already tombstoned", pubkey.Address(), infractionHeight))
|
||||
logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, validator already tombstoned", sdk.ConsAddress(pubkey.Address()), infractionHeight))
|
||||
return
|
||||
}
|
||||
|
||||
// double sign confirmed
|
||||
logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d", pubkey.Address(), infractionHeight, age))
|
||||
logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d", sdk.ConsAddress(pubkey.Address()), infractionHeight, age))
|
||||
|
||||
// We need to retrieve the stake distribution which signed the block, so we subtract ValidatorUpdateDelay from the evidence height.
|
||||
// Note that this *can* result in a negative "distributionHeight", up to -ValidatorUpdateDelay,
|
||||
|
@ -151,7 +151,7 @@ func (k Keeper) HandleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
|
|||
consAddr := sdk.ConsAddress(addr)
|
||||
pubkey, err := k.getPubkey(ctx, addr)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))
|
||||
panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr.String()))
|
||||
}
|
||||
|
||||
// fetch signing info
|
||||
|
@ -193,7 +193,7 @@ func (k Keeper) HandleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
|
|||
),
|
||||
)
|
||||
|
||||
logger.Info(fmt.Sprintf("Absent validator %s (%v) at height %d, %d missed, threshold %d", addr, pubkey, height, signInfo.MissedBlocksCounter, k.MinSignedPerWindow(ctx)))
|
||||
logger.Info(fmt.Sprintf("Absent validator %s (%s) at height %d, %d missed, threshold %d", addr, pubkey, height, signInfo.MissedBlocksCounter, k.MinSignedPerWindow(ctx)))
|
||||
}
|
||||
|
||||
minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx)
|
||||
|
@ -206,7 +206,7 @@ func (k Keeper) HandleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
|
|||
|
||||
// Downtime confirmed: slash and jail the validator
|
||||
logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d",
|
||||
pubkey.Address(), minHeight, k.MinSignedPerWindow(ctx)))
|
||||
sdk.ConsAddress(pubkey.Address()), minHeight, k.MinSignedPerWindow(ctx)))
|
||||
|
||||
// We need to retrieve the stake distribution which signed the block, so we subtract ValidatorUpdateDelay from the evidence height,
|
||||
// and subtract an additional 1 since this is the LastCommit.
|
||||
|
@ -236,7 +236,7 @@ func (k Keeper) HandleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
|
|||
} else {
|
||||
// Validator was (a) not found or (b) already jailed, don't slash
|
||||
logger.Info(fmt.Sprintf("Validator %s would have been slashed for downtime, but was either not found in store or already jailed",
|
||||
pubkey.Address()))
|
||||
sdk.ConsAddress(pubkey.Address())))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ func (k Keeper) getPubkey(ctx sdk.Context, address crypto.Address) (crypto.PubKe
|
|||
var pubkey crypto.PubKey
|
||||
err := k.cdc.UnmarshalBinaryLengthPrefixed(store.Get(types.GetAddrPubkeyRelationKey(address)), &pubkey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("address %v not found", address)
|
||||
return nil, fmt.Errorf("address %s not found", sdk.ConsAddress(address))
|
||||
}
|
||||
return pubkey, nil
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func TestHandleDoubleSign(t *testing.T) {
|
|||
staking.EndBlocker(ctx, sk)
|
||||
require.Equal(
|
||||
t, ck.GetCoins(ctx, sdk.AccAddress(operatorAddr)),
|
||||
sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, initCoins.Sub(amt))},
|
||||
sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, initTokens.Sub(amt))),
|
||||
)
|
||||
require.Equal(t, amt, sk.Validator(ctx, operatorAddr).GetBondedTokens())
|
||||
|
||||
|
@ -100,7 +100,7 @@ func TestPastMaxEvidenceAge(t *testing.T) {
|
|||
staking.EndBlocker(ctx, sk)
|
||||
require.Equal(
|
||||
t, ck.GetCoins(ctx, sdk.AccAddress(operatorAddr)),
|
||||
sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, initCoins.Sub(amt))},
|
||||
sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, initTokens.Sub(amt))),
|
||||
)
|
||||
require.Equal(t, amt, sk.Validator(ctx, operatorAddr).GetBondedTokens())
|
||||
|
||||
|
@ -138,7 +138,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
|||
|
||||
require.Equal(
|
||||
t, ck.GetCoins(ctx, sdk.AccAddress(addr)),
|
||||
sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, initCoins.Sub(amt))},
|
||||
sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, initTokens.Sub(amt))),
|
||||
)
|
||||
require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens())
|
||||
|
||||
|
@ -174,8 +174,8 @@ func TestHandleAbsentValidator(t *testing.T) {
|
|||
// validator should be bonded still
|
||||
validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val))
|
||||
require.Equal(t, sdk.Bonded, validator.GetStatus())
|
||||
pool := sk.GetPool(ctx)
|
||||
require.True(sdk.IntEq(t, amt, pool.BondedTokens))
|
||||
bondPool := sk.GetBondedPool(ctx)
|
||||
require.True(sdk.IntEq(t, amt, bondPool.GetCoins().AmountOf(sk.BondDenom(ctx))))
|
||||
|
||||
// 501st block missed
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
|
@ -231,8 +231,8 @@ func TestHandleAbsentValidator(t *testing.T) {
|
|||
require.Equal(t, sdk.Bonded, validator.GetStatus())
|
||||
|
||||
// validator should have been slashed
|
||||
pool = sk.GetPool(ctx)
|
||||
require.Equal(t, amt.Int64()-slashAmt, pool.BondedTokens.Int64())
|
||||
bondPool = sk.GetBondedPool(ctx)
|
||||
require.Equal(t, amt.Int64()-slashAmt, bondPool.GetCoins().AmountOf(sk.BondDenom(ctx)).Int64())
|
||||
|
||||
// Validator start height should not have been changed
|
||||
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
|
||||
|
@ -292,7 +292,7 @@ func TestHandleNewValidator(t *testing.T) {
|
|||
|
||||
require.Equal(
|
||||
t, ck.GetCoins(ctx, sdk.AccAddress(addr)),
|
||||
sdk.Coins{sdk.NewCoin(sk.GetParams(ctx).BondDenom, initCoins.Sub(amt))},
|
||||
sdk.NewCoins(sdk.NewCoin(sk.GetParams(ctx).BondDenom, initTokens.Sub(amt))),
|
||||
)
|
||||
require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens())
|
||||
|
||||
|
@ -311,9 +311,9 @@ func TestHandleNewValidator(t *testing.T) {
|
|||
// validator should be bonded still, should not have been jailed or slashed
|
||||
validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val))
|
||||
require.Equal(t, sdk.Bonded, validator.GetStatus())
|
||||
pool := sk.GetPool(ctx)
|
||||
bondPool := sk.GetBondedPool(ctx)
|
||||
expTokens := sdk.TokensFromConsensusPower(100)
|
||||
require.Equal(t, expTokens, pool.BondedTokens)
|
||||
require.Equal(t, expTokens.Int64(), bondPool.GetCoins().AmountOf(sk.BondDenom(ctx)).Int64())
|
||||
}
|
||||
|
||||
// Test a jailed validator being "down" twice
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
// TODO remove dependencies on staking (should only refer to validator set type from sdk)
|
||||
|
@ -36,13 +37,15 @@ var (
|
|||
sdk.ValAddress(pks[1].Address()),
|
||||
sdk.ValAddress(pks[2].Address()),
|
||||
}
|
||||
initCoins = sdk.TokensFromConsensusPower(200)
|
||||
initTokens = sdk.TokensFromConsensusPower(200)
|
||||
initCoins = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))
|
||||
)
|
||||
|
||||
func createTestCodec() *codec.Codec {
|
||||
cdc := codec.New()
|
||||
sdk.RegisterCodec(cdc)
|
||||
auth.RegisterCodec(cdc)
|
||||
supply.RegisterCodec(cdc)
|
||||
bank.RegisterCodec(cdc)
|
||||
staking.RegisterCodec(cdc)
|
||||
codec.RegisterCrypto(cdc)
|
||||
|
@ -54,6 +57,7 @@ func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, s
|
|||
keyStaking := sdk.NewKVStoreKey(staking.StoreKey)
|
||||
tkeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey)
|
||||
keySlashing := sdk.NewKVStoreKey(StoreKey)
|
||||
keySupply := sdk.NewKVStoreKey(supply.StoreKey)
|
||||
keyParams := sdk.NewKVStoreKey(params.StoreKey)
|
||||
tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey)
|
||||
db := dbm.NewMemDB()
|
||||
|
@ -61,6 +65,7 @@ func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, s
|
|||
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyStaking, sdk.StoreTypeTransient, nil)
|
||||
ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
|
||||
|
@ -71,18 +76,29 @@ func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, s
|
|||
paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace)
|
||||
accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount)
|
||||
|
||||
ck := bank.NewBaseKeeper(accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace)
|
||||
sk := staking.NewKeeper(cdc, keyStaking, tkeyStaking, ck, paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
|
||||
bk := bank.NewBaseKeeper(accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace)
|
||||
supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bk, supply.DefaultCodespace,
|
||||
[]string{auth.FeeCollectorName}, []string{}, []string{staking.NotBondedPoolName, staking.BondedPoolName})
|
||||
|
||||
totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens.MulRaw(int64(len(addrs)))))
|
||||
supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply))
|
||||
|
||||
sk := staking.NewKeeper(cdc, keyStaking, tkeyStaking, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
|
||||
genesis := staking.DefaultGenesisState()
|
||||
|
||||
genesis.Pool.NotBondedTokens = initCoins.MulRaw(int64(len(addrs)))
|
||||
// set module accounts
|
||||
feeCollectorAcc := supply.NewEmptyModuleAccount(auth.FeeCollectorName, supply.Basic)
|
||||
notBondedPool := supply.NewEmptyModuleAccount(staking.NotBondedPoolName, supply.Burner)
|
||||
bondPool := supply.NewEmptyModuleAccount(staking.BondedPoolName, supply.Burner)
|
||||
|
||||
_ = staking.InitGenesis(ctx, sk, accountKeeper, genesis)
|
||||
supplyKeeper.SetModuleAccount(ctx, feeCollectorAcc)
|
||||
supplyKeeper.SetModuleAccount(ctx, bondPool)
|
||||
supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
_ = staking.InitGenesis(ctx, sk, accountKeeper, supplyKeeper, genesis)
|
||||
|
||||
for _, addr := range addrs {
|
||||
_, err = ck.AddCoins(ctx, sdk.AccAddress(addr), sdk.Coins{
|
||||
{sk.GetParams(ctx).BondDenom, initCoins},
|
||||
})
|
||||
_, err = bk.AddCoins(ctx, sdk.AccAddress(addr), initCoins)
|
||||
}
|
||||
require.Nil(t, err)
|
||||
paramstore := paramsKeeper.Subspace(DefaultParamspace)
|
||||
|
@ -93,7 +109,7 @@ func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, s
|
|||
InitGenesis(ctx, keeper, sk, GenesisState{defaults, nil, nil})
|
||||
})
|
||||
|
||||
return ctx, ck, sk, paramstore, keeper
|
||||
return ctx, bk, sk, paramstore, keeper
|
||||
}
|
||||
|
||||
func newPubKey(pk string) (res crypto.PubKey) {
|
||||
|
|
|
@ -31,6 +31,8 @@ const (
|
|||
DefaultUnbondingTime = types.DefaultUnbondingTime
|
||||
DefaultMaxValidators = types.DefaultMaxValidators
|
||||
DefaultMaxEntries = types.DefaultMaxEntries
|
||||
NotBondedPoolName = types.NotBondedPoolName
|
||||
BondedPoolName = types.BondedPoolName
|
||||
QueryValidators = types.QueryValidators
|
||||
QueryValidator = types.QueryValidator
|
||||
QueryDelegatorDelegations = types.QueryDelegatorDelegations
|
||||
|
@ -56,7 +58,7 @@ var (
|
|||
// functions aliases
|
||||
RegisterInvariants = keeper.RegisterInvariants
|
||||
AllInvariants = keeper.AllInvariants
|
||||
SupplyInvariants = keeper.SupplyInvariants
|
||||
ModuleAccountInvariants = keeper.ModuleAccountInvariants
|
||||
NonNegativePowerInvariant = keeper.NonNegativePowerInvariant
|
||||
PositiveDelegationInvariant = keeper.PositiveDelegationInvariant
|
||||
DelegatorSharesInvariant = keeper.DelegatorSharesInvariant
|
||||
|
@ -166,9 +168,7 @@ var (
|
|||
DefaultParams = types.DefaultParams
|
||||
MustUnmarshalParams = types.MustUnmarshalParams
|
||||
UnmarshalParams = types.UnmarshalParams
|
||||
InitialPool = types.InitialPool
|
||||
MustUnmarshalPool = types.MustUnmarshalPool
|
||||
UnmarshalPool = types.UnmarshalPool
|
||||
NewPool = types.NewPool
|
||||
NewQueryDelegatorParams = types.NewQueryDelegatorParams
|
||||
NewQueryValidatorParams = types.NewQueryValidatorParams
|
||||
NewQueryBondsParams = types.NewQueryBondsParams
|
||||
|
@ -223,7 +223,6 @@ type (
|
|||
RedelegationEntryResponse = types.RedelegationEntryResponse
|
||||
RedelegationResponses = types.RedelegationResponses
|
||||
CodeType = types.CodeType
|
||||
AccountKeeper = types.AccountKeeper
|
||||
GenesisState = types.GenesisState
|
||||
LastValidatorPower = types.LastValidatorPower
|
||||
MultiStakingHooks = types.MultiStakingHooks
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
// getMockApp returns an initialized mock application for this module.
|
||||
|
@ -18,18 +19,22 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) {
|
|||
mApp := mock.NewApp()
|
||||
|
||||
RegisterCodec(mApp.Cdc)
|
||||
supply.RegisterCodec(mApp.Cdc)
|
||||
|
||||
keyStaking := sdk.NewKVStoreKey(StoreKey)
|
||||
tkeyStaking := sdk.NewTransientStoreKey(TStoreKey)
|
||||
keySupply := sdk.NewKVStoreKey(supply.StoreKey)
|
||||
|
||||
bankKeeper := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace)
|
||||
keeper := NewKeeper(mApp.Cdc, keyStaking, tkeyStaking, bankKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace)
|
||||
supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bankKeeper, supply.DefaultCodespace,
|
||||
[]string{auth.FeeCollectorName}, []string{}, []string{types.NotBondedPoolName, types.BondedPoolName})
|
||||
keeper := NewKeeper(mApp.Cdc, keyStaking, tkeyStaking, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace)
|
||||
|
||||
mApp.Router().AddRoute(RouterKey, NewHandler(keeper))
|
||||
mApp.SetEndBlocker(getEndBlocker(keeper))
|
||||
mApp.SetInitChainer(getInitChainer(mApp, keeper, mApp.AccountKeeper))
|
||||
mApp.SetInitChainer(getInitChainer(mApp, keeper, mApp.AccountKeeper, supplyKeeper))
|
||||
|
||||
require.NoError(t, mApp.CompleteSetup(keyStaking, tkeyStaking))
|
||||
require.NoError(t, mApp.CompleteSetup(keyStaking, tkeyStaking, keySupply))
|
||||
return mApp, keeper
|
||||
}
|
||||
|
||||
|
@ -46,15 +51,21 @@ func getEndBlocker(keeper Keeper) sdk.EndBlocker {
|
|||
|
||||
// getInitChainer initializes the chainer of the mock app and sets the genesis
|
||||
// state. It returns an empty ResponseInitChain.
|
||||
func getInitChainer(mapp *mock.App, keeper Keeper, accountKeeper types.AccountKeeper) sdk.InitChainer {
|
||||
func getInitChainer(mapp *mock.App, keeper Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper) sdk.InitChainer {
|
||||
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
mapp.InitChainer(ctx, req)
|
||||
|
||||
stakingGenesis := DefaultGenesisState()
|
||||
tokens := sdk.TokensFromConsensusPower(100000)
|
||||
stakingGenesis.Pool.NotBondedTokens = tokens
|
||||
// set module accounts
|
||||
feeCollector := supply.NewEmptyModuleAccount(auth.FeeCollectorName, supply.Basic)
|
||||
notBondedPool := supply.NewEmptyModuleAccount(types.NotBondedPoolName, supply.Burner)
|
||||
bondPool := supply.NewEmptyModuleAccount(types.BondedPoolName, supply.Burner)
|
||||
|
||||
validators := InitGenesis(ctx, keeper, accountKeeper, stakingGenesis)
|
||||
supplyKeeper.SetModuleAccount(ctx, feeCollector)
|
||||
supplyKeeper.SetModuleAccount(ctx, bondPool)
|
||||
supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
stakingGenesis := DefaultGenesisState()
|
||||
validators := InitGenesis(ctx, keeper, accountKeeper, supplyKeeper, stakingGenesis)
|
||||
return abci.ResponseInitChain{
|
||||
Validators: validators,
|
||||
}
|
||||
|
|
|
@ -545,17 +545,22 @@ $ %s query staking pool
|
|||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
res, _, err := cliCtx.QueryStore(types.PoolKey, storeName)
|
||||
bz, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/pool", storeName), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cliCtx.PrintOutput(types.MustUnmarshalPool(cdc, res))
|
||||
var pool types.Pool
|
||||
if err := cdc.UnmarshalJSON(bz, &pool); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cliCtx.PrintOutput(pool)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetCmdQueryPool implements the params query command.
|
||||
// GetCmdQueryParams implements the params query command.
|
||||
func GetCmdQueryParams(storeName string, cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "params",
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
)
|
||||
|
@ -17,7 +16,11 @@ import (
|
|||
// setting the indexes. In addition, it also sets any delegations found in
|
||||
// data. Finally, it updates the bonded validators.
|
||||
// Returns final validator set after applying all declaration and delegations
|
||||
func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeeper, data types.GenesisState) (res []abci.ValidatorUpdate) {
|
||||
func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeeper,
|
||||
supplyKeeper types.SupplyKeeper, data types.GenesisState) (res []abci.ValidatorUpdate) {
|
||||
|
||||
bondedTokens := sdk.ZeroInt()
|
||||
notBondedTokens := sdk.ZeroInt()
|
||||
|
||||
// We need to pretend to be "n blocks before genesis", where "n" is the
|
||||
// validator update delay, so that e.g. slashing periods are correctly
|
||||
|
@ -26,18 +29,6 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeep
|
|||
// genesis.json are in block 0.
|
||||
ctx = ctx.WithBlockHeight(1 - sdk.ValidatorUpdateDelay)
|
||||
|
||||
// manually set the total supply for staking based on accounts if not provided
|
||||
if data.Pool.NotBondedTokens.IsZero() {
|
||||
accountKeeper.IterateAccounts(ctx,
|
||||
func(acc auth.Account) (stop bool) {
|
||||
data.Pool.NotBondedTokens = data.Pool.NotBondedTokens.
|
||||
Add(acc.GetCoins().AmountOf(data.Params.BondDenom))
|
||||
return false
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
keeper.SetPool(ctx, data.Pool) // TODO remove pool from genesis data and always calculate?
|
||||
keeper.SetParams(ctx, data.Params)
|
||||
keeper.SetLastTotalPower(ctx, data.LastTotalPower)
|
||||
|
||||
|
@ -53,10 +44,19 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeep
|
|||
keeper.AfterValidatorCreated(ctx, validator.OperatorAddress)
|
||||
}
|
||||
|
||||
// Set timeslice if necessary
|
||||
// update timeslice if necessary
|
||||
if validator.IsUnbonding() {
|
||||
keeper.InsertValidatorQueue(ctx, validator)
|
||||
}
|
||||
|
||||
switch validator.GetStatus() {
|
||||
case sdk.Bonded:
|
||||
bondedTokens = bondedTokens.Add(validator.GetTokens())
|
||||
case sdk.Unbonding, sdk.Unbonded:
|
||||
notBondedTokens = notBondedTokens.Add(validator.GetTokens())
|
||||
default:
|
||||
panic("invalid validator status")
|
||||
}
|
||||
}
|
||||
|
||||
for _, delegation := range data.Delegations {
|
||||
|
@ -65,6 +65,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeep
|
|||
keeper.BeforeDelegationCreated(ctx, delegation.DelegatorAddress, delegation.ValidatorAddress)
|
||||
}
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
// Call the after-modification hook if not exported
|
||||
if !data.Exported {
|
||||
keeper.AfterDelegationModified(ctx, delegation.DelegatorAddress, delegation.ValidatorAddress)
|
||||
|
@ -75,6 +76,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeep
|
|||
keeper.SetUnbondingDelegation(ctx, ubd)
|
||||
for _, entry := range ubd.Entries {
|
||||
keeper.InsertUBDQueue(ctx, ubd, entry.CompletionTime)
|
||||
notBondedTokens = notBondedTokens.Add(entry.Balance)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,13 +87,43 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeep
|
|||
}
|
||||
}
|
||||
|
||||
bondedCoins := sdk.NewCoins(sdk.NewCoin(data.Params.BondDenom, bondedTokens))
|
||||
notBondedCoins := sdk.NewCoins(sdk.NewCoin(data.Params.BondDenom, notBondedTokens))
|
||||
|
||||
// check if the unbonded and bonded pools accounts exists
|
||||
bondedPool := keeper.GetBondedPool(ctx)
|
||||
if bondedPool == nil {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.BondedPoolName))
|
||||
}
|
||||
|
||||
// TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862
|
||||
// add coins if not provided on genesis
|
||||
if bondedPool.GetCoins().IsZero() {
|
||||
if err := bondedPool.SetCoins(bondedCoins); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
supplyKeeper.SetModuleAccount(ctx, bondedPool)
|
||||
}
|
||||
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
if notBondedPool == nil {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.NotBondedPoolName))
|
||||
}
|
||||
|
||||
if notBondedPool.GetCoins().IsZero() {
|
||||
if err := notBondedPool.SetCoins(notBondedCoins); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
}
|
||||
|
||||
// don't need to run Tendermint updates if we exported
|
||||
if data.Exported {
|
||||
for _, lv := range data.LastValidatorPowers {
|
||||
keeper.SetLastValidatorPower(ctx, lv.Address, lv.Power)
|
||||
validator, found := keeper.GetValidator(ctx, lv.Address)
|
||||
if !found {
|
||||
panic("expected validator, not found")
|
||||
panic(fmt.Sprintf("validator %s not found", lv.Address))
|
||||
}
|
||||
update := validator.ABCIValidatorUpdate()
|
||||
update.Power = lv.Power // keep the next-val-set offset, use the last power for the first block
|
||||
|
@ -108,7 +140,6 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeep
|
|||
// GenesisState will contain the pool, params, validators, and bonds found in
|
||||
// the keeper.
|
||||
func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
||||
pool := keeper.GetPool(ctx)
|
||||
params := keeper.GetParams(ctx)
|
||||
lastTotalPower := keeper.GetLastTotalPower(ctx)
|
||||
validators := keeper.GetAllValidators(ctx)
|
||||
|
@ -130,7 +161,6 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
|||
})
|
||||
|
||||
return types.GenesisState{
|
||||
Pool: pool,
|
||||
Params: params,
|
||||
LastTotalPower: lastTotalPower,
|
||||
LastValidatorPowers: lastValidatorPowers,
|
||||
|
|
|
@ -17,10 +17,8 @@ import (
|
|||
)
|
||||
|
||||
func TestInitGenesis(t *testing.T) {
|
||||
ctx, accKeeper, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, accKeeper, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000)
|
||||
|
||||
pool := keeper.GetPool(ctx)
|
||||
pool.BondedTokens = sdk.TokensFromConsensusPower(2)
|
||||
valTokens := sdk.TokensFromConsensusPower(1)
|
||||
|
||||
params := keeper.GetParams(ctx)
|
||||
|
@ -41,11 +39,10 @@ func TestInitGenesis(t *testing.T) {
|
|||
validators[1].Tokens = valTokens
|
||||
validators[1].DelegatorShares = valTokens.ToDec()
|
||||
|
||||
genesisState := types.NewGenesisState(pool, params, validators, delegations)
|
||||
vals := InitGenesis(ctx, keeper, accKeeper, genesisState)
|
||||
genesisState := types.NewGenesisState(params, validators, delegations)
|
||||
vals := InitGenesis(ctx, keeper, accKeeper, supplyKeeper, genesisState)
|
||||
|
||||
actualGenesis := ExportGenesis(ctx, keeper)
|
||||
require.Equal(t, genesisState.Pool, actualGenesis.Pool)
|
||||
require.Equal(t, genesisState.Params, actualGenesis.Params)
|
||||
require.Equal(t, genesisState.Delegations, actualGenesis.Delegations)
|
||||
require.EqualValues(t, keeper.GetAllValidators(ctx), actualGenesis.Validators)
|
||||
|
@ -71,12 +68,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) {
|
|||
size := 200
|
||||
require.True(t, size > 100)
|
||||
|
||||
ctx, accKeeper, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
|
||||
// Assigning 2 to the first 100 vals, 1 to the rest
|
||||
pool := keeper.GetPool(ctx)
|
||||
bondedTokens := sdk.TokensFromConsensusPower(int64(200 + (size - 100)))
|
||||
pool.BondedTokens = bondedTokens
|
||||
ctx, accKeeper, keeper, supplyKeeper := keep.CreateTestInput(t, false, 1000)
|
||||
|
||||
params := keeper.GetParams(ctx)
|
||||
delegations := []Delegation{}
|
||||
|
@ -96,8 +88,8 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) {
|
|||
validators[i].DelegatorShares = tokens.ToDec()
|
||||
}
|
||||
|
||||
genesisState := types.NewGenesisState(pool, params, validators, delegations)
|
||||
vals := InitGenesis(ctx, keeper, accKeeper, genesisState)
|
||||
genesisState := types.NewGenesisState(params, validators, delegations)
|
||||
vals := InitGenesis(ctx, keeper, accKeeper, supplyKeeper, genesisState)
|
||||
|
||||
abcivals := make([]abci.ValidatorUpdate, 100)
|
||||
for i, val := range validators[:100] {
|
||||
|
|
|
@ -146,7 +146,8 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k
|
|||
|
||||
// move coins from the msg.Address account to a (self-delegation) delegator account
|
||||
// the validator account and global shares are updated within here
|
||||
_, err = k.Delegate(ctx, msg.DelegatorAddress, msg.Value.Amount, validator, true)
|
||||
// NOTE source will always be from a wallet which are unbonded
|
||||
_, err = k.Delegate(ctx, msg.DelegatorAddress, msg.Value.Amount, sdk.Unbonded, validator, true)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
@ -232,7 +233,8 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper)
|
|||
return ErrBadDenom(k.Codespace()).Result()
|
||||
}
|
||||
|
||||
_, err := k.Delegate(ctx, msg.DelegatorAddress, msg.Amount.Amount, validator, true)
|
||||
// NOTE: source funds are always unbonded
|
||||
_, err := k.Delegate(ctx, msg.DelegatorAddress, msg.Amount.Amount, sdk.Unbonded, validator, true)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
|||
|
||||
initPower := int64(1000000)
|
||||
initBond := sdk.TokensFromConsensusPower(initPower)
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, initPower)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower)
|
||||
_ = setInstantUnbondPeriod(keeper, ctx)
|
||||
|
||||
// create validator
|
||||
|
@ -114,7 +114,7 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDuplicatesMsgCreateValidator(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
|
||||
addr1, addr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1])
|
||||
pk1, pk2 := keep.PKs[0], keep.PKs[1]
|
||||
|
@ -166,7 +166,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
|
||||
addr := sdk.ValAddress(keep.Addrs[0])
|
||||
invalidPk := secp256k1.GenPrivKey().PubKey()
|
||||
|
@ -185,7 +185,7 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLegacyValidatorDelegations(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, int64(1000))
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, int64(1000))
|
||||
setInstantUnbondPeriod(keeper, ctx)
|
||||
|
||||
bondAmount := sdk.TokensFromConsensusPower(10)
|
||||
|
@ -279,7 +279,7 @@ func TestLegacyValidatorDelegations(t *testing.T) {
|
|||
func TestIncrementsMsgDelegate(t *testing.T) {
|
||||
initPower := int64(1000)
|
||||
initBond := sdk.TokensFromConsensusPower(initPower)
|
||||
ctx, accMapper, keeper := keep.CreateTestInput(t, false, initPower)
|
||||
ctx, accMapper, keeper, _ := keep.CreateTestInput(t, false, initPower)
|
||||
params := keeper.GetParams(ctx)
|
||||
|
||||
bondAmount := sdk.TokensFromConsensusPower(10)
|
||||
|
@ -306,8 +306,8 @@ func TestIncrementsMsgDelegate(t *testing.T) {
|
|||
require.True(t, found)
|
||||
require.Equal(t, bondAmount, bond.Shares.RoundInt())
|
||||
|
||||
pool := keeper.GetPool(ctx)
|
||||
require.Equal(t, bondAmount, pool.BondedTokens)
|
||||
bondedTokens := keeper.TotalBondedTokens(ctx)
|
||||
require.Equal(t, bondAmount.Int64(), bondedTokens.Int64())
|
||||
|
||||
// just send the same msgbond multiple times
|
||||
msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount)
|
||||
|
@ -349,7 +349,7 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) {
|
|||
|
||||
initPower := int64(100)
|
||||
initBond := sdk.TokensFromConsensusPower(100)
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, initPower)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower)
|
||||
_ = setInstantUnbondPeriod(keeper, ctx)
|
||||
|
||||
// create validator
|
||||
|
@ -381,7 +381,7 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) {
|
|||
|
||||
initPower := int64(100)
|
||||
initBond := sdk.TokensFromConsensusPower(100)
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, initPower)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, initPower)
|
||||
_ = setInstantUnbondPeriod(keeper, ctx)
|
||||
|
||||
// create validator
|
||||
|
@ -411,7 +411,7 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) {
|
|||
func TestIncrementsMsgUnbond(t *testing.T) {
|
||||
initPower := int64(1000)
|
||||
initBond := sdk.TokensFromConsensusPower(initPower)
|
||||
ctx, accMapper, keeper := keep.CreateTestInput(t, false, initPower)
|
||||
ctx, accMapper, keeper, _ := keep.CreateTestInput(t, false, initPower)
|
||||
params := setInstantUnbondPeriod(keeper, ctx)
|
||||
denom := params.BondDenom
|
||||
|
||||
|
@ -469,13 +469,13 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
|||
gotDelegatorShares := validator.DelegatorShares.RoundInt()
|
||||
gotDelegatorAcc := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(params.BondDenom)
|
||||
|
||||
require.Equal(t, expBond, gotBond,
|
||||
require.Equal(t, expBond.Int64(), gotBond.Int64(),
|
||||
"i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n",
|
||||
i, expBond, gotBond, validator, bond)
|
||||
require.Equal(t, expDelegatorShares, gotDelegatorShares,
|
||||
require.Equal(t, expDelegatorShares.Int64(), gotDelegatorShares.Int64(),
|
||||
"i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n",
|
||||
i, expDelegatorShares, gotDelegatorShares, validator, bond)
|
||||
require.Equal(t, expDelegatorAcc, gotDelegatorAcc,
|
||||
require.Equal(t, expDelegatorAcc.Int64(), gotDelegatorAcc.Int64(),
|
||||
"i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n",
|
||||
i, expDelegatorAcc, gotDelegatorAcc, validator, bond)
|
||||
}
|
||||
|
@ -509,7 +509,7 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
|||
func TestMultipleMsgCreateValidator(t *testing.T) {
|
||||
initPower := int64(1000)
|
||||
initTokens := sdk.TokensFromConsensusPower(initPower)
|
||||
ctx, accMapper, keeper := keep.CreateTestInput(t, false, initPower)
|
||||
ctx, accMapper, keeper, _ := keep.CreateTestInput(t, false, initPower)
|
||||
params := setInstantUnbondPeriod(keeper, ctx)
|
||||
|
||||
validatorAddrs := []sdk.ValAddress{
|
||||
|
@ -576,7 +576,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMultipleMsgDelegate(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr, delegatorAddrs := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1:]
|
||||
_ = setInstantUnbondPeriod(keeper, ctx)
|
||||
|
||||
|
@ -618,7 +618,7 @@ func TestMultipleMsgDelegate(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestJailValidator(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
|
||||
_ = setInstantUnbondPeriod(keeper, ctx)
|
||||
|
||||
|
@ -664,7 +664,7 @@ func TestJailValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestValidatorQueue(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
|
||||
|
||||
// set the unbonding time
|
||||
|
@ -722,7 +722,7 @@ func TestValidatorQueue(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUnbondingPeriod(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr := sdk.ValAddress(keep.Addrs[0])
|
||||
|
||||
// set the unbonding time
|
||||
|
@ -768,7 +768,7 @@ func TestUnbondingPeriod(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUnbondingFromUnbondingValidator(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
|
||||
|
||||
// create the validator
|
||||
|
@ -809,7 +809,7 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRedelegationPeriod(t *testing.T) {
|
||||
ctx, AccMapper, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, AccMapper, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1])
|
||||
denom := keeper.GetParams(ctx).BondDenom
|
||||
|
||||
|
@ -868,7 +868,7 @@ func TestRedelegationPeriod(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTransitiveRedelegation(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr := sdk.ValAddress(keep.Addrs[0])
|
||||
validatorAddr2 := sdk.ValAddress(keep.Addrs[1])
|
||||
validatorAddr3 := sdk.ValAddress(keep.Addrs[2])
|
||||
|
@ -911,7 +911,7 @@ func TestTransitiveRedelegation(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMultipleRedelegationAtSameTime(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
valAddr := sdk.ValAddress(keep.Addrs[0])
|
||||
valAddr2 := sdk.ValAddress(keep.Addrs[1])
|
||||
|
||||
|
@ -963,7 +963,7 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMultipleRedelegationAtUniqueTimes(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
valAddr := sdk.ValAddress(keep.Addrs[0])
|
||||
valAddr2 := sdk.ValAddress(keep.Addrs[1])
|
||||
|
||||
|
@ -1017,7 +1017,7 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
valAddr := sdk.ValAddress(keep.Addrs[0])
|
||||
|
||||
// set the unbonding time
|
||||
|
@ -1064,7 +1064,7 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
valAddr := sdk.ValAddress(keep.Addrs[0])
|
||||
|
||||
// set the unbonding time
|
||||
|
@ -1118,7 +1118,7 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUnbondingWhenExcessValidators(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr1 := sdk.ValAddress(keep.Addrs[0])
|
||||
validatorAddr2 := sdk.ValAddress(keep.Addrs[1])
|
||||
validatorAddr3 := sdk.ValAddress(keep.Addrs[2])
|
||||
|
@ -1174,7 +1174,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2]
|
||||
consAddr0 := sdk.ConsAddress(keep.PKs[0].Address())
|
||||
|
||||
|
@ -1283,7 +1283,7 @@ func TestInvalidMsg(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInvalidCoinDenom(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
ctx, _, keeper, _ := keep.CreateTestInput(t, false, 1000)
|
||||
valA, valB, delAddr := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2]
|
||||
|
||||
valTokens := sdk.TokensFromConsensusPower(100)
|
||||
|
|
|
@ -88,31 +88,6 @@ func (k Keeper) ValidatorByConsAddr(ctx sdk.Context, addr sdk.ConsAddress) expor
|
|||
return val
|
||||
}
|
||||
|
||||
// total staking tokens supply which is bonded
|
||||
func (k Keeper) TotalBondedTokens(ctx sdk.Context) sdk.Int {
|
||||
pool := k.GetPool(ctx)
|
||||
return pool.BondedTokens
|
||||
}
|
||||
|
||||
// total staking tokens supply bonded and unbonded
|
||||
func (k Keeper) TotalTokens(ctx sdk.Context) sdk.Int {
|
||||
pool := k.GetPool(ctx)
|
||||
return pool.TokenSupply()
|
||||
}
|
||||
|
||||
// the fraction of the staking tokens which are currently bonded
|
||||
func (k Keeper) BondedRatio(ctx sdk.Context) sdk.Dec {
|
||||
pool := k.GetPool(ctx)
|
||||
return pool.BondedRatio()
|
||||
}
|
||||
|
||||
// when minting new tokens
|
||||
func (k Keeper) InflateSupply(ctx sdk.Context, newTokens sdk.Int) {
|
||||
pool := k.GetPool(ctx)
|
||||
pool.NotBondedTokens = pool.NotBondedTokens.Add(newTokens)
|
||||
k.SetPool(ctx, pool)
|
||||
}
|
||||
|
||||
//_______________________________________________________________________
|
||||
// Delegation Set
|
||||
|
||||
|
|
|
@ -25,16 +25,26 @@ func (k Keeper) GetDelegation(ctx sdk.Context,
|
|||
return delegation, true
|
||||
}
|
||||
|
||||
// return all delegations used during genesis dump
|
||||
func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegation) {
|
||||
// IterateAllDelegations iterate through all of the delegations
|
||||
func (k Keeper) IterateAllDelegations(ctx sdk.Context, cb func(delegation types.Delegation) (stop bool)) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, types.DelegationKey)
|
||||
defer iterator.Close()
|
||||
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value())
|
||||
delegations = append(delegations, delegation)
|
||||
if cb(delegation) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetAllDelegations returns all delegations used during genesis dump
|
||||
func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegation) {
|
||||
k.IterateAllDelegations(ctx, func(delegation types.Delegation) bool {
|
||||
delegations = append(delegations, delegation)
|
||||
return false
|
||||
})
|
||||
return delegations
|
||||
}
|
||||
|
||||
|
@ -292,7 +302,7 @@ func (k Keeper) GetRedelegation(ctx sdk.Context,
|
|||
}
|
||||
|
||||
// return all redelegations from a particular validator
|
||||
func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAddress) (reds []types.Redelegation) {
|
||||
func (k Keeper) GetRedelegationsFromSrcValidator(ctx sdk.Context, valAddr sdk.ValAddress) (reds []types.Redelegation) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, types.GetREDsFromValSrcIndexKey(valAddr))
|
||||
defer iterator.Close()
|
||||
|
@ -445,7 +455,8 @@ func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time
|
|||
}
|
||||
|
||||
// Perform a delegation, set/update everything necessary within the store.
|
||||
func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Int,
|
||||
// tokenSrc indicates the bond status of the incoming funds.
|
||||
func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Int, tokenSrc sdk.BondStatus,
|
||||
validator types.Validator, subtractAccount bool) (newShares sdk.Dec, err sdk.Error) {
|
||||
|
||||
// In some situations, the exchange rate becomes invalid, e.g. if
|
||||
|
@ -468,11 +479,46 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.In
|
|||
k.BeforeDelegationCreated(ctx, delAddr, validator.OperatorAddress)
|
||||
}
|
||||
|
||||
// if subtractAccount is true then we are
|
||||
// performing a delegation and not a redelegation, thus the source tokens are
|
||||
// all non bonded
|
||||
if subtractAccount {
|
||||
err := k.bankKeeper.DelegateCoins(ctx, delegation.DelegatorAddress, sdk.Coins{sdk.NewCoin(k.GetParams(ctx).BondDenom, bondAmt)})
|
||||
if tokenSrc == sdk.Bonded {
|
||||
panic("delegation token source cannot be bonded")
|
||||
}
|
||||
|
||||
var sendName string
|
||||
switch {
|
||||
case validator.IsBonded():
|
||||
sendName = types.BondedPoolName
|
||||
case validator.IsUnbonding(), validator.IsUnbonded():
|
||||
sendName = types.NotBondedPoolName
|
||||
default:
|
||||
panic("invalid validator status")
|
||||
}
|
||||
|
||||
coins := sdk.NewCoins(sdk.NewCoin(k.BondDenom(ctx), bondAmt))
|
||||
err := k.supplyKeeper.DelegateCoinsFromAccountToModule(ctx, delegation.DelegatorAddress, sendName, coins)
|
||||
if err != nil {
|
||||
return sdk.Dec{}, err
|
||||
}
|
||||
} else {
|
||||
|
||||
// potentially transfer tokens between pools, if
|
||||
switch {
|
||||
case tokenSrc == sdk.Bonded && validator.IsBonded():
|
||||
// do nothing
|
||||
case (tokenSrc == sdk.Unbonded || tokenSrc == sdk.Unbonding) && !validator.IsBonded():
|
||||
// do nothing
|
||||
case (tokenSrc == sdk.Unbonded || tokenSrc == sdk.Unbonding) && validator.IsBonded():
|
||||
// transfer pools
|
||||
k.notBondedTokensToBonded(ctx, bondAmt)
|
||||
case tokenSrc == sdk.Bonded && !validator.IsBonded():
|
||||
// transfer pools
|
||||
k.bondedTokensToNotBonded(ctx, bondAmt)
|
||||
default:
|
||||
panic("unknown token source bond status")
|
||||
}
|
||||
}
|
||||
|
||||
validator, newShares = k.AddValidatorTokensAndShares(ctx, validator, bondAmt)
|
||||
|
@ -514,7 +560,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
|
|||
// subtract shares from delegation
|
||||
delegation.Shares = delegation.Shares.Sub(shares)
|
||||
|
||||
isValidatorOperator := bytes.Equal(delegation.DelegatorAddress, validator.OperatorAddress)
|
||||
isValidatorOperator := delegation.DelegatorAddress.Equals(validator.OperatorAddress)
|
||||
|
||||
// if the delegation is the operator of the validator and undelegating will decrease the validator's self delegation below their minimum
|
||||
// trigger a jail validator
|
||||
|
@ -535,6 +581,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
|
|||
}
|
||||
|
||||
// remove the shares and coins from the validator
|
||||
// NOTE that the amount is later (in keeper.Delegation) moved between staking module pools
|
||||
validator, amount = k.RemoveValidatorTokensAndShares(ctx, validator, shares)
|
||||
|
||||
if validator.DelegatorShares.IsZero() && validator.IsUnbonded() {
|
||||
|
@ -583,6 +630,11 @@ func (k Keeper) Undelegate(
|
|||
ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec,
|
||||
) (time.Time, sdk.Error) {
|
||||
|
||||
validator, found := k.GetValidator(ctx, valAddr)
|
||||
if !found {
|
||||
return time.Time{}, types.ErrNoDelegatorForAddress(k.Codespace())
|
||||
}
|
||||
|
||||
if k.HasMaxUnbondingDelegationEntries(ctx, delAddr, valAddr) {
|
||||
return time.Time{}, types.ErrMaxUnbondingDelegationEntries(k.Codespace())
|
||||
}
|
||||
|
@ -592,6 +644,11 @@ func (k Keeper) Undelegate(
|
|||
return time.Time{}, err
|
||||
}
|
||||
|
||||
// transfer the validator tokens to the not bonded pool
|
||||
if validator.IsBonded() {
|
||||
k.bondedTokensToNotBonded(ctx, returnAmount)
|
||||
}
|
||||
|
||||
completionTime := ctx.BlockHeader().Time.Add(k.UnbondingTime(ctx))
|
||||
ubd := k.SetUnbondingDelegationEntry(ctx, delAddr, valAddr, ctx.BlockHeight(), completionTime, returnAmount)
|
||||
k.InsertUBDQueue(ctx, ubd, completionTime)
|
||||
|
@ -620,7 +677,8 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress,
|
|||
|
||||
// track undelegation only when remaining or truncated shares are non-zero
|
||||
if !entry.Balance.IsZero() {
|
||||
err := k.bankKeeper.UndelegateCoins(ctx, ubd.DelegatorAddress, sdk.Coins{sdk.NewCoin(k.GetParams(ctx).BondDenom, entry.Balance)})
|
||||
amt := sdk.NewCoins(sdk.NewCoin(k.GetParams(ctx).BondDenom, entry.Balance))
|
||||
err := k.supplyKeeper.UndelegateCoinsFromModuleToAccount(ctx, types.NotBondedPoolName, ubd.DelegatorAddress, amt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -647,6 +705,16 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
|
|||
return time.Time{}, types.ErrSelfRedelegation(k.Codespace())
|
||||
}
|
||||
|
||||
dstValidator, found := k.GetValidator(ctx, valDstAddr)
|
||||
if !found {
|
||||
return time.Time{}, types.ErrBadRedelegationDst(k.Codespace())
|
||||
}
|
||||
|
||||
srcValidator, found := k.GetValidator(ctx, valSrcAddr)
|
||||
if !found {
|
||||
return time.Time{}, types.ErrBadRedelegationDst(k.Codespace())
|
||||
}
|
||||
|
||||
// check if this is a transitive redelegation
|
||||
if k.HasReceivingRedelegation(ctx, delAddr, valSrcAddr) {
|
||||
return time.Time{}, types.ErrTransitiveRedelegation(k.Codespace())
|
||||
|
@ -664,12 +732,8 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
|
|||
if returnAmount.IsZero() {
|
||||
return time.Time{}, types.ErrVerySmallRedelegation(k.Codespace())
|
||||
}
|
||||
dstValidator, found := k.GetValidator(ctx, valDstAddr)
|
||||
if !found {
|
||||
return time.Time{}, types.ErrBadRedelegationDst(k.Codespace())
|
||||
}
|
||||
|
||||
sharesCreated, err := k.Delegate(ctx, delAddr, returnAmount, dstValidator, false)
|
||||
sharesCreated, err := k.Delegate(ctx, delAddr, returnAmount, srcValidator.GetStatus(), dstValidator, false)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
|
|
@ -13,18 +13,16 @@ import (
|
|||
|
||||
// tests GetDelegation, GetDelegatorDelegations, SetDelegation, RemoveDelegation, GetDelegatorDelegations
|
||||
func TestDelegation(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 10)
|
||||
pool := keeper.GetPool(ctx)
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 10)
|
||||
|
||||
//construct the validators
|
||||
amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)}
|
||||
var validators [3]types.Validator
|
||||
for i, amt := range amts {
|
||||
validators[i] = types.NewValidator(addrVals[i], PKs[i], types.Description{})
|
||||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt)
|
||||
validators[i], _ = validators[i].AddTokensFromDel(amt)
|
||||
}
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], true)
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], true)
|
||||
validators[2] = TestingUpdateValidator(keeper, ctx, validators[2], true)
|
||||
|
@ -130,7 +128,7 @@ func TestDelegation(t *testing.T) {
|
|||
|
||||
// tests Get/Set/Remove UnbondingDelegation
|
||||
func TestUnbondingDelegation(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
|
||||
ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0,
|
||||
time.Unix(0, 0), sdk.NewInt(5))
|
||||
|
@ -169,21 +167,23 @@ func TestUnbondingDelegation(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUnbondDelegation(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
|
||||
startTokens := sdk.TokensFromConsensusPower(10)
|
||||
pool.NotBondedTokens = startTokens
|
||||
|
||||
//create a validator and a delegator to that validator
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
err := notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens)))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
// create a validator and a delegator to that validator
|
||||
// note this validator starts not-bonded
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, startTokens)
|
||||
require.Equal(t, startTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
|
||||
pool = keeper.GetPool(ctx)
|
||||
require.Equal(t, startTokens, pool.BondedTokens)
|
||||
require.Equal(t, startTokens, validator.BondedTokens())
|
||||
validator, issuedShares := validator.AddTokensFromDel(startTokens)
|
||||
require.Equal(t, startTokens, issuedShares.RoundInt())
|
||||
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
|
||||
delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
@ -197,37 +197,41 @@ func TestUnbondDelegation(t *testing.T) {
|
|||
require.True(t, found)
|
||||
validator, found = keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
pool = keeper.GetPool(ctx)
|
||||
|
||||
remainingTokens := startTokens.Sub(bondTokens)
|
||||
require.Equal(t, remainingTokens, delegation.Shares.RoundInt())
|
||||
require.Equal(t, remainingTokens, validator.BondedTokens())
|
||||
require.Equal(t, bondTokens, pool.NotBondedTokens, "%v", pool)
|
||||
require.Equal(t, remainingTokens, pool.BondedTokens)
|
||||
}
|
||||
|
||||
func TestUnbondingDelegationsMaxEntries(t *testing.T) {
|
||||
ctx, ak, keeper := CreateTestInput(t, false, 1)
|
||||
pool := keeper.GetPool(ctx)
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 1)
|
||||
startTokens := sdk.TokensFromConsensusPower(10)
|
||||
pool.NotBondedTokens = startTokens
|
||||
bondDenom := keeper.BondDenom(ctx)
|
||||
|
||||
bondedPool := keeper.GetBondedPool(ctx)
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
err := notBondedPool.SetCoins(sdk.NewCoins(sdk.NewCoin(bondDenom, startTokens)))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
// create a validator and a delegator to that validator
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, startTokens)
|
||||
require.Equal(t, startTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
|
||||
pool = keeper.GetPool(ctx)
|
||||
require.Equal(t, startTokens, pool.BondedTokens)
|
||||
require.Equal(t, startTokens, validator.BondedTokens())
|
||||
validator, issuedShares := validator.AddTokensFromDel(startTokens)
|
||||
require.Equal(t, startTokens, issuedShares.RoundInt())
|
||||
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
require.True(sdk.IntEq(t, startTokens, validator.BondedTokens()))
|
||||
require.True(t, validator.IsBonded())
|
||||
|
||||
delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
maxEntries := keeper.MaxEntries(ctx)
|
||||
|
||||
oldBonded := keeper.GetBondedPool(ctx).GetCoins().AmountOf(bondDenom)
|
||||
oldNotBonded := keeper.GetNotBondedPool(ctx).GetCoins().AmountOf(bondDenom)
|
||||
|
||||
// should all pass
|
||||
var completionTime time.Time
|
||||
for i := uint16(0); i < maxEntries; i++ {
|
||||
|
@ -236,87 +240,97 @@ func TestUnbondingDelegationsMaxEntries(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// delegator shares should be reduced by 7
|
||||
delegator, _ := keeper.GetDelegation(ctx, addrDels[0], addrVals[0])
|
||||
require.Equal(t, sdk.NewDec(9999993), delegator.GetShares())
|
||||
bondedPool = keeper.GetBondedPool(ctx)
|
||||
notBondedPool = keeper.GetNotBondedPool(ctx)
|
||||
require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded.SubRaw(int64(maxEntries))))
|
||||
require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded.AddRaw(int64(maxEntries))))
|
||||
|
||||
acc := ak.GetAccount(ctx, addrDels[0])
|
||||
require.Equal(t, int64(1000000), acc.GetCoins().AmountOf("stake").Int64())
|
||||
oldBonded = bondedPool.GetCoins().AmountOf(bondDenom)
|
||||
oldNotBonded = notBondedPool.GetCoins().AmountOf(bondDenom)
|
||||
|
||||
// an additional unbond should fail due to max entries
|
||||
_, err := keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1))
|
||||
_, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1))
|
||||
require.Error(t, err)
|
||||
|
||||
// delegator shares should not reduced
|
||||
delegator, _ = keeper.GetDelegation(ctx, addrDels[0], addrVals[0])
|
||||
require.Equal(t, sdk.NewDec(9999993), delegator.GetShares())
|
||||
bondedPool = keeper.GetBondedPool(ctx)
|
||||
notBondedPool = keeper.GetNotBondedPool(ctx)
|
||||
require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded))
|
||||
require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded))
|
||||
|
||||
// mature unbonding delegations
|
||||
ctx = ctx.WithBlockTime(completionTime)
|
||||
err = keeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0])
|
||||
require.NoError(t, err)
|
||||
|
||||
// delegator account balance should be increased by 7
|
||||
acc = ak.GetAccount(ctx, addrDels[0])
|
||||
require.Equal(t, int64(1000007), acc.GetCoins().AmountOf("stake").Int64())
|
||||
bondedPool = keeper.GetBondedPool(ctx)
|
||||
notBondedPool = keeper.GetNotBondedPool(ctx)
|
||||
require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded))
|
||||
require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded.SubRaw(int64(maxEntries))))
|
||||
|
||||
completionTime, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(3))
|
||||
require.NoError(t, err)
|
||||
|
||||
// delegator shares should be reduced by 3
|
||||
dele2, _ := keeper.GetDelegation(ctx, addrDels[0], addrVals[0])
|
||||
require.Equal(t, sdk.NewDec(9999990), dele2.GetShares())
|
||||
|
||||
// mature unbonding delegations
|
||||
ctx = ctx.WithBlockTime(completionTime)
|
||||
err = keeper.CompleteUnbonding(ctx, addrDels[0], addrVals[0])
|
||||
require.NoError(t, err)
|
||||
|
||||
// delegator account balance should be increased by 3
|
||||
acc = ak.GetAccount(ctx, addrDels[0])
|
||||
require.Equal(t, int64(1000010), acc.GetCoins().AmountOf("stake").Int64())
|
||||
oldNotBonded = notBondedPool.GetCoins().AmountOf(bondDenom)
|
||||
|
||||
// unbonding should work again
|
||||
_, err = keeper.Undelegate(ctx, addrDels[0], addrVals[0], sdk.NewDec(1))
|
||||
require.NoError(t, err)
|
||||
|
||||
bondedPool = keeper.GetBondedPool(ctx)
|
||||
|
||||
notBondedPool = keeper.GetNotBondedPool(ctx)
|
||||
require.True(sdk.IntEq(t, bondedPool.GetCoins().AmountOf(bondDenom), oldBonded.SubRaw(1)))
|
||||
require.True(sdk.IntEq(t, notBondedPool.GetCoins().AmountOf(bondDenom), oldNotBonded.AddRaw(1)))
|
||||
}
|
||||
|
||||
// test undelegating self delegation from a validator pushing it below MinSelfDelegation
|
||||
// shift it from the bonded to unbonding state and jailed
|
||||
func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) {
|
||||
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
startTokens := sdk.TokensFromConsensusPower(20)
|
||||
pool.NotBondedTokens = startTokens
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
delTokens := sdk.TokensFromConsensusPower(10)
|
||||
delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens))
|
||||
|
||||
//create a validator with a self-delegation
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
|
||||
valTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator.MinSelfDelegation = valTokens
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
validator.MinSelfDelegation = delTokens
|
||||
validator, issuedShares := validator.AddTokensFromDel(delTokens)
|
||||
require.Equal(t, delTokens, issuedShares.RoundInt())
|
||||
|
||||
// add bonded tokens to pool for delegations
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
require.True(t, validator.IsBonded())
|
||||
|
||||
selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
// add bonded tokens to pool for delegations
|
||||
bondedPool := keeper.GetBondedPool(ctx)
|
||||
err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool)
|
||||
|
||||
// create a second delegation to this validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator)
|
||||
delTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, delTokens)
|
||||
validator, issuedShares = validator.AddTokensFromDel(delTokens)
|
||||
require.True(t, validator.IsBonded())
|
||||
require.Equal(t, delTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
|
||||
// add bonded tokens to pool for delegations
|
||||
bondedPool = keeper.GetBondedPool(ctx)
|
||||
err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool)
|
||||
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
_, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], sdk.TokensFromConsensusPower(6).ToDec())
|
||||
_, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], sdk.TokensFromConsensusPower(6).ToDec())
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -331,34 +345,53 @@ func TestUndelegateSelfDelegationBelowMinSelfDelegation(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUndelegateFromUnbondingValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
startTokens := sdk.TokensFromConsensusPower(20)
|
||||
pool.NotBondedTokens = startTokens
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
delTokens := sdk.TokensFromConsensusPower(10)
|
||||
delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens))
|
||||
|
||||
//create a validator with a self-delegation
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
|
||||
valTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator, issuedShares := validator.AddTokensFromDel(delTokens)
|
||||
require.Equal(t, delTokens, issuedShares.RoundInt())
|
||||
|
||||
// add bonded tokens to pool for delegations
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
require.True(t, validator.IsBonded())
|
||||
|
||||
selfDelegation := types.NewDelegation(sdk.AccAddress(addrVals[0].Bytes()), addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
bondedPool := keeper.GetBondedPool(ctx)
|
||||
err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool)
|
||||
|
||||
// create a second delegation to this validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator)
|
||||
delTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, delTokens)
|
||||
|
||||
validator, issuedShares = validator.AddTokensFromDel(delTokens)
|
||||
require.Equal(t, delTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
|
||||
bondedPool = keeper.GetBondedPool(ctx)
|
||||
err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool)
|
||||
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
bondedPool = keeper.GetBondedPool(ctx)
|
||||
err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool)
|
||||
|
||||
header := ctx.BlockHeader()
|
||||
blockHeight := int64(10)
|
||||
header.Height = blockHeight
|
||||
|
@ -368,7 +401,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) {
|
|||
|
||||
// unbond the all self-delegation to put validator in unbonding state
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
_, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec())
|
||||
_, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec())
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -400,32 +433,40 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 1)
|
||||
pool := keeper.GetPool(ctx)
|
||||
startTokens := sdk.TokensFromConsensusPower(20)
|
||||
pool.NotBondedTokens = startTokens
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 1)
|
||||
delTokens := sdk.TokensFromConsensusPower(10)
|
||||
delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens))
|
||||
|
||||
// add bonded tokens to pool for delegations
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
// create a validator with a self-delegation
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
|
||||
valTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, valTokens)
|
||||
validator, issuedShares := validator.AddTokensFromDel(valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
require.True(t, validator.IsBonded())
|
||||
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
bondedPool := keeper.GetBondedPool(ctx)
|
||||
err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool)
|
||||
|
||||
// create a second delegation to this validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator)
|
||||
delTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, delTokens)
|
||||
validator, issuedShares = validator.AddTokensFromDel(delTokens)
|
||||
require.Equal(t, delTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
require.True(t, validator.IsBonded())
|
||||
delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
|
@ -433,7 +474,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockTime(time.Unix(333, 0))
|
||||
|
||||
// unbond the all self-delegation to put validator in unbonding state
|
||||
_, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec())
|
||||
_, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec())
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -471,32 +512,43 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUnbondingAllDelegationFromValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
startTokens := sdk.TokensFromConsensusPower(20)
|
||||
pool.NotBondedTokens = startTokens
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
delTokens := sdk.TokensFromConsensusPower(10)
|
||||
delCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), delTokens))
|
||||
|
||||
// add bonded tokens to pool for delegations
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(delCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
//create a validator with a self-delegation
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
|
||||
valTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, valTokens)
|
||||
validator, issuedShares := validator.AddTokensFromDel(valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
require.True(t, validator.IsBonded())
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
|
||||
selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
// create a second delegation to this validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator)
|
||||
delTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, delTokens)
|
||||
validator, issuedShares = validator.AddTokensFromDel(delTokens)
|
||||
require.Equal(t, delTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
|
||||
bondedPool := keeper.GetBondedPool(ctx)
|
||||
err = bondedPool.SetCoins(bondedPool.GetCoins().Add(delCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, bondedPool)
|
||||
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
require.True(t, validator.IsBonded())
|
||||
|
||||
delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
|
@ -504,7 +556,7 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockTime(time.Unix(333, 0))
|
||||
|
||||
// unbond the all self-delegation to put validator in unbonding state
|
||||
_, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec())
|
||||
_, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], valTokens.ToDec())
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -530,8 +582,8 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
// Make sure that that the retrieving the delegations doesn't affect the state
|
||||
func TestGetRedelegationsFromValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
func TestGetRedelegationsFromSrcValidator(t *testing.T) {
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
|
||||
rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0,
|
||||
time.Unix(0, 0), sdk.NewInt(5),
|
||||
|
@ -543,19 +595,19 @@ func TestGetRedelegationsFromValidator(t *testing.T) {
|
|||
require.True(t, found)
|
||||
|
||||
// get the redelegations one time
|
||||
redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
|
||||
redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0])
|
||||
require.Equal(t, 1, len(redelegations))
|
||||
require.True(t, redelegations[0].Equal(resBond))
|
||||
|
||||
// get the redelegations a second time, should be exactly the same
|
||||
redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
|
||||
redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0])
|
||||
require.Equal(t, 1, len(redelegations))
|
||||
require.True(t, redelegations[0].Equal(resBond))
|
||||
}
|
||||
|
||||
// tests Get/Set/Remove/Has UnbondingDelegation
|
||||
func TestRedelegation(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
|
||||
rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0,
|
||||
time.Unix(0, 0), sdk.NewInt(5),
|
||||
|
@ -570,7 +622,7 @@ func TestRedelegation(t *testing.T) {
|
|||
resRed, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||
require.True(t, found)
|
||||
|
||||
redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
|
||||
redelegations := keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0])
|
||||
require.Equal(t, 1, len(redelegations))
|
||||
require.True(t, redelegations[0].Equal(resRed))
|
||||
|
||||
|
@ -594,7 +646,7 @@ func TestRedelegation(t *testing.T) {
|
|||
require.True(t, found)
|
||||
require.True(t, rd.Equal(resRed))
|
||||
|
||||
redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
|
||||
redelegations = keeper.GetRedelegationsFromSrcValidator(ctx, addrVals[0])
|
||||
require.Equal(t, 1, len(redelegations))
|
||||
require.True(t, redelegations[0].Equal(resRed))
|
||||
|
||||
|
@ -615,52 +667,58 @@ func TestRedelegation(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRedelegateToSameValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
startTokens := sdk.TokensFromConsensusPower(30)
|
||||
pool.NotBondedTokens = startTokens
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
valTokens := sdk.TokensFromConsensusPower(10)
|
||||
startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), valTokens))
|
||||
|
||||
// add bonded tokens to pool for delegations
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
// create a validator with a self-delegation
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
valTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, valTokens)
|
||||
validator, issuedShares := validator.AddTokensFromDel(valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
require.True(t, validator.IsBonded())
|
||||
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
_, err := keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5))
|
||||
_, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[0], sdk.NewDec(5))
|
||||
require.Error(t, err)
|
||||
|
||||
}
|
||||
|
||||
func TestRedelegationMaxEntries(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
startTokens := sdk.TokensFromConsensusPower(20)
|
||||
pool.NotBondedTokens = startTokens
|
||||
startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens))
|
||||
|
||||
// add bonded tokens to pool for delegations
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
// create a validator with a self-delegation
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
valTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, valTokens)
|
||||
validator, issuedShares := validator.AddTokensFromDel(valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
// create a second validator
|
||||
validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{})
|
||||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, valTokens)
|
||||
validator2, issuedShares = validator2.AddTokensFromDel(valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
pool.BondedTokens = pool.BondedTokens.Add(valTokens)
|
||||
keeper.SetPool(ctx, pool)
|
||||
|
||||
validator2 = TestingUpdateValidator(keeper, ctx, validator2, true)
|
||||
require.Equal(t, sdk.Bonded, validator2.Status)
|
||||
|
||||
|
@ -675,7 +733,7 @@ func TestRedelegationMaxEntries(t *testing.T) {
|
|||
}
|
||||
|
||||
// an additional redelegation should fail due to max entries
|
||||
_, err := keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1))
|
||||
_, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(1))
|
||||
require.Error(t, err)
|
||||
|
||||
// mature redelegations
|
||||
|
@ -689,44 +747,45 @@ func TestRedelegationMaxEntries(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRedelegateSelfDelegation(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
startTokens := sdk.TokensFromConsensusPower(30)
|
||||
pool.NotBondedTokens = startTokens
|
||||
startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens))
|
||||
|
||||
// add bonded tokens to pool for delegations
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
//create a validator with a self-delegation
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
valTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, valTokens)
|
||||
validator, issuedShares := validator.AddTokensFromDel(valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
// create a second validator
|
||||
validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{})
|
||||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, valTokens)
|
||||
validator2, issuedShares = validator2.AddTokensFromDel(valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
pool.BondedTokens = pool.BondedTokens.Add(valTokens)
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = TestingUpdateValidator(keeper, ctx, validator2, true)
|
||||
require.Equal(t, sdk.Bonded, validator2.Status)
|
||||
|
||||
// create a second delegation to validator 1
|
||||
delTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, delTokens)
|
||||
validator, issuedShares = validator.AddTokensFromDel(delTokens)
|
||||
require.Equal(t, delTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
|
||||
delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
_, err := keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], delTokens.ToDec())
|
||||
_, err = keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], delTokens.ToDec())
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -740,20 +799,23 @@ func TestRedelegateSelfDelegation(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
startTokens := sdk.TokensFromConsensusPower(30)
|
||||
pool.NotBondedTokens = startTokens
|
||||
startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens))
|
||||
|
||||
// add bonded tokens to pool for delegations
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
//create a validator with a self-delegation
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
|
||||
valTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, valTokens)
|
||||
validator, issuedShares := validator.AddTokensFromDel(valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
@ -761,19 +823,16 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
|||
// create a second delegation to this validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator)
|
||||
delTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, delTokens)
|
||||
validator, issuedShares = validator.AddTokensFromDel(delTokens)
|
||||
require.Equal(t, delTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
// create a second validator
|
||||
validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{})
|
||||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, valTokens)
|
||||
validator2, issuedShares = validator2.AddTokensFromDel(valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = TestingUpdateValidator(keeper, ctx, validator2, true)
|
||||
|
||||
header := ctx.BlockHeader()
|
||||
|
@ -784,7 +843,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond the all self-delegation to put validator in unbonding state
|
||||
_, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec())
|
||||
_, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec())
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -819,20 +878,23 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
ctx, _, keeper, _ := CreateTestInput(t, false, 0)
|
||||
startTokens := sdk.TokensFromConsensusPower(30)
|
||||
pool.NotBondedTokens = startTokens
|
||||
startCoins := sdk.NewCoins(sdk.NewCoin(keeper.BondDenom(ctx), startTokens))
|
||||
|
||||
// add bonded tokens to pool for delegations
|
||||
notBondedPool := keeper.GetNotBondedPool(ctx)
|
||||
err := notBondedPool.SetCoins(notBondedPool.GetCoins().Add(startCoins))
|
||||
require.NoError(t, err)
|
||||
keeper.supplyKeeper.SetModuleAccount(ctx, notBondedPool)
|
||||
|
||||
//create a validator with a self-delegation
|
||||
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||
|
||||
valTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, valTokens)
|
||||
validator, issuedShares := validator.AddTokensFromDel(valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.NewDelegation(val0AccAddr, addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
@ -840,19 +902,16 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
|||
// create a second delegation to this validator
|
||||
keeper.DeleteValidatorByPowerIndex(ctx, validator)
|
||||
delTokens := sdk.TokensFromConsensusPower(10)
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, delTokens)
|
||||
validator, issuedShares = validator.AddTokensFromDel(delTokens)
|
||||
require.Equal(t, delTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator, true)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.NewDelegation(addrDels[0], addrVals[0], issuedShares)
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
// create a second validator
|
||||
validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{})
|
||||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, valTokens)
|
||||
validator2, issuedShares = validator2.AddTokensFromDel(valTokens)
|
||||
require.Equal(t, valTokens, issuedShares.RoundInt())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = TestingUpdateValidator(keeper, ctx, validator2, true)
|
||||
require.Equal(t, sdk.Bonded, validator2.Status)
|
||||
|
||||
|
@ -860,7 +919,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockTime(time.Unix(333, 0))
|
||||
|
||||
// unbond the all self-delegation to put validator in unbonding state
|
||||
_, err := keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec())
|
||||
_, err = keeper.Undelegate(ctx, val0AccAddr, addrVals[0], delTokens.ToDec())
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
|
|
@ -5,17 +5,15 @@ import (
|
|||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
)
|
||||
|
||||
// register all staking invariants
|
||||
func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper, f types.FeeCollectionKeeper,
|
||||
d types.DistributionKeeper, am types.AccountKeeper) {
|
||||
// RegisterInvariants registers all staking invariants
|
||||
func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
|
||||
|
||||
ir.RegisterRoute(types.ModuleName, "supply",
|
||||
SupplyInvariants(k, f, d, am))
|
||||
ir.RegisterRoute(types.ModuleName, "module-accounts",
|
||||
ModuleAccountInvariants(k))
|
||||
ir.RegisterRoute(types.ModuleName, "nonnegative-power",
|
||||
NonNegativePowerInvariant(k))
|
||||
ir.RegisterRoute(types.ModuleName, "positive-delegation",
|
||||
|
@ -25,11 +23,10 @@ func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper, f types.FeeCollectio
|
|||
}
|
||||
|
||||
// AllInvariants runs all invariants of the staking module.
|
||||
func AllInvariants(k Keeper, f types.FeeCollectionKeeper,
|
||||
d types.DistributionKeeper, am types.AccountKeeper) sdk.Invariant {
|
||||
func AllInvariants(k Keeper) sdk.Invariant {
|
||||
|
||||
return func(ctx sdk.Context) error {
|
||||
err := SupplyInvariants(k, f, d, am)(ctx)
|
||||
err := ModuleAccountInvariants(k)(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -44,66 +41,57 @@ func AllInvariants(k Keeper, f types.FeeCollectionKeeper,
|
|||
return err
|
||||
}
|
||||
|
||||
err = DelegatorSharesInvariant(k)(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return DelegatorSharesInvariant(k)(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// SupplyInvariants checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations
|
||||
// nolint: unparam
|
||||
func SupplyInvariants(k Keeper, f types.FeeCollectionKeeper,
|
||||
d types.DistributionKeeper, am types.AccountKeeper) sdk.Invariant {
|
||||
|
||||
// ModuleAccountInvariants checks that the bonded and notBonded ModuleAccounts pools
|
||||
// reflects the tokens actively bonded and not bonded
|
||||
func ModuleAccountInvariants(k Keeper) sdk.Invariant {
|
||||
return func(ctx sdk.Context) error {
|
||||
pool := k.GetPool(ctx)
|
||||
bonded := sdk.ZeroInt()
|
||||
notBonded := sdk.ZeroInt()
|
||||
bondedPool := k.GetBondedPool(ctx)
|
||||
notBondedPool := k.GetNotBondedPool(ctx)
|
||||
bondDenom := k.BondDenom(ctx)
|
||||
|
||||
loose := sdk.ZeroDec()
|
||||
bonded := sdk.ZeroDec()
|
||||
am.IterateAccounts(ctx, func(acc auth.Account) bool {
|
||||
loose = loose.Add(acc.GetCoins().AmountOf(k.BondDenom(ctx)).ToDec())
|
||||
return false
|
||||
})
|
||||
k.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) bool {
|
||||
for _, entry := range ubd.Entries {
|
||||
loose = loose.Add(entry.Balance.ToDec())
|
||||
}
|
||||
return false
|
||||
})
|
||||
k.IterateValidators(ctx, func(_ int64, validator exported.ValidatorI) bool {
|
||||
switch validator.GetStatus() {
|
||||
case sdk.Bonded:
|
||||
bonded = bonded.Add(validator.GetBondedTokens().ToDec())
|
||||
bonded = bonded.Add(validator.GetTokens())
|
||||
case sdk.Unbonding, sdk.Unbonded:
|
||||
loose = loose.Add(validator.GetTokens().ToDec())
|
||||
notBonded = notBonded.Add(validator.GetTokens())
|
||||
default:
|
||||
panic("invalid validator status")
|
||||
}
|
||||
// add yet-to-be-withdrawn
|
||||
loose = loose.Add(d.GetValidatorOutstandingRewardsCoins(ctx, validator.GetOperator()).AmountOf(k.BondDenom(ctx)))
|
||||
return false
|
||||
})
|
||||
|
||||
// add outstanding fees
|
||||
loose = loose.Add(f.GetCollectedFees(ctx).AmountOf(k.BondDenom(ctx)).ToDec())
|
||||
k.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) bool {
|
||||
for _, entry := range ubd.Entries {
|
||||
notBonded = notBonded.Add(entry.Balance)
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// add community pool
|
||||
loose = loose.Add(d.GetFeePoolCommunityCoins(ctx).AmountOf(k.BondDenom(ctx)))
|
||||
|
||||
// Not-bonded tokens should equal coin supply plus unbonding delegations
|
||||
// plus tokens on unbonded validators
|
||||
if !pool.NotBondedTokens.ToDec().Equal(loose) {
|
||||
return fmt.Errorf("loose token invariance:\n"+
|
||||
"\tpool.NotBondedTokens: %v\n"+
|
||||
"\tsum of account tokens: %v", pool.NotBondedTokens, loose)
|
||||
}
|
||||
poolBonded := bondedPool.GetCoins().AmountOf(bondDenom)
|
||||
poolNotBonded := notBondedPool.GetCoins().AmountOf(bondDenom)
|
||||
|
||||
// Bonded tokens should equal sum of tokens with bonded validators
|
||||
if !pool.BondedTokens.ToDec().Equal(bonded) {
|
||||
return fmt.Errorf("bonded token invariance:\n"+
|
||||
"\tpool.BondedTokens: %v\n"+
|
||||
"\tsum of account tokens: %v", pool.BondedTokens, bonded)
|
||||
// Not-bonded tokens should equal unbonding delegations plus tokens on unbonded validators
|
||||
if !poolBonded.Equal(bonded) || !poolNotBonded.Equal(notBonded) {
|
||||
return fmt.Errorf(
|
||||
"bonded token invariance:\n"+
|
||||
"\tPool's bonded tokens: %v\n"+
|
||||
"\tsum of bonded tokens: %v\n"+
|
||||
"not bonded token invariance:\n"+
|
||||
"\tPool's not bonded tokens: %v\n"+
|
||||
"\tsum of not bonded tokens: %v\n"+
|
||||
"module accounts total (bonded + not bonded):\n"+
|
||||
"\tModule Accounts' tokens: %v\n"+
|
||||
"\tsum tokens: %v\n",
|
||||
poolBonded, bonded, poolNotBonded, notBonded, poolBonded.Add(poolNotBonded), bonded.Add(notBonded),
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -25,7 +25,7 @@ type Keeper struct {
|
|||
storeKey sdk.StoreKey
|
||||
storeTKey sdk.StoreKey
|
||||
cdc *codec.Codec
|
||||
bankKeeper types.BankKeeper
|
||||
supplyKeeper types.SupplyKeeper
|
||||
hooks types.StakingHooks
|
||||
paramstore params.Subspace
|
||||
validatorCache map[string]cachedValidator
|
||||
|
@ -35,21 +35,30 @@ type Keeper struct {
|
|||
codespace sdk.CodespaceType
|
||||
}
|
||||
|
||||
func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, bk types.BankKeeper,
|
||||
// NewKeeper creates a new staking Keeper instance
|
||||
func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, supplyKeeper types.SupplyKeeper,
|
||||
paramstore params.Subspace, codespace sdk.CodespaceType) Keeper {
|
||||
|
||||
keeper := Keeper{
|
||||
// ensure bonded and not bonded module accounts are set
|
||||
if addr := supplyKeeper.GetModuleAddress(types.BondedPoolName); addr == nil {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.BondedPoolName))
|
||||
}
|
||||
|
||||
if addr := supplyKeeper.GetModuleAddress(types.NotBondedPoolName); addr == nil {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.NotBondedPoolName))
|
||||
}
|
||||
|
||||
return Keeper{
|
||||
storeKey: key,
|
||||
storeTKey: tkey,
|
||||
cdc: cdc,
|
||||
bankKeeper: bk,
|
||||
supplyKeeper: supplyKeeper,
|
||||
paramstore: paramstore.WithKeyTable(ParamKeyTable()),
|
||||
hooks: nil,
|
||||
validatorCache: make(map[string]cachedValidator, aminoCacheSize),
|
||||
validatorCacheList: list.New(),
|
||||
codespace: codespace,
|
||||
}
|
||||
return keeper
|
||||
}
|
||||
|
||||
// Logger returns a module-specific logger.
|
||||
|
@ -71,24 +80,6 @@ func (k Keeper) Codespace() sdk.CodespaceType {
|
|||
return k.codespace
|
||||
}
|
||||
|
||||
// get the pool
|
||||
func (k Keeper) GetPool(ctx sdk.Context) (pool types.Pool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := store.Get(types.PoolKey)
|
||||
if b == nil {
|
||||
panic("stored pool should not have been nil")
|
||||
}
|
||||
k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &pool)
|
||||
return
|
||||
}
|
||||
|
||||
// set the pool
|
||||
func (k Keeper) SetPool(ctx sdk.Context, pool types.Pool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := k.cdc.MustMarshalBinaryLengthPrefixed(pool)
|
||||
store.Set(types.PoolKey, b)
|
||||
}
|
||||
|
||||
// Load the last total validator power.
|
||||
func (k Keeper) GetLastTotalPower(ctx sdk.Context) (power sdk.Int) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue