From 750cbc53ec289e275e070d395b6676ba8e7f2e19 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 3 May 2018 13:38:02 -0400 Subject: [PATCH] stake cleanup, functionality for total prevote power --- CHANGELOG.md | 6 +- baseapp/baseapp.go | 8 +- examples/democoin/x/cool/keeper_test.go | 2 +- examples/democoin/x/pow/handler_test.go | 2 +- examples/democoin/x/pow/keeper_test.go | 2 +- .../democoin/x/simplestake/keeper_test.go | 4 +- types/context.go | 5 +- types/context_test.go | 4 +- types/lib/mapper_test.go | 2 +- x/auth/ante_test.go | 10 +- x/auth/context_test.go | 2 +- x/auth/mapper_test.go | 2 +- x/bank/keeper_test.go | 6 +- x/ibc/ibc_test.go | 2 +- x/stake/keeper.go | 178 ++++++++---------- x/stake/keeper_keys.go | 13 +- x/stake/keeper_test.go | 91 +++++---- x/stake/test_common.go | 2 +- x/stake/types.go | 10 +- 19 files changed, 167 insertions(+), 184 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce684911ae..7dbf953431 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## 0.18.0 (TBD) +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 + FEATURES * [x/auth] Added ability to change pubkey to auth module @@ -53,7 +58,6 @@ BREAKING CHANGES * gaiad init now requires use of `--name` flag * Removed Get from Msg interface * types/rational now extends big.Rat -* Queries against the store must be prefixed with the path "/store" FEATURES: diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 12dbf85d39..81d3e4f860 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -234,9 +234,9 @@ func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error { // NewContext returns a new Context with the correct store, the given header, and nil txBytes. func (app *BaseApp) NewContext(isCheckTx bool, header abci.Header) sdk.Context { if isCheckTx { - return sdk.NewContext(app.checkState.ms, header, true, nil, app.Logger) + return sdk.NewContext(app.checkState.ms, header, true, nil, app.Logger, nil) } - return sdk.NewContext(app.deliverState.ms, header, false, nil, app.Logger) + return sdk.NewContext(app.deliverState.ms, header, false, nil, app.Logger, nil) } type state struct { @@ -252,7 +252,7 @@ func (app *BaseApp) setCheckState(header abci.Header) { ms := app.cms.CacheMultiStore() app.checkState = &state{ ms: ms, - ctx: sdk.NewContext(ms, header, true, nil, app.Logger), + ctx: sdk.NewContext(ms, header, true, nil, app.Logger, nil), } } @@ -260,7 +260,7 @@ func (app *BaseApp) setDeliverState(header abci.Header) { ms := app.cms.CacheMultiStore() app.deliverState = &state{ ms: ms, - ctx: sdk.NewContext(ms, header, false, nil, app.Logger), + ctx: sdk.NewContext(ms, header, false, nil, app.Logger, nil), } } diff --git a/examples/democoin/x/cool/keeper_test.go b/examples/democoin/x/cool/keeper_test.go index d497dee699..f632ae31ee 100644 --- a/examples/democoin/x/cool/keeper_test.go +++ b/examples/democoin/x/cool/keeper_test.go @@ -30,7 +30,7 @@ func TestCoolKeeper(t *testing.T) { auth.RegisterBaseAccount(cdc) am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, nil, nil) ck := bank.NewKeeper(am) keeper := NewKeeper(capKey, ck, DefaultCodespace) diff --git a/examples/democoin/x/pow/handler_test.go b/examples/democoin/x/pow/handler_test.go index 30aeafa2a5..867120eb84 100644 --- a/examples/democoin/x/pow/handler_test.go +++ b/examples/democoin/x/pow/handler_test.go @@ -20,7 +20,7 @@ func TestPowHandler(t *testing.T) { auth.RegisterBaseAccount(cdc) am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) config := NewConfig("pow", int64(1)) ck := bank.NewKeeper(am) keeper := NewKeeper(capKey, config, ck, DefaultCodespace) diff --git a/examples/democoin/x/pow/keeper_test.go b/examples/democoin/x/pow/keeper_test.go index a4afb876a9..98e8ebcfea 100644 --- a/examples/democoin/x/pow/keeper_test.go +++ b/examples/democoin/x/pow/keeper_test.go @@ -33,7 +33,7 @@ func TestPowKeeperGetSet(t *testing.T) { auth.RegisterBaseAccount(cdc) am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) config := NewConfig("pow", int64(1)) ck := bank.NewKeeper(am) keeper := NewKeeper(capKey, config, ck, DefaultCodespace) diff --git a/examples/democoin/x/simplestake/keeper_test.go b/examples/democoin/x/simplestake/keeper_test.go index 302a2e58b6..c886c04b54 100644 --- a/examples/democoin/x/simplestake/keeper_test.go +++ b/examples/democoin/x/simplestake/keeper_test.go @@ -33,7 +33,7 @@ func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey) { func TestKeeperGetSet(t *testing.T) { ms, _, capKey := setupMultiStore() - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) stakeKeeper := NewKeeper(capKey, bank.NewKeeper(nil), DefaultCodespace) addr := sdk.Address([]byte("some-address")) @@ -60,7 +60,7 @@ func TestBonding(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := bank.NewKeeper(accountMapper) diff --git a/types/context.go b/types/context.go index cde4ce194e..ac095abfe6 100644 --- a/types/context.go +++ b/types/context.go @@ -30,7 +30,9 @@ type Context struct { } // create a new context -func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byte, logger log.Logger) Context { +func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, + txBytes []byte, logger log.Logger, absentValidators []int32) Context { + c := Context{ Context: context.Background(), pst: newThePast(), @@ -44,6 +46,7 @@ func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byt c = c.WithTxBytes(txBytes) c = c.WithLogger(logger) c = c.WithGasMeter(NewInfiniteGasMeter()) + c = c.WithAbsentValidators(absentValidators) return c } diff --git a/types/context_test.go b/types/context_test.go index ec5faab440..1eafdaf7e7 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -43,7 +43,7 @@ func (l MockLogger) With(kvs ...interface{}) log.Logger { func TestContextGetOpShouldNeverPanic(t *testing.T) { var ms types.MultiStore - ctx := types.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := types.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) indices := []int64{ -10, 1, 0, 10, 20, } @@ -58,7 +58,7 @@ func defaultContext(key types.StoreKey) types.Context { cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, types.StoreTypeIAVL, db) cms.LoadLatestVersion() - ctx := types.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := types.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger(), nil) return ctx } diff --git a/types/lib/mapper_test.go b/types/lib/mapper_test.go index e1759b06ac..a610f1e0fa 100644 --- a/types/lib/mapper_test.go +++ b/types/lib/mapper_test.go @@ -25,7 +25,7 @@ func defaultComponents(key sdk.StoreKey) (sdk.Context, *wire.Codec) { cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) cms.LoadLatestVersion() - ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger(), nil) cdc := wire.NewCodec() return ctx, cdc } diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index ec296b12be..054c18bbf4 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -74,7 +74,7 @@ func TestAnteHandlerSigErrors(t *testing.T) { RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) anteHandler := NewAnteHandler(mapper, BurnFeeHandler) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) // keys and addresses priv1, addr1 := privAndAddr() @@ -115,7 +115,7 @@ func TestAnteHandlerSequences(t *testing.T) { RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) anteHandler := NewAnteHandler(mapper, BurnFeeHandler) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) // keys and addresses priv1, addr1 := privAndAddr() @@ -181,7 +181,7 @@ func TestAnteHandlerFees(t *testing.T) { RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) anteHandler := NewAnteHandler(mapper, BurnFeeHandler) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) // keys and addresses priv1, addr1 := privAndAddr() @@ -218,7 +218,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) anteHandler := NewAnteHandler(mapper, BurnFeeHandler) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) // keys and addresses priv1, addr1 := privAndAddr() @@ -293,7 +293,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) { RegisterBaseAccount(cdc) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) anteHandler := NewAnteHandler(mapper, BurnFeeHandler) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) // keys and addresses priv1, addr1 := privAndAddr() diff --git a/x/auth/context_test.go b/x/auth/context_test.go index 89e318e0a1..cc38f846d8 100644 --- a/x/auth/context_test.go +++ b/x/auth/context_test.go @@ -13,7 +13,7 @@ import ( func TestContextWithSigners(t *testing.T) { ms, _ := setupMultiStore() - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) _, _, addr1 := keyPubAddr() _, _, addr2 := keyPubAddr() diff --git a/x/auth/mapper_test.go b/x/auth/mapper_test.go index cdd418990a..2d14f0973d 100644 --- a/x/auth/mapper_test.go +++ b/x/auth/mapper_test.go @@ -29,7 +29,7 @@ func TestAccountMapperGetSet(t *testing.T) { RegisterBaseAccount(cdc) // make context and mapper - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) addr := sdk.Address([]byte("some-address")) diff --git a/x/bank/keeper_test.go b/x/bank/keeper_test.go index 117c69e7ae..07ba91e0c5 100644 --- a/x/bank/keeper_test.go +++ b/x/bank/keeper_test.go @@ -31,7 +31,7 @@ func TestKeeper(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := NewKeeper(accountMapper) @@ -116,7 +116,7 @@ func TestSendKeeper(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := NewKeeper(accountMapper) sendKeeper := NewSendKeeper(accountMapper) @@ -185,7 +185,7 @@ func TestViewKeeper(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := NewKeeper(accountMapper) viewKeeper := NewViewKeeper(accountMapper) diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index 60cc59bad9..342b8fe45c 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -24,7 +24,7 @@ func defaultContext(key sdk.StoreKey) sdk.Context { cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) cms.LoadLatestVersion() - ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger(), nil) return ctx } diff --git a/x/stake/keeper.go b/x/stake/keeper.go index b2e3a3635f..fc53f501a4 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/bank" abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" ) // keeper of the staking store @@ -41,20 +42,14 @@ func (k Keeper) getCounter(ctx sdk.Context) int16 { return 0 } var counter int16 - err := k.cdc.UnmarshalBinary(b, &counter) - if err != nil { - panic(err) - } + k.cdc.MustUnmarshalBinary(b, &counter) return counter } // set the current in-block validator operation counter func (k Keeper) setCounter(ctx sdk.Context, counter int16) { store := ctx.KVStore(k.storeKey) - bz, err := k.cdc.MarshalBinary(counter) - if err != nil { - panic(err) - } + bz := k.cdc.MustMarshalBinary(counter) store.Set(CounterKey, bz) } @@ -67,10 +62,7 @@ func (k Keeper) GetCandidate(ctx sdk.Context, addr sdk.Address) (candidate Candi if b == nil { return candidate, false } - err := k.cdc.UnmarshalBinary(b, &candidate) - if err != nil { - panic(err) - } + k.cdc.MustUnmarshalBinary(b, &candidate) return candidate, true } @@ -88,10 +80,7 @@ func (k Keeper) GetCandidates(ctx sdk.Context, maxRetrieve int16) (candidates Ca } bz := iterator.Value() var candidate Candidate - err := k.cdc.UnmarshalBinary(bz, &candidate) - if err != nil { - panic(err) - } + k.cdc.MustUnmarshalBinary(bz, &candidate) candidates[i] = candidate iterator.Next() } @@ -112,11 +101,8 @@ func (k Keeper) setCandidate(ctx sdk.Context, candidate Candidate) { } // 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) + bz := k.cdc.MustMarshalBinary(candidate) + store.Set(GetCandidateKey(address), bz) // if the voting power is the same no need to update any of the other indexes if oldFound && oldCandidate.Assets.Equal(candidate.Assets) { @@ -127,7 +113,7 @@ func (k Keeper) setCandidate(ctx sdk.Context, candidate Candidate) { // update the list ordered by voting power if oldFound { - if !k.isNewValidator(ctx, store, candidate.Address) { + if !k.isNewValidator(ctx, store, address) { updateHeight = true } // else already in the validator set - retain the old validator height and counter @@ -145,37 +131,28 @@ func (k Keeper) setCandidate(ctx sdk.Context, candidate Candidate) { } // update the candidate record - bz, err = k.cdc.MarshalBinary(candidate) - if err != nil { - panic(err) - } - store.Set(GetCandidateKey(candidate.Address), bz) + bz = k.cdc.MustMarshalBinary(candidate) + store.Set(GetCandidateKey(address), bz) // marshal the new validator record validator := candidate.validator() - bz, err = k.cdc.MarshalBinary(validator) - if err != nil { - panic(err) - } - + bz = k.cdc.MustMarshalBinary(validator) store.Set(GetValidatorKey(address, validator.Power, validator.Height, validator.Counter, k.cdc), bz) // add to the validators to update list if is already a validator // or is a new validator setAcc := false - if store.Get(GetRecentValidatorKey(address)) != nil { + if store.Get(GetRecentValidatorKey(candidate.PubKey)) != nil { setAcc = true // want to check in the else statement because inefficient } else if k.isNewValidator(ctx, store, address) { setAcc = true } + if setAcc { - bz, err = k.cdc.MarshalBinary(validator.abciValidator(k.cdc)) - if err != nil { - panic(err) - } - store.Set(GetAccUpdateValidatorKey(validator.Address), bz) + bz = k.cdc.MustMarshalBinary(validator.abciValidator(k.cdc)) + store.Set(GetAccUpdateValidatorKey(address), bz) } @@ -197,15 +174,12 @@ func (k Keeper) removeCandidate(ctx sdk.Context, address sdk.Address) { // 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 { + if store.Get(GetRecentValidatorKey(candidate.PubKey)) == nil { return } - bz, err := k.cdc.MarshalBinary(candidate.validator().abciValidatorZero(k.cdc)) - if err != nil { - panic(err) - } + bz := k.cdc.MustMarshalBinary(candidate.validator().abciValidatorZero(k.cdc)) store.Set(GetAccUpdateValidatorKey(address), bz) - store.Delete(GetRecentValidatorKey(address)) + store.Delete(GetRecentValidatorKey(candidate.PubKey)) } //___________________________________________________________________________ @@ -222,7 +196,11 @@ func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) { // clear the recent validators store, add to the ToKickOut Temp store iterator := store.SubspaceIterator(RecentValidatorsKey) for ; iterator.Valid(); iterator.Next() { - addr := AddrFromKey(iterator.Key()) + + bz := iterator.Value() + var validator Validator + k.cdc.MustUnmarshalBinary(bz, &validator) + addr := validator.Address // iterator.Value is the validator object store.Set(GetToKickOutValidatorKey(addr), iterator.Value()) @@ -242,17 +220,14 @@ func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) { } bz := iterator.Value() var validator Validator - err := k.cdc.UnmarshalBinary(bz, &validator) - if err != nil { - panic(err) - } + k.cdc.MustUnmarshalBinary(bz, &validator) validators[i] = validator // remove from ToKickOut group store.Delete(GetToKickOutValidatorKey(validator.Address)) // also add to the recent validators group - store.Set(GetRecentValidatorKey(validator.Address), bz) + store.Set(GetRecentValidatorKey(validator.PubKey), bz) iterator.Next() } @@ -266,14 +241,8 @@ func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) { // get the zero abci validator from the ToKickOut iterator value bz := iterator.Value() var validator Validator - err := k.cdc.UnmarshalBinary(bz, &validator) - if err != nil { - panic(err) - } - bz, err = k.cdc.MarshalBinary(validator.abciValidatorZero(k.cdc)) - if err != nil { - panic(err) - } + k.cdc.MustUnmarshalBinary(bz, &validator) + bz = k.cdc.MustMarshalBinary(validator.abciValidatorZero(k.cdc)) store.Set(GetAccUpdateValidatorKey(addr), bz) store.Delete(key) @@ -297,10 +266,7 @@ func (k Keeper) isNewValidator(ctx sdk.Context, store sdk.KVStore, address sdk.A } bz := iterator.Value() var val Validator - err := k.cdc.UnmarshalBinary(bz, &val) - if err != nil { - panic(err) - } + k.cdc.MustUnmarshalBinary(bz, &val) if bytes.Equal(val.Address, address) { return true } @@ -311,14 +277,53 @@ func (k Keeper) isNewValidator(ctx sdk.Context, store sdk.KVStore, address sdk.A } // Is the address provided a part of the most recently saved validator group? -func (k Keeper) IsRecentValidator(ctx sdk.Context, address sdk.Address) bool { +func (k Keeper) IsRecentValidator(ctx sdk.Context, pk crypto.PubKey) bool { store := ctx.KVStore(k.storeKey) - if store.Get(GetRecentValidatorKey(address)) == nil { + if store.Get(GetRecentValidatorKey(pk)) == nil { return false } return true } +// Is the power of 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(RecentValidatorsKey) + 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 { + break + } + + 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 validator set @@ -330,10 +335,7 @@ func (k Keeper) getAccUpdateValidators(ctx sdk.Context) (updates []abci.Validato for ; iterator.Valid(); iterator.Next() { valBytes := iterator.Value() var val abci.Validator - err := k.cdc.UnmarshalBinary(valBytes, &val) - if err != nil { - panic(err) - } + k.cdc.MustUnmarshalBinary(valBytes, &val) updates = append(updates, val) } iterator.Close() @@ -364,10 +366,7 @@ func (k Keeper) GetDelegatorBond(ctx sdk.Context, return bond, false } - err := k.cdc.UnmarshalBinary(delegatorBytes, &bond) - if err != nil { - panic(err) - } + k.cdc.MustUnmarshalBinary(delegatorBytes, &bond) return bond, true } @@ -385,10 +384,7 @@ func (k Keeper) getBonds(ctx sdk.Context, maxRetrieve int16) (bonds []DelegatorB } bondBytes := iterator.Value() var bond DelegatorBond - err := k.cdc.UnmarshalBinary(bondBytes, &bond) - if err != nil { - panic(err) - } + k.cdc.MustUnmarshalBinary(bondBytes, &bond) bonds[i] = bond iterator.Next() } @@ -410,10 +406,7 @@ func (k Keeper) GetDelegatorBonds(ctx sdk.Context, delegator sdk.Address, maxRet } bondBytes := iterator.Value() var bond DelegatorBond - err := k.cdc.UnmarshalBinary(bondBytes, &bond) - if err != nil { - panic(err) - } + k.cdc.MustUnmarshalBinary(bondBytes, &bond) bonds[i] = bond iterator.Next() } @@ -422,10 +415,7 @@ func (k Keeper) GetDelegatorBonds(ctx sdk.Context, delegator sdk.Address, maxRet 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) - } + b := k.cdc.MustMarshalBinary(bond) store.Set(GetDelegatorBondKey(bond.DelegatorAddr, bond.CandidateAddr, k.cdc), b) } @@ -448,18 +438,12 @@ func (k Keeper) GetParams(ctx sdk.Context) (params Params) { panic("Stored params should not have been nil") } - err := k.cdc.UnmarshalBinary(b, ¶ms) - if err != nil { - panic(err) - } + k.cdc.MustUnmarshalBinary(b, ¶ms) return } func (k Keeper) setParams(ctx sdk.Context, params Params) { store := ctx.KVStore(k.storeKey) - b, err := k.cdc.MarshalBinary(params) - if err != nil { - panic(err) - } + b := k.cdc.MustMarshalBinary(params) store.Set(ParamKey, b) k.params = Params{} // clear the cache } @@ -477,19 +461,13 @@ func (k Keeper) GetPool(ctx sdk.Context) (pool Pool) { if b == nil { panic("Stored pool should not have been nil") } - err := k.cdc.UnmarshalBinary(b, &pool) - if err != nil { - panic(err) // This error should never occur big problem if does - } + k.cdc.MustUnmarshalBinary(b, &pool) return } func (k Keeper) setPool(ctx sdk.Context, p Pool) { store := ctx.KVStore(k.storeKey) - b, err := k.cdc.MarshalBinary(p) - if err != nil { - panic(err) - } + b := k.cdc.MustMarshalBinary(p) store.Set(PoolKey, b) k.pool = Pool{} //clear the cache } diff --git a/x/stake/keeper_keys.go b/x/stake/keeper_keys.go index eb641b883b..263008d761 100644 --- a/x/stake/keeper_keys.go +++ b/x/stake/keeper_keys.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + crypto "github.com/tendermint/go-crypto" ) // TODO remove some of these prefixes once have working multistore @@ -18,12 +19,9 @@ var ( 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{0x05} // prefix for each key to the last updated validator group - ToKickOutValidatorsKey = []byte{0x06} // prefix for each key to the last updated validator group - DelegatorBondKeyPrefix = []byte{0x07} // prefix for each key to a delegator's bond - - CounterKey = []byte{0x08} // key for block-local tx index + CounterKey = []byte{0x08} // key for block-local tx index ) const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch @@ -48,12 +46,13 @@ func GetAccUpdateValidatorKey(addr sdk.Address) []byte { return append(AccUpdateValidatorsKey, addr.Bytes()...) } -// get the key for the accumulated update validators -func GetRecentValidatorKey(addr sdk.Address) []byte { +// get the key for the recent validator group, ordered like tendermint +func GetRecentValidatorKey(pk crypto.PubKey) []byte { + addr := pk.Address() return append(RecentValidatorsKey, addr.Bytes()...) } -// reverse operation of GetRecentValidatorKey +// remove the prefix byte from a key func AddrFromKey(key []byte) sdk.Address { return key[1:] } diff --git a/x/stake/keeper_test.go b/x/stake/keeper_test.go index b537bd92e2..120450803e 100644 --- a/x/stake/keeper_test.go +++ b/x/stake/keeper_test.go @@ -31,12 +31,9 @@ func TestCandidate(t *testing.T) { var candidates [3]Candidate amts := []int64{9, 8, 7} for i, amt := range amts { - candidates[i] = Candidate{ - Address: addrVals[i], - PubKey: pks[i], - Assets: sdk.NewRat(amt), - Liabilities: sdk.NewRat(amt), - } + candidates[i] = NewCandidate(addrVals[i], pks[i], Description{}) + candidates[i].Assets = sdk.NewRat(amt) + candidates[i].Liabilities = sdk.NewRat(amt) } // check the empty keeper first @@ -92,12 +89,9 @@ func TestBond(t *testing.T) { amts := []int64{9, 8, 7} var candidates [3]Candidate for i, amt := range amts { - candidates[i] = Candidate{ - Address: addrVals[i], - PubKey: pks[i], - Assets: sdk.NewRat(amt), - Liabilities: sdk.NewRat(amt), - } + candidates[i] = NewCandidate(addrVals[i], pks[i], Description{}) + candidates[i].Assets = sdk.NewRat(amt) + candidates[i].Liabilities = sdk.NewRat(amt) } // first add a candidates[0] to delegate too @@ -194,15 +188,10 @@ func TestGetValidators(t *testing.T) { n := len(amts) var candidates [5]Candidate for i, amt := range amts { - c := Candidate{ - Status: Unbonded, - PubKey: pks[i], - Address: addrs[i], - Assets: sdk.NewRat(amt), - Liabilities: sdk.NewRat(amt), - } - keeper.setCandidate(ctx, c) - candidates[i] = c + candidates[i] = NewCandidate(addrs[i], pks[i], Description{}) + candidates[i].Assets = sdk.NewRat(amt) + candidates[i].Liabilities = sdk.NewRat(amt) + keeper.setCandidate(ctx, candidates[i]) } // first make sure everything as normal is ordered @@ -383,15 +372,10 @@ func TestClearAccUpdateValidators(t *testing.T) { amts := []int64{100, 400, 200} candidates := make([]Candidate, len(amts)) for i, amt := range amts { - c := Candidate{ - Status: Unbonded, - PubKey: pks[i], - Address: addrs[i], - Assets: sdk.NewRat(amt), - Liabilities: sdk.NewRat(amt), - } - candidates[i] = c - keeper.setCandidate(ctx, c) + candidates[i] = NewCandidate(addrs[i], pks[i], Description{}) + candidates[i].Assets = sdk.NewRat(amt) + candidates[i].Liabilities = sdk.NewRat(amt) + keeper.setCandidate(ctx, candidates[i]) } acc := keeper.getAccUpdateValidators(ctx) @@ -416,12 +400,9 @@ func TestGetAccUpdateValidators(t *testing.T) { amts := []int64{10, 11, 12, 13, 1} var candidatesIn [5]Candidate for i, amt := range amts { - candidatesIn[i] = Candidate{ - Address: addrs[i], - PubKey: pks[i], - Assets: sdk.NewRat(amt), - Liabilities: sdk.NewRat(amt), - } + candidatesIn[i] = NewCandidate(addrs[i], pks[i], Description{}) + candidatesIn[i].Assets = sdk.NewRat(amt) + candidatesIn[i].Liabilities = sdk.NewRat(amt) } // test from nothing to something @@ -620,12 +601,9 @@ func TestIsRecentValidator(t *testing.T) { amts := []int64{9, 8, 7, 10, 6} var candidatesIn [5]Candidate for i, amt := range amts { - candidatesIn[i] = Candidate{ - Address: addrVals[i], - PubKey: pks[i], - Assets: sdk.NewRat(amt), - Liabilities: sdk.NewRat(amt), - } + candidatesIn[i] = NewCandidate(addrVals[i], pks[i], Description{}) + candidatesIn[i].Assets = sdk.NewRat(amt) + candidatesIn[i].Liabilities = sdk.NewRat(amt) } // test that an empty validator set doesn't have any validators @@ -643,17 +621,38 @@ func TestIsRecentValidator(t *testing.T) { assert.True(t, c1ValWithCounter.equal(validators[1])) // test a basic retrieve of something that should be a recent validator - assert.True(t, keeper.IsRecentValidator(ctx, candidatesIn[0].Address)) - assert.True(t, keeper.IsRecentValidator(ctx, candidatesIn[1].Address)) + assert.True(t, keeper.IsRecentValidator(ctx, candidatesIn[0].PubKey)) + assert.True(t, keeper.IsRecentValidator(ctx, candidatesIn[1].PubKey)) // test a basic retrieve of something that should not be a recent validator - assert.False(t, keeper.IsRecentValidator(ctx, candidatesIn[2].Address)) + assert.False(t, keeper.IsRecentValidator(ctx, candidatesIn[2].PubKey)) // remove that validator, but don't retrieve the recent validator group keeper.removeCandidate(ctx, candidatesIn[0].Address) // test that removed validator is not considered a recent validator - assert.False(t, keeper.IsRecentValidator(ctx, candidatesIn[0].Address)) + assert.False(t, keeper.IsRecentValidator(ctx, candidatesIn[0].PubKey)) +} + +// test if is a validator from the last update +func TestGetTotalPrecommitVotingPower(t *testing.T) { + ctx, _, keeper := createTestInput(t, false, 0) + + // set absent validators to be the 1st and 3rd record sorted by pubKey address + ctx = ctx.WithAbsentValidators([]int32{1, 3}) + + amts := []int64{9, 8, 7, 10, 6} + var candidatesIn [5]Candidate + for i, amt := range amts { + candidatesIn[i] = NewCandidate(addrVals[i], pks[i], Description{}) + candidatesIn[i].Assets = sdk.NewRat(amt) + candidatesIn[i].Liabilities = sdk.NewRat(amt) + keeper.setCandidate(ctx, candidatesIn[i]) + } + + // test that an empty validator set doesn't have any validators + validators := keeper.GetValidators(ctx) + assert.Equal(t, 5, len(validators)) } func TestParams(t *testing.T) { diff --git a/x/stake/test_common.go b/x/stake/test_common.go index b5139b4b34..78a18353c8 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -92,7 +92,7 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context err := ms.LoadLatestVersion() require.Nil(t, err) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil, log.NewNopLogger(), nil) cdc := makeTestCodec() accountMapper := auth.NewAccountMapper( cdc, // amino codec diff --git a/x/stake/types.go b/x/stake/types.go index 918075358b..d06f078d1a 100644 --- a/x/stake/types.go +++ b/x/stake/types.go @@ -111,10 +111,10 @@ func initialPool() Pool { InflationLastTime: 0, Inflation: sdk.NewRat(7, 100), DateLastCommissionReset: 0, - ReservePool: sdk.Coins{}, - FeePool: sdk.Coins{}, - SumFeesReceived: sdk.Coins{}, - RecentFee: sdk.Coins{}, + ReservePool: sdk.Coins(nil), + FeePool: sdk.Coins(nil), + SumFeesReceived: sdk.Coins(nil), + RecentFee: sdk.Coins(nil), Adjustment: sdk.ZeroRat(), } } @@ -184,7 +184,7 @@ func (c Candidate) equal(c2 Candidate) bool { c.Liabilities.Equal(c2.Liabilities) && c.Description == c2.Description && c.ValidatorBondHeight == c2.ValidatorBondHeight && - c.ValidatorBondCounter == c2.ValidatorBondCounter && + //c.ValidatorBondCounter == c2.ValidatorBondCounter && // counter is always changing c.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) && c.Commission.Equal(c2.Commission) && c.CommissionMax.Equal(c2.CommissionMax) &&