From 675dc5df159a8e08d1b8221c514220672df1401b Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 10 May 2018 19:02:35 -0400 Subject: [PATCH] staking refactor compiling --- CHANGELOG.md | 9 +- cmd/gaia/app/app.go | 3 +- cmd/gaia/app/genesis.go | 6 +- cmd/gaia/cmd/gaiacli/main.go | 4 +- types/stake.go | 18 ++-- x/fee_distribution/keeper.go | 91 ++++++++++++++++ x/fee_distribution/movement.go | 100 +++++++++--------- x/fee_distribution/types.go | 184 ++++++++++++++++----------------- x/stake/keeper.go | 98 +++--------------- x/stake/keeper_keys.go | 6 +- x/stake/keeper_test.go | 2 +- x/stake/pool.go | 8 +- x/stake/types.go | 71 +++++++------ 13 files changed, 316 insertions(+), 284 deletions(-) create mode 100644 x/fee_distribution/keeper.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 07167e5a4..5ee9da049 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,13 @@ BREAKING CHANGES * Queries against the store must be prefixed with the path "/store" * RecentValidator store now take pubkey instead of address, is sorted like Tendermint by pk's address -* RecentValidator store now take pubkey instead of address, is sorted like Tendermint by pk's address * `gaiacli query candidate` takes and argument instead of using the `--address-candidate` flag +* Staking refactor + * store names more understandable + * removed temporary ToKick store + * removed distinction between candidates and validators + * everything is now a validator + * only validators with a status == bonded are actively validating/receiving rewards FEATURES @@ -17,6 +22,8 @@ FEATURES * Transactions which run out of gas stop execution and revert state changes * A "simulate" query has been added to determine how much gas a transaction will need * Modules can include their own gas costs for execution of particular message types +* Seperation of fee distribution to a new module +* Creation of a validator/delegation generics in `/types` ## 0.17.0 (May 15, 2018) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 6f49b95a0..42869c955 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" + feed "github.com/cosmos/cosmos-sdk/x/fee_distribution" "github.com/cosmos/cosmos-sdk/x/ibc" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -81,7 +82,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { app.SetInitChainer(app.initChainer) app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper)) app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake) - app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.stakeKeeper.FeeHandler)) + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, feed.BurnFeeHandler)) err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 834c86dab..e96fe2fba 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -160,9 +160,9 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso // add the validator if len(genTx.Name) > 0 { desc := stake.NewDescription(genTx.Name, "", "", "") - candidate := stake.NewCandidate(genTx.Address, genTx.PubKey, desc) - candidate.BondedShares = sdk.NewRat(freeFermionVal) - stakeData.Candidates = append(stakeData.Candidates, candidate) + validator := stake.NewValidator(genTx.Address, genTx.PubKey, desc) + validator.BondedShares = sdk.NewRat(freeFermionVal) + stakeData.Validators = append(stakeData.Validators, validator) // pool logic stakeData.Pool.TotalSupply += freeFermionVal diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index 76314f036..2f36201b2 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -45,8 +45,8 @@ func main() { rootCmd.AddCommand( client.GetCommands( authcmd.GetAccountCmd("acc", cdc, authcmd.GetAccountDecoder(cdc)), - stakecmd.GetCmdQueryCandidate("stake", cdc), - stakecmd.GetCmdQueryCandidates("stake", cdc), + stakecmd.GetCmdQueryValidator("stake", cdc), + stakecmd.GetCmdQueryValidators("stake", cdc), stakecmd.GetCmdQueryDelegation("stake", cdc), stakecmd.GetCmdQueryDelegations("stake", cdc), )...) diff --git a/types/stake.go b/types/stake.go index e34f9e891..3c9d797b1 100644 --- a/types/stake.go +++ b/types/stake.go @@ -18,11 +18,11 @@ const ( // validator for a delegated proof of stake system type Validator interface { - Status() ValidatorStatus // status of the validator - GetOwner() Address // owner address to receive/return validators coins - GetPubKey() crypto.PubKey // validation pubkey - GetPower() Rat // validation power - GetBondHeight() int64 // height in which the validator became active + GetStatus() ValidatorStatus // status of the validator + GetAddress() Address // owner address to receive/return validators coins + GetPubKey() crypto.PubKey // validation pubkey + GetPower() Rat // validation power + GetBondHeight() int64 // height in which the validator became active } // validator which fulfills abci validator interface for use in Tendermint @@ -35,9 +35,9 @@ func ABCIValidator(v Validator) abci.Validator { // properties for the set of all validators type ValidatorSet interface { - IterateValidatorsBonded(func(index int64, validator Validator)) // execute arbitrary logic for each validator - Validator(Context, Address) Validator // get a particular validator by owner address - TotalPower(Context) Rat // total power of the validator set + IterateValidatorsBonded(Context, func(index int64, validator Validator)) // execute arbitrary logic for each validator + Validator(Context, Address) Validator // get a particular validator by owner address + TotalPower(Context) Rat // total power of the validator set } //_______________________________________________________________________________ @@ -53,5 +53,5 @@ type Delegation interface { type DelegationSet interface { // execute arbitrary logic for each validator which a delegator has a delegation for - IterateDelegators(delegator Address, fn func(index int64, delegation Delegation)) + IterateDelegators(Context, delegator Address, fn func(index int64, delegation Delegation)) } diff --git a/x/fee_distribution/keeper.go b/x/fee_distribution/keeper.go new file mode 100644 index 000000000..145071719 --- /dev/null +++ b/x/fee_distribution/keeper.go @@ -0,0 +1,91 @@ +package stake + +//// keeper of the staking store +//type Keeper struct { +//storeKey sdk.StoreKey +//cdc *wire.Codec +//coinKeeper bank.Keeper + +//// codespace +//codespace sdk.CodespaceType +//} + +//func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.Keeper, codespace sdk.CodespaceType) Keeper { +//keeper := Keeper{ +//storeKey: key, +//cdc: cdc, +//coinKeeper: ck, +//codespace: codespace, +//} +//return keeper +//} + +////_________________________________________________________________________ + +//// cummulative power of the non-absent prevotes +//func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Rat { +//store := ctx.KVStore(k.storeKey) + +//// get absent prevote indexes +//absents := ctx.AbsentValidators() + +//TotalPower := sdk.ZeroRat() +//i := int32(0) +//iterator := store.SubspaceIterator(ValidatorsBondedKey) +//for ; iterator.Valid(); iterator.Next() { + +//skip := false +//for j, absentIndex := range absents { +//if absentIndex > i { +//break +//} + +//// if non-voting validator found, skip adding its power +//if absentIndex == i { +//absents = append(absents[:j], absents[j+1:]...) // won't need again +//skip = true +//break +//} +//} +//if skip { +//continue +//} + +//bz := iterator.Value() +//var validator Validator +//k.cdc.MustUnmarshalBinary(bz, &validator) +//TotalPower = TotalPower.Add(validator.Power) +//i++ +//} +//iterator.Close() +//return TotalPower +//} + +////_______________________________________________________________________ + +//// XXX TODO trim functionality + +//// retrieve all the power changes which occur after a height +//func (k Keeper) GetPowerChangesAfterHeight(ctx sdk.Context, earliestHeight int64) (pcs []PowerChange) { +//store := ctx.KVStore(k.storeKey) + +//iterator := store.SubspaceIterator(PowerChangeKey) //smallest to largest +//for ; iterator.Valid(); iterator.Next() { +//pcBytes := iterator.Value() +//var pc PowerChange +//k.cdc.MustUnmarshalBinary(pcBytes, &pc) +//if pc.Height < earliestHeight { +//break +//} +//pcs = append(pcs, pc) +//} +//iterator.Close() +//return +//} + +//// set a power change +//func (k Keeper) setPowerChange(ctx sdk.Context, pc PowerChange) { +//store := ctx.KVStore(k.storeKey) +//b := k.cdc.MustMarshalBinary(pc) +//store.Set(GetPowerChangeKey(pc.Height), b) +//} diff --git a/x/fee_distribution/movement.go b/x/fee_distribution/movement.go index 02d2c62a1..e2ecf4905 100644 --- a/x/fee_distribution/movement.go +++ b/x/fee_distribution/movement.go @@ -7,66 +7,66 @@ import ( // burn burn burn func BurnFeeHandler(ctx sdk.Context, collectedFees sdk.Coins) {} -// Handle fee distribution to the validators and delegators -func (k Keeper) FeeHandler(ctx sdk.Context, collectedFees sdk.Coins) { - pool := k.GetPool(ctx) - params := k.GetParams(ctx) +//// Handle fee distribution to the validators and delegators +//func (k Keeper) FeeHandler(ctx sdk.Context, collectedFees sdk.Coins) { +//pool := k.GetPool(ctx) +//params := k.GetParams(ctx) - // XXX determine - candidate := NewCandidate(addrs[0], pks[0], Description{}) +//// XXX determine +//candidate := NewCandidate(addrs[0], pks[0], Description{}) - // calculate the proposer reward - precommitPower := k.GetTotalPrecommitVotingPower(ctx) - toProposer := coinsMulRat(collectedFees, (sdk.NewRat(1, 100).Add(sdk.NewRat(4, 100).Mul(precommitPower).Quo(pool.BondedShares)))) - candidate.ProposerRewardPool = candidate.ProposerRewardPool.Plus(toProposer) +//// calculate the proposer reward +//precommitPower := k.GetTotalPrecommitVotingPower(ctx) +//toProposer := coinsMulRat(collectedFees, (sdk.NewRat(1, 100).Add(sdk.NewRat(4, 100).Mul(precommitPower).Quo(pool.BondedShares)))) +//candidate.ProposerRewardPool = candidate.ProposerRewardPool.Plus(toProposer) - toReservePool := coinsMulRat(collectedFees, params.ReservePoolFee) - pool.FeeReservePool = pool.FeeReservePool.Plus(toReservePool) +//toReservePool := coinsMulRat(collectedFees, params.ReservePoolFee) +//pool.FeeReservePool = pool.FeeReservePool.Plus(toReservePool) - distributedReward := (collectedFees.Minus(toProposer)).Minus(toReservePool) - pool.FeePool = pool.FeePool.Plus(distributedReward) - pool.FeeSumReceived = pool.FeeSumReceived.Plus(distributedReward) - pool.FeeRecent = distributedReward +//distributedReward := (collectedFees.Minus(toProposer)).Minus(toReservePool) +//pool.FeePool = pool.FeePool.Plus(distributedReward) +//pool.FeeSumReceived = pool.FeeSumReceived.Plus(distributedReward) +//pool.FeeRecent = distributedReward - // lastly update the FeeRecent term - pool.FeeRecent = collectedFees +//// lastly update the FeeRecent term +//pool.FeeRecent = collectedFees - k.setPool(ctx, pool) -} +//k.setPool(ctx, pool) +//} -func coinsMulRat(coins sdk.Coins, rat sdk.Rat) sdk.Coins { - var res sdk.Coins - for _, coin := range coins { - coinMulAmt := rat.Mul(sdk.NewRat(coin.Amount)).Evaluate() - coinMul := sdk.Coins{{coin.Denom, coinMulAmt}} - res = res.Plus(coinMul) - } - return res -} +//func coinsMulRat(coins sdk.Coins, rat sdk.Rat) sdk.Coins { +//var res sdk.Coins +//for _, coin := range coins { +//coinMulAmt := rat.Mul(sdk.NewRat(coin.Amount)).Evaluate() +//coinMul := sdk.Coins{{coin.Denom, coinMulAmt}} +//res = res.Plus(coinMul) +//} +//return res +//} -//____________________________________________________________________________- +////____________________________________________________________________________- -// calculate adjustment changes for a candidate at a height -func CalculateAdjustmentChange(candidate Candidate, pool Pool, denoms []string, height int64) (Candidate, Pool) { +//// calculate adjustment changes for a candidate at a height +//func CalculateAdjustmentChange(candidate Candidate, pool Pool, denoms []string, height int64) (Candidate, Pool) { - heightRat := sdk.NewRat(height) - lastHeightRat := sdk.NewRat(height - 1) - candidateFeeCount := candidate.BondedShares.Mul(heightRat) - poolFeeCount := pool.BondedShares.Mul(heightRat) +//heightRat := sdk.NewRat(height) +//lastHeightRat := sdk.NewRat(height - 1) +//candidateFeeCount := candidate.BondedShares.Mul(heightRat) +//poolFeeCount := pool.BondedShares.Mul(heightRat) - for i, denom := range denoms { - poolFeeSumReceived := sdk.NewRat(pool.FeeSumReceived.AmountOf(denom)) - poolFeeRecent := sdk.NewRat(pool.FeeRecent.AmountOf(denom)) - // calculate simple and projected pools - simplePool := candidateFeeCount.Quo(poolFeeCount).Mul(poolFeeSumReceived) - calc1 := candidate.PrevBondedShares.Mul(lastHeightRat).Quo(pool.PrevBondedShares.Mul(lastHeightRat)).Mul(poolFeeRecent) - calc2 := candidate.BondedShares.Quo(pool.BondedShares).Mul(poolFeeRecent) - projectedPool := calc1.Add(calc2) +//for i, denom := range denoms { +//poolFeeSumReceived := sdk.NewRat(pool.FeeSumReceived.AmountOf(denom)) +//poolFeeRecent := sdk.NewRat(pool.FeeRecent.AmountOf(denom)) +//// calculate simple and projected pools +//simplePool := candidateFeeCount.Quo(poolFeeCount).Mul(poolFeeSumReceived) +//calc1 := candidate.PrevBondedShares.Mul(lastHeightRat).Quo(pool.PrevBondedShares.Mul(lastHeightRat)).Mul(poolFeeRecent) +//calc2 := candidate.BondedShares.Quo(pool.BondedShares).Mul(poolFeeRecent) +//projectedPool := calc1.Add(calc2) - AdjustmentChange := simplePool.Sub(projectedPool) - candidate.FeeAdjustments[i] = candidate.FeeAdjustments[i].Add(AdjustmentChange) - pool.FeeAdjustments[i] = pool.FeeAdjustments[i].Add(AdjustmentChange) - } +//AdjustmentChange := simplePool.Sub(projectedPool) +//candidate.FeeAdjustments[i] = candidate.FeeAdjustments[i].Add(AdjustmentChange) +//pool.FeeAdjustments[i] = pool.FeeAdjustments[i].Add(AdjustmentChange) +//} - return candidate, pool -} +//return candidate, pool +//} diff --git a/x/fee_distribution/types.go b/x/fee_distribution/types.go index 1303e9a62..f9d4f905f 100644 --- a/x/fee_distribution/types.go +++ b/x/fee_distribution/types.go @@ -1,113 +1,107 @@ package stake -import ( - "encoding/binary" +//// GenesisState - all staking state that must be provided at genesis +//type GenesisState struct { +//Pool Pool `json:"pool"` +//Params Params `json:"params"` +//} - sdk "github.com/cosmos/cosmos-sdk/types" -) +//func NewGenesisState(pool Pool, params Params, candidates []Candidate, bonds []Delegation) GenesisState { +//return GenesisState{ +//Pool: pool, +//Params: params, +//} +//} -// GenesisState - all staking state that must be provided at genesis -type GenesisState struct { - Pool Pool `json:"pool"` - Params Params `json:"params"` -} +//// get raw genesis raw message for testing +//func DefaultGenesisState() GenesisState { +//return GenesisState{ +//Pool: initialPool(), +//Params: defaultParams(), +//} +//} -func NewGenesisState(pool Pool, params Params, candidates []Candidate, bonds []Delegation) GenesisState { - return GenesisState{ - Pool: pool, - Params: params, - } -} +//// fee information for a validator +//type Validator struct { +//Adjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms +//PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools +//} -// get raw genesis raw message for testing -func DefaultGenesisState() GenesisState { - return GenesisState{ - Pool: initialPool(), - Params: defaultParams(), - } -} +////_________________________________________________________________________ -// fee information for a validator -type Validator struct { - Adjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms - PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools -} +//// Params defines the high level settings for staking +//type Params struct { +//FeeDenoms []string `json:"fee_denoms"` // accepted fee denoms +//ReservePoolFee sdk.Rat `json:"reserve_pool_fee"` // percent of fees which go to reserve pool +//} -//_________________________________________________________________________ +//func (p Params) equal(p2 Params) bool { +//return p.BondDenom == p2.BondDenom && +//p.ReservePoolFee.Equal(p2.ReservePoolFee) +//} -// Params defines the high level settings for staking -type Params struct { - FeeDenoms []string `json:"fee_denoms"` // accepted fee denoms - ReservePoolFee sdk.Rat `json:"reserve_pool_fee"` // percent of fees which go to reserve pool -} +//func defaultParams() Params { +//return Params{ +//FeeDenoms: []string{"steak"}, +//ReservePoolFee: sdk.NewRat(5, 100), +//} +//} -func (p Params) equal(p2 Params) bool { - return p.BondDenom == p2.BondDenom && - p.ReservePoolFee.Equal(p2.ReservePoolFee) -} +////_________________________________________________________________________ -func defaultParams() Params { - return Params{ - FeeDenoms: []string{"steak"}, - ReservePoolFee: sdk.NewRat(5, 100), - } -} +//// Pool - dynamic parameters of the current state +//type Pool struct { +//FeeReservePool sdk.Coins `json:"fee_reserve_pool"` // XXX reserve pool of collected fees for use by governance +//FeePool sdk.Coins `json:"fee_pool"` // XXX fee pool for all the fee shares which have already been distributed +//FeeSumReceived sdk.Coins `json:"fee_sum_received"` // XXX sum of all fees received, post reserve pool `json:"fee_sum_received"` +//FeeRecent sdk.Coins `json:"fee_recent"` // XXX most recent fee collected +//FeeAdjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms +//PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // XXX last recorded bonded shares +//} -//_________________________________________________________________________ +//func (p Pool) equal(p2 Pool) bool { +//return p.FeeReservePool.IsEqual(p2.FeeReservePool) && +//p.FeePool.IsEqual(p2.FeePool) && +//p.FeeSumReceived.IsEqual(p2.FeeSumReceived) && +//p.FeeRecent.IsEqual(p2.FeeRecent) && +//sdk.RatsEqual(p.FeeAdjustments, p2.FeeAdjustments) && +//p.PrevBondedShares.Equal(p2.PrevBondedShares) +//} -// Pool - dynamic parameters of the current state -type Pool struct { - FeeReservePool sdk.Coins `json:"fee_reserve_pool"` // XXX reserve pool of collected fees for use by governance - FeePool sdk.Coins `json:"fee_pool"` // XXX fee pool for all the fee shares which have already been distributed - FeeSumReceived sdk.Coins `json:"fee_sum_received"` // XXX sum of all fees received, post reserve pool `json:"fee_sum_received"` - FeeRecent sdk.Coins `json:"fee_recent"` // XXX most recent fee collected - FeeAdjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms - PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // XXX last recorded bonded shares -} +//// initial pool for testing +//func initialPool() Pool { +//return Pool{ +//FeeReservePool: sdk.Coins(nil), +//FeePool: sdk.Coins(nil), +//FeeSumReceived: sdk.Coins(nil), +//FeeRecent: sdk.Coins(nil), +//FeeAdjustments: []sdk.Rat{sdk.ZeroRat()}, +//PrevBondedShares: sdk.ZeroRat(), +//} +//} -func (p Pool) equal(p2 Pool) bool { - return p.FeeReservePool.IsEqual(p2.FeeReservePool) && - p.FeePool.IsEqual(p2.FeePool) && - p.FeeSumReceived.IsEqual(p2.FeeSumReceived) && - p.FeeRecent.IsEqual(p2.FeeRecent) && - sdk.RatsEqual(p.FeeAdjustments, p2.FeeAdjustments) && - p.PrevBondedShares.Equal(p2.PrevBondedShares) -} +////_________________________________________________________________________ -// initial pool for testing -func initialPool() Pool { - return Pool{ - FeeReservePool: sdk.Coins(nil), - FeePool: sdk.Coins(nil), - FeeSumReceived: sdk.Coins(nil), - FeeRecent: sdk.Coins(nil), - FeeAdjustments: []sdk.Rat{sdk.ZeroRat()}, - PrevBondedShares: sdk.ZeroRat(), - } -} +//// Used in calculation of fee shares, added to a queue for each block where a power change occures +//type PowerChange struct { +//Height int64 `json:"height"` // block height at change +//Power sdk.Rat `json:"power"` // total power at change +//PrevPower sdk.Rat `json:"prev_power"` // total power at previous height-1 +//FeesIn sdk.Coins `json:"fees_in"` // fees in at block height +//PrevFeePool sdk.Coins `json:"prev_fee_pool"` // total fees in at previous block height +//} -//_________________________________________________________________________ +////_________________________________________________________________________ +//// KEY MANAGEMENT -// Used in calculation of fee shares, added to a queue for each block where a power change occures -type PowerChange struct { - Height int64 `json:"height"` // block height at change - Power sdk.Rat `json:"power"` // total power at change - PrevPower sdk.Rat `json:"prev_power"` // total power at previous height-1 - FeesIn sdk.Coins `json:"fees_in"` // fees in at block height - PrevFeePool sdk.Coins `json:"prev_fee_pool"` // total fees in at previous block height -} +//var ( +//// Keys for store prefixes +//PowerChangeKey = []byte{0x09} // prefix for power change object +//) -//_________________________________________________________________________ -// KEY MANAGEMENT - -var ( - // Keys for store prefixes - PowerChangeKey = []byte{0x09} // prefix for power change object -) - -// get the key for the accumulated update validators -func GetPowerChangeKey(height int64) []byte { - heightBytes := make([]byte, binary.MaxVarintLen64) - binary.BigEndian.PutUint64(heightBytes, ^uint64(height)) // invert height (older validators first) - return append(PowerChangeKey, heightBytes...) -} +//// get the key for the accumulated update validators +//func GetPowerChangeKey(height int64) []byte { +//heightBytes := make([]byte, binary.MaxVarintLen64) +//binary.BigEndian.PutUint64(heightBytes, ^uint64(height)) // invert height (older validators first) +//return append(PowerChangeKey, heightBytes...) +//} diff --git a/x/stake/keeper.go b/x/stake/keeper.go index ad97b3764..40b209ae7 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -3,7 +3,6 @@ package stake import ( "bytes" - "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/bank" @@ -77,8 +76,8 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) { // if found, copy the old block height and counter if oldFound { - validator.ValidatorBondHeight = oldValidator.ValidatorBondHeight - validator.ValidatorBondCounter = oldValidator.ValidatorBondCounter + validator.BondHeight = oldValidator.BondHeight + validator.BondIntraTxCounter = oldValidator.BondIntraTxCounter } // marshal the validator record and add to the state @@ -93,9 +92,9 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) { // if this validator wasn't just bonded then update the height and counter if oldValidator.Status != sdk.Bonded { - validator.ValidatorBondHeight = ctx.BlockHeight() + validator.BondHeight = ctx.BlockHeight() counter := k.getIntraTxCounter(ctx) - validator.ValidatorBondCounter = counter + validator.BondIntraTxCounter = counter k.setIntraTxCounter(ctx, counter+1) } @@ -205,7 +204,7 @@ func (k Keeper) GetValidatorsBondedByPower(ctx sdk.Context) []Validator { func (k Keeper) addNewValidatorOrNot(ctx sdk.Context, store sdk.KVStore, address sdk.Address) { // clear the current validators store, add to the ToKickOut temp store - toKickOut := make(map[[]byte][]byte) // map[key]value + toKickOut := make(map[string][]byte) // map[key]value iterator := store.SubspaceIterator(ValidatorsBondedKey) for ; iterator.Valid(); iterator.Next() { @@ -216,7 +215,7 @@ func (k Keeper) addNewValidatorOrNot(ctx sdk.Context, store sdk.KVStore, address addr := validator.Address // iterator.Value is the validator object - toKickOut[addr] = iterator.Value() + toKickOut[string(addr)] = iterator.Value() store.Delete(iterator.Key()) } iterator.Close() @@ -235,7 +234,7 @@ func (k Keeper) addNewValidatorOrNot(ctx sdk.Context, store sdk.KVStore, address k.cdc.MustUnmarshalBinary(bz, &validator) // remove from ToKickOut group - toKickOut[validator.Address] = nil + toKickOut[string(validator.Address)] = nil // also add to the current validators group store.Set(GetValidatorsBondedBondedKey(validator.PubKey), bz) @@ -251,7 +250,7 @@ func (k Keeper) addNewValidatorOrNot(ctx sdk.Context, store sdk.KVStore, address // add any kicked out validators to the accumulated changes for tendermint for key, value := range toKickOut { - addr := AddrFromKey(key) + addr := AddrFromKey([]byte(key)) var validator Validator k.cdc.MustUnmarshalBinary(value, &validator) @@ -260,45 +259,6 @@ func (k Keeper) addNewValidatorOrNot(ctx sdk.Context, store sdk.KVStore, address } } -// cummulative power of the non-absent prevotes -//func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Rat { -//store := ctx.KVStore(k.storeKey) - -//// get absent prevote indexes -//absents := ctx.AbsentValidators() - -//TotalPower := sdk.ZeroRat() -//i := int32(0) -//iterator := store.SubspaceIterator(ValidatorsBondedKey) -//for ; iterator.Valid(); iterator.Next() { - -//skip := false -//for j, absentIndex := range absents { -//if absentIndex > i { -//break -//} - -//// if non-voting validator found, skip adding its power -//if absentIndex == i { -//absents = append(absents[:j], absents[j+1:]...) // won't need again -//skip = true -//break -//} -//} -//if skip { -//continue -//} - -//bz := iterator.Value() -//var validator Validator -//k.cdc.MustUnmarshalBinary(bz, &validator) -//TotalPower = TotalPower.Add(validator.Power) -//i++ -//} -//iterator.Close() -//return TotalPower -//} - //_________________________________________________________________________ // Accumulated updates to the active/bonded validator set for tendermint @@ -401,35 +361,6 @@ func (k Keeper) removeDelegation(ctx sdk.Context, bond Delegation) { //_______________________________________________________________________ -// XXX TODO trim functionality - -// retrieve all the power changes which occur after a height -func (k Keeper) GetPowerChangesAfterHeight(ctx sdk.Context, earliestHeight int64) (pcs []PowerChange) { - store := ctx.KVStore(k.storeKey) - - iterator := store.SubspaceIterator(PowerChangeKey) //smallest to largest - for ; iterator.Valid(); iterator.Next() { - pcBytes := iterator.Value() - var pc PowerChange - k.cdc.MustUnmarshalBinary(pcBytes, &pc) - if pc.Height < earliestHeight { - break - } - pcs = append(pcs, pc) - } - iterator.Close() - return -} - -// set a power change -func (k Keeper) setPowerChange(ctx sdk.Context, pc PowerChange) { - store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinary(pc) - store.Set(GetPowerChangeKey(pc.Height), b) -} - -//_______________________________________________________________________ - // load/save the global staking params func (k Keeper) GetParams(ctx sdk.Context) (params Params) { // check if cached before anything @@ -483,10 +414,10 @@ func (k Keeper) setPool(ctx sdk.Context, p Pool) { var _ sdk.ValidatorSet = Keeper{} // iterate through the active validator set and perform the provided function -func (k Keeper) IterateValidatorsBonded(fn func(index int64, validator sdk.Validator)) { +func (k Keeper) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, validator sdk.Validator)) { store := ctx.KVStore(k.storeKey) iterator := store.SubspaceIterator(ValidatorsBondedKey) - i := 0 + i := int64(0) for ; iterator.Valid(); iterator.Next() { bz := iterator.Value() var validator Validator @@ -528,15 +459,16 @@ func (k Keeper) Delegation(ctx sdk.Context, addrDel sdk.Address, addrVal sdk.Add } // iterate through the active validator set and perform the provided function -func (k Keeper) IterateDelegators(delAddr sdk.Address, fn func(index int64, delegator sdk.Delegator)) { +func (k Keeper) IterateDelegators(ctx sdk.Context, delAddr sdk.Address, fn func(index int64, delegation sdk.Delegation)) { + store := ctx.KVStore(k.storeKey) key := GetDelegationsKey(delAddr, k.cdc) - iterator := store.SubspaceIterator(ValidatorsBondedKey) - i := 0 + iterator := store.SubspaceIterator(key) + i := int64(0) for ; iterator.Valid(); iterator.Next() { bz := iterator.Value() var delegation Delegation k.cdc.MustUnmarshalBinary(bz, &delegation) - fn(i, delegator) // XXX is this safe will the fields be able to get written to? + fn(i, delegation) // XXX is this safe will the fields be able to get written to? i++ } iterator.Close() diff --git a/x/stake/keeper_keys.go b/x/stake/keeper_keys.go index 8185864c1..75efac977 100644 --- a/x/stake/keeper_keys.go +++ b/x/stake/keeper_keys.go @@ -32,14 +32,14 @@ func GetValidatorKey(addr sdk.Address) []byte { // get the key for the validator used in the power-store func GetValidatorsBondedByPowerKey(validator Validator) []byte { - powerBytes := []byte(validator.Power.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first) + powerBytes := []byte(validator.BondedShares.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first) // TODO ensure that the key will be a readable string.. probably should add seperators and have // heightBytes and counterBytes represent strings like powerBytes does heightBytes := make([]byte, binary.MaxVarintLen64) - binary.BigEndian.PutUint64(heightBytes, ^uint64(validator.Height)) // invert height (older validators first) + binary.BigEndian.PutUint64(heightBytes, ^uint64(validator.BondHeight)) // invert height (older validators first) counterBytes := make([]byte, 2) - binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.Counter)) // invert counter (first txns have priority) + binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.BondIntraTxCounter)) // invert counter (first txns have priority) return append(ValidatorsByPowerKey, append(powerBytes, append(heightBytes, diff --git a/x/stake/keeper_test.go b/x/stake/keeper_test.go index 2905aa906..da27b663c 100644 --- a/x/stake/keeper_test.go +++ b/x/stake/keeper_test.go @@ -319,7 +319,7 @@ func TestGetValidatorsBondedEdgeCases(t *testing.T) { require.Equal(t, validators[3].Address, validators[1].Address, "%v", validators) validator, exists := keeper.GetValidator(ctx, validators[4].Address) require.Equal(t, exists, true) - require.Equal(t, validator.ValidatorBondHeight, int64(40)) + require.Equal(t, validator.BondHeight, int64(40)) //If two validators both increase to the same voting power in the same block, //the one with the first transaction should take precedence (become a validator). diff --git a/x/stake/pool.go b/x/stake/pool.go index e3134955e..f22352c29 100644 --- a/x/stake/pool.go +++ b/x/stake/pool.go @@ -34,7 +34,7 @@ func (p Pool) bondedToUnbondedPool(validator Validator) (Pool, Validator) { // replace bonded shares with unbonded shares p, tokens := p.removeSharesBonded(validator.BondedShares) p, validator.BondedShares = p.addTokensUnbonded(tokens) - validator.Status = Unbonded + validator.Status = sdk.Unbonded return p, validator } @@ -44,7 +44,7 @@ func (p Pool) unbondedToBondedPool(validator Validator) (Pool, Validator) { // replace unbonded shares with bonded shares p, tokens := p.removeSharesUnbonded(validator.BondedShares) p, validator.BondedShares = p.addTokensBonded(tokens) - validator.Status = Bonded + validator.Status = sdk.Bonded return p, validator } @@ -87,7 +87,7 @@ func (p Pool) validatorAddTokens(validator Validator, exRate := validator.delegatorShareExRate() var receivedGlobalShares sdk.Rat - if validator.Status == Bonded { + if validator.Status == sdk.Bonded { p, receivedGlobalShares = p.addTokensBonded(amount) } else { p, receivedGlobalShares = p.addTokensUnbonded(amount) @@ -107,7 +107,7 @@ func (p Pool) validatorRemoveShares(validator Validator, //exRate := validator.delegatorShareExRate() //XXX make sure not used globalPoolSharesToRemove := validator.delegatorShareExRate().Mul(shares) - if validator.Status == Bonded { + if validator.Status == sdk.Bonded { p, createdCoins = p.removeSharesBonded(globalPoolSharesToRemove) } else { p, createdCoins = p.removeSharesUnbonded(globalPoolSharesToRemove) diff --git a/x/stake/types.go b/x/stake/types.go index 39f09f559..ebae5aa36 100644 --- a/x/stake/types.go +++ b/x/stake/types.go @@ -127,17 +127,17 @@ func initialPool() Pool { // exchange rate. type Validator struct { Status sdk.ValidatorStatus `json:"status"` // Bonded status - Address sdk.Address `json:"owner"` // Sender of BondTx - UnbondTx returns here + Address sdk.Address `json:"address"` // Sender of BondTx - UnbondTx returns here PubKey crypto.PubKey `json:"pub_key"` // Pubkey of validator - BondedShares sdk.Rat `json:"bonded_shares"` // total shares of a global hold pools - UnbondingShares sdk.Rat `json:"unbonding_shares"` // total shares of a global hold pools - UnbondedShares sdk.Rat `json:"unbonded_shares"` // total shares of a global hold pools + BondedShares sdk.Rat `json:"bonded_shares"` // total shares of bonded global hold pool + UnbondingShares sdk.Rat `json:"unbonding_shares"` // total shares of unbonding global hold pool + UnbondedShares sdk.Rat `json:"unbonded_shares"` // total shares of unbonded global hold pool DelegatorShares sdk.Rat `json:"liabilities"` // total shares issued to a validator's delegators - Description Description `json:"description"` // Description terms for the validator - ValidatorBondHeight int64 `json:"validator_bond_height"` // Earliest height as a bonded validator - ValidatorBondCounter int16 `json:"validator_bond_counter"` // Block-local tx index of validator change - ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer + Description Description `json:"description"` // Description terms for the validator + BondHeight int64 `json:"validator_bond_height"` // Earliest height as a bonded validator + BondIntraTxCounter int16 `json:"validator_bond_counter"` // Block-local tx index of validator change + ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge @@ -154,21 +154,20 @@ type Validators []Validator // NewValidator - initialize a new validator func NewValidator(address sdk.Address, pubKey crypto.PubKey, description Description) Validator { return Validator{ - Status: Unbonded, - Address: address, - PubKey: pubKey, - BondedShares: sdk.ZeroRat(), - DelegatorShares: sdk.ZeroRat(), - Description: description, - ValidatorBondHeight: int64(0), - ValidatorBondIntraTxCounter: int16(0), - ProposerRewardPool: sdk.Coins{}, - Commission: sdk.ZeroRat(), - CommissionMax: sdk.ZeroRat(), - CommissionChangeRate: sdk.ZeroRat(), - CommissionChangeToday: sdk.ZeroRat(), - FeeAdjustments: []sdk.Rat(nil), - PrevBondedShares: sdk.ZeroRat(), + Status: sdk.Unbonded, + Address: address, + PubKey: pubKey, + BondedShares: sdk.ZeroRat(), + DelegatorShares: sdk.ZeroRat(), + Description: description, + BondHeight: int64(0), + BondIntraTxCounter: int16(0), + ProposerRewardPool: sdk.Coins{}, + Commission: sdk.ZeroRat(), + CommissionMax: sdk.ZeroRat(), + CommissionChangeRate: sdk.ZeroRat(), + CommissionChangeToday: sdk.ZeroRat(), + PrevBondedShares: sdk.ZeroRat(), } } @@ -179,14 +178,13 @@ func (v Validator) equal(c2 Validator) bool { v.BondedShares.Equal(c2.BondedShares) && v.DelegatorShares.Equal(c2.DelegatorShares) && v.Description == c2.Description && - v.ValidatorBondHeight == c2.ValidatorBondHeight && - //v.ValidatorBondCounter == c2.ValidatorBondCounter && // counter is always changing + v.BondHeight == c2.BondHeight && + //v.BondIntraTxCounter == c2.BondIntraTxCounter && // counter is always changing v.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) && v.Commission.Equal(c2.Commission) && v.CommissionMax.Equal(c2.CommissionMax) && v.CommissionChangeRate.Equal(c2.CommissionChangeRate) && v.CommissionChangeToday.Equal(c2.CommissionChangeToday) && - sdk.RatsEqual(v.FeeAdjustments, c2.FeeAdjustments) && v.PrevBondedShares.Equal(c2.PrevBondedShares) } @@ -212,14 +210,21 @@ func (v Validator) delegatorShareExRate() sdk.Rat { if v.DelegatorShares.IsZero() { return sdk.OneRat() } - return v.BondedShares.Quo(v.DelegatorShares) + switch v.Status { + case sdk.Bonded: + return v.BondedShares.Quo(v.DelegatorShares) + case sdk.Unbonding: + return v.UnbondingShares.Quo(v.DelegatorShares) + default: //sdk.Unbonded, sdk.Revoked: + return v.UnbondedShares.Quo(v.DelegatorShares) + } } // abci validator from stake validator type func (v Validator) abciValidator(cdc *wire.Codec) abci.Validator { return abci.Validator{ PubKey: v.PubKey.Bytes(), - Power: v.Power.Evaluate(), + Power: v.BondedShares.Evaluate(), } } @@ -241,9 +246,11 @@ func (v Validator) abciValidatorZero(cdc *wire.Codec) abci.Validator { var _ sdk.Validator = Validator{} // nolint - for sdk.Validator -func (v Validator) GetAddress() sdk.Address { return v.Address } -func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } -func (v Validator) GetPower() sdk.Rat { return v.Power } +func (v Validator) GetStatus() sdk.ValidatorStatus { return v.Status } +func (v Validator) GetAddress() sdk.Address { return v.Address } +func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } +func (v Validator) GetPower() sdk.Rat { return v.BondedShares } +func (v Validator) GetBondHeight() int64 { return v.BondHeight } //_________________________________________________________________________ @@ -271,4 +278,4 @@ var _ sdk.Delegation = Delegation{} // nolint - for sdk.Delegation func (b Delegation) GetDelegator() sdk.Address { return b.DelegatorAddr } func (b Delegation) GetValidator() sdk.Address { return b.ValidatorAddr } -func (b Delegation) GetBondAmount() sdk.Rat { return b.Shares } +func (b Delegation) GetBondShares() sdk.Rat { return b.Shares }