Merge PR #2236: Distr-PR-5 Implement Distribution

This commit is contained in:
Christopher Goes 2018-10-16 08:18:21 +02:00 committed by GitHub
commit 2803830c7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 2133 additions and 279 deletions

View File

@ -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)
}

View File

@ -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(),
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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

View File

@ -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),
)...)

View File

@ -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)
```

View File

@ -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

View File

@ -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

View File

@ -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
}
```

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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
}

View File

@ -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) {}

View File

@ -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{})
}

View File

@ -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))
}

76
x/distribution/alias.go Normal file
View File

@ -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
)

View File

@ -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
}

38
x/distribution/genesis.go Normal file
View File

@ -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)
}

84
x/distribution/handler.go Normal file
View File

@ -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,
}
}

View File

@ -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)
}

View File

@ -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))
}

View File

@ -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
}

View File

@ -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))
}

View File

@ -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
}

View File

@ -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) {}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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()...)
}

View File

@ -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{}
}

View File

@ -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)
}
}

View File

@ -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))
}

View File

@ -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
)

View File

@ -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)

View File

@ -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

View File

@ -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,
}
}

View File

@ -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

View File

@ -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,

View File

@ -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)

View File

@ -33,7 +33,7 @@ func TestHandleDoubleSign(t *testing.T) {
sk = sk.WithHooks(keeper.Hooks())
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)
@ -75,7 +75,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)
@ -142,7 +142,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)
@ -294,7 +294,7 @@ func TestHandleNewValidator(t *testing.T) {
ctx, ck, sk, _, keeper := createTestInput(t, keeperTestParams())
addr, val, amt := addrs[0], pks[0], int64(100)
sh := stake.NewHandler(sk)
got := sh(ctx, newTestMsgCreateValidator(addr, val, sdk.NewInt(amt)))
got := sh(ctx, NewTestMsgCreateValidator(addr, val, sdk.NewInt(amt)))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
@ -332,7 +332,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)

View File

@ -111,7 +111,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{},

View File

@ -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)

View File

@ -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)

View File

@ -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.

View File

@ -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)

View File

@ -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)

View File

@ -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")
@ -918,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
@ -962,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")

View File

@ -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
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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())

View File

@ -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)

View File

@ -56,6 +56,7 @@ var (
GetREDsFromValSrcIndexKey = keeper.GetREDsFromValSrcIndexKey
GetREDsToValDstIndexKey = keeper.GetREDsToValDstIndexKey
GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey
TestingUpdateValidator = keeper.TestingUpdateValidator
DefaultParamspace = keeper.DefaultParamspace
KeyInflationRateChange = types.KeyInflationRateChange

62
x/stake/test_common.go Normal file
View File

@ -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)),
}
}