From 9a1a89247bc96aa5c77d048009a41fdf83563a82 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 25 Jan 2018 09:06:25 +0000 Subject: [PATCH] porting over gaia store --- x/stake/store.go | 129 ++++++++++++++++++++++++++---------------- x/stake/store_test.go | 34 +++++++---- 2 files changed, 103 insertions(+), 60 deletions(-) diff --git a/x/stake/store.go b/x/stake/store.go index f0a2e38179..ded46418dc 100644 --- a/x/stake/store.go +++ b/x/stake/store.go @@ -1,6 +1,8 @@ package stake import ( + "encoding/binary" + crypto "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire" @@ -102,7 +104,10 @@ type Candidate struct { //nolint type Candidates []*Candidate -type Validator Candidate +type Validator struct { + PubKey crypto.PubKey `json:"pub_key"` // Pubkey of candidate + VotingPower int64 `json:"voting_power"` // Voting power if considered a validator +} type Validators []Validator // Description - description fields for a candidate @@ -143,8 +148,9 @@ var ( // Key prefixes CandidateKeyPrefix = []byte{0x04} // prefix for each key to a candidate - DelegatorBondKeyPrefix = []byte{0x05} // prefix for each key to a delegator's bond - DelegatorBondsKeyPrefix = []byte{0x06} // prefix for each key to a delegator's bond + ValidatorKeyPrefix = []byte{0x05} // prefix for each key to a candidate + DelegatorBondKeyPrefix = []byte{0x06} // prefix for each key to a delegator's bond + DelegatorBondsKeyPrefix = []byte{0x07} // prefix for each key to a delegator's bond ) // GetCandidateKey - get the key for the candidate with pubKey @@ -152,6 +158,13 @@ func GetCandidateKey(pubKey crypto.PubKey) []byte { return append(CandidateKeyPrefix, pubKey.Bytes()...) } +// GetValidatorKey - get the key for the validator used in the power-store +func GetValidatorKey(pubKey crypto.PubKey, power int64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, uint64(power)) + return append(ValidatorKeyPrefix, append(b, pubKey.Bytes()...)...) // TODO does this need prefix if its in its own store +} + // GetDelegatorBondKey - get the key for delegator bond with candidate func GetDelegatorBondKey(delegator crypto.Address, candidate crypto.PubKey) []byte { return append(GetDelegatorBondKeyPrefix(delegator), candidate.Bytes()...) @@ -177,7 +190,6 @@ func GetDelegatorBondsKey(delegator crypto.Address) []byte { //--------------------------------------------------------------------- -// loadCandidate - loads the candidate object for the provided pubkey func loadCandidate(store types.KVStore, pubKey crypto.PubKey) *Candidate { //if pubKey.Empty() { //return nil @@ -189,18 +201,16 @@ func loadCandidate(store types.KVStore, pubKey crypto.PubKey) *Candidate { candidate := new(Candidate) err := cdc.UnmarshalBinary(b, candidate) if err != nil { - panic(err) // This error should never occure big problem if does + panic(err) // This error should never occur big problem if does } return candidate } func saveCandidate(store types.KVStore, candidate *Candidate) { - if !store.Has(GetCandidateKey(candidate.PubKey)) { - // TODO to be replaced with iteration in the multistore? - pks := loadCandidatesPubKeys(store) - saveCandidatesPubKeys(store, append(pks, candidate.PubKey)) - } + removeValidatorFromKey(store, candidate.PubKey) + validator := &Validator{candidate.PubKey, candidate.VotingPower} + saveValidator(store, validator) b, err := cdc.MarshalBinary(*candidate) if err != nil { @@ -210,57 +220,52 @@ func saveCandidate(store types.KVStore, candidate *Candidate) { } func removeCandidate(store types.KVStore, pubKey crypto.PubKey) { + removeValidatorFromKey(store, pubKey) store.Delete(GetCandidateKey(pubKey)) - - // TODO to be replaced with iteration in the multistore? - pks := loadCandidatesPubKeys(store) - for i := range pks { - if pks[i].Equals(pubKey) { - saveCandidatesPubKeys(store, - append(pks[:i], pks[i+1:]...)) - break - } - } } //--------------------------------------------------------------------- -// Get the active list of all the candidate pubKeys and owners -func loadCandidatesPubKeys(store types.KVStore) (pubKeys []crypto.PubKey) { - bytes := store.Get(CandidatesPubKeysKey) - if bytes == nil { - return +func loadValidator(store types.KVStore, pubKey crypto.PubKey, votingPower int64) *Validator { + b := store.Get(GetValidatorKey(pubKey, votingPower)) + if b == nil { + return nil } - err := cdc.UnmarshalBinary(bytes, &pubKeys) + validator := new(Validator) + err := cdc.UnmarshalBinary(b, validator) if err != nil { - panic(err) + panic(err) // This error should never occur big problem if does } - return -} -func saveCandidatesPubKeys(store types.KVStore, pubKeys []crypto.PubKey) { - b, err := cdc.MarshalBinary(pubKeys) - if err != nil { - panic(err) - } - store.Set(CandidatesPubKeysKey, b) + return validator } -// loadCandidates - get the active list of all candidates TODO replace with multistore -func loadCandidates(store types.KVStore) (candidates Candidates) { - pks := loadCandidatesPubKeys(store) - for _, pk := range pks { - candidates = append(candidates, loadCandidate(store, pk)) +func saveValidator(store types.KVStore, validator *Validator) { + b, err := cdc.MarshalBinary(*validator) + if err != nil { + panic(err) + } + store.Set(GetValidatorKey(validator.PubKey, validator.VotingPower), b) +} + +func removeValidator(store types.KVStore, pubKey crypto.PubKey, votingPower int64) { + store.Delete(GetValidatorKey(pubKey, votingPower)) +} + +func removeValidatorFromKey(store types.KVStore, pubKey crypto.PubKey) { + // remove validator if already there, then add new validator + candidate := loadCandidate(store, pubKey) + if candidate != nil { + removeValidator(store, pubKey, candidate.VotingPower) } - return } // Validators - 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 -func getValidators(powerStore types.KVStore, maxVal int) Validators { +func getValidators(store types.KVStore, maxVal int) Validators { - iterator := powerStore.Iterator([]byte{}, []byte{nil}) //smallest to largest + iterator := store.Iterator(ValidatorKeyPrefix, ValidatorKeyPrefix) //smallest to largest validators := make(Validators, maxVal) for i := 0; ; i++ { @@ -268,13 +273,13 @@ func getValidators(powerStore types.KVStore, maxVal int) Validators { iterator.Close() break } - pkBytes := iterator.Value() - var pk crypto.PubKey - err := cdc.UnmarshalBinary(pkBytes, &pk) + valBytes := iterator.Value() + var val Validator + err := cdc.UnmarshalBinary(valBytes, &val) if err != nil { panic(err) } - validators[i] = pk + validators[i] = val iterator.Next() } @@ -283,6 +288,31 @@ func getValidators(powerStore types.KVStore, maxVal int) Validators { //--------------------------------------------------------------------- +// loadCandidates - get the active list of all candidates TODO replace with multistore +func loadCandidates(store types.KVStore) (candidates Candidates) { + + iterator := store.Iterator(CandidateKeyPrefix, CandidateKeyPrefix) //smallest to largest + + for i := 0; ; i++ { + if !iterator.Valid() { + iterator.Close() + break + } + candidateBytes := iterator.Value() + var candidate Candidate + err := cdc.UnmarshalBinary(candidateBytes, &candidate) + if err != nil { + panic(err) + } + candidates[i] = &candidate + iterator.Next() + } + + return candidates +} + +//--------------------------------------------------------------------- + // load the pubkeys of all candidates a delegator is delegated too func loadDelegatorCandidates(store types.KVStore, delegator crypto.Address) (candidates []crypto.PubKey) { @@ -340,7 +370,6 @@ func saveDelegatorBond(store types.KVStore, delegator crypto.Address, bond *Dele } func removeDelegatorBond(store types.KVStore, delegator crypto.Address, candidate crypto.PubKey) { - // TODO use list queries on multistore to remove iterations here! // first remove from the list of bonds pks := loadDelegatorCandidates(store, delegator) @@ -404,7 +433,7 @@ func loadParams(store types.KVStore) (params Params) { err := cdc.UnmarshalBinary(b, ¶ms) if err != nil { - panic(err) // This error should never occure big problem if does + panic(err) // This error should never occur big problem if does } return @@ -428,7 +457,7 @@ func loadGlobalState(store types.KVStore) (gs *GlobalState) { gs = new(GlobalState) err := cdc.UnmarshalBinary(b, gs) if err != nil { - panic(err) // This error should never occure big problem if does + panic(err) // This error should never occur big problem if does } return } diff --git a/x/stake/store_test.go b/x/stake/store_test.go index 868dced6c6..e82154a6c2 100644 --- a/x/stake/store_test.go +++ b/x/stake/store_test.go @@ -136,15 +136,29 @@ func TestState(t *testing.T) { assert.Equal(params, resParams) } -//func TestGetValidators(t *testing.T) { -//assert, require := assert.New(t), require.New(t) +func candidatesFromActors(actors []sdk.Actor, amts []int) (candidates Candidates) { + for i := 0; i < len(actors); i++ { + c := &Candidate{ + PubKey: pks[i], + Owner: actors[i], + Shares: int64(amts[i]), + VotingPower: int64(amts[i]), + } + candidates = append(candidates, c) + } -//N := 5 -//actors := newActors(N) -//candidates := candidatesFromActors(actors, []int{400, 200, 0, 0, 0}) + return +} -//validators := candidates.Validators() -//require.Equal(2, len(validators)) -//assert.Equal(candidates[0].PubKey, validators[0].PubKey) -//assert.Equal(candidates[1].PubKey, validators[1].PubKey) -//} +func TestGetValidators(t *testing.T) { + assert, require := assert.New(t), require.New(t) + + N := 5 + actors := newActors(N) + candidates := candidatesFromActors(actors, []int{400, 200, 0, 0, 0}) + + validators := candidates.Validators() + require.Equal(2, len(validators)) + assert.Equal(candidates[0].PubKey, validators[0].PubKey) + assert.Equal(candidates[1].PubKey, validators[1].PubKey) +}