diff --git a/x/stake/commands/query.go b/x/stake/commands/query.go index b6ccb712e..ed436305c 100644 --- a/x/stake/commands/query.go +++ b/x/stake/commands/query.go @@ -45,7 +45,7 @@ func GetCmdQueryCandidates(cdc *wire.Codec, storeName string) *cobra.Command { Short: "Query for the set of validator-candidates pubkeys", RunE: func(cmd *cobra.Command, args []string) error { - key := PrefixedKey(stake.MsgType, stake.CandidatesAddrKey) + key := PrefixedKey(stake.MsgType, stake.CandidatesKey) res, err := builder.Query(key, storeName) if err != nil { diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 8f314e41c..7f82d747a 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -12,7 +12,7 @@ type Keeper struct { cdc *wire.Codec coinKeeper bank.CoinKeeper - //just caches + // caches gs Pool params Params } @@ -42,30 +42,10 @@ func (k Keeper) GetCandidate(ctx sdk.Context, addr sdk.Address) (candidate Candi return candidate, true } -func (k Keeper) setCandidate(ctx sdk.Context, candidate Candidate) { - store := ctx.KVStore(k.storeKey) - - k.removeValidator(ctx, candidate.Address) - validator := Validator{candidate.Address, candidate.VotingPower} - k.updateValidator(ctx, validator) - - b, err := k.cdc.MarshalBinary(candidate) - if err != nil { - panic(err) - } - store.Set(GetCandidateKey(candidate.Address), b) -} - -func (k Keeper) removeCandidate(ctx sdk.Context, candidateAddr sdk.Address) { - store := ctx.KVStore(k.storeKey) - k.removeValidator(ctx, candidateAddr) - store.Delete(GetCandidateKey(candidateAddr)) -} - // Get the set of all candidates, retrieve a maxRetrieve number of records func (k Keeper) GetCandidates(ctx sdk.Context, maxRetrieve int16) (candidates Candidates) { store := ctx.KVStore(k.storeKey) - iterator := store.Iterator(subspace(CandidateKeyPrefix)) + iterator := store.Iterator(subspace(CandidatesKey)) candidates = make([]Candidate, maxRetrieve) i := 0 @@ -86,53 +66,82 @@ func (k Keeper) GetCandidates(ctx sdk.Context, maxRetrieve int16) (candidates Ca return candidates[:i] // trim } -//___________________________________________________________________________ - -// updateValidator - update a validator and create accumulate any changes -// in the changed validator substore -func (k Keeper) updateValidator(ctx sdk.Context, validator Validator) { +func (k Keeper) setCandidate(ctx sdk.Context, candidate Candidate) { store := ctx.KVStore(k.storeKey) + address := candidate.Address - b, err := k.cdc.MarshalBinary(validator) + // retreive the old candidate record + oldCandidate, oldFound := k.GetCandidate(ctx, address) + + // marshal the candidate record and add to the state + bz, err := k.cdc.MarshalBinary(candidate) if err != nil { panic(err) } + store.Set(GetCandidateKey(candidate.Address), bz) - // add to the validators to update list if necessary - store.Set(GetValidatorUpdatesKey(validator.Address), b) + // mashal the new validator record + validator := Validator{address, candidate.VotingPower} + bz, err = k.cdc.MarshalBinary(validator) + if err != nil { + panic(err) + } // update the list ordered by voting power - store.Set(GetValidatorKey(validator.Address, validator.VotingPower, k.cdc), b) + if oldFound { + store.Delete(GetValidatorKey(address, oldCandidate.VotingPower, k.cdc)) + } + store.Set(GetValidatorKey(address, validator.VotingPower, k.cdc), bz) + + // add to the validators to update list if is already a validator + if store.Get(GetRecentValidatorKey(address)) == nil { + return + } + store.Set(GetAccUpdateValidatorKey(validator.Address), bz) + } -func (k Keeper) removeValidator(ctx sdk.Context, address sdk.Address) { +func (k Keeper) removeCandidate(ctx sdk.Context, address sdk.Address) { + + // first retreive the old candidate record + oldCandidate, found := k.GetCandidate(ctx, address) + if !found { + return + } + + // delete the old candidate record store := ctx.KVStore(k.storeKey) + store.Delete(GetCandidateKey(address)) - // XXX ensure that this record is a validator even? - - //add validator with zero power to the validator updates - b, err := k.cdc.MarshalBinary(Validator{address, sdk.ZeroRat}) + // delete from recent and power weighted validator groups if the validator + // exists and add validator with zero power to the validator updates + if store.Get(GetRecentValidatorKey(address)) == nil { + return + } + bz, err := k.cdc.MarshalBinary(Validator{address, sdk.ZeroRat}) if err != nil { panic(err) } - store.Set(GetValidatorUpdatesKey(address), b) - - // now actually delete from the validator set - candidate, found := k.GetCandidate(ctx, address) - if found { - store.Delete(GetValidatorKey(address, candidate.VotingPower, k.cdc)) - } + store.Set(GetAccUpdateValidatorKey(address), bz) + store.Delete(GetRecentValidatorKey(address)) + store.Delete(GetValidatorKey(address, oldCandidate.VotingPower, k.cdc)) } +//___________________________________________________________________________ + // get the most recent updated validator set from the Candidates. These bonds // are already sorted by VotingPower from the UpdateVotingPower function which // is the only function which is to modify the VotingPower +// this function also updaates the most recent validators saved in store func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) { store := ctx.KVStore(k.storeKey) + + // clear the recent validators store + k.deleteSubSpace(store, RecentValidatorsKey) + + // add the actual validator power sorted store maxVal := k.GetParams(ctx).MaxValidators - - iterator := store.Iterator(subspace(ValidatorKeyPrefix)) //smallest to largest - + iterator := store.Iterator(subspace(ValidatorsKey)) //smallest to largest validators = make([]Validator, maxVal) i := 0 for ; ; i++ { @@ -140,26 +149,40 @@ func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) { iterator.Close() break } - valBytes := iterator.Value() + bz := iterator.Value() var val Validator - err := k.cdc.UnmarshalBinary(valBytes, &val) + err := k.cdc.UnmarshalBinary(bz, &val) if err != nil { panic(err) } validators[i] = val + + // also add to the recent validators group + store.Set(GetRecentValidatorKey(val.Address), bz) + iterator.Next() } + return validators[:i] // trim } -//_________________________________________________________________________ +// Is the address provided a part of the most recently saved validator group? +func (k Keeper) IsRecentValidator(ctx sdk.Context, address sdk.Address) bool { + store := ctx.KVStore(k.storeKey) + if store.Get(GetRecentValidatorKey(address)) == nil { + return false + } + return true +} -// get the most updated validators -func (k Keeper) getValidatorUpdates(ctx sdk.Context) (updates []Validator) { +//_________________________________________________________________________ +// Accumulated updates to the validator set + +// get the most recently updated validators +func (k Keeper) getAccUpdateValidators(ctx sdk.Context) (updates []Validator) { store := ctx.KVStore(k.storeKey) - iterator := store.Iterator(subspace(ValidatorUpdatesKeyPrefix)) //smallest to largest - + iterator := store.Iterator(subspace(AccUpdateValidatorsKey)) //smallest to largest for ; iterator.Valid(); iterator.Next() { valBytes := iterator.Value() var val Validator @@ -169,17 +192,21 @@ func (k Keeper) getValidatorUpdates(ctx sdk.Context) (updates []Validator) { } updates = append(updates, val) } - iterator.Close() return } // remove all validator update entries -func (k Keeper) clearValidatorUpdates(ctx sdk.Context, maxVal int) { +func (k Keeper) clearAccUpdateValidators(ctx sdk.Context) { store := ctx.KVStore(k.storeKey) - iterator := store.Iterator(subspace(ValidatorUpdatesKeyPrefix)) + k.deleteSubSpace(store, AccUpdateValidatorsKey) +} + +// TODO move to common functionality somewhere +func (k Keeper) deleteSubSpace(store sdk.KVStore, key []byte) { + iterator := store.Iterator(subspace(key)) for ; iterator.Valid(); iterator.Next() { - store.Delete(iterator.Key()) // XXX write test for this, may need to be in a second loop + store.Delete(iterator.Key()) } iterator.Close() } @@ -202,20 +229,6 @@ func (k Keeper) getDelegatorBond(ctx sdk.Context, return bond, true } -func (k Keeper) setDelegatorBond(ctx sdk.Context, bond DelegatorBond) { - store := ctx.KVStore(k.storeKey) - b, err := k.cdc.MarshalBinary(bond) - if err != nil { - panic(err) - } - store.Set(GetDelegatorBondKey(bond.DelegatorAddr, bond.CandidateAddr, k.cdc), b) -} - -func (k Keeper) removeDelegatorBond(ctx sdk.Context, bond DelegatorBond) { - store := ctx.KVStore(k.storeKey) - store.Delete(GetDelegatorBondKey(bond.DelegatorAddr, bond.CandidateAddr, k.cdc)) -} - // load all bonds of a delegator func (k Keeper) getDelegatorBonds(ctx sdk.Context, delegator sdk.Address, maxRetrieve int16) (bonds []DelegatorBond) { store := ctx.KVStore(k.storeKey) @@ -241,6 +254,20 @@ func (k Keeper) getDelegatorBonds(ctx sdk.Context, delegator sdk.Address, maxRet return bonds[:i] // trim } +func (k Keeper) setDelegatorBond(ctx sdk.Context, bond DelegatorBond) { + store := ctx.KVStore(k.storeKey) + b, err := k.cdc.MarshalBinary(bond) + if err != nil { + panic(err) + } + store.Set(GetDelegatorBondKey(bond.DelegatorAddr, bond.CandidateAddr, k.cdc), b) +} + +func (k Keeper) removeDelegatorBond(ctx sdk.Context, bond DelegatorBond) { + store := ctx.KVStore(k.storeKey) + store.Delete(GetDelegatorBondKey(bond.DelegatorAddr, bond.CandidateAddr, k.cdc)) +} + //_______________________________________________________________________ // load/save the global staking params diff --git a/x/stake/keeper_keys.go b/x/stake/keeper_keys.go index c31d65f2c..ae0928bcc 100644 --- a/x/stake/keeper_keys.go +++ b/x/stake/keeper_keys.go @@ -5,43 +5,51 @@ import ( "github.com/cosmos/cosmos-sdk/wire" ) +// TODO remove some of these prefixes once have working multistore + //nolint var ( // Keys for store prefixes - CandidatesAddrKey = []byte{0x01} // key for all candidates' addresses - ParamKey = []byte{0x02} // key for global parameters relating to staking - PoolKey = []byte{0x03} // key for global parameters relating to staking + ParamKey = []byte{0x00} // key for global parameters relating to staking + PoolKey = []byte{0x01} // key for global parameters relating to staking + CandidatesKey = []byte{0x02} // prefix for each key to a candidate + ValidatorsKey = []byte{0x03} // prefix for each key to a validator + AccUpdateValidatorsKey = []byte{0x04} // prefix for each key to a validator which is being updated + RecentValidatorsKey = []byte{0x04} // prefix for each key to the last updated validator group - // Key prefixes - CandidateKeyPrefix = []byte{0x04} // prefix for each key to a candidate - ValidatorKeyPrefix = []byte{0x05} // prefix for each key to a candidate - ValidatorUpdatesKeyPrefix = []byte{0x06} // prefix for each key to a candidate - DelegatorBondKeyPrefix = []byte{0x07} // prefix for each key to a delegator's bond + DelegatorBondKeyPrefix = []byte{0x05} // prefix for each key to a delegator's bond ) -// XXX remove beggining word get from all these keys -// GetCandidateKey - get the key for the candidate with address +// get the key for the candidate with address func GetCandidateKey(addr sdk.Address) []byte { - return append(CandidateKeyPrefix, addr.Bytes()...) + return append(CandidatesKey, addr.Bytes()...) } -// GetValidatorKey - get the key for the validator used in the power-store +// get the key for the validator used in the power-store func GetValidatorKey(addr sdk.Address, power sdk.Rat, cdc *wire.Codec) []byte { - b, _ := cdc.MarshalBinary(power) // TODO need to handle error here? - return append(ValidatorKeyPrefix, append(b, addr.Bytes()...)...) // TODO does this need prefix if its in its own store + b, err := cdc.MarshalBinary(power) + if err != nil { + panic(err) + } + return append(ValidatorsKey, append(b, addr.Bytes()...)...) } -// GetValidatorUpdatesKey - get the key for the validator used in the power-store -func GetValidatorUpdatesKey(addr sdk.Address) []byte { - return append(ValidatorUpdatesKeyPrefix, addr.Bytes()...) // TODO does this need prefix if its in its own store +// get the key for the accumulated update validators +func GetAccUpdateValidatorKey(addr sdk.Address) []byte { + return append(AccUpdateValidatorsKey, addr.Bytes()...) } -// GetDelegatorBondKey - get the key for delegator bond with candidate +// get the key for the accumulated update validators +func GetRecentValidatorKey(addr sdk.Address) []byte { + return append(RecentValidatorsKey, addr.Bytes()...) +} + +// get the key for delegator bond with candidate func GetDelegatorBondKey(delegatorAddr, candidateAddr sdk.Address, cdc *wire.Codec) []byte { return append(GetDelegatorBondsKey(delegatorAddr, cdc), candidateAddr.Bytes()...) } -// GetDelegatorBondKeyPrefix - get the prefix for a delegator for all candidates +// get the prefix for a delegator for all candidates func GetDelegatorBondsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { res, err := cdc.MarshalBinary(&delegatorAddr) if err != nil {