Merge branch 'develop' into cwgoes/fix-signing-info-bugs
This commit is contained in:
commit
3f59cf1517
|
@ -71,6 +71,8 @@ BREAKING CHANGES
|
|||
* [x/stake] \#2394 Split up UpdateValidator into distinct state transitions applied only in EndBlock
|
||||
* [x/slashing] \#2480 Fix signing info handling bugs & faulty slashing
|
||||
* [x/stake] \#2412 Added an unbonding validator queue to EndBlock to automatically update validator.Status when finished Unbonding
|
||||
* [x/stake] \#2500 Block conflicting redelegations until we add an index
|
||||
* [x/params] Global Paramstore refactored
|
||||
|
||||
* Tendermint
|
||||
* Update tendermint version from v0.23.0 to v0.25.0, notable changes
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
|
@ -43,6 +44,8 @@ type GaiaApp struct {
|
|||
keyStake *sdk.KVStoreKey
|
||||
tkeyStake *sdk.TransientStoreKey
|
||||
keySlashing *sdk.KVStoreKey
|
||||
keyDistr *sdk.KVStoreKey
|
||||
tkeyDistr *sdk.TransientStoreKey
|
||||
keyGov *sdk.KVStoreKey
|
||||
keyFeeCollection *sdk.KVStoreKey
|
||||
keyParams *sdk.KVStoreKey
|
||||
|
@ -54,6 +57,7 @@ type GaiaApp struct {
|
|||
bankKeeper bank.Keeper
|
||||
stakeKeeper stake.Keeper
|
||||
slashingKeeper slashing.Keeper
|
||||
distrKeeper distr.Keeper
|
||||
govKeeper gov.Keeper
|
||||
paramsKeeper params.Keeper
|
||||
}
|
||||
|
@ -72,6 +76,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
|||
keyAccount: sdk.NewKVStoreKey("acc"),
|
||||
keyStake: sdk.NewKVStoreKey("stake"),
|
||||
tkeyStake: sdk.NewTransientStoreKey("transient_stake"),
|
||||
keyDistr: sdk.NewKVStoreKey("distr"),
|
||||
tkeyDistr: sdk.NewTransientStoreKey("transient_distr"),
|
||||
keySlashing: sdk.NewKVStoreKey("slashing"),
|
||||
keyGov: sdk.NewKVStoreKey("gov"),
|
||||
keyFeeCollection: sdk.NewKVStoreKey("fee"),
|
||||
|
@ -88,30 +94,33 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
|||
|
||||
// add handlers
|
||||
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
|
||||
|
||||
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(
|
||||
app.cdc,
|
||||
app.keyFeeCollection,
|
||||
)
|
||||
app.paramsKeeper = params.NewKeeper(
|
||||
app.cdc,
|
||||
app.keyParams, app.tkeyParams,
|
||||
)
|
||||
|
||||
app.stakeKeeper = stake.NewKeeper(
|
||||
app.cdc,
|
||||
app.keyStake, app.tkeyStake,
|
||||
app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace),
|
||||
app.RegisterCodespace(stake.DefaultCodespace),
|
||||
)
|
||||
|
||||
app.distrKeeper = distr.NewKeeper(
|
||||
app.cdc,
|
||||
app.keyDistr,
|
||||
app.paramsKeeper.Subspace(distr.DefaultParamspace),
|
||||
app.bankKeeper, app.stakeKeeper, app.feeCollectionKeeper,
|
||||
app.RegisterCodespace(stake.DefaultCodespace),
|
||||
)
|
||||
app.slashingKeeper = slashing.NewKeeper(
|
||||
app.cdc,
|
||||
app.keySlashing,
|
||||
app.stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
|
||||
app.RegisterCodespace(slashing.DefaultCodespace),
|
||||
)
|
||||
|
||||
app.stakeKeeper = app.stakeKeeper.WithHooks(
|
||||
app.slashingKeeper.Hooks(),
|
||||
)
|
||||
|
||||
app.govKeeper = gov.NewKeeper(
|
||||
app.cdc,
|
||||
app.keyGov,
|
||||
|
@ -119,15 +128,15 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
|||
app.RegisterCodespace(gov.DefaultCodespace),
|
||||
)
|
||||
|
||||
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(
|
||||
app.cdc,
|
||||
app.keyFeeCollection,
|
||||
)
|
||||
// register the staking hooks
|
||||
app.stakeKeeper = app.stakeKeeper.WithHooks(
|
||||
NewHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()))
|
||||
|
||||
// register message routes
|
||||
app.Router().
|
||||
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
|
||||
AddRoute("stake", stake.NewHandler(app.stakeKeeper)).
|
||||
AddRoute("distr", distr.NewHandler(app.distrKeeper)).
|
||||
AddRoute("slashing", slashing.NewHandler(app.slashingKeeper)).
|
||||
AddRoute("gov", gov.NewHandler(app.govKeeper))
|
||||
|
||||
|
@ -138,11 +147,12 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
|||
// initialize BaseApp
|
||||
app.SetInitChainer(app.initChainer)
|
||||
app.SetBeginBlocker(app.BeginBlocker)
|
||||
app.SetEndBlocker(app.EndBlocker)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
|
||||
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyStake,
|
||||
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyStake, app.keyDistr,
|
||||
app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams)
|
||||
app.MountStoresTransient(app.tkeyParams, app.tkeyStake)
|
||||
app.MountStoresTransient(app.tkeyParams, app.tkeyStake, app.tkeyDistr)
|
||||
app.SetEndBlocker(app.EndBlocker)
|
||||
|
||||
err := app.LoadLatestVersion(app.keyMain)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
|
@ -156,6 +166,7 @@ func MakeCodec() *codec.Codec {
|
|||
var cdc = codec.New()
|
||||
bank.RegisterCodec(cdc)
|
||||
stake.RegisterCodec(cdc)
|
||||
distr.RegisterCodec(cdc)
|
||||
slashing.RegisterCodec(cdc)
|
||||
gov.RegisterCodec(cdc)
|
||||
auth.RegisterCodec(cdc)
|
||||
|
@ -168,6 +179,9 @@ func MakeCodec() *codec.Codec {
|
|||
func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
||||
tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper)
|
||||
|
||||
// distribute rewards from previous block
|
||||
distr.BeginBlocker(ctx, req, app.distrKeeper)
|
||||
|
||||
return abci.ResponseBeginBlock{
|
||||
Tags: tags.ToKVPairs(),
|
||||
}
|
||||
|
@ -176,10 +190,13 @@ func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) ab
|
|||
// application updates every end block
|
||||
// nolint: unparam
|
||||
func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
||||
|
||||
tags := gov.EndBlocker(ctx, app.govKeeper)
|
||||
validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper)
|
||||
|
||||
// Add these new validators to the addr -> pubkey map.
|
||||
app.slashingKeeper.AddValidators(ctx, validatorUpdates)
|
||||
|
||||
return abci.ResponseEndBlock{
|
||||
ValidatorUpdates: validatorUpdates,
|
||||
Tags: tags,
|
||||
|
@ -208,18 +225,17 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
// load the initial stake information
|
||||
validators, err := stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
|
||||
if err != nil {
|
||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
panic(err) // TODO find a way to do this w/o panics
|
||||
}
|
||||
|
||||
// load the address to pubkey map
|
||||
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakeData)
|
||||
|
||||
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
|
||||
distr.InitGenesis(ctx, app.distrKeeper, genesisState.DistrData)
|
||||
err = GaiaValidateGenesisState(genesisState)
|
||||
if err != nil {
|
||||
// TODO find a way to do this w/o panics
|
||||
panic(err)
|
||||
panic(err) // TODO find a way to do this w/o panics
|
||||
}
|
||||
|
||||
return abci.ResponseInitChain{
|
||||
|
@ -243,6 +259,7 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val
|
|||
genState := GenesisState{
|
||||
Accounts: accounts,
|
||||
StakeData: stake.WriteGenesis(ctx, app.stakeKeeper),
|
||||
DistrData: distr.WriteGenesis(ctx, app.distrKeeper),
|
||||
GovData: gov.WriteGenesis(ctx, app.govKeeper),
|
||||
}
|
||||
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
||||
|
@ -252,3 +269,43 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val
|
|||
validators = stake.WriteValidators(ctx, app.stakeKeeper)
|
||||
return appState, validators, nil
|
||||
}
|
||||
|
||||
//______________________________________________________________________________________________
|
||||
|
||||
// Combined Staking Hooks
|
||||
type Hooks struct {
|
||||
dh distr.Hooks
|
||||
sh slashing.Hooks
|
||||
}
|
||||
|
||||
func NewHooks(dh distr.Hooks, sh slashing.Hooks) Hooks {
|
||||
return Hooks{dh, sh}
|
||||
}
|
||||
|
||||
var _ sdk.StakingHooks = Hooks{}
|
||||
|
||||
// nolint
|
||||
func (h Hooks) OnValidatorCreated(ctx sdk.Context, addr sdk.ValAddress) {
|
||||
h.dh.OnValidatorCreated(ctx, addr)
|
||||
}
|
||||
func (h Hooks) OnValidatorCommissionChange(ctx sdk.Context, addr sdk.ValAddress) {
|
||||
h.dh.OnValidatorCommissionChange(ctx, addr)
|
||||
}
|
||||
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, addr sdk.ValAddress) {
|
||||
h.dh.OnValidatorRemoved(ctx, addr)
|
||||
}
|
||||
func (h Hooks) OnValidatorBonded(ctx sdk.Context, addr sdk.ConsAddress) {
|
||||
h.sh.OnValidatorBonded(ctx, addr)
|
||||
}
|
||||
func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, addr sdk.ConsAddress) {
|
||||
h.sh.OnValidatorBeginUnbonding(ctx, addr)
|
||||
}
|
||||
func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnDelegationCreated(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h Hooks) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnDelegationSharesModified(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h Hooks) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnDelegationRemoved(ctx, delAddr, valAddr)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -24,6 +25,7 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
|
|||
genesisState := GenesisState{
|
||||
Accounts: genaccs,
|
||||
StakeData: stake.DefaultGenesisState(),
|
||||
DistrData: distr.DefaultGenesisState(),
|
||||
SlashingData: slashing.DefaultGenesisState(),
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/server/config"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
|
@ -34,6 +35,7 @@ var (
|
|||
type GenesisState struct {
|
||||
Accounts []GenesisAccount `json:"accounts"`
|
||||
StakeData stake.GenesisState `json:"stake"`
|
||||
DistrData distr.GenesisState `json:"distr"`
|
||||
GovData gov.GenesisState `json:"gov"`
|
||||
SlashingData slashing.GenesisState `json:"slashing"`
|
||||
}
|
||||
|
@ -196,6 +198,7 @@ func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisStat
|
|||
genesisState = GenesisState{
|
||||
Accounts: genaccs,
|
||||
StakeData: stakeData,
|
||||
DistrData: distr.DefaultGenesisState(),
|
||||
GovData: gov.DefaultGenesisState(),
|
||||
SlashingData: slashingData,
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||
|
@ -60,13 +61,18 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
|||
slashingGenesis := slashing.DefaultGenesisState()
|
||||
var validators []stake.Validator
|
||||
var delegations []stake.Delegation
|
||||
|
||||
// XXX Try different numbers of initially bonded validators
|
||||
numInitiallyBonded := int64(50)
|
||||
valAddrs := make([]sdk.ValAddress, numInitiallyBonded)
|
||||
for i := 0; i < int(numInitiallyBonded); i++ {
|
||||
validator := stake.NewValidator(sdk.ValAddress(accs[i].Address), accs[i].PubKey, stake.Description{})
|
||||
valAddr := sdk.ValAddress(accs[i].Address)
|
||||
valAddrs[i] = valAddr
|
||||
|
||||
validator := stake.NewValidator(valAddr, accs[i].PubKey, stake.Description{})
|
||||
validator.Tokens = sdk.NewDec(100)
|
||||
validator.DelegatorShares = sdk.NewDec(100)
|
||||
delegation := stake.Delegation{accs[i].Address, sdk.ValAddress(accs[i].Address), sdk.NewDec(100), 0}
|
||||
delegation := stake.Delegation{accs[i].Address, valAddr, sdk.NewDec(100), 0}
|
||||
validators = append(validators, validator)
|
||||
delegations = append(delegations, delegation)
|
||||
}
|
||||
|
@ -76,9 +82,11 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
|||
// No inflation, for now
|
||||
stakeGenesis.Params.InflationMax = sdk.NewDec(0)
|
||||
stakeGenesis.Params.InflationMin = sdk.NewDec(0)
|
||||
|
||||
genesis := GenesisState{
|
||||
Accounts: genesisAccounts,
|
||||
StakeData: stakeGenesis,
|
||||
DistrData: distr.DefaultGenesisWithValidators(valAddrs),
|
||||
SlashingData: slashingGenesis,
|
||||
GovData: govGenesis,
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
|
@ -72,6 +73,7 @@ func NewTestGaiaAppGenState(
|
|||
return GenesisState{
|
||||
Accounts: genAccs,
|
||||
StakeData: stakeData,
|
||||
DistrData: distr.DefaultGenesisState(),
|
||||
SlashingData: slashing.DefaultGenesisState(),
|
||||
GovData: gov.DefaultGenesisState(),
|
||||
}, nil
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
|
@ -10,18 +14,17 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/lcd"
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||
distrcmd "github.com/cosmos/cosmos-sdk/x/distribution/client/cli"
|
||||
govcmd "github.com/cosmos/cosmos-sdk/x/gov/client/cli"
|
||||
slashingcmd "github.com/cosmos/cosmos-sdk/x/slashing/client/cli"
|
||||
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
||||
|
||||
_ "github.com/cosmos/cosmos-sdk/client/lcd/statik"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/spf13/viper"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -101,11 +104,13 @@ func main() {
|
|||
stakecmd.GetCmdCreateValidator(cdc),
|
||||
stakecmd.GetCmdEditValidator(cdc),
|
||||
stakecmd.GetCmdDelegate(cdc),
|
||||
govcmd.GetCmdDeposit(cdc),
|
||||
stakecmd.GetCmdRedelegate(storeStake, cdc),
|
||||
stakecmd.GetCmdUnbond(storeStake, cdc),
|
||||
distrcmd.GetCmdWithdrawRewards(cdc),
|
||||
distrcmd.GetCmdSetWithdrawAddr(cdc),
|
||||
govcmd.GetCmdDeposit(cdc),
|
||||
bankcmd.SendTxCmd(cdc),
|
||||
govcmd.GetCmdSubmitProposal(cdc),
|
||||
stakecmd.GetCmdUnbond(storeStake, cdc),
|
||||
slashingcmd.GetCmdUnjail(cdc),
|
||||
govcmd.GetCmdVote(cdc),
|
||||
)...)
|
||||
|
|
|
@ -15,7 +15,7 @@ pool which validator holds individually
|
|||
(`ValidatorDistribution.ProvisionsRewardPool`).
|
||||
|
||||
```
|
||||
func AllocateFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
|
||||
func AllocateFees(feesCollected sdk.Coins, feePool FeePool, proposer ValidatorDistribution,
|
||||
sumPowerPrecommitValidators, totalBondedTokens, communityTax,
|
||||
proposerCommissionRate sdk.Dec)
|
||||
|
||||
|
@ -28,13 +28,11 @@ func AllocateFees(feesCollected sdk.Coins, global Global, proposer ValidatorDist
|
|||
proposer.Pool += proposerReward - commission
|
||||
|
||||
communityFunding = feesCollectedDec * communityTax
|
||||
global.CommunityFund += communityFunding
|
||||
feePool.CommunityFund += communityFunding
|
||||
|
||||
poolReceived = feesCollectedDec - proposerReward - communityFunding
|
||||
global.Pool += poolReceived
|
||||
global.EverReceivedPool += poolReceived
|
||||
global.LastReceivedPool = poolReceived
|
||||
feePool.Pool += poolReceived
|
||||
|
||||
SetValidatorDistribution(proposer)
|
||||
SetGlobal(global)
|
||||
SetFeePool(feePool)
|
||||
```
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
The pool of a new delegator bond will be 0 for the height at which the bond was
|
||||
added, or the withdrawal has taken place. This is achieved by setting
|
||||
`DelegatorDistInfo.WithdrawalHeight` to the height of the triggering transaction.
|
||||
`DelegationDistInfo.WithdrawalHeight` to the height of the triggering transaction.
|
||||
|
||||
## Commission rate change
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ to independently and lazily withdraw their rewards.
|
|||
|
||||
As a part of the lazy computations, each delegator holds an accumulation term
|
||||
specific to each validator which is used to estimate what their approximate
|
||||
fair portion of tokens held in the global pool is owed to them.
|
||||
fair portion of tokens held in the global fee pool is owed to them.
|
||||
|
||||
```
|
||||
entitlement = delegator-accumulation / all-delegators-accumulation
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
## State
|
||||
|
||||
### Global
|
||||
### FeePool
|
||||
|
||||
All globally tracked parameters for distribution are stored within
|
||||
`Global`. Rewards are collected and added to the reward pool and
|
||||
`FeePool`. Rewards are collected and added to the reward pool and
|
||||
distributed to validators/delegators from here.
|
||||
|
||||
Note that the reward pool holds decimal coins (`DecCoins`) to allow
|
||||
|
@ -11,7 +11,7 @@ for fractions of coins to be received from operations like inflation.
|
|||
When coins are distributed from the pool they are truncated back to
|
||||
`sdk.Coins` which are non-decimal.
|
||||
|
||||
- Global: `0x00 -> amino(global)`
|
||||
- FeePool: `0x00 -> amino(FeePool)`
|
||||
|
||||
```golang
|
||||
// coins with decimal
|
||||
|
@ -22,7 +22,7 @@ type DecCoin struct {
|
|||
Denom string
|
||||
}
|
||||
|
||||
type Global struct {
|
||||
type FeePool struct {
|
||||
TotalValAccumUpdateHeight int64 // last height which the total validator accum was updated
|
||||
TotalValAccum sdk.Dec // total valdator accum held by validators
|
||||
Pool DecCoins // funds for all validators which have yet to be withdrawn
|
||||
|
@ -42,7 +42,7 @@ Validator distribution information for the relevant validator is updated each ti
|
|||
|
||||
```golang
|
||||
type ValidatorDistInfo struct {
|
||||
GlobalWithdrawalHeight int64 // last height this validator withdrew from the global pool
|
||||
FeePoolWithdrawalHeight int64 // last height this validator withdrew from the global fee pool
|
||||
Pool DecCoins // rewards owed to delegators, commission has already been charged (includes proposer reward)
|
||||
PoolCommission DecCoins // commission collected by this validator (pending withdrawal)
|
||||
|
||||
|
@ -59,10 +59,10 @@ properties change (aka bonded tokens etc.) its properties will remain constant
|
|||
and the delegator's _accumulation_ factor can be calculated passively knowing
|
||||
only the height of the last withdrawal and its current properties.
|
||||
|
||||
- DelegatorDistInfo: ` 0x02 | DelegatorAddr | ValOperatorAddr -> amino(delegatorDist)`
|
||||
- DelegationDistInfo: ` 0x02 | DelegatorAddr | ValOperatorAddr -> amino(delegatorDist)`
|
||||
|
||||
```golang
|
||||
type DelegatorDistInfo struct {
|
||||
type DelegationDistInfo struct {
|
||||
WithdrawalHeight int64 // last time this delegation withdrew rewards
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
# Transactions
|
||||
|
||||
## TxWithdrawDelegationRewardsAll
|
||||
## MsgWithdrawDelegationRewardsAll
|
||||
|
||||
When a delegator wishes to withdraw their rewards it must send
|
||||
`TxWithdrawDelegationRewardsAll`. Note that parts of this transaction logic are also
|
||||
`MsgWithdrawDelegationRewardsAll`. Note that parts of this transaction logic are also
|
||||
triggered each with any change in individual delegations, such as an unbond,
|
||||
redelegation, or delegation of additional tokens to a specific validator.
|
||||
|
||||
```golang
|
||||
type TxWithdrawDelegationRewardsAll struct {
|
||||
delegatorAddr sdk.AccAddress
|
||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||
type MsgWithdrawDelegationRewardsAll struct {
|
||||
DelegatorAddr sdk.AccAddress
|
||||
}
|
||||
|
||||
func WithdrawDelegationRewardsAll(delegatorAddr, withdrawAddr sdk.AccAddress)
|
||||
|
@ -26,31 +25,30 @@ func GetDelegatorRewardsAll(delegatorAddr sdk.AccAddress, height int64) DecCoins
|
|||
// collect all entitled rewards
|
||||
withdraw = 0
|
||||
pool = stake.GetPool()
|
||||
global = GetGlobal()
|
||||
feePool = GetFeePool()
|
||||
for delegation = range delegations
|
||||
delInfo = GetDelegationDistInfo(delegation.DelegatorAddr,
|
||||
delegation.ValidatorAddr)
|
||||
valInfo = GetValidatorDistInfo(delegation.ValidatorAddr)
|
||||
validator = GetValidator(delegation.ValidatorAddr)
|
||||
|
||||
global, diWithdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens,
|
||||
feePool, diWithdraw = delInfo.WithdrawRewards(feePool, valInfo, height, pool.BondedTokens,
|
||||
validator.Tokens, validator.DelegatorShares, validator.Commission)
|
||||
withdraw += diWithdraw
|
||||
|
||||
SetGlobal(global)
|
||||
SetFeePool(feePool)
|
||||
return withdraw
|
||||
```
|
||||
|
||||
## TxWithdrawDelegationReward
|
||||
## MsgWithdrawDelegationReward
|
||||
|
||||
under special circumstances a delegator may wish to withdraw rewards from only
|
||||
a single validator.
|
||||
|
||||
```golang
|
||||
type TxWithdrawDelegationReward struct {
|
||||
delegatorAddr sdk.AccAddress
|
||||
validatorAddr sdk.AccAddress
|
||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||
type MsgWithdrawDelegationReward struct {
|
||||
DelegatorAddr sdk.AccAddress
|
||||
ValidatorAddr sdk.ValAddress
|
||||
}
|
||||
|
||||
func WithdrawDelegationReward(delegatorAddr, validatorAddr, withdrawAddr sdk.AccAddress)
|
||||
|
@ -58,39 +56,38 @@ func WithdrawDelegationReward(delegatorAddr, validatorAddr, withdrawAddr sdk.Acc
|
|||
|
||||
// get all distribution scenarios
|
||||
pool = stake.GetPool()
|
||||
global = GetGlobal()
|
||||
feePool = GetFeePool()
|
||||
delInfo = GetDelegationDistInfo(delegatorAddr,
|
||||
validatorAddr)
|
||||
valInfo = GetValidatorDistInfo(validatorAddr)
|
||||
validator = GetValidator(validatorAddr)
|
||||
|
||||
global, withdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens,
|
||||
feePool, withdraw = delInfo.WithdrawRewards(feePool, valInfo, height, pool.BondedTokens,
|
||||
validator.Tokens, validator.DelegatorShares, validator.Commission)
|
||||
|
||||
SetGlobal(global)
|
||||
SetFeePool(feePool)
|
||||
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
|
||||
```
|
||||
|
||||
|
||||
## TxWithdrawValidatorRewardsAll
|
||||
## MsgWithdrawValidatorRewardsAll
|
||||
|
||||
When a validator wishes to withdraw their rewards it must send
|
||||
`TxWithdrawValidatorRewardsAll`. Note that parts of this transaction logic are also
|
||||
`MsgWithdrawValidatorRewardsAll`. Note that parts of this transaction logic are also
|
||||
triggered each with any change in individual delegations, such as an unbond,
|
||||
redelegation, or delegation of additional tokens to a specific validator. This
|
||||
transaction withdraws the validators commission fee, as well as any rewards
|
||||
earning on their self-delegation.
|
||||
|
||||
```
|
||||
type TxWithdrawValidatorRewardsAll struct {
|
||||
operatorAddr sdk.AccAddress // validator address to withdraw from
|
||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||
type MsgWithdrawValidatorRewardsAll struct {
|
||||
OperatorAddr sdk.ValAddress // validator address to withdraw from
|
||||
}
|
||||
|
||||
func WithdrawValidatorRewardsAll(operatorAddr, withdrawAddr sdk.AccAddress)
|
||||
|
||||
height = GetHeight()
|
||||
global = GetGlobal()
|
||||
feePool = GetFeePool()
|
||||
pool = GetPool()
|
||||
ValInfo = GetValidatorDistInfo(delegation.ValidatorAddr)
|
||||
validator = GetValidator(delegation.ValidatorAddr)
|
||||
|
@ -99,10 +96,10 @@ func WithdrawValidatorRewardsAll(operatorAddr, withdrawAddr sdk.AccAddress)
|
|||
withdraw = GetDelegatorRewardsAll(validator.OperatorAddr, height)
|
||||
|
||||
// withdrawal validator commission rewards
|
||||
global, commission = valInfo.WithdrawCommission(global, valInfo, height, pool.BondedTokens,
|
||||
feePool, commission = valInfo.WithdrawCommission(feePool, valInfo, height, pool.BondedTokens,
|
||||
validator.Tokens, validator.Commission)
|
||||
withdraw += commission
|
||||
SetGlobal(global)
|
||||
SetFeePool(feePool)
|
||||
|
||||
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
|
||||
```
|
||||
|
@ -117,7 +114,7 @@ block. The accum is always additive to the existing accum. This term is to be
|
|||
updated each time rewards are withdrawn from the system.
|
||||
|
||||
```
|
||||
func (g Global) UpdateTotalValAccum(height int64, totalBondedTokens Dec) Global
|
||||
func (g FeePool) UpdateTotalValAccum(height int64, totalBondedTokens Dec) FeePool
|
||||
blocks = height - g.TotalValAccumUpdateHeight
|
||||
g.TotalValAccum += totalDelShares * blocks
|
||||
g.TotalValAccumUpdateHeight = height
|
||||
|
@ -140,7 +137,7 @@ func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares Dec
|
|||
return vi
|
||||
```
|
||||
|
||||
### Global pool to validator pool
|
||||
### FeePool pool to validator pool
|
||||
|
||||
Every time a validator or delegator executes a withdrawal or the validator is
|
||||
the proposer and receives new tokens, the relevant validator must move tokens
|
||||
|
@ -148,14 +145,14 @@ from the passive global pool to their own pool. It is at this point that the
|
|||
commission is withdrawn
|
||||
|
||||
```
|
||||
func (vi ValidatorDistInfo) TakeAccum(g Global, height int64, totalBonded, vdTokens, commissionRate Dec) (
|
||||
vi ValidatorDistInfo, g Global)
|
||||
func (vi ValidatorDistInfo) TakeFeePoolRewards(g FeePool, height int64, totalBonded, vdTokens, commissionRate Dec) (
|
||||
vi ValidatorDistInfo, g FeePool)
|
||||
|
||||
g.UpdateTotalValAccum(height, totalBondedShares)
|
||||
|
||||
// update the validators pool
|
||||
blocks = height - vi.GlobalWithdrawalHeight
|
||||
vi.GlobalWithdrawalHeight = height
|
||||
blocks = height - vi.FeePoolWithdrawalHeight
|
||||
vi.FeePoolWithdrawalHeight = height
|
||||
accum = blocks * vdTokens
|
||||
withdrawalTokens := g.Pool * accum / g.TotalValAccum
|
||||
commission := withdrawalTokens * commissionRate
|
||||
|
@ -175,12 +172,12 @@ For delegations (including validator's self-delegation) all rewards from reward
|
|||
pool have already had the validator's commission taken away.
|
||||
|
||||
```
|
||||
func (di DelegatorDistInfo) WithdrawRewards(g Global, vi ValidatorDistInfo,
|
||||
func (di DelegationDistInfo) WithdrawRewards(g FeePool, vi ValidatorDistInfo,
|
||||
height int64, totalBonded, vdTokens, totalDelShares, commissionRate Dec) (
|
||||
di DelegatorDistInfo, g Global, withdrawn DecCoins)
|
||||
di DelegationDistInfo, g FeePool, withdrawn DecCoins)
|
||||
|
||||
vi.UpdateTotalDelAccum(height, totalDelShares)
|
||||
g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
|
||||
g = vi.TakeFeePoolRewards(g, height, totalBonded, vdTokens, commissionRate)
|
||||
|
||||
blocks = height - di.WithdrawalHeight
|
||||
di.WithdrawalHeight = height
|
||||
|
@ -200,11 +197,11 @@ func (di DelegatorDistInfo) WithdrawRewards(g Global, vi ValidatorDistInfo,
|
|||
Commission is calculated each time rewards enter into the validator.
|
||||
|
||||
```
|
||||
func (vi ValidatorDistInfo) WithdrawCommission(g Global, height int64,
|
||||
func (vi ValidatorDistInfo) WithdrawCommission(g FeePool, height int64,
|
||||
totalBonded, vdTokens, commissionRate Dec) (
|
||||
vi ValidatorDistInfo, g Global, withdrawn DecCoins)
|
||||
vi ValidatorDistInfo, g FeePool, withdrawn DecCoins)
|
||||
|
||||
g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
|
||||
g = vi.TakeFeePoolRewards(g, height, totalBonded, vdTokens, commissionRate)
|
||||
|
||||
withdrawalTokens := vi.PoolCommission
|
||||
vi.PoolCommission = 0
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Params module specification
|
||||
|
||||
## Abstract
|
||||
|
||||
Package params provides a globally available parameter store.
|
||||
|
||||
There are two main types, Keeper and Subspace. Subspace is an isolated namespace for a
|
||||
paramstore, where keys are prefixed by preconfigured spacename. Keeper has a
|
||||
permission to access all existing spaces.
|
||||
|
||||
Subspace can be used by the individual keepers, who needs a private parameter store
|
||||
that the other keeper cannot modify. Keeper can be used by the Governance keeper,
|
||||
who need to modify any parameter in case of the proposal passes.
|
||||
|
||||
The following contents explains how to use params module for master and user modules.
|
||||
|
||||
## Contents
|
||||
|
||||
1. [Keeper](keeper.md)
|
||||
1. [Subspace](subspace.md)
|
|
@ -0,0 +1,17 @@
|
|||
# Keeper
|
||||
|
||||
In the app initialization stage, `Keeper.Subspace(Paramspace)` is passed to the user modules, and the subspaces are stored in `Keeper.spaces`. Later it can be retrieved with `Keeper.GetSubspace`, so the keepers holding `Keeper` can access to any subspace. For example, Gov module can take `Keeper` as its argument and modify parameter of any subspace when a `ParameterChangeProposal` is accepted.
|
||||
|
||||
```go
|
||||
type MasterKeeper struct {
|
||||
pk params.Keeper
|
||||
}
|
||||
|
||||
func (k MasterKeeper) SetParam(ctx sdk.Context, space string, key string, param interface{}) {
|
||||
space, ok := k.ps.GetSubspace(space)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
space.Set(ctx, key, param)
|
||||
}
|
||||
```
|
|
@ -0,0 +1,76 @@
|
|||
# Subspace
|
||||
|
||||
## Basic Usage
|
||||
|
||||
First, declare parameter space and parameter keys for the module. Then include params.Subspace in the keeper. Since we prefix the keys with the spacename, it is recommended to use the same name with the module's.
|
||||
|
||||
```go
|
||||
const (
|
||||
DefaultParamspace = "mymodule"
|
||||
)
|
||||
|
||||
const (
|
||||
KeyParameter1 = "myparameter1"
|
||||
KeyParameter2 = "myparameter2"
|
||||
)
|
||||
|
||||
type Keeper struct {
|
||||
cdc *wire.Codec
|
||||
key sdk.StoreKey
|
||||
|
||||
ps params.Subspace
|
||||
}
|
||||
```
|
||||
|
||||
Pass a params.Subspace to NewKeeper with DefaultParamSubspace (or another)
|
||||
|
||||
```go
|
||||
app.myKeeper = mymodule.NewKeeper(cdc, key, app.paramStore.SubStore(mymodule.DefaultParamspace))
|
||||
```
|
||||
|
||||
`NewKeeper` should register a `TypeTable`, which defines a map from parameter keys from types.
|
||||
|
||||
```go
|
||||
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, space params.Subspace) Keeper {
|
||||
return Keeper {
|
||||
cdc: cdc,
|
||||
key: key,
|
||||
ps: space.WithTypeTable(ParamTypeTable()),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now we can access to the paramstore using Paramstore Keys
|
||||
|
||||
```go
|
||||
var param MyStruct
|
||||
k.ps.Get(KeyParameter1, ¶m)
|
||||
k.ps.Set(KeyParameter2, param)
|
||||
```
|
||||
|
||||
# Genesis Usage
|
||||
|
||||
Declare a struct for parameters and make it implement params.ParamSet. It will then be able to be passed to SetParamSet.
|
||||
|
||||
```go
|
||||
type MyParams struct {
|
||||
Parameter1 uint64
|
||||
Parameter2 string
|
||||
}
|
||||
|
||||
// Implements params.ParamSet
|
||||
// KeyValuePairs must return the list of (ParamKey, PointerToTheField)
|
||||
func (p *MyParams) KeyValuePairs() params.KeyValuePairs {
|
||||
return params.KeyFieldPairs {
|
||||
{KeyParameter1, &p.Parameter1},
|
||||
{KeyParameter2, &p.Parameter2},
|
||||
}
|
||||
}
|
||||
|
||||
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
||||
k.ps.SetParamSet(ctx, &data.params)
|
||||
}
|
||||
```
|
||||
|
||||
The method is pointer receiver because there could be a case that we read from the store and set the result to the struct.
|
||||
|
|
@ -48,6 +48,11 @@ func (v Validator) GetDelegatorShares() sdk.Dec {
|
|||
return sdk.ZeroDec()
|
||||
}
|
||||
|
||||
// Implements sdk.Validator
|
||||
func (v Validator) GetCommission() sdk.Dec {
|
||||
return sdk.ZeroDec()
|
||||
}
|
||||
|
||||
// Implements sdk.Validator
|
||||
func (v Validator) GetJailed() bool {
|
||||
return false
|
||||
|
|
|
@ -119,10 +119,6 @@ func TestPrefixStoreIterate(t *testing.T) {
|
|||
}
|
||||
|
||||
func incFirstByte(bz []byte) {
|
||||
if bz[0] == byte(255) {
|
||||
bz[0] = byte(0)
|
||||
return
|
||||
}
|
||||
bz[0]++
|
||||
}
|
||||
|
||||
|
|
|
@ -187,6 +187,12 @@ func (c Context) WithBlockTime(newTime time.Time) Context {
|
|||
return c.WithBlockHeader(newHeader)
|
||||
}
|
||||
|
||||
func (c Context) WithProposer(addr ConsAddress) Context {
|
||||
newHeader := c.BlockHeader()
|
||||
newHeader.ProposerAddress = addr.Bytes()
|
||||
return c.WithBlockHeader(newHeader)
|
||||
}
|
||||
|
||||
func (c Context) WithBlockHeight(height int64) Context {
|
||||
newHeader := c.BlockHeader()
|
||||
newHeader.Height = height
|
||||
|
|
|
@ -241,6 +241,12 @@ func (d Dec) Quo(d2 Dec) Dec {
|
|||
return Dec{chopped}
|
||||
}
|
||||
|
||||
// quotient
|
||||
func (d Dec) QuoInt(i Int) Dec {
|
||||
mul := new(big.Int).Quo(d.Int, i.i)
|
||||
return Dec{mul}
|
||||
}
|
||||
|
||||
func (d Dec) String() string {
|
||||
str := d.ToLeftPaddedWithDecimals(Precision)
|
||||
placement := len(str) - Precision
|
||||
|
@ -462,6 +468,6 @@ func MaxDec(d1, d2 Dec) Dec {
|
|||
}
|
||||
|
||||
// intended to be used with require/assert: require.True(DecEq(...))
|
||||
func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) {
|
||||
return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got
|
||||
func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, string, string) {
|
||||
return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String()
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package types
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"math/big"
|
||||
"math/rand"
|
||||
|
@ -525,3 +526,10 @@ func (i *Uint) UnmarshalJSON(bz []byte) error {
|
|||
}
|
||||
return unmarshalJSON(i.i, bz)
|
||||
}
|
||||
|
||||
//__________________________________________________________________________
|
||||
|
||||
// intended to be used with require/assert: require.True(IntEq(...))
|
||||
func IntEq(t *testing.T, exp, got Int) (*testing.T, bool, string, string, string) {
|
||||
return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String()
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ type Validator interface {
|
|||
GetConsAddr() ConsAddress // validation consensus address
|
||||
GetPower() Dec // validation power
|
||||
GetTokens() Dec // validation tokens
|
||||
GetCommission() Dec // validator commission rate
|
||||
GetDelegatorShares() Dec // Total out standing delegator shares
|
||||
GetBondHeight() int64 // height in which the validator became active
|
||||
}
|
||||
|
|
|
@ -302,6 +302,3 @@ func getSignBytesList(chainID string, stdTx StdTx, stdSigs []StdSignature) (sign
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// BurnFeeHandler burns all fees (decreasing total supply)
|
||||
func BurnFeeHandler(_ sdk.Context, _ sdk.Tx, _ sdk.Coins) {}
|
||||
|
|
|
@ -20,7 +20,6 @@ type FeeCollectionKeeper struct {
|
|||
cdc *codec.Codec
|
||||
}
|
||||
|
||||
// NewFeeKeeper returns a new FeeKeeper
|
||||
func NewFeeCollectionKeeper(cdc *codec.Codec, key sdk.StoreKey) FeeCollectionKeeper {
|
||||
return FeeCollectionKeeper{
|
||||
key: key,
|
||||
|
@ -28,7 +27,7 @@ func NewFeeCollectionKeeper(cdc *codec.Codec, key sdk.StoreKey) FeeCollectionKee
|
|||
}
|
||||
}
|
||||
|
||||
// Adds to Collected Fee Pool
|
||||
// retrieves the collected fee pool
|
||||
func (fck FeeCollectionKeeper) GetCollectedFees(ctx sdk.Context) sdk.Coins {
|
||||
store := ctx.KVStore(fck.key)
|
||||
bz := store.Get(collectedFeesKey)
|
||||
|
@ -41,14 +40,12 @@ func (fck FeeCollectionKeeper) GetCollectedFees(ctx sdk.Context) sdk.Coins {
|
|||
return *feePool
|
||||
}
|
||||
|
||||
// Sets to Collected Fee Pool
|
||||
func (fck FeeCollectionKeeper) setCollectedFees(ctx sdk.Context, coins sdk.Coins) {
|
||||
bz := fck.cdc.MustMarshalBinary(coins)
|
||||
store := ctx.KVStore(fck.key)
|
||||
store.Set(collectedFeesKey, bz)
|
||||
}
|
||||
|
||||
// Adds to Collected Fee Pool
|
||||
func (fck FeeCollectionKeeper) addCollectedFees(ctx sdk.Context, coins sdk.Coins) sdk.Coins {
|
||||
newCoins := fck.GetCollectedFees(ctx).Plus(coins)
|
||||
fck.setCollectedFees(ctx, newCoins)
|
||||
|
@ -56,7 +53,7 @@ func (fck FeeCollectionKeeper) addCollectedFees(ctx sdk.Context, coins sdk.Coins
|
|||
return newCoins
|
||||
}
|
||||
|
||||
// Clears the collected Fee Pool
|
||||
// clear the fee pool
|
||||
func (fck FeeCollectionKeeper) ClearCollectedFees(ctx sdk.Context) {
|
||||
fck.setCollectedFees(ctx, sdk.Coins{})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package distribution
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/keeper"
|
||||
)
|
||||
|
||||
// set the proposer for determining distribution during endblock
|
||||
func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper) {
|
||||
|
||||
if ctx.BlockHeight() > 1 {
|
||||
previousPercentPrecommitVotes := getPreviousPercentPrecommitVotes(req)
|
||||
previousProposer := k.GetPreviousProposerConsAddr(ctx)
|
||||
k.AllocateFees(ctx, previousPercentPrecommitVotes, previousProposer)
|
||||
}
|
||||
|
||||
consAddr := sdk.ConsAddress(req.Header.ProposerAddress)
|
||||
k.SetPreviousProposerConsAddr(ctx, consAddr)
|
||||
}
|
||||
|
||||
// percent precommit votes for the previous block
|
||||
func getPreviousPercentPrecommitVotes(req abci.RequestBeginBlock) sdk.Dec {
|
||||
|
||||
// determine the total number of signed power
|
||||
totalPower, sumPrecommitPower := int64(0), int64(0)
|
||||
for _, voteInfo := range req.LastCommitInfo.GetVotes() {
|
||||
totalPower += voteInfo.Validator.Power
|
||||
if voteInfo.SignedLastBlock {
|
||||
sumPrecommitPower += voteInfo.Validator.Power
|
||||
}
|
||||
}
|
||||
|
||||
if totalPower == 0 {
|
||||
return sdk.ZeroDec()
|
||||
}
|
||||
return sdk.NewDec(sumPrecommitPower).Quo(sdk.NewDec(totalPower))
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
// nolint
|
||||
package distribution
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/tags"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
type (
|
||||
Keeper = keeper.Keeper
|
||||
Hooks = keeper.Hooks
|
||||
|
||||
DelegatorWithdrawInfo = types.DelegatorWithdrawInfo
|
||||
DelegationDistInfo = types.DelegationDistInfo
|
||||
ValidatorDistInfo = types.ValidatorDistInfo
|
||||
TotalAccum = types.TotalAccum
|
||||
FeePool = types.FeePool
|
||||
|
||||
MsgSetWithdrawAddress = types.MsgSetWithdrawAddress
|
||||
MsgWithdrawDelegatorRewardsAll = types.MsgWithdrawDelegatorRewardsAll
|
||||
MsgWithdrawDelegatorReward = types.MsgWithdrawDelegatorReward
|
||||
MsgWithdrawValidatorRewardsAll = types.MsgWithdrawValidatorRewardsAll
|
||||
|
||||
GenesisState = types.GenesisState
|
||||
)
|
||||
|
||||
var (
|
||||
NewKeeper = keeper.NewKeeper
|
||||
|
||||
GetValidatorDistInfoKey = keeper.GetValidatorDistInfoKey
|
||||
GetDelegationDistInfoKey = keeper.GetDelegationDistInfoKey
|
||||
GetDelegationDistInfosKey = keeper.GetDelegationDistInfosKey
|
||||
GetDelegatorWithdrawAddrKey = keeper.GetDelegatorWithdrawAddrKey
|
||||
FeePoolKey = keeper.FeePoolKey
|
||||
ValidatorDistInfoKey = keeper.ValidatorDistInfoKey
|
||||
DelegationDistInfoKey = keeper.DelegationDistInfoKey
|
||||
DelegatorWithdrawInfoKey = keeper.DelegatorWithdrawInfoKey
|
||||
ProposerKey = keeper.ProposerKey
|
||||
DefaultParamspace = keeper.DefaultParamspace
|
||||
|
||||
InitialFeePool = types.InitialFeePool
|
||||
|
||||
NewGenesisState = types.NewGenesisState
|
||||
DefaultGenesisState = types.DefaultGenesisState
|
||||
DefaultGenesisWithValidators = types.DefaultGenesisWithValidators
|
||||
|
||||
RegisterCodec = types.RegisterCodec
|
||||
|
||||
NewMsgSetWithdrawAddress = types.NewMsgSetWithdrawAddress
|
||||
NewMsgWithdrawDelegatorRewardsAll = types.NewMsgWithdrawDelegatorRewardsAll
|
||||
NewMsgWithdrawDelegationReward = types.NewMsgWithdrawDelegatorReward
|
||||
NewMsgWithdrawValidatorRewardsAll = types.NewMsgWithdrawValidatorRewardsAll
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultCodespace = types.DefaultCodespace
|
||||
CodeInvalidInput = types.CodeInvalidInput
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNilDelegatorAddr = types.ErrNilDelegatorAddr
|
||||
ErrNilWithdrawAddr = types.ErrNilWithdrawAddr
|
||||
ErrNilValidatorAddr = types.ErrNilValidatorAddr
|
||||
)
|
||||
|
||||
var (
|
||||
ActionModifyWithdrawAddress = tags.ActionModifyWithdrawAddress
|
||||
ActionWithdrawDelegatorRewardsAll = tags.ActionWithdrawDelegatorRewardsAll
|
||||
ActionWithdrawDelegatorReward = tags.ActionWithdrawDelegatorReward
|
||||
ActionWithdrawValidatorRewardsAll = tags.ActionWithdrawValidatorRewardsAll
|
||||
|
||||
TagAction = tags.Action
|
||||
TagValidator = tags.Validator
|
||||
TagDelegator = tags.Delegator
|
||||
)
|
|
@ -0,0 +1,114 @@
|
|||
// nolint
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
var (
|
||||
flagOnlyFromValidator = "only-from-validator"
|
||||
flagIsValidator = "is-validator"
|
||||
)
|
||||
|
||||
// command to withdraw rewards
|
||||
func GetCmdWithdrawRewards(cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "withdraw-rewards",
|
||||
Short: "withdraw rewards for either: all-delegations, a delegation, or a validator",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
onlyFromVal := viper.GetString(flagOnlyFromValidator)
|
||||
isVal := viper.GetBool(flagIsValidator)
|
||||
|
||||
if onlyFromVal != "" && isVal {
|
||||
return fmt.Errorf("cannot use --%v, and --%v flags together",
|
||||
flagOnlyFromValidator, flagIsValidator)
|
||||
}
|
||||
|
||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
WithCodec(cdc).
|
||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
||||
|
||||
var msg sdk.Msg
|
||||
switch {
|
||||
case isVal:
|
||||
addr, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
valAddr := sdk.ValAddress(addr.Bytes())
|
||||
msg = types.NewMsgWithdrawValidatorRewardsAll(valAddr)
|
||||
case onlyFromVal != "":
|
||||
delAddr, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
valAddr, err := sdk.ValAddressFromBech32(onlyFromVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg = types.NewMsgWithdrawDelegatorReward(delAddr, valAddr)
|
||||
default:
|
||||
delAddr, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg = types.NewMsgWithdrawDelegatorRewardsAll(delAddr)
|
||||
}
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
},
|
||||
}
|
||||
cmd.Flags().String(flagOnlyFromValidator, "", "only withdraw from this validator address (in bech)")
|
||||
cmd.Flags().Bool(flagIsValidator, false, "also withdraw validator's commission")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdDelegate implements the delegate command.
|
||||
func GetCmdSetWithdrawAddr(cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "set-withdraw-addr [withdraw-addr]",
|
||||
Short: "change the default withdraw address for rewards associated with an address",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
WithCodec(cdc).
|
||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
||||
|
||||
delAddr, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
withdrawAddr, err := sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := types.NewMsgSetWithdrawAddress(delAddr, withdrawAddr)
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package distribution
|
||||
|
||||
import (
|
||||
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) {
|
||||
keeper.SetFeePool(ctx, data.FeePool)
|
||||
keeper.SetCommunityTax(ctx, data.CommunityTax)
|
||||
keeper.SetBaseProposerReward(ctx, data.BaseProposerReward)
|
||||
keeper.SetBonusProposerReward(ctx, data.BonusProposerReward)
|
||||
|
||||
for _, vdi := range data.ValidatorDistInfos {
|
||||
keeper.SetValidatorDistInfo(ctx, vdi)
|
||||
}
|
||||
for _, ddi := range data.DelegationDistInfos {
|
||||
keeper.SetDelegationDistInfo(ctx, ddi)
|
||||
}
|
||||
for _, dw := range data.DelegatorWithdrawInfos {
|
||||
keeper.SetDelegatorWithdrawAddr(ctx, dw.DelegatorAddr, dw.WithdrawAddr)
|
||||
}
|
||||
}
|
||||
|
||||
// WriteGenesis returns a GenesisState for a given context and keeper. The
|
||||
// GenesisState will contain the pool, and validator/delegator distribution info's
|
||||
func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
||||
feePool := keeper.GetFeePool(ctx)
|
||||
communityTax := keeper.GetCommunityTax(ctx)
|
||||
baseProposerRewards := keeper.GetBaseProposerReward(ctx)
|
||||
bonusProposerRewards := keeper.GetBonusProposerReward(ctx)
|
||||
vdis := keeper.GetAllValidatorDistInfos(ctx)
|
||||
ddis := keeper.GetAllDelegationDistInfos(ctx)
|
||||
dwis := keeper.GetAllDelegatorWithdrawInfos(ctx)
|
||||
return NewGenesisState(feePool, communityTax, baseProposerRewards,
|
||||
bonusProposerRewards, vdis, ddis, dwis)
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package distribution
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/tags"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
func NewHandler(k keeper.Keeper) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||
// NOTE msg already has validate basic run
|
||||
switch msg := msg.(type) {
|
||||
case types.MsgSetWithdrawAddress:
|
||||
return handleMsgModifyWithdrawAddress(ctx, msg, k)
|
||||
case types.MsgWithdrawDelegatorRewardsAll:
|
||||
return handleMsgWithdrawDelegatorRewardsAll(ctx, msg, k)
|
||||
case types.MsgWithdrawDelegatorReward:
|
||||
return handleMsgWithdrawDelegatorReward(ctx, msg, k)
|
||||
case types.MsgWithdrawValidatorRewardsAll:
|
||||
return handleMsgWithdrawValidatorRewardsAll(ctx, msg, k)
|
||||
default:
|
||||
return sdk.ErrTxDecode("invalid message parse in distribution module").Result()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
|
||||
// These functions assume everything has been authenticated,
|
||||
// now we just perform action and save
|
||||
|
||||
func handleMsgModifyWithdrawAddress(ctx sdk.Context, msg types.MsgSetWithdrawAddress, k keeper.Keeper) sdk.Result {
|
||||
|
||||
k.SetDelegatorWithdrawAddr(ctx, msg.DelegatorAddr, msg.WithdrawAddr)
|
||||
|
||||
tags := sdk.NewTags(
|
||||
tags.Action, tags.ActionModifyWithdrawAddress,
|
||||
tags.Delegator, []byte(msg.DelegatorAddr.String()),
|
||||
)
|
||||
return sdk.Result{
|
||||
Tags: tags,
|
||||
}
|
||||
}
|
||||
|
||||
func handleMsgWithdrawDelegatorRewardsAll(ctx sdk.Context, msg types.MsgWithdrawDelegatorRewardsAll, k keeper.Keeper) sdk.Result {
|
||||
|
||||
k.WithdrawDelegationRewardsAll(ctx, msg.DelegatorAddr)
|
||||
|
||||
tags := sdk.NewTags(
|
||||
tags.Action, tags.ActionWithdrawDelegatorRewardsAll,
|
||||
tags.Delegator, []byte(msg.DelegatorAddr.String()),
|
||||
)
|
||||
return sdk.Result{
|
||||
Tags: tags,
|
||||
}
|
||||
}
|
||||
|
||||
func handleMsgWithdrawDelegatorReward(ctx sdk.Context, msg types.MsgWithdrawDelegatorReward, k keeper.Keeper) sdk.Result {
|
||||
|
||||
k.WithdrawDelegationReward(ctx, msg.DelegatorAddr, msg.ValidatorAddr)
|
||||
|
||||
tags := sdk.NewTags(
|
||||
tags.Action, tags.ActionWithdrawDelegatorReward,
|
||||
tags.Delegator, []byte(msg.DelegatorAddr.String()),
|
||||
tags.Validator, []byte(msg.ValidatorAddr.String()),
|
||||
)
|
||||
return sdk.Result{
|
||||
Tags: tags,
|
||||
}
|
||||
}
|
||||
|
||||
func handleMsgWithdrawValidatorRewardsAll(ctx sdk.Context, msg types.MsgWithdrawValidatorRewardsAll, k keeper.Keeper) sdk.Result {
|
||||
|
||||
k.WithdrawValidatorRewardsAll(ctx, msg.ValidatorAddr)
|
||||
|
||||
tags := sdk.NewTags(
|
||||
tags.Action, tags.ActionWithdrawValidatorRewardsAll,
|
||||
tags.Validator, []byte(msg.ValidatorAddr.String()),
|
||||
)
|
||||
return sdk.Result{
|
||||
Tags: tags,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
// Allocate fees handles distribution of the collected fees
|
||||
func (k Keeper) AllocateFees(ctx sdk.Context, percentVotes sdk.Dec, proposer sdk.ConsAddress) {
|
||||
ctx.Logger().With("module", "x/distribution").Error(fmt.Sprintf("allocation height: %v", ctx.BlockHeight()))
|
||||
|
||||
// get the proposer of this block
|
||||
proposerValidator := k.stakeKeeper.ValidatorByConsAddr(ctx, proposer)
|
||||
proposerDist := k.GetValidatorDistInfo(ctx, proposerValidator.GetOperator())
|
||||
|
||||
// get the fees which have been getting collected through all the
|
||||
// transactions in the block
|
||||
feesCollected := k.feeCollectionKeeper.GetCollectedFees(ctx)
|
||||
feesCollectedDec := types.NewDecCoins(feesCollected)
|
||||
|
||||
// allocated rewards to proposer
|
||||
baseProposerReward := k.GetBaseProposerReward(ctx)
|
||||
bonusProposerReward := k.GetBonusProposerReward(ctx)
|
||||
proposerMultiplier := baseProposerReward.Add(bonusProposerReward.Mul(percentVotes))
|
||||
proposerReward := feesCollectedDec.MulDec(proposerMultiplier)
|
||||
|
||||
// apply commission
|
||||
commission := proposerReward.MulDec(proposerValidator.GetCommission())
|
||||
remaining := proposerReward.Minus(commission)
|
||||
proposerDist.PoolCommission = proposerDist.PoolCommission.Plus(commission)
|
||||
proposerDist.Pool = proposerDist.Pool.Plus(remaining)
|
||||
|
||||
// allocate community funding
|
||||
communityTax := k.GetCommunityTax(ctx)
|
||||
communityFunding := feesCollectedDec.MulDec(communityTax)
|
||||
feePool := k.GetFeePool(ctx)
|
||||
feePool.CommunityPool = feePool.CommunityPool.Plus(communityFunding)
|
||||
|
||||
// set the global pool within the distribution module
|
||||
poolReceived := feesCollectedDec.Minus(proposerReward).Minus(communityFunding)
|
||||
feePool.Pool = feePool.Pool.Plus(poolReceived)
|
||||
|
||||
k.SetValidatorDistInfo(ctx, proposerDist)
|
||||
k.SetFeePool(ctx, feePool)
|
||||
|
||||
// clear the now distributed fees
|
||||
k.feeCollectionKeeper.ClearCollectedFees(ctx)
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAllocateFeesBasic(t *testing.T) {
|
||||
|
||||
// no community tax on inputs
|
||||
ctx, _, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//first make a validator
|
||||
totalPower := int64(10)
|
||||
totalPowerDec := sdk.NewDec(totalPower)
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidator(valOpAddr1, valConsPk1, totalPower)
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// verify everything has been set in staking correctly
|
||||
validator, found := sk.GetValidator(ctx, valOpAddr1)
|
||||
require.True(t, found)
|
||||
require.Equal(t, sdk.Bonded, validator.Status)
|
||||
assert.True(sdk.DecEq(t, totalPowerDec, validator.Tokens))
|
||||
assert.True(sdk.DecEq(t, totalPowerDec, validator.DelegatorShares))
|
||||
bondedTokens := sk.TotalPower(ctx)
|
||||
assert.True(sdk.DecEq(t, totalPowerDec, bondedTokens))
|
||||
|
||||
// initial fee pool should be empty
|
||||
feePool := keeper.GetFeePool(ctx)
|
||||
require.Nil(t, feePool.Pool)
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(100)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
|
||||
// verify that these fees have been received by the feePool
|
||||
percentProposer := sdk.NewDecWithPrec(5, 2)
|
||||
percentRemaining := sdk.OneDec().Sub(percentProposer)
|
||||
feePool = keeper.GetFeePool(ctx)
|
||||
expRes := sdk.NewDecFromInt(feeInputs).Mul(percentRemaining)
|
||||
require.Equal(t, 1, len(feePool.Pool))
|
||||
require.True(sdk.DecEq(t, expRes, feePool.Pool[0].Amount))
|
||||
}
|
||||
|
||||
func TestAllocateFeesWithCommunityTax(t *testing.T) {
|
||||
communityTax := sdk.NewDecWithPrec(1, 2) //1%
|
||||
ctx, _, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, communityTax)
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//first make a validator
|
||||
totalPower := int64(10)
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidator(valOpAddr1, valConsPk1, totalPower)
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(100)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
|
||||
// verify that these fees have been received by the feePool
|
||||
feePool := keeper.GetFeePool(ctx)
|
||||
// 5% goes to proposer, 1% community tax
|
||||
percentProposer := sdk.NewDecWithPrec(5, 2)
|
||||
percentRemaining := sdk.OneDec().Sub(communityTax.Add(percentProposer))
|
||||
expRes := sdk.NewDecFromInt(feeInputs).Mul(percentRemaining)
|
||||
require.Equal(t, 1, len(feePool.Pool))
|
||||
require.True(sdk.DecEq(t, expRes, feePool.Pool[0].Amount))
|
||||
}
|
||||
|
||||
func TestAllocateFeesWithPartialPrecommitPower(t *testing.T) {
|
||||
communityTax := sdk.NewDecWithPrec(1, 2)
|
||||
ctx, _, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, communityTax)
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//first make a validator
|
||||
totalPower := int64(100)
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidator(valOpAddr1, valConsPk1, totalPower)
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(100)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
percentPrecommitVotes := sdk.NewDecWithPrec(25, 2)
|
||||
keeper.AllocateFees(ctx, percentPrecommitVotes, valConsAddr1)
|
||||
|
||||
// verify that these fees have been received by the feePool
|
||||
feePool := keeper.GetFeePool(ctx)
|
||||
// 1% + 4%*0.25 to proposer + 1% community tax = 97%
|
||||
percentProposer := sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(4, 2).Mul(percentPrecommitVotes))
|
||||
percentRemaining := sdk.OneDec().Sub(communityTax.Add(percentProposer))
|
||||
expRes := sdk.NewDecFromInt(feeInputs).Mul(percentRemaining)
|
||||
require.Equal(t, 1, len(feePool.Pool))
|
||||
require.True(sdk.DecEq(t, expRes, feePool.Pool[0].Amount))
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
// get the delegator distribution info
|
||||
func (k Keeper) GetDelegationDistInfo(ctx sdk.Context, delAddr sdk.AccAddress,
|
||||
valOperatorAddr sdk.ValAddress) (ddi types.DelegationDistInfo) {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
b := store.Get(GetDelegationDistInfoKey(delAddr, valOperatorAddr))
|
||||
if b == nil {
|
||||
panic("Stored delegation-distribution info should not have been nil")
|
||||
}
|
||||
|
||||
k.cdc.MustUnmarshalBinary(b, &ddi)
|
||||
return
|
||||
}
|
||||
|
||||
// set the delegator distribution info
|
||||
func (k Keeper) SetDelegationDistInfo(ctx sdk.Context, ddi types.DelegationDistInfo) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := k.cdc.MustMarshalBinary(ddi)
|
||||
store.Set(GetDelegationDistInfoKey(ddi.DelegatorAddr, ddi.ValOperatorAddr), b)
|
||||
}
|
||||
|
||||
// remove a delegator distribution info
|
||||
func (k Keeper) RemoveDelegationDistInfo(ctx sdk.Context, delAddr sdk.AccAddress,
|
||||
valOperatorAddr sdk.ValAddress) {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
store.Delete(GetDelegationDistInfoKey(delAddr, valOperatorAddr))
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________________
|
||||
|
||||
// get the delegator withdraw address, return the delegator address if not set
|
||||
func (k Keeper) GetDelegatorWithdrawAddr(ctx sdk.Context, delAddr sdk.AccAddress) sdk.AccAddress {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
b := store.Get(GetDelegatorWithdrawAddrKey(delAddr))
|
||||
if b == nil {
|
||||
return delAddr
|
||||
}
|
||||
return sdk.AccAddress(b)
|
||||
}
|
||||
|
||||
// set the delegator withdraw address
|
||||
func (k Keeper) SetDelegatorWithdrawAddr(ctx sdk.Context, delAddr, withdrawAddr sdk.AccAddress) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
store.Set(GetDelegatorWithdrawAddrKey(delAddr), withdrawAddr.Bytes())
|
||||
}
|
||||
|
||||
// remove a delegator withdraw info
|
||||
func (k Keeper) RemoveDelegatorWithdrawAddr(ctx sdk.Context, delAddr, withdrawAddr sdk.AccAddress) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
store.Delete(GetDelegatorWithdrawAddrKey(delAddr))
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________________
|
||||
|
||||
// withdraw all the rewards for a single delegation
|
||||
func (k Keeper) WithdrawDelegationReward(ctx sdk.Context, delegatorAddr sdk.AccAddress,
|
||||
validatorAddr sdk.ValAddress) {
|
||||
|
||||
height := ctx.BlockHeight()
|
||||
bondedTokens := k.stakeKeeper.TotalPower(ctx)
|
||||
feePool := k.GetFeePool(ctx)
|
||||
delInfo := k.GetDelegationDistInfo(ctx, delegatorAddr, validatorAddr)
|
||||
valInfo := k.GetValidatorDistInfo(ctx, validatorAddr)
|
||||
validator := k.stakeKeeper.Validator(ctx, validatorAddr)
|
||||
delegation := k.stakeKeeper.Delegation(ctx, delegatorAddr, validatorAddr)
|
||||
|
||||
delInfo, valInfo, feePool, withdraw := delInfo.WithdrawRewards(feePool, valInfo, height, bondedTokens,
|
||||
validator.GetTokens(), validator.GetDelegatorShares(), delegation.GetShares(), validator.GetCommission())
|
||||
|
||||
k.SetFeePool(ctx, feePool)
|
||||
k.SetValidatorDistInfo(ctx, valInfo)
|
||||
k.SetDelegationDistInfo(ctx, delInfo)
|
||||
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, delegatorAddr)
|
||||
_, _, err := k.bankKeeper.AddCoins(ctx, withdrawAddr, withdraw.TruncateDecimal())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________________
|
||||
|
||||
// return all rewards for all delegations of a delegator
|
||||
func (k Keeper) WithdrawDelegationRewardsAll(ctx sdk.Context, delegatorAddr sdk.AccAddress) {
|
||||
height := ctx.BlockHeight()
|
||||
withdraw := k.getDelegatorRewardsAll(ctx, delegatorAddr, height)
|
||||
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, delegatorAddr)
|
||||
_, _, err := k.bankKeeper.AddCoins(ctx, withdrawAddr, withdraw.TruncateDecimal())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// return all rewards for all delegations of a delegator
|
||||
func (k Keeper) getDelegatorRewardsAll(ctx sdk.Context, delAddr sdk.AccAddress, height int64) types.DecCoins {
|
||||
|
||||
withdraw := types.DecCoins{}
|
||||
bondedTokens := k.stakeKeeper.TotalPower(ctx)
|
||||
feePool := k.GetFeePool(ctx)
|
||||
|
||||
// iterate over all the delegations
|
||||
operationAtDelegation := func(_ int64, del sdk.Delegation) (stop bool) {
|
||||
valAddr := del.GetValidator()
|
||||
delInfo := k.GetDelegationDistInfo(ctx, delAddr, valAddr)
|
||||
valInfo := k.GetValidatorDistInfo(ctx, valAddr)
|
||||
validator := k.stakeKeeper.Validator(ctx, valAddr)
|
||||
delegation := k.stakeKeeper.Delegation(ctx, delAddr, valAddr)
|
||||
|
||||
delInfo, valInfo, feePool, diWithdraw := delInfo.WithdrawRewards(feePool, valInfo, height, bondedTokens,
|
||||
validator.GetTokens(), validator.GetDelegatorShares(), delegation.GetShares(), validator.GetCommission())
|
||||
withdraw = withdraw.Plus(diWithdraw)
|
||||
k.SetFeePool(ctx, feePool)
|
||||
k.SetValidatorDistInfo(ctx, valInfo)
|
||||
k.SetDelegationDistInfo(ctx, delInfo)
|
||||
return false
|
||||
}
|
||||
k.stakeKeeper.IterateDelegations(ctx, delAddr, operationAtDelegation)
|
||||
|
||||
k.SetFeePool(ctx, feePool)
|
||||
return withdraw
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWithdrawDelegationRewardBasic(t *testing.T) {
|
||||
ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//first make a validator
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidator(valOpAddr1, valConsPk1, 10)
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// delegate
|
||||
msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10)
|
||||
got = stakeHandler(ctx, msgDelegate)
|
||||
require.True(t, got.IsOK())
|
||||
amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, int64(90), amt.Int64())
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(100)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
|
||||
// withdraw delegation
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1)
|
||||
amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
|
||||
expRes := sdk.NewDec(90).Add(sdk.NewDec(100).Quo(sdk.NewDec(2))).TruncateInt() // 90 + 100 tokens * 10/20
|
||||
require.True(sdk.IntEq(t, expRes, amt))
|
||||
}
|
||||
|
||||
func TestWithdrawDelegationRewardWithCommission(t *testing.T) {
|
||||
ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//first make a validator with 10% commission
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidatorWithCommission(
|
||||
valOpAddr1, valConsPk1, 10, sdk.NewDecWithPrec(1, 1))
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// delegate
|
||||
msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10)
|
||||
got = stakeHandler(ctx, msgDelegate)
|
||||
require.True(t, got.IsOK())
|
||||
amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, int64(90), amt.Int64())
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(100)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
|
||||
// withdraw delegation
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1)
|
||||
amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
|
||||
expRes := sdk.NewDec(90).Add(sdk.NewDec(90).Quo(sdk.NewDec(2))).TruncateInt() // 90 + 100*90% tokens * 10/20
|
||||
require.True(sdk.IntEq(t, expRes, amt))
|
||||
}
|
||||
|
||||
func TestWithdrawDelegationRewardTwoDelegators(t *testing.T) {
|
||||
ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//first make a validator with 10% commission
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidatorWithCommission(
|
||||
valOpAddr1, valConsPk1, 10, sdk.NewDecWithPrec(1, 1))
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// delegate
|
||||
msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10)
|
||||
got = stakeHandler(ctx, msgDelegate)
|
||||
require.True(t, got.IsOK())
|
||||
amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, int64(90), amt.Int64())
|
||||
|
||||
msgDelegate = stake.NewTestMsgDelegate(delAddr2, valOpAddr1, 20)
|
||||
got = stakeHandler(ctx, msgDelegate)
|
||||
require.True(t, got.IsOK())
|
||||
amt = accMapper.GetAccount(ctx, delAddr2).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, int64(80), amt.Int64())
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(100)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
|
||||
// delegator 1 withdraw delegation
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1)
|
||||
amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
|
||||
expRes := sdk.NewDec(90).Add(sdk.NewDec(90).Quo(sdk.NewDec(4))).TruncateInt() // 90 + 100*90% tokens * 10/40
|
||||
require.True(sdk.IntEq(t, expRes, amt))
|
||||
}
|
||||
|
||||
// this test demonstrates how two delegators with the same power can end up
|
||||
// with different rewards in the end
|
||||
func TestWithdrawDelegationRewardTwoDelegatorsUneven(t *testing.T) {
|
||||
ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//first make a validator with no commission
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidatorWithCommission(
|
||||
valOpAddr1, valConsPk1, 10, sdk.ZeroDec())
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// delegate
|
||||
msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10)
|
||||
got = stakeHandler(ctx, msgDelegate)
|
||||
require.True(t, got.IsOK())
|
||||
amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, int64(90), amt.Int64())
|
||||
|
||||
msgDelegate = stake.NewTestMsgDelegate(delAddr2, valOpAddr1, 10)
|
||||
got = stakeHandler(ctx, msgDelegate)
|
||||
require.True(t, got.IsOK())
|
||||
amt = accMapper.GetAccount(ctx, delAddr2).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, int64(90), amt.Int64())
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(90)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
|
||||
// delegator 1 withdraw delegation early, delegator 2 just keeps it's accum
|
||||
keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1)
|
||||
amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
|
||||
expRes1 := sdk.NewDec(90).Add(sdk.NewDec(90).Quo(sdk.NewDec(3))).TruncateInt() // 90 + 100 * 10/30
|
||||
require.True(sdk.IntEq(t, expRes1, amt))
|
||||
|
||||
// allocate 200 denom of fees
|
||||
feeInputs = sdk.NewInt(180)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
ctx = ctx.WithBlockHeight(2)
|
||||
|
||||
// delegator 2 now withdraws everything it's entitled to
|
||||
keeper.WithdrawDelegationReward(ctx, delAddr2, valOpAddr1)
|
||||
amt = accMapper.GetAccount(ctx, delAddr2).GetCoins().AmountOf(denom)
|
||||
// existingTokens + (100+200 * (10/(20+30))
|
||||
withdrawnFromVal := sdk.NewDec(60 + 180).Mul(sdk.NewDec(2)).Quo(sdk.NewDec(5))
|
||||
expRes2 := sdk.NewDec(90).Add(withdrawnFromVal).TruncateInt()
|
||||
require.True(sdk.IntEq(t, expRes2, amt))
|
||||
|
||||
// finally delegator 1 withdraws the remainder of its reward
|
||||
keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1)
|
||||
amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
|
||||
remainingInVal := sdk.NewDec(60 + 180).Sub(withdrawnFromVal)
|
||||
expRes3 := sdk.NewDecFromInt(expRes1).Add(remainingInVal.Mul(sdk.NewDec(1)).Quo(sdk.NewDec(3))).TruncateInt()
|
||||
require.True(sdk.IntEq(t, expRes3, amt))
|
||||
|
||||
// verify the final withdraw amounts are different
|
||||
require.True(t, expRes2.GT(expRes3))
|
||||
}
|
||||
|
||||
func TestWithdrawDelegationRewardsAll(t *testing.T) {
|
||||
ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//make some validators with different commissions
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidatorWithCommission(
|
||||
valOpAddr1, valConsPk1, 10, sdk.NewDecWithPrec(1, 1))
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
|
||||
msgCreateValidator = stake.NewTestMsgCreateValidatorWithCommission(
|
||||
valOpAddr2, valConsPk2, 50, sdk.NewDecWithPrec(2, 1))
|
||||
got = stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
|
||||
msgCreateValidator = stake.NewTestMsgCreateValidatorWithCommission(
|
||||
valOpAddr3, valConsPk3, 40, sdk.NewDecWithPrec(3, 1))
|
||||
got = stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// delegate to all the validators
|
||||
msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10)
|
||||
require.True(t, stakeHandler(ctx, msgDelegate).IsOK())
|
||||
msgDelegate = stake.NewTestMsgDelegate(delAddr1, valOpAddr2, 20)
|
||||
require.True(t, stakeHandler(ctx, msgDelegate).IsOK())
|
||||
msgDelegate = stake.NewTestMsgDelegate(delAddr1, valOpAddr3, 30)
|
||||
require.True(t, stakeHandler(ctx, msgDelegate).IsOK())
|
||||
|
||||
// 40 tokens left after delegating 60 of them
|
||||
amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, int64(40), amt.Int64())
|
||||
|
||||
// total power of each validator:
|
||||
// validator 1: 10 (self) + 10 (delegator) = 20
|
||||
// validator 2: 50 (self) + 20 (delegator) = 70
|
||||
// validator 3: 40 (self) + 30 (delegator) = 70
|
||||
// grand total: 160
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(1000)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
|
||||
// withdraw delegation
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
keeper.WithdrawDelegationRewardsAll(ctx, delAddr1)
|
||||
amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
|
||||
// orig-amount + fees *(1-proposerReward)* (val1Portion * delegatorPotion * (1-val1Commission) ... etc)
|
||||
// + fees *(proposerReward) * (delegatorPotion * (1-val1Commission))
|
||||
// 40 + 1000 *(1- 0.95)* (20/160 * 10/20 * 0.9 + 70/160 * 20/70 * 0.8 + 70/160 * 30/70 * 0.7)
|
||||
// 40 + 1000 *( 0.05) * (10/20 * 0.9)
|
||||
feesInNonProposer := sdk.NewDecFromInt(feeInputs).Mul(sdk.NewDecWithPrec(95, 2))
|
||||
feesInProposer := sdk.NewDecFromInt(feeInputs).Mul(sdk.NewDecWithPrec(5, 2))
|
||||
feesInVal1 := feesInNonProposer.Mul(sdk.NewDec(10).Quo(sdk.NewDec(160))).Mul(sdk.NewDecWithPrec(9, 1))
|
||||
feesInVal2 := feesInNonProposer.Mul(sdk.NewDec(20).Quo(sdk.NewDec(160))).Mul(sdk.NewDecWithPrec(8, 1))
|
||||
feesInVal3 := feesInNonProposer.Mul(sdk.NewDec(30).Quo(sdk.NewDec(160))).Mul(sdk.NewDecWithPrec(7, 1))
|
||||
feesInVal1Proposer := feesInProposer.Mul(sdk.NewDec(10).Quo(sdk.NewDec(20))).Mul(sdk.NewDecWithPrec(9, 1))
|
||||
expRes := sdk.NewDec(40).Add(feesInVal1).Add(feesInVal2).Add(feesInVal3).Add(feesInVal1Proposer).TruncateInt()
|
||||
require.True(sdk.IntEq(t, expRes, amt))
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
// Get the set of all validator-distribution-info's with no limits, used during genesis dump
|
||||
func (k Keeper) GetAllValidatorDistInfos(ctx sdk.Context) (vdis []types.ValidatorDistInfo) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, ValidatorDistInfoKey)
|
||||
defer iterator.Close()
|
||||
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
var vdi types.ValidatorDistInfo
|
||||
k.cdc.MustUnmarshalBinary(iterator.Value(), &vdi)
|
||||
vdis = append(vdis, vdi)
|
||||
}
|
||||
return vdis
|
||||
}
|
||||
|
||||
// Get the set of all delegator-distribution-info's with no limits, used during genesis dump
|
||||
func (k Keeper) GetAllDelegationDistInfos(ctx sdk.Context) (ddis []types.DelegationDistInfo) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, DelegationDistInfoKey)
|
||||
defer iterator.Close()
|
||||
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
var ddi types.DelegationDistInfo
|
||||
k.cdc.MustUnmarshalBinary(iterator.Value(), &ddi)
|
||||
ddis = append(ddis, ddi)
|
||||
}
|
||||
return ddis
|
||||
}
|
||||
|
||||
// Get the set of all delegator-withdraw addresses with no limits, used during genesis dump
|
||||
func (k Keeper) GetAllDelegatorWithdrawInfos(ctx sdk.Context) (dwis []types.DelegatorWithdrawInfo) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, DelegationDistInfoKey)
|
||||
defer iterator.Close()
|
||||
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
dw := types.DelegatorWithdrawInfo{
|
||||
DelegatorAddr: sdk.AccAddress(iterator.Key()),
|
||||
WithdrawAddr: sdk.AccAddress(iterator.Value()),
|
||||
}
|
||||
dwis = append(dwis, dw)
|
||||
}
|
||||
return dwis
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
// Create a new validator distribution record
|
||||
func (k Keeper) onValidatorCreated(ctx sdk.Context, addr sdk.ValAddress) {
|
||||
|
||||
height := ctx.BlockHeight()
|
||||
vdi := types.ValidatorDistInfo{
|
||||
OperatorAddr: addr,
|
||||
FeePoolWithdrawalHeight: height,
|
||||
Pool: types.DecCoins{},
|
||||
PoolCommission: types.DecCoins{},
|
||||
DelAccum: types.NewTotalAccum(height),
|
||||
}
|
||||
k.SetValidatorDistInfo(ctx, vdi)
|
||||
}
|
||||
|
||||
// Withdrawal all validator rewards
|
||||
func (k Keeper) onValidatorCommissionChange(ctx sdk.Context, addr sdk.ValAddress) {
|
||||
k.WithdrawValidatorRewardsAll(ctx, addr)
|
||||
}
|
||||
|
||||
// Withdrawal all validator distribution rewards and cleanup the distribution record
|
||||
func (k Keeper) onValidatorRemoved(ctx sdk.Context, addr sdk.ValAddress) {
|
||||
k.RemoveValidatorDistInfo(ctx, addr)
|
||||
}
|
||||
|
||||
//_________________________________________________________________________________________
|
||||
|
||||
// Create a new delegator distribution record
|
||||
func (k Keeper) onDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress,
|
||||
valAddr sdk.ValAddress) {
|
||||
|
||||
ddi := types.DelegationDistInfo{
|
||||
DelegatorAddr: delAddr,
|
||||
ValOperatorAddr: valAddr,
|
||||
WithdrawalHeight: ctx.BlockHeight(),
|
||||
}
|
||||
k.SetDelegationDistInfo(ctx, ddi)
|
||||
ctx.Logger().With("module", "x/distribution").Error(fmt.Sprintf("ddi created: %v", ddi))
|
||||
}
|
||||
|
||||
// Withdrawal all validator rewards
|
||||
func (k Keeper) onDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress,
|
||||
valAddr sdk.ValAddress) {
|
||||
|
||||
k.WithdrawDelegationReward(ctx, delAddr, valAddr)
|
||||
}
|
||||
|
||||
// Withdrawal all validator distribution rewards and cleanup the distribution record
|
||||
func (k Keeper) onDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress,
|
||||
valAddr sdk.ValAddress) {
|
||||
|
||||
k.RemoveDelegationDistInfo(ctx, delAddr, valAddr)
|
||||
}
|
||||
|
||||
//_________________________________________________________________________________________
|
||||
|
||||
// Wrapper struct
|
||||
type Hooks struct {
|
||||
k Keeper
|
||||
}
|
||||
|
||||
var _ sdk.StakingHooks = Hooks{}
|
||||
|
||||
// New Validator Hooks
|
||||
func (k Keeper) Hooks() Hooks { return Hooks{k} }
|
||||
|
||||
// nolint
|
||||
func (h Hooks) OnValidatorCreated(ctx sdk.Context, addr sdk.ValAddress) {
|
||||
h.k.onValidatorCreated(ctx, addr)
|
||||
}
|
||||
func (h Hooks) OnValidatorCommissionChange(ctx sdk.Context, addr sdk.ValAddress) {
|
||||
h.k.onValidatorCommissionChange(ctx, addr)
|
||||
}
|
||||
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, addr sdk.ValAddress) {
|
||||
h.k.onValidatorRemoved(ctx, addr)
|
||||
}
|
||||
func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.k.onDelegationCreated(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h Hooks) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.k.onDelegationSharesModified(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h Hooks) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.k.onDelegationRemoved(ctx, delAddr, valAddr)
|
||||
}
|
||||
|
||||
// nolint - unused hooks for interface
|
||||
func (h Hooks) OnValidatorBonded(ctx sdk.Context, addr sdk.ConsAddress) {}
|
||||
func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, addr sdk.ConsAddress) {}
|
|
@ -0,0 +1,129 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
)
|
||||
|
||||
// keeper of the stake store
|
||||
type Keeper struct {
|
||||
storeKey sdk.StoreKey
|
||||
cdc *codec.Codec
|
||||
paramSpace params.Subspace
|
||||
bankKeeper types.BankKeeper
|
||||
stakeKeeper types.StakeKeeper
|
||||
feeCollectionKeeper types.FeeCollectionKeeper
|
||||
|
||||
// codespace
|
||||
codespace sdk.CodespaceType
|
||||
}
|
||||
|
||||
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, ck types.BankKeeper,
|
||||
sk types.StakeKeeper, fck types.FeeCollectionKeeper, codespace sdk.CodespaceType) Keeper {
|
||||
|
||||
keeper := Keeper{
|
||||
storeKey: key,
|
||||
cdc: cdc,
|
||||
paramSpace: paramSpace.WithTypeTable(ParamTypeTable()),
|
||||
bankKeeper: ck,
|
||||
stakeKeeper: sk,
|
||||
feeCollectionKeeper: fck,
|
||||
codespace: codespace,
|
||||
}
|
||||
return keeper
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// get the global fee pool distribution info
|
||||
func (k Keeper) GetFeePool(ctx sdk.Context) (feePool types.FeePool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := store.Get(FeePoolKey)
|
||||
if b == nil {
|
||||
panic("Stored fee pool should not have been nil")
|
||||
}
|
||||
k.cdc.MustUnmarshalBinary(b, &feePool)
|
||||
return
|
||||
}
|
||||
|
||||
// set the global fee pool distribution info
|
||||
func (k Keeper) SetFeePool(ctx sdk.Context, feePool types.FeePool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := k.cdc.MustMarshalBinary(feePool)
|
||||
store.Set(FeePoolKey, b)
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// set the proposer public key for this block
|
||||
func (k Keeper) GetPreviousProposerConsAddr(ctx sdk.Context) (consAddr sdk.ConsAddress) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
b := store.Get(ProposerKey)
|
||||
if b == nil {
|
||||
panic("Previous proposer not set")
|
||||
}
|
||||
|
||||
k.cdc.MustUnmarshalBinary(b, &consAddr)
|
||||
return
|
||||
}
|
||||
|
||||
// get the proposer public key for this block
|
||||
func (k Keeper) SetPreviousProposerConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := k.cdc.MustMarshalBinary(consAddr)
|
||||
store.Set(ProposerKey, b)
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
// PARAM STORE
|
||||
|
||||
// Type declaration for parameters
|
||||
func ParamTypeTable() params.TypeTable {
|
||||
return params.NewTypeTable(
|
||||
ParamStoreKeyCommunityTax, sdk.Dec{},
|
||||
ParamStoreKeyBaseProposerReward, sdk.Dec{},
|
||||
ParamStoreKeyBonusProposerReward, sdk.Dec{},
|
||||
)
|
||||
}
|
||||
|
||||
// Returns the current CommunityTax rate from the global param store
|
||||
// nolint: errcheck
|
||||
func (k Keeper) GetCommunityTax(ctx sdk.Context) sdk.Dec {
|
||||
var percent sdk.Dec
|
||||
k.paramSpace.Get(ctx, ParamStoreKeyCommunityTax, &percent)
|
||||
return percent
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
func (k Keeper) SetCommunityTax(ctx sdk.Context, percent sdk.Dec) {
|
||||
k.paramSpace.Set(ctx, ParamStoreKeyCommunityTax, &percent)
|
||||
}
|
||||
|
||||
// Returns the current BaseProposerReward rate from the global param store
|
||||
// nolint: errcheck
|
||||
func (k Keeper) GetBaseProposerReward(ctx sdk.Context) sdk.Dec {
|
||||
var percent sdk.Dec
|
||||
k.paramSpace.Get(ctx, ParamStoreKeyBaseProposerReward, &percent)
|
||||
return percent
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
func (k Keeper) SetBaseProposerReward(ctx sdk.Context, percent sdk.Dec) {
|
||||
k.paramSpace.Set(ctx, ParamStoreKeyBaseProposerReward, &percent)
|
||||
}
|
||||
|
||||
// Returns the current BaseProposerReward rate from the global param store
|
||||
// nolint: errcheck
|
||||
func (k Keeper) GetBonusProposerReward(ctx sdk.Context) sdk.Dec {
|
||||
var percent sdk.Dec
|
||||
k.paramSpace.Get(ctx, ParamStoreKeyBonusProposerReward, &percent)
|
||||
return percent
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
func (k Keeper) SetBonusProposerReward(ctx sdk.Context, percent sdk.Dec) {
|
||||
k.paramSpace.Set(ctx, ParamStoreKeyBonusProposerReward, &percent)
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSetGetPreviousProposerConsAddr(t *testing.T) {
|
||||
ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 0)
|
||||
|
||||
keeper.SetPreviousProposerConsAddr(ctx, valConsAddr1)
|
||||
res := keeper.GetPreviousProposerConsAddr(ctx)
|
||||
require.True(t, res.Equals(valConsAddr1), "expected: %v got: %v", valConsAddr1.String(), res.String())
|
||||
}
|
||||
|
||||
func TestSetGetCommunityTax(t *testing.T) {
|
||||
ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 0)
|
||||
|
||||
someDec := sdk.NewDec(333)
|
||||
keeper.SetCommunityTax(ctx, someDec)
|
||||
res := keeper.GetCommunityTax(ctx)
|
||||
require.True(sdk.DecEq(t, someDec, res))
|
||||
}
|
||||
|
||||
func TestSetGetFeePool(t *testing.T) {
|
||||
ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 0)
|
||||
|
||||
fp := types.InitialFeePool()
|
||||
fp.ValAccum.UpdateHeight = 777
|
||||
|
||||
keeper.SetFeePool(ctx, fp)
|
||||
res := keeper.GetFeePool(ctx)
|
||||
require.Equal(t, fp.ValAccum, res.ValAccum)
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// keys/key-prefixes
|
||||
var (
|
||||
FeePoolKey = []byte{0x00} // key for global distribution state
|
||||
ValidatorDistInfoKey = []byte{0x01} // prefix for each key to a validator distribution
|
||||
DelegationDistInfoKey = []byte{0x02} // prefix for each key to a delegation distribution
|
||||
DelegatorWithdrawInfoKey = []byte{0x03} // prefix for each key to a delegator withdraw info
|
||||
ProposerKey = []byte{0x04} // key for storing the proposer operator address
|
||||
|
||||
// params store
|
||||
ParamStoreKeyCommunityTax = []byte("community-tax")
|
||||
ParamStoreKeyBaseProposerReward = []byte("base-proposer-reward")
|
||||
ParamStoreKeyBonusProposerReward = []byte("bonus-proposer-reward")
|
||||
)
|
||||
|
||||
const (
|
||||
// default paramspace for params keeper
|
||||
DefaultParamspace = "distr"
|
||||
)
|
||||
|
||||
// gets the key for the validator distribution info from address
|
||||
// VALUE: distribution/types.ValidatorDistInfo
|
||||
func GetValidatorDistInfoKey(operatorAddr sdk.ValAddress) []byte {
|
||||
return append(ValidatorDistInfoKey, operatorAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// gets the key for delegator distribution for a validator
|
||||
// VALUE: distribution/types.DelegationDistInfo
|
||||
func GetDelegationDistInfoKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte {
|
||||
return append(GetDelegationDistInfosKey(delAddr), valAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// gets the prefix for a delegator's distributions across all validators
|
||||
func GetDelegationDistInfosKey(delAddr sdk.AccAddress) []byte {
|
||||
return append(DelegationDistInfoKey, delAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// gets the prefix for a delegator's withdraw info
|
||||
func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte {
|
||||
return append(DelegatorWithdrawInfoKey, delAddr.Bytes()...)
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
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"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
var (
|
||||
delPk1 = ed25519.GenPrivKey().PubKey()
|
||||
delPk2 = ed25519.GenPrivKey().PubKey()
|
||||
delPk3 = ed25519.GenPrivKey().PubKey()
|
||||
delAddr1 = sdk.AccAddress(delPk1.Address())
|
||||
delAddr2 = sdk.AccAddress(delPk2.Address())
|
||||
delAddr3 = sdk.AccAddress(delPk3.Address())
|
||||
|
||||
valOpPk1 = ed25519.GenPrivKey().PubKey()
|
||||
valOpPk2 = ed25519.GenPrivKey().PubKey()
|
||||
valOpPk3 = ed25519.GenPrivKey().PubKey()
|
||||
valOpAddr1 = sdk.ValAddress(valOpPk1.Address())
|
||||
valOpAddr2 = sdk.ValAddress(valOpPk2.Address())
|
||||
valOpAddr3 = sdk.ValAddress(valOpPk3.Address())
|
||||
valAccAddr1 = sdk.AccAddress(valOpPk1.Address()) // generate acc addresses for these validator keys too
|
||||
valAccAddr2 = sdk.AccAddress(valOpPk2.Address())
|
||||
valAccAddr3 = sdk.AccAddress(valOpPk3.Address())
|
||||
|
||||
valConsPk1 = ed25519.GenPrivKey().PubKey()
|
||||
valConsPk2 = ed25519.GenPrivKey().PubKey()
|
||||
valConsPk3 = ed25519.GenPrivKey().PubKey()
|
||||
valConsAddr1 = sdk.ConsAddress(valConsPk1.Address())
|
||||
valConsAddr2 = sdk.ConsAddress(valConsPk2.Address())
|
||||
valConsAddr3 = sdk.ConsAddress(valConsPk3.Address())
|
||||
|
||||
addrs = []sdk.AccAddress{
|
||||
delAddr1, delAddr2, delAddr3,
|
||||
valAccAddr1, valAccAddr2, valAccAddr3,
|
||||
}
|
||||
|
||||
emptyDelAddr sdk.AccAddress
|
||||
emptyValAddr sdk.ValAddress
|
||||
emptyPubkey crypto.PubKey
|
||||
)
|
||||
|
||||
// create a codec used only for testing
|
||||
func MakeTestCodec() *codec.Codec {
|
||||
var cdc = codec.New()
|
||||
bank.RegisterCodec(cdc)
|
||||
stake.RegisterCodec(cdc)
|
||||
auth.RegisterCodec(cdc)
|
||||
sdk.RegisterCodec(cdc)
|
||||
codec.RegisterCrypto(cdc)
|
||||
|
||||
types.RegisterCodec(cdc) // distr
|
||||
return cdc
|
||||
}
|
||||
|
||||
// test input with default values
|
||||
func CreateTestInputDefault(t *testing.T, isCheckTx bool, initCoins int64) (
|
||||
sdk.Context, auth.AccountMapper, Keeper, stake.Keeper, DummyFeeCollectionKeeper) {
|
||||
|
||||
communityTax := sdk.NewDecWithPrec(2, 2)
|
||||
return CreateTestInputAdvanced(t, isCheckTx, initCoins, communityTax)
|
||||
}
|
||||
|
||||
// hogpodge of all sorts of input required for testing
|
||||
func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initCoins int64,
|
||||
communityTax sdk.Dec) (
|
||||
sdk.Context, auth.AccountMapper, Keeper, stake.Keeper, DummyFeeCollectionKeeper) {
|
||||
|
||||
keyDistr := sdk.NewKVStoreKey("distr")
|
||||
keyStake := sdk.NewKVStoreKey("stake")
|
||||
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
||||
keyAcc := sdk.NewKVStoreKey("acc")
|
||||
keyFeeCollection := sdk.NewKVStoreKey("fee")
|
||||
keyParams := sdk.NewKVStoreKey("params")
|
||||
tkeyParams := sdk.NewTransientStoreKey("transient_params")
|
||||
|
||||
db := dbm.NewMemDB()
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
|
||||
ms.MountStoreWithDB(keyDistr, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyStake, sdk.StoreTypeTransient, nil)
|
||||
ms.MountStoreWithDB(keyStake, 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)
|
||||
|
||||
err := ms.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
|
||||
cdc := MakeTestCodec()
|
||||
pk := params.NewKeeper(cdc, keyParams, tkeyParams)
|
||||
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger())
|
||||
accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount)
|
||||
ck := bank.NewBaseKeeper(accountMapper)
|
||||
sk := stake.NewKeeper(cdc, keyStake, tkeyStake, ck, pk.Subspace(stake.DefaultParamspace), stake.DefaultCodespace)
|
||||
sk.SetPool(ctx, stake.InitialPool())
|
||||
sk.SetParams(ctx, stake.DefaultParams())
|
||||
sk.InitIntraTxCounter(ctx)
|
||||
|
||||
// fill all the addresses with some coins, set the loose pool tokens simultaneously
|
||||
for _, addr := range addrs {
|
||||
pool := sk.GetPool(ctx)
|
||||
_, _, err := ck.AddCoins(ctx, addr, sdk.Coins{
|
||||
{sk.GetParams(ctx).BondDenom, sdk.NewInt(initCoins)},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(initCoins))
|
||||
sk.SetPool(ctx, pool)
|
||||
}
|
||||
|
||||
fck := DummyFeeCollectionKeeper{}
|
||||
keeper := NewKeeper(cdc, keyDistr, pk.Subspace(DefaultParamspace), ck, sk, fck, types.DefaultCodespace)
|
||||
|
||||
// set the distribution hooks on staking
|
||||
sk = sk.WithHooks(keeper.Hooks())
|
||||
|
||||
// set genesis items required for distribution
|
||||
keeper.SetFeePool(ctx, types.InitialFeePool())
|
||||
keeper.SetCommunityTax(ctx, communityTax)
|
||||
keeper.SetBaseProposerReward(ctx, sdk.NewDecWithPrec(1, 2))
|
||||
keeper.SetBonusProposerReward(ctx, sdk.NewDecWithPrec(4, 2))
|
||||
|
||||
return ctx, accountMapper, keeper, sk, fck
|
||||
}
|
||||
|
||||
//__________________________________________________________________________________
|
||||
// fee collection keeper used only for testing
|
||||
type DummyFeeCollectionKeeper struct{}
|
||||
|
||||
var heldFees sdk.Coins
|
||||
var _ types.FeeCollectionKeeper = DummyFeeCollectionKeeper{}
|
||||
|
||||
// nolint
|
||||
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.Coins{}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
)
|
||||
|
||||
// get the validator distribution info
|
||||
func (k Keeper) GetValidatorDistInfo(ctx sdk.Context,
|
||||
operatorAddr sdk.ValAddress) (vdi types.ValidatorDistInfo) {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
b := store.Get(GetValidatorDistInfoKey(operatorAddr))
|
||||
if b == nil {
|
||||
panic("Stored validator-distribution info should not have been nil")
|
||||
}
|
||||
|
||||
k.cdc.MustUnmarshalBinary(b, &vdi)
|
||||
return
|
||||
}
|
||||
|
||||
// set the validator distribution info
|
||||
func (k Keeper) SetValidatorDistInfo(ctx sdk.Context, vdi types.ValidatorDistInfo) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := k.cdc.MustMarshalBinary(vdi)
|
||||
store.Set(GetValidatorDistInfoKey(vdi.OperatorAddr), b)
|
||||
}
|
||||
|
||||
// remove a validator distribution info
|
||||
func (k Keeper) RemoveValidatorDistInfo(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
store.Delete(GetValidatorDistInfoKey(valAddr))
|
||||
}
|
||||
|
||||
// withdrawal all the validator rewards including the commission
|
||||
func (k Keeper) WithdrawValidatorRewardsAll(ctx sdk.Context, operatorAddr sdk.ValAddress) {
|
||||
|
||||
// withdraw self-delegation
|
||||
height := ctx.BlockHeight()
|
||||
validator := k.stakeKeeper.Validator(ctx, operatorAddr)
|
||||
accAddr := sdk.AccAddress(operatorAddr.Bytes())
|
||||
withdraw := k.getDelegatorRewardsAll(ctx, accAddr, height)
|
||||
|
||||
// withdrawal validator commission rewards
|
||||
bondedTokens := k.stakeKeeper.TotalPower(ctx)
|
||||
valInfo := k.GetValidatorDistInfo(ctx, operatorAddr)
|
||||
feePool := k.GetFeePool(ctx)
|
||||
valInfo, feePool, commission := valInfo.WithdrawCommission(feePool, height, bondedTokens,
|
||||
validator.GetTokens(), validator.GetCommission())
|
||||
withdraw = withdraw.Plus(commission)
|
||||
k.SetValidatorDistInfo(ctx, valInfo)
|
||||
k.SetFeePool(ctx, feePool)
|
||||
|
||||
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, accAddr)
|
||||
_, _, err := k.bankKeeper.AddCoins(ctx, withdrawAddr, withdraw.TruncateDecimal())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWithdrawValidatorRewardsAllNoDelegator(t *testing.T) {
|
||||
ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//first make a validator
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidator(valOpAddr1, valConsPk1, 10)
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(100)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
|
||||
// withdraw self-delegation reward
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
keeper.WithdrawValidatorRewardsAll(ctx, valOpAddr1)
|
||||
amt := accMapper.GetAccount(ctx, valAccAddr1).GetCoins().AmountOf(denom)
|
||||
expRes := sdk.NewDec(90).Add(sdk.NewDec(100)).TruncateInt()
|
||||
require.True(sdk.IntEq(t, expRes, amt))
|
||||
}
|
||||
|
||||
func TestWithdrawValidatorRewardsAllDelegatorNoCommission(t *testing.T) {
|
||||
ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//first make a validator
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidator(valOpAddr1, valConsPk1, 10)
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// delegate
|
||||
msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10)
|
||||
got = stakeHandler(ctx, msgDelegate)
|
||||
require.True(t, got.IsOK())
|
||||
amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, int64(90), amt.Int64())
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(100)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
|
||||
// withdraw self-delegation reward
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
keeper.WithdrawValidatorRewardsAll(ctx, valOpAddr1)
|
||||
amt = accMapper.GetAccount(ctx, valAccAddr1).GetCoins().AmountOf(denom)
|
||||
expRes := sdk.NewDec(90).Add(sdk.NewDec(100).Quo(sdk.NewDec(2))).TruncateInt() // 90 + 100 tokens * 10/20
|
||||
require.True(sdk.IntEq(t, expRes, amt))
|
||||
}
|
||||
|
||||
func TestWithdrawValidatorRewardsAllDelegatorWithCommission(t *testing.T) {
|
||||
ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//first make a validator
|
||||
commissionRate := sdk.NewDecWithPrec(1, 1)
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidatorWithCommission(
|
||||
valOpAddr1, valConsPk1, 10, commissionRate)
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// delegate
|
||||
msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10)
|
||||
got = stakeHandler(ctx, msgDelegate)
|
||||
require.True(t, got.IsOK())
|
||||
amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, int64(90), amt.Int64())
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(100)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
|
||||
// withdraw validator reward
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
keeper.WithdrawValidatorRewardsAll(ctx, valOpAddr1)
|
||||
amt = accMapper.GetAccount(ctx, valAccAddr1).GetCoins().AmountOf(denom)
|
||||
commissionTaken := sdk.NewDec(100).Mul(commissionRate)
|
||||
afterCommission := sdk.NewDec(100).Sub(commissionTaken)
|
||||
selfDelegationReward := afterCommission.Quo(sdk.NewDec(2))
|
||||
expRes := sdk.NewDec(90).Add(commissionTaken).Add(selfDelegationReward).TruncateInt() // 90 + 100 tokens * 10/20
|
||||
require.True(sdk.IntEq(t, expRes, amt))
|
||||
}
|
||||
|
||||
func TestWithdrawValidatorRewardsAllMultipleValidator(t *testing.T) {
|
||||
ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//make some validators with different commissions
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidatorWithCommission(
|
||||
valOpAddr1, valConsPk1, 10, sdk.NewDecWithPrec(1, 1))
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
|
||||
msgCreateValidator = stake.NewTestMsgCreateValidatorWithCommission(
|
||||
valOpAddr2, valConsPk2, 50, sdk.NewDecWithPrec(2, 1))
|
||||
got = stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
|
||||
msgCreateValidator = stake.NewTestMsgCreateValidatorWithCommission(
|
||||
valOpAddr3, valConsPk3, 40, sdk.NewDecWithPrec(3, 1))
|
||||
got = stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(1000)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
|
||||
// withdraw validator reward
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
keeper.WithdrawValidatorRewardsAll(ctx, valOpAddr1)
|
||||
amt := accMapper.GetAccount(ctx, valAccAddr1).GetCoins().AmountOf(denom)
|
||||
|
||||
feesInNonProposer := sdk.NewDecFromInt(feeInputs).Mul(sdk.NewDecWithPrec(95, 2))
|
||||
feesInProposer := sdk.NewDecFromInt(feeInputs).Mul(sdk.NewDecWithPrec(5, 2))
|
||||
expRes := sdk.NewDec(90). // orig tokens (100 - 10)
|
||||
Add(feesInNonProposer.Quo(sdk.NewDec(10))). // validator 1 has 1/10 total power
|
||||
Add(feesInProposer).
|
||||
TruncateInt()
|
||||
require.True(sdk.IntEq(t, expRes, amt))
|
||||
}
|
||||
|
||||
func TestWithdrawValidatorRewardsAllMultipleDelegator(t *testing.T) {
|
||||
ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||
stakeHandler := stake.NewHandler(sk)
|
||||
denom := sk.GetParams(ctx).BondDenom
|
||||
|
||||
//first make a validator with 10% commission
|
||||
commissionRate := sdk.NewDecWithPrec(1, 1)
|
||||
msgCreateValidator := stake.NewTestMsgCreateValidatorWithCommission(
|
||||
valOpAddr1, valConsPk1, 10, sdk.NewDecWithPrec(1, 1))
|
||||
got := stakeHandler(ctx, msgCreateValidator)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
// delegate
|
||||
msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10)
|
||||
got = stakeHandler(ctx, msgDelegate)
|
||||
require.True(t, got.IsOK())
|
||||
amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, int64(90), amt.Int64())
|
||||
|
||||
msgDelegate = stake.NewTestMsgDelegate(delAddr2, valOpAddr1, 20)
|
||||
got = stakeHandler(ctx, msgDelegate)
|
||||
require.True(t, got.IsOK())
|
||||
amt = accMapper.GetAccount(ctx, delAddr2).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, int64(80), amt.Int64())
|
||||
|
||||
// allocate 100 denom of fees
|
||||
feeInputs := sdk.NewInt(100)
|
||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
||||
|
||||
// withdraw validator reward
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
keeper.WithdrawValidatorRewardsAll(ctx, valOpAddr1)
|
||||
amt = accMapper.GetAccount(ctx, valAccAddr1).GetCoins().AmountOf(denom)
|
||||
|
||||
commissionTaken := sdk.NewDec(100).Mul(commissionRate)
|
||||
afterCommission := sdk.NewDec(100).Sub(commissionTaken)
|
||||
expRes := sdk.NewDec(90).
|
||||
Add(afterCommission.Quo(sdk.NewDec(4))).
|
||||
Add(commissionTaken).
|
||||
TruncateInt() // 90 + 100*90% tokens * 10/40
|
||||
require.True(sdk.IntEq(t, expRes, amt))
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// nolint
|
||||
package tags
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
var (
|
||||
ActionModifyWithdrawAddress = []byte("modify-withdraw-address")
|
||||
ActionWithdrawDelegatorRewardsAll = []byte("withdraw-delegator-rewards-all")
|
||||
ActionWithdrawDelegatorReward = []byte("withdraw-delegator-reward")
|
||||
ActionWithdrawValidatorRewardsAll = []byte("withdraw-validator-rewards-all")
|
||||
|
||||
Action = sdk.TagAction
|
||||
Validator = sdk.TagSrcValidator
|
||||
Delegator = sdk.TagDelegator
|
||||
)
|
|
@ -5,16 +5,16 @@ import (
|
|||
)
|
||||
|
||||
// distribution info for a delegation - used to determine entitled rewards
|
||||
type DelegatorDistInfo struct {
|
||||
type DelegationDistInfo struct {
|
||||
DelegatorAddr sdk.AccAddress `json:"delegator_addr"`
|
||||
ValOperatorAddr sdk.ValAddress `json:"val_operator_addr"`
|
||||
WithdrawalHeight int64 `json:"withdrawal_height"` // last time this delegation withdrew rewards
|
||||
}
|
||||
|
||||
func NewDelegatorDistInfo(delegatorAddr sdk.AccAddress, valOperatorAddr sdk.ValAddress,
|
||||
currentHeight int64) DelegatorDistInfo {
|
||||
func NewDelegationDistInfo(delegatorAddr sdk.AccAddress, valOperatorAddr sdk.ValAddress,
|
||||
currentHeight int64) DelegationDistInfo {
|
||||
|
||||
return DelegatorDistInfo{
|
||||
return DelegationDistInfo{
|
||||
DelegatorAddr: delegatorAddr,
|
||||
ValOperatorAddr: valOperatorAddr,
|
||||
WithdrawalHeight: currentHeight,
|
||||
|
@ -22,9 +22,9 @@ func NewDelegatorDistInfo(delegatorAddr sdk.AccAddress, valOperatorAddr sdk.ValA
|
|||
}
|
||||
|
||||
// withdraw rewards from delegator
|
||||
func (di DelegatorDistInfo) WithdrawRewards(fp FeePool, vi ValidatorDistInfo,
|
||||
func (di DelegationDistInfo) WithdrawRewards(fp FeePool, vi ValidatorDistInfo,
|
||||
height int64, totalBonded, vdTokens, totalDelShares, delegatorShares,
|
||||
commissionRate sdk.Dec) (DelegatorDistInfo, ValidatorDistInfo, FeePool, DecCoins) {
|
||||
commissionRate sdk.Dec) (DelegationDistInfo, ValidatorDistInfo, FeePool, DecCoins) {
|
||||
|
||||
vi = vi.UpdateTotalDelAccum(height, totalDelShares)
|
||||
|
||||
|
|
|
@ -18,10 +18,10 @@ func TestWithdrawRewards(t *testing.T) {
|
|||
validatorDelShares := sdk.NewDec(10)
|
||||
totalBondedTokens := validatorTokens.Add(sdk.NewDec(90)) // validator-1 is 10% of total power
|
||||
|
||||
di1 := NewDelegatorDistInfo(delAddr1, valAddr1, height)
|
||||
di1 := NewDelegationDistInfo(delAddr1, valAddr1, height)
|
||||
di1Shares := sdk.NewDec(5) // this delegator has half the shares in the validator
|
||||
|
||||
di2 := NewDelegatorDistInfo(delAddr2, valAddr1, height)
|
||||
di2 := NewDelegationDistInfo(delAddr2, valAddr1, height)
|
||||
di2Shares := sdk.NewDec(5)
|
||||
|
||||
// simulate adding some stake for inflation
|
||||
|
|
|
@ -12,22 +12,56 @@ type DelegatorWithdrawInfo struct {
|
|||
// GenesisState - all distribution state that must be provided at genesis
|
||||
type GenesisState struct {
|
||||
FeePool FeePool `json:"fee_pool"`
|
||||
CommunityTax sdk.Dec `json:"community_tax"`
|
||||
BaseProposerReward sdk.Dec `json:"base_proposer_reward"`
|
||||
BonusProposerReward sdk.Dec `json:"bonus_proposer_reward"`
|
||||
ValidatorDistInfos []ValidatorDistInfo `json:"validator_dist_infos"`
|
||||
DelegatorDistInfos []DelegatorDistInfo `json:"delegator_dist_infos"`
|
||||
DelegationDistInfos []DelegationDistInfo `json:"delegator_dist_infos"`
|
||||
DelegatorWithdrawInfos []DelegatorWithdrawInfo `json:"delegator_withdraw_infos"`
|
||||
}
|
||||
|
||||
func NewGenesisState(feePool FeePool, vdis []ValidatorDistInfo, ddis []DelegatorDistInfo) GenesisState {
|
||||
func NewGenesisState(feePool FeePool, communityTax, baseProposerReward, bonusProposerReward sdk.Dec,
|
||||
vdis []ValidatorDistInfo, ddis []DelegationDistInfo, dwis []DelegatorWithdrawInfo) GenesisState {
|
||||
|
||||
return GenesisState{
|
||||
FeePool: feePool,
|
||||
ValidatorDistInfos: vdis,
|
||||
DelegatorDistInfos: ddis,
|
||||
FeePool: feePool,
|
||||
CommunityTax: communityTax,
|
||||
BaseProposerReward: baseProposerReward,
|
||||
BonusProposerReward: bonusProposerReward,
|
||||
ValidatorDistInfos: vdis,
|
||||
DelegationDistInfos: ddis,
|
||||
DelegatorWithdrawInfos: dwis,
|
||||
}
|
||||
}
|
||||
|
||||
// get raw genesis raw message for testing
|
||||
func DefaultGenesisState() GenesisState {
|
||||
return GenesisState{
|
||||
FeePool: InitialFeePool(),
|
||||
FeePool: InitialFeePool(),
|
||||
CommunityTax: sdk.NewDecWithPrec(2, 2), // 2%
|
||||
BaseProposerReward: sdk.NewDecWithPrec(1, 2), // 1%
|
||||
BonusProposerReward: sdk.NewDecWithPrec(4, 2), // 4%
|
||||
}
|
||||
}
|
||||
|
||||
// default genesis utility function, initialize for starting validator set
|
||||
func DefaultGenesisWithValidators(valAddrs []sdk.ValAddress) GenesisState {
|
||||
|
||||
vdis := make([]ValidatorDistInfo, len(valAddrs))
|
||||
ddis := make([]DelegationDistInfo, len(valAddrs))
|
||||
|
||||
for i, valAddr := range valAddrs {
|
||||
vdis[i] = NewValidatorDistInfo(valAddr, 0)
|
||||
accAddr := sdk.AccAddress(valAddr)
|
||||
ddis[i] = NewDelegationDistInfo(accAddr, valAddr, 0)
|
||||
}
|
||||
|
||||
return GenesisState{
|
||||
FeePool: InitialFeePool(),
|
||||
CommunityTax: sdk.NewDecWithPrec(2, 2), // 2%
|
||||
BaseProposerReward: sdk.NewDecWithPrec(1, 2), // 1%
|
||||
BonusProposerReward: sdk.NewDecWithPrec(4, 2), // 4%
|
||||
ValidatorDistInfos: vdis,
|
||||
DelegationDistInfos: ddis,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ var (
|
|||
valPk1 = ed25519.GenPrivKey().PubKey()
|
||||
valPk2 = ed25519.GenPrivKey().PubKey()
|
||||
valPk3 = ed25519.GenPrivKey().PubKey()
|
||||
valAddr1 = sdk.ValAddress(delPk1.Address())
|
||||
valAddr2 = sdk.ValAddress(delPk2.Address())
|
||||
valAddr3 = sdk.ValAddress(delPk3.Address())
|
||||
valAddr1 = sdk.ValAddress(valPk1.Address())
|
||||
valAddr2 = sdk.ValAddress(valPk2.Address())
|
||||
valAddr3 = sdk.ValAddress(valPk3.Address())
|
||||
emptyValAddr sdk.ValAddress
|
||||
|
||||
emptyPubkey crypto.PubKey
|
|
@ -15,6 +15,7 @@ import (
|
|||
"time"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
common "github.com/tendermint/tendermint/libs/common"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
|
@ -81,7 +82,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
|||
// Initially this is the same as the initial validator set
|
||||
nextValidators := validators
|
||||
|
||||
header := abci.Header{Height: 0, Time: timestamp}
|
||||
header := abci.Header{Height: 0, Time: timestamp, ProposerAddress: randomProposer(r, validators)}
|
||||
opCount := 0
|
||||
|
||||
// Setup code to catch SIGTERM's
|
||||
|
@ -150,6 +151,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
|||
res := app.EndBlock(abci.RequestEndBlock{})
|
||||
header.Height++
|
||||
header.Time = header.Time.Add(time.Duration(minTimePerBlock) * time.Second).Add(time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second)
|
||||
header.ProposerAddress = randomProposer(r, validators)
|
||||
logWriter("EndBlock")
|
||||
|
||||
if testingMode {
|
||||
|
@ -318,6 +320,21 @@ func getKeys(validators map[string]mockValidator) []string {
|
|||
return keys
|
||||
}
|
||||
|
||||
// randomProposer picks a random proposer from the current validator set
|
||||
func randomProposer(r *rand.Rand, validators map[string]mockValidator) common.HexBytes {
|
||||
keys := getKeys(validators)
|
||||
if len(keys) == 0 {
|
||||
return nil
|
||||
}
|
||||
key := keys[r.Intn(len(keys))]
|
||||
proposer := validators[key].val
|
||||
pk, err := tmtypes.PB2TM.PubKey(proposer.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return pk.Address()
|
||||
}
|
||||
|
||||
// RandomRequestBeginBlock generates a list of signing validators according to the provided list of validators, signing fraction, and evidence fraction
|
||||
// nolint: unparam
|
||||
func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator, livenessTransitions TransitionMatrix, evidenceFraction float64,
|
||||
|
|
|
@ -3,18 +3,18 @@ package params
|
|||
/*
|
||||
Package params provides a globally available parameter store.
|
||||
|
||||
There are two main types, Keeper and Space. Space is an isolated namespace for a
|
||||
There are two main types, Keeper and Subspace. Subspace is an isolated namespace for a
|
||||
paramstore, where keys are prefixed by preconfigured spacename. Keeper has a
|
||||
permission to access all existing spaces and create new space.
|
||||
permission to access all existing spaces.
|
||||
|
||||
Space can be used by the individual keepers, who needs a private parameter store
|
||||
that the other keeper are not able to modify. Keeper can be used by the Governance
|
||||
keeper, who need to modify any parameter in case of the proposal passes.
|
||||
Subspace can be used by the individual keepers, who needs a private parameter store
|
||||
that the other keeper cannot modify. Keeper can be used by the Governance keeper,
|
||||
who need to modify any parameter in case of the proposal passes.
|
||||
|
||||
Basic Usage:
|
||||
|
||||
First, declare parameter space and parameter keys for the module. Then include
|
||||
params.Store in the keeper. Since we prefix the keys with the spacename, it is
|
||||
params.Subspace in the keeper. Since we prefix the keys with the spacename, it is
|
||||
recommended to use the same name with the module's.
|
||||
|
||||
const (
|
||||
|
@ -33,26 +33,29 @@ recommended to use the same name with the module's.
|
|||
ps params.Subspace
|
||||
}
|
||||
|
||||
Pass a params.Store to NewKeeper with DefaultParamSpace (or another)
|
||||
Pass a params.Subspace to NewKeeper with DefaultParamspace (or another)
|
||||
|
||||
app.myKeeper = mymodule.NewKeeper(app.paramStore.SubStore(mymodule.DefaultParamspace))
|
||||
|
||||
Now we can access to the paramstore using Paramstore Keys
|
||||
|
||||
var param MyStruct
|
||||
k.ps.Get(KeyParameter1, ¶m)
|
||||
k.ps.Set(KeyParameter2, param)
|
||||
|
||||
Genesis Usage:
|
||||
|
||||
Declare a struct for parameters and make it implement ParamStruct. It will then
|
||||
be able to be passed to SetFromParamStruct.
|
||||
Declare a struct for parameters and make it implement params.ParamSet. It will then
|
||||
be able to be passed to SetParamSet.
|
||||
|
||||
type MyParams struct {
|
||||
Parameter1 uint64
|
||||
Parameter2 string
|
||||
}
|
||||
|
||||
func (p *MyParams) KeyFieldPairs() params.KeyFieldPairs {
|
||||
// Implements params.ParamSet
|
||||
// KeyValuePairs must return the list of (ParamKey, PointerToTheField)
|
||||
func (p *MyParams) KeyValuePairs() params.KeyValuePairs {
|
||||
return params.KeyFieldPairs {
|
||||
{KeyParameter1, &p.Parameter1},
|
||||
{KeyParameter2, &p.Parameter2},
|
||||
|
@ -60,26 +63,26 @@ be able to be passed to SetFromParamStruct.
|
|||
}
|
||||
|
||||
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
||||
k.ps.SetFromParamStruct(ctx, &data.params)
|
||||
k.ps.SetParamSet(ctx, &data.params)
|
||||
}
|
||||
|
||||
The method is pointer receiver because there could be a case that we read from
|
||||
the store and set the result to the struct.
|
||||
|
||||
Master Permission Usage:
|
||||
Master Keeper Usage:
|
||||
|
||||
Keepers that require master permission to the paramstore, such as gov, can take
|
||||
params.Keeper itself to access all substores(using GetSubstore)
|
||||
params.Keeper itself to access all subspace(using GetSubspace)
|
||||
|
||||
type MasterKeeper struct {
|
||||
ps params.Store
|
||||
pk params.Keeper
|
||||
}
|
||||
|
||||
func (k MasterKeeper) SetParam(ctx sdk.Context, space string, key string, param interface{}) {
|
||||
store, ok := k.ps.GetSubstore(space)
|
||||
space, ok := k.pk.GetSubspace(space)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
store.Set(ctx, key, param)
|
||||
space.Set(ctx, key, param)
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -65,45 +65,82 @@ func TestKeeper(t *testing.T) {
|
|||
[]byte("extra2"), string(""),
|
||||
)
|
||||
|
||||
cdc := codec.New()
|
||||
skey := sdk.NewKVStoreKey("test")
|
||||
tkey := sdk.NewTransientStoreKey("transient_test")
|
||||
ctx := defaultContext(skey, tkey)
|
||||
store := NewKeeper(codec.New(), skey, tkey).Subspace("test").WithTypeTable(table)
|
||||
keeper := NewKeeper(cdc, skey, tkey)
|
||||
space := keeper.Subspace("test").WithTypeTable(table)
|
||||
store := ctx.KVStore(skey).Prefix([]byte("test/"))
|
||||
|
||||
// Set params
|
||||
for i, kv := range kvs {
|
||||
require.NotPanics(t, func() { store.Set(ctx, []byte(kv.key), kv.param) }, "store.Set panics, tc #%d", i)
|
||||
require.NotPanics(t, func() { space.Set(ctx, []byte(kv.key), kv.param) }, "space.Set panics, tc #%d", i)
|
||||
}
|
||||
|
||||
// Test space.Get
|
||||
for i, kv := range kvs {
|
||||
var param int64
|
||||
require.NotPanics(t, func() { store.Get(ctx, []byte(kv.key), ¶m) }, "store.Get panics, tc #%d", i)
|
||||
require.NotPanics(t, func() { space.Get(ctx, []byte(kv.key), ¶m) }, "space.Get panics, tc #%d", i)
|
||||
require.Equal(t, kv.param, param, "stored param not equal, tc #%d", i)
|
||||
}
|
||||
|
||||
cdc := codec.New()
|
||||
// Test space.GetRaw
|
||||
for i, kv := range kvs {
|
||||
var param int64
|
||||
bz := store.GetRaw(ctx, []byte(kv.key))
|
||||
bz := space.GetRaw(ctx, []byte(kv.key))
|
||||
err := cdc.UnmarshalJSON(bz, ¶m)
|
||||
require.Nil(t, err, "err is not nil, tc #%d", i)
|
||||
require.Equal(t, kv.param, param, "stored param not equal, tc #%d", i)
|
||||
}
|
||||
|
||||
// Test store.Get equals space.Get
|
||||
for i, kv := range kvs {
|
||||
var param bool
|
||||
require.Panics(t, func() { store.Get(ctx, []byte(kv.key), ¶m) }, "invalid store.Get not panics, tc #%d", i)
|
||||
var param int64
|
||||
bz := store.Get([]byte(kv.key))
|
||||
require.NotNil(t, bz, "KVStore.Get returns nil, tc #%d", i)
|
||||
err := cdc.UnmarshalJSON(bz, ¶m)
|
||||
require.NoError(t, err, "UnmarshalJSON returns error, tc #%d", i)
|
||||
require.Equal(t, kv.param, param, "stored param not equal, tc #%d", i)
|
||||
}
|
||||
|
||||
// Test invalid space.Get
|
||||
for i, kv := range kvs {
|
||||
require.Panics(t, func() { store.Set(ctx, []byte(kv.key), true) }, "invalid store.Set not panics, tc #%d", i)
|
||||
var param bool
|
||||
require.Panics(t, func() { space.Get(ctx, []byte(kv.key), ¶m) }, "invalid space.Get not panics, tc #%d", i)
|
||||
}
|
||||
|
||||
// Test invalid space.Set
|
||||
for i, kv := range kvs {
|
||||
require.Panics(t, func() { space.Set(ctx, []byte(kv.key), true) }, "invalid space.Set not panics, tc #%d", i)
|
||||
}
|
||||
|
||||
// Test GetSubspace
|
||||
for i, kv := range kvs {
|
||||
var gparam, param int64
|
||||
gspace, ok := keeper.GetSubspace("test")
|
||||
require.True(t, ok, "cannot retrieve subspace, tc #%d", i)
|
||||
|
||||
require.NotPanics(t, func() { gspace.Get(ctx, []byte(kv.key), &gparam) })
|
||||
require.NotPanics(t, func() { space.Get(ctx, []byte(kv.key), ¶m) })
|
||||
require.Equal(t, gparam, param, "GetSubspace().Get not equal with space.Get, tc #%d", i)
|
||||
|
||||
require.NotPanics(t, func() { gspace.Set(ctx, []byte(kv.key), int64(i)) })
|
||||
require.NotPanics(t, func() { space.Get(ctx, []byte(kv.key), ¶m) })
|
||||
require.Equal(t, int64(i), param, "GetSubspace().Set not equal with space.Get, tc #%d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
func indirect(ptr interface{}) interface{} {
|
||||
return reflect.ValueOf(ptr).Elem().Interface()
|
||||
}
|
||||
|
||||
func TestSubspace(t *testing.T) {
|
||||
cdc := createTestCodec()
|
||||
key := sdk.NewKVStoreKey("test")
|
||||
tkey := sdk.NewTransientStoreKey("transient_test")
|
||||
ctx := defaultContext(key, tkey)
|
||||
keeper := NewKeeper(createTestCodec(), key, tkey)
|
||||
keeper := NewKeeper(cdc, key, tkey)
|
||||
|
||||
kvs := []struct {
|
||||
key string
|
||||
|
@ -140,29 +177,41 @@ func TestGet(t *testing.T) {
|
|||
[]byte("struct"), s{},
|
||||
)
|
||||
|
||||
store := keeper.Subspace("test").WithTypeTable(table)
|
||||
store := ctx.KVStore(key).Prefix([]byte("test/"))
|
||||
space := keeper.Subspace("test").WithTypeTable(table)
|
||||
|
||||
// Test space.Set, space.Modified
|
||||
for i, kv := range kvs {
|
||||
require.False(t, store.Modified(ctx, []byte(kv.key)), "store.Modified returns true before setting, tc #%d", i)
|
||||
require.NotPanics(t, func() { store.Set(ctx, []byte(kv.key), kv.param) }, "store.Set panics, tc #%d", i)
|
||||
require.True(t, store.Modified(ctx, []byte(kv.key)), "store.Modified returns false after setting, tc #%d", i)
|
||||
require.False(t, space.Modified(ctx, []byte(kv.key)), "space.Modified returns true before setting, tc #%d", i)
|
||||
require.NotPanics(t, func() { space.Set(ctx, []byte(kv.key), kv.param) }, "space.Set panics, tc #%d", i)
|
||||
require.True(t, space.Modified(ctx, []byte(kv.key)), "space.Modified returns false after setting, tc #%d", i)
|
||||
}
|
||||
|
||||
// Test space.Get, space.GetIfExists
|
||||
for i, kv := range kvs {
|
||||
require.NotPanics(t, func() { store.GetIfExists(ctx, []byte("invalid"), kv.ptr) }, "store.GetIfExists panics when no value exists, tc #%d", i)
|
||||
require.Equal(t, kv.zero, reflect.ValueOf(kv.ptr).Elem().Interface(), "store.GetIfExists unmarshalls when no value exists, tc #%d", i)
|
||||
require.Panics(t, func() { store.Get(ctx, []byte("invalid"), kv.ptr) }, "invalid store.Get not panics when no value exists, tc #%d", i)
|
||||
require.Equal(t, kv.zero, reflect.ValueOf(kv.ptr).Elem().Interface(), "invalid store.Get unmarshalls when no value exists, tc #%d", i)
|
||||
require.NotPanics(t, func() { space.GetIfExists(ctx, []byte("invalid"), kv.ptr) }, "space.GetIfExists panics when no value exists, tc #%d", i)
|
||||
require.Equal(t, kv.zero, indirect(kv.ptr), "space.GetIfExists unmarshalls when no value exists, tc #%d", i)
|
||||
require.Panics(t, func() { space.Get(ctx, []byte("invalid"), kv.ptr) }, "invalid space.Get not panics when no value exists, tc #%d", i)
|
||||
require.Equal(t, kv.zero, indirect(kv.ptr), "invalid space.Get unmarshalls when no value exists, tc #%d", i)
|
||||
|
||||
require.NotPanics(t, func() { store.GetIfExists(ctx, []byte(kv.key), kv.ptr) }, "store.GetIfExists panics, tc #%d", i)
|
||||
require.Equal(t, kv.param, reflect.ValueOf(kv.ptr).Elem().Interface(), "stored param not equal, tc #%d", i)
|
||||
require.NotPanics(t, func() { store.Get(ctx, []byte(kv.key), kv.ptr) }, "store.Get panics, tc #%d", i)
|
||||
require.Equal(t, kv.param, reflect.ValueOf(kv.ptr).Elem().Interface(), "stored param not equal, tc #%d", i)
|
||||
require.NotPanics(t, func() { space.GetIfExists(ctx, []byte(kv.key), kv.ptr) }, "space.GetIfExists panics, tc #%d", i)
|
||||
require.Equal(t, kv.param, indirect(kv.ptr), "stored param not equal, tc #%d", i)
|
||||
require.NotPanics(t, func() { space.Get(ctx, []byte(kv.key), kv.ptr) }, "space.Get panics, tc #%d", i)
|
||||
require.Equal(t, kv.param, indirect(kv.ptr), "stored param not equal, tc #%d", i)
|
||||
|
||||
require.Panics(t, func() { store.Get(ctx, []byte("invalid"), kv.ptr) }, "invalid store.Get not panics when no value exists, tc #%d", i)
|
||||
require.Equal(t, kv.param, reflect.ValueOf(kv.ptr).Elem().Interface(), "invalid store.Get unmarshalls when no value existt, tc #%d", i)
|
||||
require.Panics(t, func() { space.Get(ctx, []byte("invalid"), kv.ptr) }, "invalid space.Get not panics when no value exists, tc #%d", i)
|
||||
require.Equal(t, kv.param, indirect(kv.ptr), "invalid space.Get unmarshalls when no value existt, tc #%d", i)
|
||||
|
||||
require.Panics(t, func() { store.Get(ctx, []byte(kv.key), nil) }, "invalid store.Get not panics when the pointer is nil, tc #%d", i)
|
||||
require.Panics(t, func() { store.Get(ctx, []byte(kv.key), new(invalid)) }, "invalid store.Get not panics when the pointer is different type, tc #%d", i)
|
||||
require.Panics(t, func() { space.Get(ctx, []byte(kv.key), nil) }, "invalid space.Get not panics when the pointer is nil, tc #%d", i)
|
||||
require.Panics(t, func() { space.Get(ctx, []byte(kv.key), new(invalid)) }, "invalid space.Get not panics when the pointer is different type, tc #%d", i)
|
||||
}
|
||||
|
||||
// Test store.Get equals space.Get
|
||||
for i, kv := range kvs {
|
||||
bz := store.Get([]byte(kv.key))
|
||||
require.NotNil(t, bz, "store.Get() returns nil, tc #%d", i)
|
||||
err := cdc.UnmarshalJSON(bz, kv.ptr)
|
||||
require.NoError(t, err, "cdc.UnmarshalJSON() returns error, tc #%d", i)
|
||||
require.Equal(t, kv.param, indirect(kv.ptr), "stored param not equal, tc #%d", i)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,6 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Additional capicity to be allocated for Subspace.name
|
||||
// So we don't have to allocate extra space each time appending to the key
|
||||
const extraKeyCap = 20
|
||||
|
||||
// Individual parameter store for each keeper
|
||||
// Transient store persists for a block, so we use it for
|
||||
// recording whether the parameter has been changed or not
|
||||
|
@ -30,32 +26,35 @@ func NewSubspace(cdc *codec.Codec, key sdk.StoreKey, tkey sdk.StoreKey, name str
|
|||
cdc: cdc,
|
||||
key: key,
|
||||
tkey: tkey,
|
||||
name: []byte(name),
|
||||
table: TypeTable{
|
||||
m: make(map[string]reflect.Type),
|
||||
},
|
||||
}
|
||||
|
||||
namebz := []byte(name)
|
||||
res.name = make([]byte, len(namebz), len(namebz)+extraKeyCap)
|
||||
copy(res.name, namebz)
|
||||
return
|
||||
}
|
||||
|
||||
// WithTypeTable initializes TypeTable and returns modified Subspace
|
||||
func (s Subspace) WithTypeTable(table TypeTable) (res Subspace) {
|
||||
if table == nil {
|
||||
func (s Subspace) WithTypeTable(table TypeTable) Subspace {
|
||||
if table.m == nil {
|
||||
panic("SetTypeTable() called with nil TypeTable")
|
||||
}
|
||||
if s.table != nil {
|
||||
panic("SetTypeTable() called on initialized Subspace")
|
||||
if len(s.table.m) != 0 {
|
||||
panic("SetTypeTable() called on already initialized Subspace")
|
||||
}
|
||||
|
||||
res = Subspace{
|
||||
cdc: s.cdc,
|
||||
key: s.key,
|
||||
tkey: s.tkey,
|
||||
name: s.name,
|
||||
table: table,
|
||||
for k, v := range table.m {
|
||||
s.table.m[k] = v
|
||||
}
|
||||
|
||||
return
|
||||
// Allocate additional capicity for Subspace.name
|
||||
// So we don't have to allocate extra space each time appending to the key
|
||||
name := s.name
|
||||
s.name = make([]byte, len(name), len(name)+table.maxKeyLength())
|
||||
copy(s.name, name)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Returns a KVStore identical with ctx.KVStore(s.key).Prefix()
|
||||
|
@ -118,7 +117,7 @@ func (s Subspace) Modified(ctx sdk.Context, key []byte) bool {
|
|||
func (s Subspace) Set(ctx sdk.Context, key []byte, param interface{}) {
|
||||
store := s.kvStore(ctx)
|
||||
|
||||
ty, ok := s.table[string(key)]
|
||||
ty, ok := s.table.m[string(key)]
|
||||
if !ok {
|
||||
panic("Parameter not registered")
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@ import (
|
|||
)
|
||||
|
||||
// TypeTable subspaces appropriate type for each parameter key
|
||||
type TypeTable map[string]reflect.Type
|
||||
type TypeTable struct {
|
||||
m map[string]reflect.Type
|
||||
}
|
||||
|
||||
// Constructs new table
|
||||
func NewTypeTable(keytypes ...interface{}) (res TypeTable) {
|
||||
|
@ -13,7 +15,9 @@ func NewTypeTable(keytypes ...interface{}) (res TypeTable) {
|
|||
panic("odd number arguments in NewTypeTypeTable")
|
||||
}
|
||||
|
||||
res = make(map[string]reflect.Type)
|
||||
res = TypeTable{
|
||||
m: make(map[string]reflect.Type),
|
||||
}
|
||||
|
||||
for i := 0; i < len(keytypes); i += 2 {
|
||||
res = res.RegisterType(keytypes[i].([]byte), keytypes[i+1])
|
||||
|
@ -22,10 +26,27 @@ func NewTypeTable(keytypes ...interface{}) (res TypeTable) {
|
|||
return
|
||||
}
|
||||
|
||||
func isAlphaNumeric(key []byte) bool {
|
||||
for _, b := range key {
|
||||
if !((48 <= b && b <= 57) || // numeric
|
||||
(65 <= b && b <= 90) || // upper case
|
||||
(97 <= b && b <= 122)) { // lower case
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Register single key-type pair
|
||||
func (t TypeTable) RegisterType(key []byte, ty interface{}) TypeTable {
|
||||
if len(key) == 0 {
|
||||
panic("cannot register empty key")
|
||||
}
|
||||
if !isAlphaNumeric(key) {
|
||||
panic("non alphanumeric parameter key")
|
||||
}
|
||||
keystr := string(key)
|
||||
if _, ok := t[keystr]; ok {
|
||||
if _, ok := t.m[keystr]; ok {
|
||||
panic("duplicate parameter key")
|
||||
}
|
||||
|
||||
|
@ -36,7 +57,7 @@ func (t TypeTable) RegisterType(key []byte, ty interface{}) TypeTable {
|
|||
rty = rty.Elem()
|
||||
}
|
||||
|
||||
t[keystr] = rty
|
||||
t.m[keystr] = rty
|
||||
|
||||
return t
|
||||
}
|
||||
|
@ -48,3 +69,13 @@ func (t TypeTable) RegisterParamSet(ps ParamSet) TypeTable {
|
|||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t TypeTable) maxKeyLength() (res int) {
|
||||
for k := range t.m {
|
||||
l := len(k)
|
||||
if l > res {
|
||||
res = l
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package subspace
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type testparams struct {
|
||||
i int64
|
||||
b bool
|
||||
}
|
||||
|
||||
func (tp *testparams) KeyValuePairs() KeyValuePairs {
|
||||
return KeyValuePairs{
|
||||
{[]byte("i"), &tp.i},
|
||||
{[]byte("b"), &tp.b},
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeTable(t *testing.T) {
|
||||
table := NewTypeTable()
|
||||
|
||||
require.Panics(t, func() { table.RegisterType([]byte(""), nil) })
|
||||
require.Panics(t, func() { table.RegisterType([]byte("!@#$%"), nil) })
|
||||
require.Panics(t, func() { table.RegisterType([]byte("hello,"), nil) })
|
||||
require.Panics(t, func() { table.RegisterType([]byte("hello"), nil) })
|
||||
|
||||
require.NotPanics(t, func() { table.RegisterType([]byte("hello"), bool(false)) })
|
||||
require.NotPanics(t, func() { table.RegisterType([]byte("world"), int64(0)) })
|
||||
require.Panics(t, func() { table.RegisterType([]byte("hello"), bool(false)) })
|
||||
|
||||
require.NotPanics(t, func() { table.RegisterParamSet(&testparams{}) })
|
||||
require.Panics(t, func() { table.RegisterParamSet(&testparams{}) })
|
||||
}
|
|
@ -16,7 +16,7 @@ func TestCannotUnjailUnlessJailed(t *testing.T) {
|
|||
slh := NewHandler(keeper)
|
||||
amtInt := int64(100)
|
||||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||
msg := newTestMsgCreateValidator(addr, val, amt)
|
||||
msg := NewTestMsgCreateValidator(addr, val, amt)
|
||||
got := stake.NewHandler(sk)(ctx, msg)
|
||||
require.True(t, got.IsOK())
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
@ -41,7 +41,7 @@ func TestJailedValidatorDelegations(t *testing.T) {
|
|||
valPubKey, bondAmount := pks[0], sdk.NewInt(amount)
|
||||
valAddr, consAddr := addrs[1], sdk.ConsAddress(addrs[0])
|
||||
|
||||
msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount)
|
||||
msgCreateVal := NewTestMsgCreateValidator(valAddr, valPubKey, bondAmount)
|
||||
got := stake.NewHandler(stakeKeeper)(ctx, msgCreateVal)
|
||||
require.True(t, got.IsOK(), "expected create validator msg to be ok, got: %v", got)
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ func TestHandleDoubleSign(t *testing.T) {
|
|||
ctx = ctx.WithBlockHeight(-1)
|
||||
amtInt := int64(100)
|
||||
operatorAddr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt))
|
||||
got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(operatorAddr, val, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
|
@ -73,7 +73,7 @@ func TestSlashingPeriodCap(t *testing.T) {
|
|||
amtInt := int64(100)
|
||||
operatorAddr, amt := addrs[0], sdk.NewInt(amtInt)
|
||||
valConsPubKey, valConsAddr := pks[0], pks[0].Address()
|
||||
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(operatorAddr, valConsPubKey, amt))
|
||||
got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(operatorAddr, valConsPubKey, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
|
||||
|
@ -139,7 +139,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
|||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||
sh := stake.NewHandler(sk)
|
||||
slh := NewHandler(keeper)
|
||||
got := sh(ctx, newTestMsgCreateValidator(addr, val, amt))
|
||||
got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
|
@ -331,7 +331,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
|||
amtInt := int64(100)
|
||||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||
sh := stake.NewHandler(sk)
|
||||
got := sh(ctx, newTestMsgCreateValidator(addr, val, amt))
|
||||
got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
|
|
|
@ -112,7 +112,7 @@ func testAddr(addr string) sdk.AccAddress {
|
|||
return res
|
||||
}
|
||||
|
||||
func newTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt sdk.Int) stake.MsgCreateValidator {
|
||||
func NewTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt sdk.Int) stake.MsgCreateValidator {
|
||||
commission := stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
|
||||
return stake.MsgCreateValidator{
|
||||
Description: stake.Description{},
|
||||
|
|
|
@ -18,7 +18,7 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags
|
|||
tags = sdk.NewTags("height", heightBytes)
|
||||
|
||||
// Iterate over all the validators which *should* have signed this block
|
||||
// Store whether or not they have actually signed it and slash/unbond any
|
||||
// store whether or not they have actually signed it and slash/unbond any
|
||||
// which have missed too many blocks in a row (downtime slashing)
|
||||
for _, voteInfo := range req.LastCommitInfo.GetVotes() {
|
||||
sk.handleValidatorSignature(ctx, voteInfo.Validator.Address, voteInfo.Validator.Power, voteInfo.SignedLastBlock)
|
||||
|
|
|
@ -17,7 +17,7 @@ func TestBeginBlocker(t *testing.T) {
|
|||
addr, pk, amt := addrs[2], pks[2], sdk.NewInt(100)
|
||||
|
||||
// bond the validator
|
||||
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, pk, amt))
|
||||
got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(addr, pk, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
|
|
|
@ -10,24 +10,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
)
|
||||
|
||||
var (
|
||||
priv1 = ed25519.GenPrivKey()
|
||||
addr1 = sdk.AccAddress(priv1.PubKey().Address())
|
||||
priv2 = ed25519.GenPrivKey()
|
||||
addr2 = sdk.AccAddress(priv2.PubKey().Address())
|
||||
addr3 = sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
|
||||
priv4 = ed25519.GenPrivKey()
|
||||
addr4 = sdk.AccAddress(priv4.PubKey().Address())
|
||||
coins = sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(10))}
|
||||
fee = auth.NewStdFee(
|
||||
100000,
|
||||
sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(0))}...,
|
||||
)
|
||||
|
||||
commissionMsg = NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
|
||||
)
|
||||
|
||||
// getMockApp returns an initialized mock application for this module.
|
||||
|
|
|
@ -42,10 +42,13 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [
|
|||
// Manually set indices for the first time
|
||||
keeper.SetValidatorByConsAddr(ctx, validator)
|
||||
keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool)
|
||||
|
||||
keeper.OnValidatorCreated(ctx, validator.OperatorAddr)
|
||||
}
|
||||
|
||||
for _, bond := range data.Bonds {
|
||||
keeper.SetDelegation(ctx, bond)
|
||||
for _, delegation := range data.Bonds {
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
keeper.OnDelegationCreated(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
|
||||
}
|
||||
|
||||
res = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
|
|
@ -106,7 +106,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k
|
|||
|
||||
validator := NewValidator(msg.ValidatorAddr, msg.PubKey, msg.Description)
|
||||
commission := NewCommissionWithTime(
|
||||
msg.Commission.Rate, msg.Commission.MaxChangeRate,
|
||||
msg.Commission.Rate, msg.Commission.MaxRate,
|
||||
msg.Commission.MaxChangeRate, ctx.BlockHeader().Time,
|
||||
)
|
||||
validator, err := validator.SetInitialCommission(commission)
|
||||
|
|
|
@ -7,8 +7,6 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
keep "github.com/cosmos/cosmos-sdk/x/stake/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
|
@ -16,31 +14,6 @@ import (
|
|||
|
||||
//______________________________________________________________________
|
||||
|
||||
func newTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt int64) MsgCreateValidator {
|
||||
return types.NewMsgCreateValidator(
|
||||
address, pubKey, sdk.NewCoin("steak", sdk.NewInt(amt)), Description{}, commissionMsg,
|
||||
)
|
||||
}
|
||||
|
||||
func newTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt int64) MsgDelegate {
|
||||
return MsgDelegate{
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
Delegation: sdk.NewCoin("steak", sdk.NewInt(amt)),
|
||||
}
|
||||
}
|
||||
|
||||
func newTestMsgCreateValidatorOnBehalfOf(delAddr sdk.AccAddress, valAddr sdk.ValAddress, valPubKey crypto.PubKey, amt int64) MsgCreateValidator {
|
||||
return MsgCreateValidator{
|
||||
Description: Description{},
|
||||
Commission: commissionMsg,
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
PubKey: valPubKey,
|
||||
Delegation: sdk.NewCoin("steak", sdk.NewInt(amt)),
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve params which are instant
|
||||
func setInstantUnbondPeriod(keeper keep.Keeper, ctx sdk.Context) types.Params {
|
||||
params := keeper.GetParams(ctx)
|
||||
|
@ -59,7 +32,7 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
|||
_ = setInstantUnbondPeriod(keeper, ctx)
|
||||
|
||||
// create validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got)
|
||||
|
||||
|
@ -83,7 +56,7 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
|||
require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power))
|
||||
|
||||
// create a second validator keep it bonded
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, keep.PKs[2], int64(1000000))
|
||||
msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], int64(1000000))
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got)
|
||||
|
||||
|
@ -146,7 +119,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) {
|
|||
addr1, addr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1])
|
||||
pk1, pk2 := keep.PKs[0], keep.PKs[1]
|
||||
|
||||
msgCreateValidator1 := newTestMsgCreateValidator(addr1, pk1, 10)
|
||||
msgCreateValidator1 := NewTestMsgCreateValidator(addr1, pk1, 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator1, keeper)
|
||||
require.True(t, got.IsOK(), "%v", got)
|
||||
|
||||
|
@ -162,17 +135,17 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) {
|
|||
assert.Equal(t, Description{}, validator.Description)
|
||||
|
||||
// two validators can't have the same operator address
|
||||
msgCreateValidator2 := newTestMsgCreateValidator(addr1, pk2, 10)
|
||||
msgCreateValidator2 := NewTestMsgCreateValidator(addr1, pk2, 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator2, keeper)
|
||||
require.False(t, got.IsOK(), "%v", got)
|
||||
|
||||
// two validators can't have the same pubkey
|
||||
msgCreateValidator3 := newTestMsgCreateValidator(addr2, pk1, 10)
|
||||
msgCreateValidator3 := NewTestMsgCreateValidator(addr2, pk1, 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator3, keeper)
|
||||
require.False(t, got.IsOK(), "%v", got)
|
||||
|
||||
// must have different pubkey and operator
|
||||
msgCreateValidator4 := newTestMsgCreateValidator(addr2, pk2, 10)
|
||||
msgCreateValidator4 := NewTestMsgCreateValidator(addr2, pk2, 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator4, keeper)
|
||||
require.True(t, got.IsOK(), "%v", got)
|
||||
|
||||
|
@ -197,7 +170,7 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) {
|
|||
validatorAddr := sdk.ValAddress(keep.Addrs[0])
|
||||
delegatorAddr := keep.Addrs[1]
|
||||
pk := keep.PKs[0]
|
||||
msgCreateValidatorOnBehalfOf := newTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, 10)
|
||||
msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper)
|
||||
require.True(t, got.IsOK(), "%v", got)
|
||||
|
||||
|
@ -232,7 +205,7 @@ func TestLegacyValidatorDelegations(t *testing.T) {
|
|||
delAddr := keep.Addrs[1]
|
||||
|
||||
// create validator
|
||||
msgCreateVal := newTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount)
|
||||
msgCreateVal := NewTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateVal, keeper)
|
||||
require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got)
|
||||
|
||||
|
@ -248,7 +221,7 @@ func TestLegacyValidatorDelegations(t *testing.T) {
|
|||
require.Equal(t, bondAmount, validator.BondedTokens().RoundInt64())
|
||||
|
||||
// delegate tokens to the validator
|
||||
msgDelegate := newTestMsgDelegate(delAddr, valAddr, bondAmount)
|
||||
msgDelegate := NewTestMsgDelegate(delAddr, valAddr, bondAmount)
|
||||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got)
|
||||
|
||||
|
@ -283,12 +256,12 @@ func TestLegacyValidatorDelegations(t *testing.T) {
|
|||
require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt64())
|
||||
|
||||
// verify a delegator cannot create a new delegation to the now jailed validator
|
||||
msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount)
|
||||
msgDelegate = NewTestMsgDelegate(delAddr, valAddr, bondAmount)
|
||||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.False(t, got.IsOK(), "expected delegation to not be ok, got %v", got)
|
||||
|
||||
// verify the validator can still self-delegate
|
||||
msgSelfDelegate := newTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount)
|
||||
msgSelfDelegate := NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount)
|
||||
got = handleMsgDelegate(ctx, msgSelfDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected delegation to not be ok, got %v", got)
|
||||
|
||||
|
@ -302,7 +275,7 @@ func TestLegacyValidatorDelegations(t *testing.T) {
|
|||
keeper.Unjail(ctx, valConsAddr)
|
||||
|
||||
// verify the validator can now accept delegations
|
||||
msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount)
|
||||
msgDelegate = NewTestMsgDelegate(delAddr, valAddr, bondAmount)
|
||||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got)
|
||||
|
||||
|
@ -328,7 +301,7 @@ func TestIncrementsMsgDelegate(t *testing.T) {
|
|||
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
|
||||
|
||||
// first create validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], bondAmount)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], bondAmount)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got)
|
||||
|
||||
|
@ -354,7 +327,7 @@ func TestIncrementsMsgDelegate(t *testing.T) {
|
|||
require.Equal(t, bondAmount, pool.BondedTokens.RoundInt64())
|
||||
|
||||
// just send the same msgbond multiple times
|
||||
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount)
|
||||
msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
ctx = ctx.WithBlockHeight(int64(i))
|
||||
|
@ -402,14 +375,14 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
|||
// create validator, delegate
|
||||
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
|
||||
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got)
|
||||
|
||||
// initial balance
|
||||
amt1 := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(denom)
|
||||
|
||||
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, initBond)
|
||||
msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, initBond)
|
||||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got)
|
||||
|
||||
|
@ -505,7 +478,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) {
|
|||
|
||||
// bond them all
|
||||
for i, validatorAddr := range validatorAddrs {
|
||||
msgCreateValidatorOnBehalfOf := newTestMsgCreateValidatorOnBehalfOf(delegatorAddrs[i], validatorAddr, keep.PKs[i], 10)
|
||||
msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidatorOnBehalfOf(delegatorAddrs[i], validatorAddr, keep.PKs[i], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
|
||||
|
@ -552,13 +525,13 @@ func TestMultipleMsgDelegate(t *testing.T) {
|
|||
_ = setInstantUnbondPeriod(keeper, ctx)
|
||||
|
||||
//first make a validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
|
||||
// delegate multiple parties
|
||||
for i, delegatorAddr := range delegatorAddrs {
|
||||
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
||||
msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
||||
got := handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
|
||||
|
@ -590,12 +563,12 @@ func TestJailValidator(t *testing.T) {
|
|||
_ = setInstantUnbondPeriod(keeper, ctx)
|
||||
|
||||
// create the validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// bond a delegator
|
||||
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
||||
msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
||||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected ok, got %v", got)
|
||||
|
||||
|
@ -639,12 +612,12 @@ func TestValidatorQueue(t *testing.T) {
|
|||
keeper.SetParams(ctx, params)
|
||||
|
||||
// create the validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// bond a delegator
|
||||
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
||||
msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
||||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected ok, got %v", got)
|
||||
|
||||
|
@ -689,7 +662,7 @@ func TestUnbondingPeriod(t *testing.T) {
|
|||
keeper.SetParams(ctx, params)
|
||||
|
||||
// create the validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
|
@ -727,12 +700,12 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) {
|
|||
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
|
||||
|
||||
// create the validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// bond a delegator
|
||||
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
||||
msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
||||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected ok, got %v", got)
|
||||
|
||||
|
@ -774,7 +747,7 @@ func TestRedelegationPeriod(t *testing.T) {
|
|||
keeper.SetParams(ctx, params)
|
||||
|
||||
// create the validators
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
|
||||
// initial balance
|
||||
amt1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom)
|
||||
|
@ -786,7 +759,7 @@ func TestRedelegationPeriod(t *testing.T) {
|
|||
amt2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom)
|
||||
require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted")
|
||||
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 10)
|
||||
msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
|
@ -833,15 +806,15 @@ func TestTransitiveRedelegation(t *testing.T) {
|
|||
keeper.SetParams(ctx, params)
|
||||
|
||||
// create the validators
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 10)
|
||||
msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, keep.PKs[2], 10)
|
||||
msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
|
@ -863,6 +836,48 @@ func TestTransitiveRedelegation(t *testing.T) {
|
|||
require.True(t, got.IsOK(), "expected no error")
|
||||
}
|
||||
|
||||
func TestConflictingRedelegation(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr := sdk.ValAddress(keep.Addrs[0])
|
||||
validatorAddr2 := sdk.ValAddress(keep.Addrs[1])
|
||||
|
||||
// set the unbonding time
|
||||
params := keeper.GetParams(ctx)
|
||||
params.UnbondingTime = 1
|
||||
keeper.SetParams(ctx, params)
|
||||
|
||||
// create the validators
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// end block to bond them
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
// begin redelegate
|
||||
msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, sdk.NewDec(5))
|
||||
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error, %v", got)
|
||||
|
||||
// cannot redelegate again while first redelegation still exists
|
||||
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
|
||||
require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate)
|
||||
|
||||
// progress forward in time
|
||||
ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(10 * time.Second))
|
||||
|
||||
// complete first redelegation
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
// now should be able to redelegate again
|
||||
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
}
|
||||
|
||||
func TestUnbondingWhenExcessValidators(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr1 := sdk.ValAddress(keep.Addrs[0])
|
||||
|
@ -876,21 +891,21 @@ func TestUnbondingWhenExcessValidators(t *testing.T) {
|
|||
keeper.SetParams(ctx, params)
|
||||
|
||||
// add three validators
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr1, keep.PKs[0], 50)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(validatorAddr1, keep.PKs[0], 50)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 1, len(keeper.GetValidatorsBonded(ctx)))
|
||||
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 30)
|
||||
msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 30)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
// apply TM updates
|
||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx)))
|
||||
|
||||
msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, keep.PKs[2], 10)
|
||||
msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
// apply TM updates
|
||||
|
@ -920,16 +935,16 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
|
|||
valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2]
|
||||
consAddr0 := sdk.ConsAddress(keep.PKs[0].Address())
|
||||
|
||||
msgCreateValidator := newTestMsgCreateValidator(valA, keep.PKs[0], 10)
|
||||
msgCreateValidator := NewTestMsgCreateValidator(valA, keep.PKs[0], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
msgCreateValidator = newTestMsgCreateValidator(valB, keep.PKs[1], 10)
|
||||
msgCreateValidator = NewTestMsgCreateValidator(valB, keep.PKs[1], 10)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// delegate 10 stake
|
||||
msgDelegate := newTestMsgDelegate(del, valA, 10)
|
||||
msgDelegate := NewTestMsgDelegate(del, valA, 10)
|
||||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgDelegate")
|
||||
|
||||
|
|
|
@ -380,8 +380,6 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co
|
|||
func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress,
|
||||
shares sdk.Dec) (amount sdk.Dec, err sdk.Error) {
|
||||
|
||||
k.OnDelegationSharesModified(ctx, delAddr, valAddr)
|
||||
|
||||
// check if delegation has any shares in it unbond
|
||||
delegation, found := k.GetDelegation(ctx, delAddr, valAddr)
|
||||
if !found {
|
||||
|
@ -389,6 +387,8 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
|
|||
return
|
||||
}
|
||||
|
||||
k.OnDelegationSharesModified(ctx, delAddr, valAddr)
|
||||
|
||||
// retrieve the amount to remove
|
||||
if delegation.Shares.LT(shares) {
|
||||
err = types.ErrNotEnoughDelegationShares(k.Codespace(), delegation.Shares.String())
|
||||
|
@ -430,7 +430,6 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
|
|||
k.RemoveValidator(ctx, validator.OperatorAddr)
|
||||
}
|
||||
|
||||
k.OnDelegationSharesModified(ctx, delegation.DelegatorAddr, validator.OperatorAddr)
|
||||
return amount, nil
|
||||
}
|
||||
|
||||
|
@ -526,6 +525,13 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAd
|
|||
func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
|
||||
valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) (types.Redelegation, sdk.Error) {
|
||||
|
||||
// check if there is already a redelgation in progress from src to dst
|
||||
// TODO quick fix, instead we should use an index, see https://github.com/cosmos/cosmos-sdk/issues/1402
|
||||
_, found := k.GetRedelegation(ctx, delAddr, valSrcAddr, valDstAddr)
|
||||
if found {
|
||||
return types.Redelegation{}, types.ErrConflictingRedelegation(k.Codespace())
|
||||
}
|
||||
|
||||
// check if this is a transitive redelegation
|
||||
if k.HasReceivingRedelegation(ctx, delAddr, valSrcAddr) {
|
||||
return types.Redelegation{}, types.ErrTransitiveRedelegation(k.Codespace())
|
||||
|
|
|
@ -25,9 +25,9 @@ func TestDelegation(t *testing.T) {
|
|||
}
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[2] = testingUpdateValidator(keeper, ctx, validators[2])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[2] = TestingUpdateValidator(keeper, ctx, validators[2])
|
||||
|
||||
// first add a validators[0] to delegate too
|
||||
|
||||
|
@ -184,7 +184,7 @@ func TestUnbondDelegation(t *testing.T) {
|
|||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
|
||||
pool = keeper.GetPool(ctx)
|
||||
require.Equal(t, int64(10), pool.BondedTokens.RoundInt64())
|
||||
|
@ -226,7 +226,7 @@ func TestUndelegateSelfDelegation(t *testing.T) {
|
|||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
selfDelegation := types.Delegation{
|
||||
DelegatorAddr: sdk.AccAddress(addrVals[0].Bytes()),
|
||||
|
@ -240,7 +240,7 @@ func TestUndelegateSelfDelegation(t *testing.T) {
|
|||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
|
@ -274,7 +274,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) {
|
|||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
selfDelegation := types.Delegation{
|
||||
DelegatorAddr: sdk.AccAddress(addrVals[0].Bytes()),
|
||||
|
@ -288,7 +288,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) {
|
|||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
|
@ -350,7 +350,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
|||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.Delegation{
|
||||
|
@ -365,7 +365,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
|||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
|
@ -512,7 +512,7 @@ func TestRedelegateSelfDelegation(t *testing.T) {
|
|||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.Delegation{
|
||||
|
@ -528,14 +528,14 @@ func TestRedelegateSelfDelegation(t *testing.T) {
|
|||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(10))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = testingUpdateValidator(keeper, ctx, validator2)
|
||||
validator2 = TestingUpdateValidator(keeper, ctx, validator2)
|
||||
require.Equal(t, sdk.Bonded, validator2.Status)
|
||||
|
||||
// create a second delegation to this validator
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
|
@ -569,7 +569,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
|||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.Delegation{
|
||||
|
@ -584,7 +584,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
|||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
|
@ -599,7 +599,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
|||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = testingUpdateValidator(keeper, ctx, validator2)
|
||||
validator2 = TestingUpdateValidator(keeper, ctx, validator2)
|
||||
|
||||
header := ctx.BlockHeader()
|
||||
blockHeight := int64(10)
|
||||
|
@ -653,7 +653,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
|||
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.Delegation{
|
||||
|
@ -669,7 +669,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
|||
validator.BondIntraTxCounter = 1
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
|
@ -684,7 +684,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
|||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = testingUpdateValidator(keeper, ctx, validator2)
|
||||
validator2 = TestingUpdateValidator(keeper, ctx, validator2)
|
||||
require.Equal(t, sdk.Bonded, validator2.Status)
|
||||
|
||||
ctx = ctx.WithBlockHeight(10)
|
||||
|
|
|
@ -29,7 +29,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) {
|
|||
validator.BondIntraTxCounter = int16(i)
|
||||
pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
keeper.SetValidatorByConsAddr(ctx, validator)
|
||||
}
|
||||
pool = keeper.GetPool(ctx)
|
||||
|
|
|
@ -211,7 +211,8 @@ func ValidatorByPowerIndexExists(ctx sdk.Context, keeper Keeper, power []byte) b
|
|||
return store.Has(power)
|
||||
}
|
||||
|
||||
func testingUpdateValidator(keeper Keeper, ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
// update validator for testing
|
||||
func TestingUpdateValidator(keeper Keeper, ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
pool := keeper.GetPool(ctx)
|
||||
keeper.SetValidator(ctx, validator)
|
||||
keeper.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
|
|
|
@ -84,7 +84,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) {
|
|||
require.Equal(t, sdk.Unbonded, validator.Status)
|
||||
require.Equal(t, int64(100), validator.Tokens.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
testingUpdateValidator(keeper, ctx, validator)
|
||||
TestingUpdateValidator(keeper, ctx, validator)
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool)
|
||||
|
@ -98,7 +98,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) {
|
|||
validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2)))
|
||||
require.Equal(t, int64(50), burned.RoundInt64())
|
||||
keeper.SetPool(ctx, pool) // update the pool
|
||||
testingUpdateValidator(keeper, ctx, validator) // update the validator, possibly kicking it out
|
||||
TestingUpdateValidator(keeper, ctx, validator) // update the validator, possibly kicking it out
|
||||
require.False(t, validatorByPowerIndexExists(keeper, ctx, power))
|
||||
|
||||
pool = keeper.GetPool(ctx)
|
||||
|
@ -135,7 +135,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) {
|
|||
val, pool, _ = val.AddTokensFromDel(pool, sdk.NewInt(int64((i+1)*10)))
|
||||
|
||||
keeper.SetPool(ctx, pool)
|
||||
val = testingUpdateValidator(keeper, ctx, val)
|
||||
val = TestingUpdateValidator(keeper, ctx, val)
|
||||
validators[i] = val
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) {
|
|||
keeper.DeleteValidatorByPowerIndex(ctx, nextCliffVal, pool)
|
||||
nextCliffVal, pool, _ = nextCliffVal.RemoveDelShares(pool, sdk.NewDec(21))
|
||||
keeper.SetPool(ctx, pool)
|
||||
nextCliffVal = testingUpdateValidator(keeper, ctx, nextCliffVal)
|
||||
nextCliffVal = TestingUpdateValidator(keeper, ctx, nextCliffVal)
|
||||
|
||||
expectedValStatus := map[int]sdk.BondStatus{
|
||||
9: sdk.Bonded, 8: sdk.Bonded, 7: sdk.Bonded, 5: sdk.Bonded, 4: sdk.Bonded,
|
||||
|
@ -178,7 +178,7 @@ func TestSlashToZeroPowerRemoved(t *testing.T) {
|
|||
require.Equal(t, int64(100), validator.Tokens.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
keeper.SetValidatorByConsAddr(ctx, validator)
|
||||
validator = testingUpdateValidator(keeper, ctx, validator)
|
||||
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||
require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool)
|
||||
|
||||
// slash the validator by 100%
|
||||
|
@ -223,7 +223,7 @@ func TestValidatorBasics(t *testing.T) {
|
|||
assert.True(sdk.DecEq(t, sdk.ZeroDec(), pool.BondedTokens))
|
||||
|
||||
// set and retrieve a record
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
keeper.SetValidatorByConsAddr(ctx, validators[0])
|
||||
resVal, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
|
@ -250,7 +250,7 @@ func TestValidatorBasics(t *testing.T) {
|
|||
validators[0].Status = sdk.Bonded
|
||||
validators[0].Tokens = sdk.NewDec(10)
|
||||
validators[0].DelegatorShares = sdk.NewDec(10)
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
resVal, found = keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
assert.True(ValEq(t, validators[0], resVal))
|
||||
|
@ -260,8 +260,8 @@ func TestValidatorBasics(t *testing.T) {
|
|||
assert.True(ValEq(t, validators[0], resVals[0]))
|
||||
|
||||
// add other validators
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[2] = testingUpdateValidator(keeper, ctx, validators[2])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[2] = TestingUpdateValidator(keeper, ctx, validators[2])
|
||||
resVal, found = keeper.GetValidator(ctx, addrVals[1])
|
||||
require.True(t, found)
|
||||
assert.True(ValEq(t, validators[1], resVal))
|
||||
|
@ -294,7 +294,7 @@ func GetValidatorSortingUnmixed(t *testing.T) {
|
|||
validators[i].Status = sdk.Bonded
|
||||
validators[i].Tokens = sdk.NewDec(amt)
|
||||
validators[i].DelegatorShares = sdk.NewDec(amt)
|
||||
testingUpdateValidator(keeper, ctx, validators[i])
|
||||
TestingUpdateValidator(keeper, ctx, validators[i])
|
||||
}
|
||||
|
||||
// first make sure everything made it in to the gotValidator group
|
||||
|
@ -313,14 +313,14 @@ func GetValidatorSortingUnmixed(t *testing.T) {
|
|||
|
||||
// test a basic increase in voting power
|
||||
validators[3].Tokens = sdk.NewDec(500)
|
||||
testingUpdateValidator(keeper, ctx, validators[3])
|
||||
TestingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n)
|
||||
assert.True(ValEq(t, validators[3], resValidators[0]))
|
||||
|
||||
// test a decrease in voting power
|
||||
validators[3].Tokens = sdk.NewDec(300)
|
||||
testingUpdateValidator(keeper, ctx, validators[3])
|
||||
TestingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n)
|
||||
assert.True(ValEq(t, validators[3], resValidators[0]))
|
||||
|
@ -329,7 +329,7 @@ func GetValidatorSortingUnmixed(t *testing.T) {
|
|||
// test equal voting power, different age
|
||||
validators[3].Tokens = sdk.NewDec(200)
|
||||
ctx = ctx.WithBlockHeight(10)
|
||||
testingUpdateValidator(keeper, ctx, validators[3])
|
||||
TestingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n)
|
||||
assert.True(ValEq(t, validators[3], resValidators[0]))
|
||||
|
@ -339,7 +339,7 @@ func GetValidatorSortingUnmixed(t *testing.T) {
|
|||
|
||||
// no change in voting power - no change in sort
|
||||
ctx = ctx.WithBlockHeight(20)
|
||||
testingUpdateValidator(keeper, ctx, validators[4])
|
||||
TestingUpdateValidator(keeper, ctx, validators[4])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n)
|
||||
assert.True(ValEq(t, validators[3], resValidators[0]))
|
||||
|
@ -348,11 +348,11 @@ func GetValidatorSortingUnmixed(t *testing.T) {
|
|||
// change in voting power of both validators, both still in v-set, no age change
|
||||
validators[3].Tokens = sdk.NewDec(300)
|
||||
validators[4].Tokens = sdk.NewDec(300)
|
||||
testingUpdateValidator(keeper, ctx, validators[3])
|
||||
TestingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n)
|
||||
ctx = ctx.WithBlockHeight(30)
|
||||
testingUpdateValidator(keeper, ctx, validators[4])
|
||||
TestingUpdateValidator(keeper, ctx, validators[4])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, len(resValidators), n, "%v", resValidators)
|
||||
assert.True(ValEq(t, validators[3], resValidators[0]))
|
||||
|
@ -390,7 +390,7 @@ func GetValidatorSortingMixed(t *testing.T) {
|
|||
validators[4].Tokens = sdk.NewDec(amts[4])
|
||||
|
||||
for i := range amts {
|
||||
testingUpdateValidator(keeper, ctx, validators[i])
|
||||
TestingUpdateValidator(keeper, ctx, validators[i])
|
||||
}
|
||||
val0, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[0]))
|
||||
require.True(t, found)
|
||||
|
@ -444,7 +444,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) {
|
|||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
validators[i].BondIntraTxCounter = int16(i)
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[i] = testingUpdateValidator(keeper, ctx, validators[i])
|
||||
validators[i] = TestingUpdateValidator(keeper, ctx, validators[i])
|
||||
}
|
||||
|
||||
for i := range amts {
|
||||
|
@ -460,7 +460,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) {
|
|||
keeper.DeleteValidatorByPowerIndex(ctx, validators[0], pool)
|
||||
validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(500))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, nMax, uint16(len(resValidators)))
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
|
@ -478,7 +478,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) {
|
|||
keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool)
|
||||
validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(1))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[3] = testingUpdateValidator(keeper, ctx, validators[3])
|
||||
validators[3] = TestingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, nMax, uint16(len(resValidators)))
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
|
@ -488,7 +488,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) {
|
|||
keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool)
|
||||
validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[3] = testingUpdateValidator(keeper, ctx, validators[3])
|
||||
validators[3] = TestingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, nMax, uint16(len(resValidators)))
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
|
@ -498,7 +498,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) {
|
|||
keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool)
|
||||
validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(200))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[3] = testingUpdateValidator(keeper, ctx, validators[3])
|
||||
validators[3] = TestingUpdateValidator(keeper, ctx, validators[3])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, nMax, uint16(len(resValidators)))
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
|
@ -531,13 +531,13 @@ func TestValidatorBondHeight(t *testing.T) {
|
|||
validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(100))
|
||||
keeper.SetPool(ctx, pool)
|
||||
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
|
||||
////////////////////////////////////////
|
||||
// If two validators both increase to the same voting power in the same block,
|
||||
// the one with the first transaction should become bonded
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[2] = testingUpdateValidator(keeper, ctx, validators[2])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[2] = TestingUpdateValidator(keeper, ctx, validators[2])
|
||||
|
||||
pool = keeper.GetPool(ctx)
|
||||
|
||||
|
@ -551,10 +551,10 @@ func TestValidatorBondHeight(t *testing.T) {
|
|||
validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(50))
|
||||
validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(50))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[2] = testingUpdateValidator(keeper, ctx, validators[2])
|
||||
validators[2] = TestingUpdateValidator(keeper, ctx, validators[2])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
require.Equal(t, params.MaxValidators, uint16(len(resValidators)))
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
assert.True(ValEq(t, validators[2], resValidators[1]))
|
||||
}
|
||||
|
@ -575,7 +575,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) {
|
|||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
validators[i].BondIntraTxCounter = int16(i)
|
||||
keeper.SetPool(ctx, pool)
|
||||
testingUpdateValidator(keeper, ctx, validators[i])
|
||||
TestingUpdateValidator(keeper, ctx, validators[i])
|
||||
}
|
||||
for i := range amts {
|
||||
var found bool
|
||||
|
@ -596,7 +596,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) {
|
|||
pool := keeper.GetPool(ctx)
|
||||
validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(600))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
resValidators = keeper.GetBondedValidatorsByPower(ctx)
|
||||
assert.Equal(t, max, len(resValidators))
|
||||
assert.True(ValEq(t, validators[0], resValidators[0]))
|
||||
|
@ -647,14 +647,14 @@ func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) {
|
|||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// test identical,
|
||||
// tendermintUpdate set: {} -> {}
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
}
|
||||
|
||||
|
@ -669,15 +669,15 @@ func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) {
|
|||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// test single value change
|
||||
// tendermintUpdate set: {} -> {c1'}
|
||||
validators[0].Status = sdk.Bonded
|
||||
validators[0].Tokens = sdk.NewDec(600)
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
|
@ -696,8 +696,8 @@ func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) {
|
|||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// test multiple value change
|
||||
|
@ -706,8 +706,8 @@ func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) {
|
|||
validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(190))
|
||||
validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(80))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates))
|
||||
|
@ -726,8 +726,8 @@ func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) {
|
|||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// test validtor added at the beginning
|
||||
|
@ -775,13 +775,13 @@ func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) {
|
|||
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// test validator added at the end but not inserted in the valset
|
||||
// tendermintUpdate set: {} -> {}
|
||||
testingUpdateValidator(keeper, ctx, validators[2])
|
||||
TestingUpdateValidator(keeper, ctx, validators[2])
|
||||
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
require.Equal(t, 0, len(updates))
|
||||
|
||||
|
@ -813,8 +813,8 @@ func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) {
|
|||
validators[i].BondIntraTxCounter = int16(i)
|
||||
keeper.SetPool(ctx, pool)
|
||||
}
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx)))
|
||||
|
||||
// check initial power
|
||||
|
@ -827,8 +827,8 @@ func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) {
|
|||
validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewDec(20))
|
||||
validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewDec(30))
|
||||
keeper.SetPool(ctx, pool)
|
||||
validators[0] = testingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = testingUpdateValidator(keeper, ctx, validators[1])
|
||||
validators[0] = TestingUpdateValidator(keeper, ctx, validators[0])
|
||||
validators[1] = TestingUpdateValidator(keeper, ctx, validators[1])
|
||||
|
||||
// power has changed
|
||||
require.Equal(t, sdk.NewDec(80).RoundInt64(), validators[0].GetPower().RoundInt64())
|
||||
|
|
|
@ -16,7 +16,9 @@ import (
|
|||
// SimulateMsgCreateValidator
|
||||
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accs []simulation.Account, event func(string)) (
|
||||
action string, fOp []simulation.FutureOperation, err error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
description := stake.Description{
|
||||
|
@ -71,7 +73,9 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
|
|||
// SimulateMsgEditValidator
|
||||
func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accs []simulation.Account, event func(string)) (
|
||||
action string, fOp []simulation.FutureOperation, err error) {
|
||||
|
||||
description := stake.Description{
|
||||
Moniker: simulation.RandStringOfLength(r, 10),
|
||||
|
@ -109,7 +113,9 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
|||
// SimulateMsgDelegate
|
||||
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accs []simulation.Account, event func(string)) (
|
||||
action string, fOp []simulation.FutureOperation, err error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
validatorAcc := simulation.RandomAcc(r, accs)
|
||||
|
@ -145,7 +151,9 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
|
|||
// SimulateMsgBeginUnbonding
|
||||
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accs []simulation.Account, event func(string)) (
|
||||
action string, fOp []simulation.FutureOperation, err error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
validatorAcc := simulation.RandomAcc(r, accs)
|
||||
|
@ -181,7 +189,9 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
|
|||
// SimulateMsgBeginRedelegate
|
||||
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
accs []simulation.Account, event func(string)) (
|
||||
action string, fOp []simulation.FutureOperation, err error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
sourceValidatorAcc := simulation.RandomAcc(r, accs)
|
||||
|
|
|
@ -56,6 +56,7 @@ var (
|
|||
GetREDsFromValSrcIndexKey = keeper.GetREDsFromValSrcIndexKey
|
||||
GetREDsToValDstIndexKey = keeper.GetREDsToValDstIndexKey
|
||||
GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey
|
||||
TestingUpdateValidator = keeper.TestingUpdateValidator
|
||||
|
||||
DefaultParamspace = keeper.DefaultParamspace
|
||||
KeyInflationRateChange = types.KeyInflationRateChange
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
package stake
|
||||
|
||||
import (
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
var (
|
||||
priv1 = ed25519.GenPrivKey()
|
||||
addr1 = sdk.AccAddress(priv1.PubKey().Address())
|
||||
priv2 = ed25519.GenPrivKey()
|
||||
addr2 = sdk.AccAddress(priv2.PubKey().Address())
|
||||
addr3 = sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
|
||||
priv4 = ed25519.GenPrivKey()
|
||||
addr4 = sdk.AccAddress(priv4.PubKey().Address())
|
||||
coins = sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(10))}
|
||||
fee = auth.NewStdFee(
|
||||
100000,
|
||||
sdk.Coins{sdk.NewCoin("foocoin", sdk.NewInt(0))}...,
|
||||
)
|
||||
|
||||
commissionMsg = NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
|
||||
)
|
||||
|
||||
func NewTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt int64) MsgCreateValidator {
|
||||
return types.NewMsgCreateValidator(
|
||||
address, pubKey, sdk.NewCoin("steak", sdk.NewInt(amt)), Description{}, commissionMsg,
|
||||
)
|
||||
}
|
||||
|
||||
func NewTestMsgCreateValidatorWithCommission(address sdk.ValAddress, pubKey crypto.PubKey,
|
||||
amt int64, commissionRate sdk.Dec) MsgCreateValidator {
|
||||
|
||||
commission := NewCommissionMsg(commissionRate, sdk.OneDec(), sdk.ZeroDec())
|
||||
|
||||
return types.NewMsgCreateValidator(
|
||||
address, pubKey, sdk.NewCoin("steak", sdk.NewInt(amt)), Description{}, commission,
|
||||
)
|
||||
}
|
||||
|
||||
func NewTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt int64) MsgDelegate {
|
||||
return MsgDelegate{
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
Delegation: sdk.NewCoin("steak", sdk.NewInt(amt)),
|
||||
}
|
||||
}
|
||||
|
||||
func NewTestMsgCreateValidatorOnBehalfOf(delAddr sdk.AccAddress, valAddr sdk.ValAddress, valPubKey crypto.PubKey, amt int64) MsgCreateValidator {
|
||||
return MsgCreateValidator{
|
||||
Description: Description{},
|
||||
Commission: commissionMsg,
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
PubKey: valPubKey,
|
||||
Delegation: sdk.NewCoin("steak", sdk.NewInt(amt)),
|
||||
}
|
||||
}
|
|
@ -164,6 +164,11 @@ func ErrTransitiveRedelegation(codespace sdk.CodespaceType) sdk.Error {
|
|||
"redelegation to this validator already in progress, first redelegation to this validator must complete before next redelegation")
|
||||
}
|
||||
|
||||
func ErrConflictingRedelegation(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation,
|
||||
"conflicting redelegation from this source validator to this dest validator already exists, you must wait for it to finish")
|
||||
}
|
||||
|
||||
func ErrBothShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidInput, "both shares amount and shares percent provided")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue