From 4e4749da9d8f53ceccf86ee500aa947f2b4007ef Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 20 Sep 2018 20:30:18 -0400 Subject: [PATCH 01/22] pulling in stuff from fee-distr PR --- x/slashing/handler.go | 8 ++-- x/slashing/hooks.go | 31 ++++++++----- x/slashing/keeper.go | 37 ++++++++-------- x/slashing/keeper_test.go | 47 +++++++++++--------- x/slashing/tick_test.go | 2 +- x/stake/client/cli/flags.go | 8 ++-- x/stake/genesis.go | 2 +- x/stake/handler.go | 12 ++++- x/stake/handler_test.go | 17 +++++--- x/stake/keeper/delegation.go | 16 +++++++ x/stake/keeper/hooks.go | 54 +++++++++++++++++++++++ x/stake/keeper/keeper.go | 28 ++++++------ x/stake/keeper/key.go | 8 ++-- x/stake/keeper/sdk_types.go | 33 +++++++++----- x/stake/keeper/slash.go | 33 +++++--------- x/stake/keeper/slash_test.go | 73 ++++++++++++++++--------------- x/stake/keeper/validator.go | 75 +++++++++++++++++++++++++++----- x/stake/keeper/validator_test.go | 5 ++- x/stake/stake.go | 4 +- x/stake/types/codec.go | 3 +- x/stake/types/delegation.go | 2 +- x/stake/types/errors.go | 8 ++++ x/stake/types/validator.go | 20 +++++---- 23 files changed, 341 insertions(+), 185 deletions(-) create mode 100644 x/stake/keeper/hooks.go diff --git a/x/slashing/handler.go b/x/slashing/handler.go index c43ed6be61..4f342f62a0 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -34,9 +34,9 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result { return ErrValidatorNotJailed(k.codespace).Result() } - addr := sdk.ConsAddress(validator.GetPubKey().Address()) + consAddr := sdk.ConsAddress(validator.GetPubKey().Address()) - info, found := k.getValidatorSigningInfo(ctx, addr) + info, found := k.getValidatorSigningInfo(ctx, consAddr) if !found { return ErrNoValidatorForAddress(k.codespace).Result() } @@ -49,9 +49,9 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result { // update the starting height so the validator can't be immediately jailed // again info.StartHeight = ctx.BlockHeight() - k.setValidatorSigningInfo(ctx, addr, info) + k.setValidatorSigningInfo(ctx, consAddr, info) - k.validatorSet.Unjail(ctx, validator.GetPubKey()) + k.validatorSet.Unjail(ctx, consAddr) tags := sdk.NewTags("action", []byte("unjail"), "validator", []byte(msg.ValidatorAddr.String())) diff --git a/x/slashing/hooks.go b/x/slashing/hooks.go index f5f3cc48c3..701a6b2cde 100644 --- a/x/slashing/hooks.go +++ b/x/slashing/hooks.go @@ -22,25 +22,34 @@ func (k Keeper) onValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddre k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) } -// Wrapper struct for sdk.ValidatorHooks -type ValidatorHooks struct { +//_________________________________________________________________________________________ + +// Wrapper struct +type Hooks struct { k Keeper } -// Assert implementation -var _ sdk.ValidatorHooks = ValidatorHooks{} +var _ sdk.StakingHooks = Hooks{} -// Return a sdk.ValidatorHooks interface over the wrapper struct -func (k Keeper) ValidatorHooks() sdk.ValidatorHooks { - return ValidatorHooks{k} +// Return the wrapper struct +func (k Keeper) Hooks() Hooks { + return Hooks{k} } // Implements sdk.ValidatorHooks -func (v ValidatorHooks) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) { - v.k.onValidatorBonded(ctx, address) +func (h Hooks) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) { + h.k.onValidatorBonded(ctx, address) } // Implements sdk.ValidatorHooks -func (v ValidatorHooks) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) { - v.k.onValidatorBeginUnbonding(ctx, address) +func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) { + h.k.onValidatorBeginUnbonding(ctx, address) } + +// nolint - unused hooks +func (h Hooks) OnValidatorCreated(_ sdk.Context, _ sdk.ValAddress) {} +func (h Hooks) OnValidatorCommissionChange(_ sdk.Context, _ sdk.ValAddress) {} +func (h Hooks) OnValidatorRemoved(_ sdk.Context, _ sdk.ValAddress) {} +func (h Hooks) OnDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} +func (h Hooks) OnDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} +func (h Hooks) OnDelegationRemoved(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 5a008ccec5..e639182e18 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -40,10 +40,10 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio logger := ctx.Logger().With("module", "x/slashing") time := ctx.BlockHeader().Time age := time.Sub(timestamp) - address := sdk.ConsAddress(addr) + consAddr := sdk.ConsAddress(addr) pubkey, err := k.getPubkey(ctx, addr) if err != nil { - panic(fmt.Sprintf("Validator address %v not found", addr)) + panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr)) } // Double sign too old @@ -59,37 +59,38 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio // Cap the amount slashed to the penalty for the worst infraction // within the slashing period when this infraction was committed fraction := k.SlashFractionDoubleSign(ctx) - revisedFraction := k.capBySlashingPeriod(ctx, address, fraction, infractionHeight) + revisedFraction := k.capBySlashingPeriod(ctx, consAddr, fraction, infractionHeight) logger.Info(fmt.Sprintf("Fraction slashed capped by slashing period from %v to %v", fraction, revisedFraction)) // Slash validator - k.validatorSet.Slash(ctx, pubkey, infractionHeight, power, revisedFraction) + k.validatorSet.Slash(ctx, consAddr, infractionHeight, power, revisedFraction) // Jail validator - k.validatorSet.Jail(ctx, pubkey) + k.validatorSet.Jail(ctx, consAddr) // Set validator jail duration - signInfo, found := k.getValidatorSigningInfo(ctx, address) + signInfo, found := k.getValidatorSigningInfo(ctx, consAddr) if !found { - panic(fmt.Sprintf("Expected signing info for validator %s but not found", address)) + panic(fmt.Sprintf("Expected signing info for validator %s but not found", consAddr)) } signInfo.JailedUntil = time.Add(k.DoubleSignUnbondDuration(ctx)) - k.setValidatorSigningInfo(ctx, address, signInfo) + k.setValidatorSigningInfo(ctx, consAddr, signInfo) } // handle a validator signature, must be called once per validator per block +// TODO refactor to take in a consensus address, additionally should maybe just take in the pubkey too // nolint gocyclo func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, power int64, signed bool) { logger := ctx.Logger().With("module", "x/slashing") height := ctx.BlockHeight() - address := sdk.ConsAddress(addr) + consAddr := sdk.ConsAddress(addr) pubkey, err := k.getPubkey(ctx, addr) if err != nil { - panic(fmt.Sprintf("Validator address %v not found", addr)) + panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr)) } // Local index, so counts blocks validator *should* have signed // Will use the 0-value default signing info if not present, except for start height - signInfo, found := k.getValidatorSigningInfo(ctx, address) + signInfo, found := k.getValidatorSigningInfo(ctx, consAddr) if !found { // If this validator has never been seen before, construct a new SigningInfo with the correct start height signInfo = NewValidatorSigningInfo(height, 0, time.Unix(0, 0), 0) @@ -100,16 +101,16 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p // Update signed block bit array & counter // This counter just tracks the sum of the bit array // That way we avoid needing to read/write the whole array each time - previous := k.getValidatorSigningBitArray(ctx, address, index) + previous := k.getValidatorSigningBitArray(ctx, consAddr, index) if previous == signed { // Array value at this index has not changed, no need to update counter } else if previous && !signed { // Array value has changed from signed to unsigned, decrement counter - k.setValidatorSigningBitArray(ctx, address, index, false) + k.setValidatorSigningBitArray(ctx, consAddr, index, false) signInfo.SignedBlocksCounter-- } else if !previous && signed { // Array value has changed from unsigned to signed, increment counter - k.setValidatorSigningBitArray(ctx, address, index, true) + k.setValidatorSigningBitArray(ctx, consAddr, index, true) signInfo.SignedBlocksCounter++ } @@ -118,13 +119,13 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p } minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx) if height > minHeight && signInfo.SignedBlocksCounter < k.MinSignedPerWindow(ctx) { - validator := k.validatorSet.ValidatorByPubKey(ctx, pubkey) + validator := k.validatorSet.ValidatorByConsAddr(ctx, consAddr) if validator != nil && !validator.GetJailed() { // Downtime confirmed: slash and jail the validator logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, k.MinSignedPerWindow(ctx))) - k.validatorSet.Slash(ctx, pubkey, height, power, k.SlashFractionDowntime(ctx)) - k.validatorSet.Jail(ctx, pubkey) + k.validatorSet.Slash(ctx, consAddr, height, power, k.SlashFractionDowntime(ctx)) + k.validatorSet.Jail(ctx, consAddr) signInfo.JailedUntil = ctx.BlockHeader().Time.Add(k.DowntimeUnbondDuration(ctx)) } else { // Validator was (a) not found or (b) already jailed, don't slash @@ -134,7 +135,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p } // Set the updated signing info - k.setValidatorSigningInfo(ctx, address, signInfo) + k.setValidatorSigningInfo(ctx, consAddr, signInfo) } // AddValidators adds the validators to the keepers validator addr to pubkey mapping. diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index ff50a594ea..1d69f714f0 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -18,13 +18,16 @@ func init() { defaultDoubleSignUnbondDuration = 60 * 60 } +// ______________________________________________________________ + // Test that a validator is slashed correctly // when we discover evidence of infraction +// TODO fix this test to not be using the same pubkey/address for signing and operating, it's confusing func TestHandleDoubleSign(t *testing.T) { // initial setup ctx, ck, sk, _, keeper := createTestInput(t) - sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) + sk = sk.WithHooks(keeper.Hooks()) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) @@ -43,7 +46,7 @@ func TestHandleDoubleSign(t *testing.T) { // should be jailed require.True(t, sk.Validator(ctx, addr).GetJailed()) // unjail to measure power - sk.Unjail(ctx, val) + sk.Unjail(ctx, sdk.ConsAddress(addr)) // TODO distinguish cons address // power should be reduced require.Equal( t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), @@ -61,14 +64,16 @@ func TestHandleDoubleSign(t *testing.T) { // Test that the amount a validator is slashed for multiple double signs // is correctly capped by the slashing period in which they were committed +// TODO properly distinguish between consensus and operator address is variable names func TestSlashingPeriodCap(t *testing.T) { // initial setup ctx, ck, sk, _, keeper := createTestInput(t) - sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) + sk = sk.WithHooks(keeper.Hooks()) amtInt := int64(100) - addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) - got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) + addr, amt := addrs[0], sdk.NewInt(amtInt) + valConsPubKey, valConsAddr := pks[0], sdk.ConsAddress(pks[0].Address()) + got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, valConsPubKey, amt)) require.True(t, got.IsOK()) validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) @@ -76,39 +81,39 @@ func TestSlashingPeriodCap(t *testing.T) { require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) // handle a signature to set signing info - keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true) + keeper.handleValidatorSignature(ctx, valConsPubKey.Address(), amtInt, true) // double sign less than max age - keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt) + keeper.handleDoubleSign(ctx, valConsPubKey.Address(), 0, time.Unix(0, 0), amtInt) // should be jailed require.True(t, sk.Validator(ctx, addr).GetJailed()) // update block height ctx = ctx.WithBlockHeight(int64(1)) // unjail to measure power - sk.Unjail(ctx, val) + sk.Unjail(ctx, valConsAddr) // power should be reduced expectedPower := sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))) require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower()) // double sign again, same slashing period - keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt) + keeper.handleDoubleSign(ctx, valConsPubKey.Address(), 0, time.Unix(0, 0), amtInt) // should be jailed require.True(t, sk.Validator(ctx, addr).GetJailed()) // update block height ctx = ctx.WithBlockHeight(int64(2)) // unjail to measure power - sk.Unjail(ctx, val) + sk.Unjail(ctx, valConsAddr) // power should be equal, no more should have been slashed expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))) require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower()) // double sign again, new slashing period - keeper.handleDoubleSign(ctx, val.Address(), 2, time.Unix(0, 0), amtInt) + keeper.handleDoubleSign(ctx, valConsPubKey.Address(), 2, time.Unix(0, 0), amtInt) // should be jailed require.True(t, sk.Validator(ctx, addr).GetJailed()) // unjail to measure power - sk.Unjail(ctx, val) + sk.Unjail(ctx, valConsAddr) // power should be reduced expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(18).Quo(sdk.NewDec(20))) require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower()) @@ -120,7 +125,7 @@ func TestHandleAbsentValidator(t *testing.T) { // initial setup ctx, ck, sk, _, keeper := createTestInput(t) - sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) + sk = sk.WithHooks(keeper.Hooks()) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) sh := stake.NewHandler(sk) @@ -162,7 +167,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.SignedBlocksCounter) // validator should be bonded still - validator, _ := sk.GetValidatorByPubKey(ctx, val) + validator, _ := sk.GetValidatorByConsPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) pool := sk.GetPool(ctx) require.Equal(t, amtInt, pool.BondedTokens.RoundInt64()) @@ -176,7 +181,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter) // validator should have been jailed - validator, _ = sk.GetValidatorByPubKey(ctx, val) + validator, _ = sk.GetValidatorByConsPubKey(ctx, val) require.Equal(t, sdk.Unbonding, validator.GetStatus()) // unrevocation should fail prior to jail expiration @@ -189,7 +194,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, got.IsOK()) // validator should be rebonded now - validator, _ = sk.GetValidatorByPubKey(ctx, val) + validator, _ = sk.GetValidatorByConsPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) // validator should have been slashed @@ -207,7 +212,7 @@ func TestHandleAbsentValidator(t *testing.T) { height++ ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) - validator, _ = sk.GetValidatorByPubKey(ctx, val) + validator, _ = sk.GetValidatorByConsPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) // 500 signed blocks @@ -223,7 +228,7 @@ func TestHandleAbsentValidator(t *testing.T) { ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) } - validator, _ = sk.GetValidatorByPubKey(ctx, val) + validator, _ = sk.GetValidatorByConsPubKey(ctx, val) require.Equal(t, sdk.Unbonding, validator.GetStatus()) } @@ -258,7 +263,7 @@ func TestHandleNewValidator(t *testing.T) { require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) // validator should be bonded still, should not have been jailed or slashed - validator, _ := sk.GetValidatorByPubKey(ctx, val) + validator, _ := sk.GetValidatorByConsPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) pool := sk.GetPool(ctx) require.Equal(t, int64(100), pool.BondedTokens.RoundInt64()) @@ -292,7 +297,7 @@ func TestHandleAlreadyJailed(t *testing.T) { } // validator should have been jailed and slashed - validator, _ := sk.GetValidatorByPubKey(ctx, val) + validator, _ := sk.GetValidatorByConsPubKey(ctx, val) require.Equal(t, sdk.Unbonding, validator.GetStatus()) // validator should have been slashed @@ -303,7 +308,7 @@ func TestHandleAlreadyJailed(t *testing.T) { keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) // validator should not have been slashed twice - validator, _ = sk.GetValidatorByPubKey(ctx, val) + validator, _ = sk.GetValidatorByConsPubKey(ctx, val) require.Equal(t, amtInt-1, validator.GetTokens().RoundInt64()) } diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index 81003a968a..fe273be5eb 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -78,7 +78,7 @@ func TestBeginBlocker(t *testing.T) { } // validator should be jailed - validator, found := sk.GetValidatorByPubKey(ctx, pk) + validator, found := sk.GetValidatorByConsPubKey(ctx, pk) require.True(t, found) require.Equal(t, sdk.Unbonding, validator.GetStatus()) } diff --git a/x/stake/client/cli/flags.go b/x/stake/client/cli/flags.go index d0e83ab3c6..4c36be0b54 100644 --- a/x/stake/client/cli/flags.go +++ b/x/stake/client/cli/flags.go @@ -48,8 +48,8 @@ func init() { fsDescriptionEdit.String(FlagIdentity, types.DoNotModifyDesc, "optional identity signature (ex. UPort or Keybase)") fsDescriptionEdit.String(FlagWebsite, types.DoNotModifyDesc, "optional website") fsDescriptionEdit.String(FlagDetails, types.DoNotModifyDesc, "optional details") - fsValidator.String(FlagAddressValidator, "", "hex address of the validator") - fsDelegator.String(FlagAddressDelegator, "", "hex address of the delegator") - fsRedelegation.String(FlagAddressValidatorSrc, "", "hex address of the source validator") - fsRedelegation.String(FlagAddressValidatorDst, "", "hex address of the destination validator") + fsValidator.String(FlagAddressValidator, "", "bech address of the validator") + fsDelegator.String(FlagAddressDelegator, "", "bech address of the delegator") + fsRedelegation.String(FlagAddressValidatorSrc, "", "bech address of the source validator") + fsRedelegation.String(FlagAddressValidatorDst, "", "bech address of the destination validator") } diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 7a004bccd2..a7f8493081 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -32,7 +32,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ } // Manually set indexes for the first time - keeper.SetValidatorByPubKeyIndex(ctx, validator) + keeper.SetValidatorByConsAddr(ctx, validator) keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool) if validator.Status == sdk.Bonded { diff --git a/x/stake/handler.go b/x/stake/handler.go index e7641393db..005b3af7d0 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -68,7 +68,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k if found { return ErrValidatorOwnerExists(k.Codespace()).Result() } - _, found = k.GetValidatorByPubKey(ctx, msg.PubKey) + _, found = k.GetValidatorByConsPubKey(ctx, msg.PubKey) if found { return ErrValidatorPubKeyExists(k.Codespace()).Result() } @@ -78,7 +78,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k validator := NewValidator(msg.ValidatorAddr, msg.PubKey, msg.Description) k.SetValidator(ctx, validator) - k.SetValidatorByPubKeyIndex(ctx, validator) + k.SetValidatorByConsAddr(ctx, validator) // move coins from the msg.Address account to a (self-delegation) delegator account // the validator account and global shares are updated within here @@ -87,6 +87,11 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k return err.Result() } + // call the hook if present + k.OnValidatorCreated(ctx, validator.OperatorAddr) + accAddr := sdk.AccAddress(validator.OperatorAddr) + k.OnDelegationCreated(ctx, accAddr, validator.OperatorAddr) + tags := sdk.NewTags( tags.Action, tags.ActionCreateValidator, tags.DstValidator, []byte(msg.ValidatorAddr.String()), @@ -146,6 +151,9 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) return err.Result() } + // call the hook if present + k.OnDelegationCreated(ctx, msg.DelegatorAddr, validator.OperatorAddr) + tags := sdk.NewTags( tags.Action, tags.ActionDelegate, tags.Delegator, []byte(msg.DelegatorAddr.String()), diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 70a21c171c..4bc92c0b73 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -81,8 +81,9 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // slash and jail the first validator - keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewDecWithPrec(5, 1)) - keeper.Jail(ctx, keep.PKs[0]) + consAddr0 := sdk.ConsAddress(keep.PKs[0].Address()) + keeper.Slash(ctx, consAddr0, 0, initBond, sdk.NewDecWithPrec(5, 1)) + keeper.Jail(ctx, consAddr0) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding @@ -198,11 +199,12 @@ func TestLegacyValidatorDelegations(t *testing.T) { setInstantUnbondPeriod(keeper, ctx) bondAmount := int64(10) - valAddr, valPubKey := sdk.ValAddress(keep.Addrs[0]), keep.PKs[0] + valAddr := sdk.ValAddress(keep.Addrs[0]) + valConsPubKey, valConsAddr := keep.PKs[0], sdk.ConsAddress(keep.PKs[0].Address()) delAddr := keep.Addrs[1] // create validator - msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount) + msgCreateVal := newTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount) got := handleMsgCreateValidator(ctx, msgCreateVal, keeper) require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) @@ -264,7 +266,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { require.Equal(t, bondAmount*2, validator.Tokens.RoundInt64()) // unjail the validator now that is has non-zero self-delegated shares - keeper.Unjail(ctx, valPubKey) + keeper.Unjail(ctx, valConsAddr) // verify the validator can now accept delegations msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount) @@ -911,6 +913,7 @@ func TestCliffValidator(t *testing.T) { func TestBondUnbondRedelegateSlashTwice(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2] + consAddr0 := sdk.ConsAddress(keep.PKs[0].Address()) msgCreateValidator := newTestMsgCreateValidator(valA, keep.PKs[0], 10) got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) @@ -944,7 +947,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { require.Equal(t, sdk.NewDec(6), delegation.Shares) // slash the validator by half - keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewDecWithPrec(5, 1)) + keeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1)) // unbonding delegation should have been slashed by half unbonding, found := keeper.GetUnbondingDelegation(ctx, del, valA) @@ -968,7 +971,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // slash the validator for an infraction committed after the unbonding and redelegation begin ctx = ctx.WithBlockHeight(3) - keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewDecWithPrec(5, 1)) + keeper.Slash(ctx, consAddr0, 2, 10, sdk.NewDecWithPrec(5, 1)) // unbonding delegation should be unchanged unbonding, found = keeper.GetUnbondingDelegation(ctx, del, valA) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index ef09a307e1..6ac51ac196 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -66,6 +66,12 @@ func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { // remove a delegation from store func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) { + + // call the hook if present + if k.hooks != nil { + k.hooks.OnDelegationRemoved(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr) + } + store := ctx.KVStore(k.storeKey) store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr)) } @@ -275,6 +281,11 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co k.SetDelegation(ctx, delegation) k.UpdateValidator(ctx, validator) + // call the hook if present + if k.hooks != nil { + k.hooks.OnDelegationSharesModified(ctx, delegation.DelegatorAddr, validator.OperatorAddr) + } + return } @@ -333,6 +344,11 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA k.RemoveValidator(ctx, validator.OperatorAddr) } + // call the hook if present + if k.hooks != nil { + k.hooks.OnDelegationSharesModified(ctx, delegation.DelegatorAddr, validator.OperatorAddr) + } + return amount, nil } diff --git a/x/stake/keeper/hooks.go b/x/stake/keeper/hooks.go new file mode 100644 index 0000000000..81bf5594ba --- /dev/null +++ b/x/stake/keeper/hooks.go @@ -0,0 +1,54 @@ +//nolint +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Expose the hooks if present +func (k Keeper) OnValidatorCreated(ctx sdk.Context, address sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnValidatorCreated(ctx, address) + } +} +func (k Keeper) OnValidatorCommissionChange(ctx sdk.Context, address sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnValidatorCommissionChange(ctx, address) + } +} + +func (k Keeper) OnValidatorRemoved(ctx sdk.Context, address sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnValidatorRemoved(ctx, address) + } +} + +func (k Keeper) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) { + if k.hooks != nil { + k.hooks.OnValidatorBonded(ctx, address) + } +} + +func (k Keeper) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) { + if k.hooks != nil { + k.hooks.OnValidatorBeginUnbonding(ctx, address) + } +} + +func (k Keeper) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnDelegationCreated(ctx, delAddr, valAddr) + } +} + +func (k Keeper) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnDelegationSharesModified(ctx, delAddr, valAddr) + } +} + +func (k Keeper) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnDelegationRemoved(ctx, delAddr, valAddr) + } +} diff --git a/x/stake/keeper/keeper.go b/x/stake/keeper/keeper.go index a3754f7504..82170a4aed 100644 --- a/x/stake/keeper/keeper.go +++ b/x/stake/keeper/keeper.go @@ -10,11 +10,11 @@ import ( // keeper of the stake store type Keeper struct { - storeKey sdk.StoreKey - storeTKey sdk.StoreKey - cdc *codec.Codec - bankKeeper bank.Keeper - validatorHooks sdk.ValidatorHooks + storeKey sdk.StoreKey + storeTKey sdk.StoreKey + cdc *codec.Codec + bankKeeper bank.Keeper + hooks sdk.StakingHooks // codespace codespace sdk.CodespaceType @@ -22,22 +22,22 @@ type Keeper struct { func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, ck bank.Keeper, codespace sdk.CodespaceType) Keeper { keeper := Keeper{ - storeKey: key, - storeTKey: tkey, - cdc: cdc, - bankKeeper: ck, - validatorHooks: nil, - codespace: codespace, + storeKey: key, + storeTKey: tkey, + cdc: cdc, + bankKeeper: ck, + hooks: nil, + codespace: codespace, } return keeper } // Set the validator hooks -func (k Keeper) WithValidatorHooks(v sdk.ValidatorHooks) Keeper { - if k.validatorHooks != nil { +func (k Keeper) WithHooks(sh sdk.StakingHooks) Keeper { + if k.hooks != nil { panic("cannot set validator hooks twice") } - k.validatorHooks = v + k.hooks = sh return k } diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index c445e25524..91e6a69708 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -3,8 +3,6 @@ package keeper import ( "encoding/binary" - "github.com/tendermint/tendermint/crypto" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -17,7 +15,7 @@ var ( ParamKey = []byte{0x00} // key for parameters relating to staking PoolKey = []byte{0x01} // key for the staking pools ValidatorsKey = []byte{0x02} // prefix for each key to a validator - ValidatorsByPubKeyIndexKey = []byte{0x03} // prefix for each key to a validator index, by pubkey + ValidatorsByConsAddrKey = []byte{0x03} // prefix for each key to a validator index, by pubkey ValidatorsBondedIndexKey = []byte{0x04} // prefix for each key to a validator index, for bonded validators ValidatorsByPowerIndexKey = []byte{0x05} // prefix for each key to a validator index, sorted by power ValidatorCliffIndexKey = []byte{0x06} // key for the validator index of the cliff validator @@ -44,8 +42,8 @@ func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { // gets the key for the validator with pubkey // VALUE: validator operator address ([]byte) -func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte { - return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...) +func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { + return append(ValidatorsByConsAddrKey, addr.Bytes()...) } // gets the key for the current validator group diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index e4c7a1c193..9872630a4e 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -3,10 +3,9 @@ package keeper import ( "fmt" - "github.com/tendermint/tendermint/crypto" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" + "github.com/tendermint/tendermint/crypto" ) // Implements ValidatorSet @@ -60,8 +59,17 @@ func (k Keeper) Validator(ctx sdk.Context, address sdk.ValAddress) sdk.Validator } // get the sdk.validator for a particular pubkey -func (k Keeper) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) sdk.Validator { - val, found := k.GetValidatorByPubKey(ctx, pubkey) +func (k Keeper) ValidatorByConsAddr(ctx sdk.Context, addr sdk.ConsAddress) sdk.Validator { + val, found := k.GetValidatorByConsAddr(ctx, addr) + if !found { + return nil + } + return val +} + +// get the sdk.validator for a particular pubkey +func (k Keeper) ValidatorByConsPubKey(ctx sdk.Context, consPubKey crypto.PubKey) sdk.Validator { + val, found := k.GetValidatorByConsPubKey(ctx, consPubKey) if !found { return nil } @@ -95,15 +103,16 @@ func (k Keeper) Delegation(ctx sdk.Context, addrDel sdk.AccAddress, addrVal sdk. return bond } -// iterate through the active validator set and perform the provided function -func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.AccAddress, fn func(index int64, delegation sdk.Delegation) (stop bool)) { +// iterate through all of the delegations from a delegator +func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.AccAddress, + fn func(index int64, del sdk.Delegation) (stop bool)) { + store := ctx.KVStore(k.storeKey) - key := GetDelegationsKey(delAddr) - iterator := sdk.KVStorePrefixIterator(store, key) - i := int64(0) - for ; iterator.Valid(); iterator.Next() { - delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) - stop := fn(i, delegation) // XXX is this safe will the fields be able to get written to? + delegatorPrefixKey := GetDelegationsKey(delAddr) + iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest + for i := int64(0); iterator.Valid(); iterator.Next() { + del := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) + stop := fn(i, del) if stop { break } diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 52dbd21c7e..ea378678ae 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -5,7 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/x/stake/types" - "github.com/tendermint/tendermint/crypto" ) // Slash a validator for an infraction committed at a known height @@ -24,7 +23,7 @@ import ( // not at a height in the future // // nolint: gocyclo -func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, power int64, slashFactor sdk.Dec) { +func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeight int64, power int64, slashFactor sdk.Dec) { logger := ctx.Logger().With("module", "x/stake") if slashFactor.LT(sdk.ZeroDec()) { @@ -36,7 +35,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in // ref https://github.com/cosmos/cosmos-sdk/issues/1348 // ref https://github.com/cosmos/cosmos-sdk/issues/1471 - validator, found := k.GetValidatorByPubKey(ctx, pubkey) + validator, found := k.GetValidatorByConsAddr(ctx, consAddr) if !found { // If not found, the validator must have been overslashed and removed - so we don't need to do anything // NOTE: Correctness dependent on invariant that unbonding delegations / redelegations must also have been completely @@ -44,7 +43,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in // Log the slash attempt for future reference (maybe we should tag it too) logger.Error(fmt.Sprintf( "WARNING: Ignored attempt to slash a nonexistent validator with address %s, we recommend you investigate immediately", - pubkey.Address())) + consAddr)) return } @@ -125,36 +124,28 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in } // jail a validator -func (k Keeper) Jail(ctx sdk.Context, pubkey crypto.PubKey) { - k.setJailed(ctx, pubkey, true) - validatorAddr, err := sdk.ValAddressFromHex(pubkey.Address().String()) - if err != nil { - panic(err.Error()) - } +func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) { + k.setJailed(ctx, consAddr, true) logger := ctx.Logger().With("module", "x/stake") - logger.Info(fmt.Sprintf("validator %s jailed", validatorAddr)) + logger.Info(fmt.Sprintf("validator %s jailed", consAddr)) // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 return } // unjail a validator -func (k Keeper) Unjail(ctx sdk.Context, pubkey crypto.PubKey) { - k.setJailed(ctx, pubkey, false) - validatorAddr, err := sdk.ValAddressFromHex(pubkey.Address().String()) - if err != nil { - panic(err.Error()) - } +func (k Keeper) Unjail(ctx sdk.Context, consAddr sdk.ConsAddress) { + k.setJailed(ctx, consAddr, false) logger := ctx.Logger().With("module", "x/stake") - logger.Info(fmt.Sprintf("validator %s unjailed", validatorAddr)) + logger.Info(fmt.Sprintf("validator %s unjailed", consAddr)) // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 return } // set the jailed flag on a validator -func (k Keeper) setJailed(ctx sdk.Context, pubkey crypto.PubKey, isJailed bool) { - validator, found := k.GetValidatorByPubKey(ctx, pubkey) +func (k Keeper) setJailed(ctx sdk.Context, consAddr sdk.ConsAddress, isJailed bool) { + validator, found := k.GetValidatorByConsAddr(ctx, sdk.ConsAddress(consAddr)) if !found { - panic(fmt.Errorf("validator with pubkey %s not found, cannot set jailed to %v", pubkey, isJailed)) + panic(fmt.Errorf("validator with consensus-Address %s not found, cannot set jailed to %v", consAddr, isJailed)) } validator.Jailed = isJailed k.UpdateValidator(ctx, validator) // update validator, possibly unbonding or bonding it diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 65bac2d808..c4a1edd415 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -27,7 +27,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) validator = keeper.UpdateValidator(ctx, validator) - keeper.SetValidatorByPubKeyIndex(ctx, validator) + keeper.SetValidatorByConsAddr(ctx, validator) } pool = keeper.GetPool(ctx) @@ -42,7 +42,7 @@ func TestRevocation(t *testing.T) { // setup ctx, keeper, _ := setupHelper(t, 10) addr := addrVals[0] - pk := PKs[0] + consAddr := sdk.ConsAddress(PKs[0].Address()) // initial state val, found := keeper.GetValidator(ctx, addr) @@ -50,13 +50,13 @@ func TestRevocation(t *testing.T) { require.False(t, val.GetJailed()) // test jail - keeper.Jail(ctx, pk) + keeper.Jail(ctx, consAddr) val, found = keeper.GetValidator(ctx, addr) require.True(t, found) require.True(t, val.GetJailed()) // test unjail - keeper.Unjail(ctx, pk) + keeper.Unjail(ctx, consAddr) val, found = keeper.GetValidator(ctx, addr) require.True(t, found) require.False(t, val.GetJailed()) @@ -179,24 +179,24 @@ func TestSlashRedelegation(t *testing.T) { // tests Slash at a future height (must panic) func TestSlashAtFutureHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) - pk := PKs[0] + consAddr := sdk.ConsAddress(PKs[0].Address()) fraction := sdk.NewDecWithPrec(5, 1) - require.Panics(t, func() { keeper.Slash(ctx, pk, 1, 10, fraction) }) + require.Panics(t, func() { keeper.Slash(ctx, consAddr, 1, 10, fraction) }) } // tests Slash at the current height func TestSlashValidatorAtCurrentHeight(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) - pk := PKs[0] + consAddr := sdk.ConsAddress(PKs[0].Address()) fraction := sdk.NewDecWithPrec(5, 1) oldPool := keeper.GetPool(ctx) - validator, found := keeper.GetValidatorByPubKey(ctx, pk) + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) - keeper.Slash(ctx, pk, ctx.BlockHeight(), 10, fraction) + keeper.Slash(ctx, consAddr, ctx.BlockHeight(), 10, fraction) // read updated state - validator, found = keeper.GetValidatorByPubKey(ctx, pk) + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) newPool := keeper.GetPool(ctx) @@ -209,7 +209,7 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) { // tests Slash at a previous height with an unbonding delegation func TestSlashWithUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - pk := PKs[0] + consAddr := sdk.ConsAddress(PKs[0].Address()) fraction := sdk.NewDecWithPrec(5, 1) // set an unbonding delegation @@ -227,9 +227,9 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // slash validator for the first time ctx = ctx.WithBlockHeight(12) oldPool := keeper.GetPool(ctx) - validator, found := keeper.GetValidatorByPubKey(ctx, pk) + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) - keeper.Slash(ctx, pk, 10, 10, fraction) + keeper.Slash(ctx, consAddr, 10, 10, fraction) // read updating unbonding delegation ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) @@ -241,7 +241,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // bonded tokens burned require.Equal(t, int64(3), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator - validator, found = keeper.GetValidatorByPubKey(ctx, pk) + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) // power decreased by 3 - 6 stake originally bonded at the time of infraction // was still bonded at the time of discovery and was slashed by half, 4 stake @@ -251,7 +251,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // slash validator again ctx = ctx.WithBlockHeight(13) - keeper.Slash(ctx, pk, 9, 10, fraction) + keeper.Slash(ctx, consAddr, 9, 10, fraction) ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) // balance decreased again @@ -261,7 +261,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // bonded tokens burned again require.Equal(t, int64(6), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator - validator, found = keeper.GetValidatorByPubKey(ctx, pk) + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) // power decreased by 3 again require.Equal(t, sdk.NewDec(4), validator.GetPower()) @@ -271,7 +271,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // on the unbonding delegation, but it will slash stake bonded since the infraction // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 ctx = ctx.WithBlockHeight(13) - keeper.Slash(ctx, pk, 9, 10, fraction) + keeper.Slash(ctx, consAddr, 9, 10, fraction) ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) // balance unchanged @@ -281,7 +281,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // bonded tokens burned again require.Equal(t, int64(9), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator - validator, found = keeper.GetValidatorByPubKey(ctx, pk) + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) // power decreased by 3 again require.Equal(t, sdk.NewDec(1), validator.GetPower()) @@ -291,7 +291,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // on the unbonding delegation, but it will slash stake bonded since the infraction // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 ctx = ctx.WithBlockHeight(13) - keeper.Slash(ctx, pk, 9, 10, fraction) + keeper.Slash(ctx, consAddr, 9, 10, fraction) ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) // balance unchanged @@ -303,14 +303,14 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // read updated validator // power decreased by 1 again, validator is out of stake // ergo validator should have been removed from the store - _, found = keeper.GetValidatorByPubKey(ctx, pk) + _, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.False(t, found) } // tests Slash at a previous height with a redelegation func TestSlashWithRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) - pk := PKs[0] + consAddr := sdk.ConsAddress(PKs[0].Address()) fraction := sdk.NewDecWithPrec(5, 1) // set a redelegation @@ -343,9 +343,9 @@ func TestSlashWithRedelegation(t *testing.T) { // slash validator ctx = ctx.WithBlockHeight(12) oldPool := keeper.GetPool(ctx) - validator, found := keeper.GetValidatorByPubKey(ctx, pk) + validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) - keeper.Slash(ctx, pk, 10, 10, fraction) + keeper.Slash(ctx, consAddr, 10, 10, fraction) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -357,7 +357,7 @@ func TestSlashWithRedelegation(t *testing.T) { // bonded tokens burned require.Equal(t, int64(5), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator - validator, found = keeper.GetValidatorByPubKey(ctx, pk) + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) // power decreased by 2 - 4 stake originally bonded at the time of infraction // was still bonded at the time of discovery and was slashed by half, 4 stake @@ -367,9 +367,9 @@ func TestSlashWithRedelegation(t *testing.T) { // slash the validator again ctx = ctx.WithBlockHeight(12) - validator, found = keeper.GetValidatorByPubKey(ctx, pk) + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) - require.NotPanics(t, func() { keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) }) + require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) }) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -381,16 +381,16 @@ func TestSlashWithRedelegation(t *testing.T) { // seven bonded tokens burned require.Equal(t, int64(12), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator - validator, found = keeper.GetValidatorByPubKey(ctx, pk) + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) // power decreased by 4 require.Equal(t, sdk.NewDec(4), validator.GetPower()) // slash the validator again, by 100% ctx = ctx.WithBlockHeight(12) - validator, found = keeper.GetValidatorByPubKey(ctx, pk) + validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.True(t, found) - keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) + keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -403,16 +403,16 @@ func TestSlashWithRedelegation(t *testing.T) { require.Equal(t, int64(16), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator // validator decreased to zero power, should have been removed from the store - _, found = keeper.GetValidatorByPubKey(ctx, pk) + _, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.False(t, found) // slash the validator again, by 100% // no stake remains to be slashed ctx = ctx.WithBlockHeight(12) // validator no longer in the store - _, found = keeper.GetValidatorByPubKey(ctx, pk) + _, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.False(t, found) - keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) + keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -425,7 +425,7 @@ func TestSlashWithRedelegation(t *testing.T) { require.Equal(t, int64(16), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator // power still zero, still not in the store - _, found = keeper.GetValidatorByPubKey(ctx, pk) + _, found = keeper.GetValidatorByConsAddr(ctx, consAddr) require.False(t, found) } @@ -472,9 +472,10 @@ func TestSlashBoth(t *testing.T) { // slash validator ctx = ctx.WithBlockHeight(12) oldPool := keeper.GetPool(ctx) - validator, found := keeper.GetValidatorByPubKey(ctx, PKs[0]) + validator, found := keeper.GetValidatorByConsPubKey(ctx, PKs[0]) require.True(t, found) - keeper.Slash(ctx, PKs[0], 10, 10, fraction) + consAddr0 := sdk.ConsAddress(PKs[0].Address()) + keeper.Slash(ctx, consAddr0, 10, 10, fraction) // read updating redelegation rdA, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -488,7 +489,7 @@ func TestSlashBoth(t *testing.T) { // bonded tokens burned require.Equal(t, int64(3), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator - validator, found = keeper.GetValidatorByPubKey(ctx, PKs[0]) + validator, found = keeper.GetValidatorByConsPubKey(ctx, PKs[0]) require.True(t, found) // power not decreased, all stake was bonded since require.Equal(t, sdk.NewDec(10), validator.GetPower()) diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 996bf06bf5..af7d77e207 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -58,14 +58,25 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator ty return validator, true } -// get a single validator by pubkey -func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (validator types.Validator, found bool) { +// get a single validator by consensus address +func (k Keeper) GetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) (validator types.Validator, found bool) { store := ctx.KVStore(k.storeKey) - addr := store.Get(GetValidatorByPubKeyIndexKey(pubkey)) - if addr == nil { + opAddr := store.Get(GetValidatorByConsAddrKey(consAddr)) + if opAddr == nil { return validator, false } - return k.GetValidator(ctx, addr) + return k.GetValidator(ctx, opAddr) +} + +// get a single validator by pubkey +func (k Keeper) GetValidatorByConsPubKey(ctx sdk.Context, consPubKey crypto.PubKey) (validator types.Validator, found bool) { + store := ctx.KVStore(k.storeKey) + consAddr := sdk.ConsAddress(consPubKey.Address()) + opAddr := store.Get(GetValidatorByConsAddrKey(consAddr)) + if opAddr == nil { + return validator, false + } + return k.GetValidator(ctx, opAddr) } // set the main record holding validator details @@ -76,9 +87,11 @@ func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { } // validator index -func (k Keeper) SetValidatorByPubKeyIndex(ctx sdk.Context, validator types.Validator) { +// TODO change to SetValidatorByConsAddr? used for retrieving from ConsPubkey as well- kinda confusing +func (k Keeper) SetValidatorByConsAddr(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - store.Set(GetValidatorByPubKeyIndexKey(validator.ConsPubKey), validator.OperatorAddr) + consAddr := sdk.ConsAddress(validator.OperatorAddr.Bytes()) + store.Set(GetValidatorByConsAddrKey(consAddr), validator.OperatorAddr) } // validator index @@ -622,8 +635,8 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) // call the unbond hook if present - if k.validatorHooks != nil { - k.validatorHooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) + if k.hooks != nil { + k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) } // return updated validator @@ -657,8 +670,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) // call the bond hook if present - if k.validatorHooks != nil { - k.validatorHooks.OnValidatorBonded(ctx, validator.ConsAddress()) + if k.hooks != nil { + k.hooks.OnValidatorBonded(ctx, validator.ConsAddress()) } // return updated validator @@ -668,6 +681,11 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. // remove the validator record and associated indexes func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { + // call the hook if present + if k.hooks != nil { + k.hooks.OnValidatorRemoved(ctx, address) + } + // first retrieve the old validator record validator, found := k.GetValidator(ctx, address) if !found { @@ -678,7 +696,7 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { store := ctx.KVStore(k.storeKey) pool := k.GetPool(ctx) store.Delete(GetValidatorKey(address)) - store.Delete(GetValidatorByPubKeyIndexKey(validator.ConsPubKey)) + store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address()))) store.Delete(GetValidatorsByPowerIndexKey(validator, pool)) // delete from the current and power weighted validator groups if the validator @@ -727,3 +745,36 @@ func ensureValidatorFound(found bool, ownerAddr []byte) { panic(fmt.Sprintf("validator record not found for address: %X\n", ownerAddr)) } } + +//__________________________________________________________________________ + +// XXX remove this code - this is should be superceded by commission work that bez is doing +// get a single validator +func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, addr sdk.ValAddress, newCommission sdk.Dec) sdk.Error { + + // call the hook if present + if k.hooks != nil { + k.hooks.OnValidatorCommissionChange(ctx, addr) + } + + validator, found := k.GetValidator(ctx, addr) + + // check for errors + switch { + case !found: + return types.ErrNoValidatorFound(k.Codespace()) + case newCommission.LT(sdk.ZeroDec()): + return types.ErrCommissionNegative(k.Codespace()) + case newCommission.GT(validator.CommissionMax): + return types.ErrCommissionBeyondMax(k.Codespace()) + //case rateChange(Commission) > CommissionMaxChange: // XXX XXX XXX TODO implementation + //return types.ErrCommissionPastRate(k.Codespace()) + } + + // TODO adjust all the commission terms appropriately + + validator.Commission = newCommission + + k.SetValidator(ctx, validator) + return nil +} diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index e23d3b0aad..a541600d9f 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -260,12 +260,13 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { require.Equal(t, sdk.Unbonded, validator.Status) require.Equal(t, int64(100), validator.Tokens.RoundInt64()) keeper.SetPool(ctx, pool) - keeper.SetValidatorByPubKeyIndex(ctx, validator) + keeper.SetValidatorByConsAddr(ctx, validator) validator = keeper.UpdateValidator(ctx, validator) require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) // slash the validator by 100% - keeper.Slash(ctx, PKs[0], 0, 100, sdk.OneDec()) + consAddr0 := sdk.ConsAddress(PKs[0].Address()) + keeper.Slash(ctx, consAddr0, 0, 100, sdk.OneDec()) // validator should have been deleted _, found := keeper.GetValidator(ctx, addrVals[0]) require.False(t, found) diff --git a/x/stake/stake.go b/x/stake/stake.go index 18b99fd4a0..6b4036d281 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -35,7 +35,7 @@ var ( NewKeeper = keeper.NewKeeper GetValidatorKey = keeper.GetValidatorKey - GetValidatorByPubKeyIndexKey = keeper.GetValidatorByPubKeyIndexKey + GetValidatorByConsAddrKey = keeper.GetValidatorByConsAddrKey GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey GetValidatorsByPowerIndexKey = keeper.GetValidatorsByPowerIndexKey GetTendermintUpdatesTKey = keeper.GetTendermintUpdatesTKey @@ -44,7 +44,7 @@ var ( ParamKey = keeper.ParamKey PoolKey = keeper.PoolKey ValidatorsKey = keeper.ValidatorsKey - ValidatorsByPubKeyIndexKey = keeper.ValidatorsByPubKeyIndexKey + ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey ValidatorsBondedIndexKey = keeper.ValidatorsBondedIndexKey ValidatorsByPowerIndexKey = keeper.ValidatorsByPowerIndexKey ValidatorCliffIndexKey = keeper.ValidatorCliffIndexKey diff --git a/x/stake/types/codec.go b/x/stake/types/codec.go index aa4f64f8a2..4921cdf8e2 100644 --- a/x/stake/types/codec.go +++ b/x/stake/types/codec.go @@ -22,6 +22,5 @@ func init() { cdc := codec.New() RegisterCodec(cdc) codec.RegisterCrypto(cdc) - MsgCdc = cdc - //MsgCdc = cdc.Seal() //TODO use when upgraded to go-amino 0.9.10 + MsgCdc = cdc.Seal() } diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 38a94c3695..57ac70a571 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -89,7 +89,7 @@ var _ sdk.Delegation = Delegation{} // nolint - for sdk.Delegation func (d Delegation) GetDelegator() sdk.AccAddress { return d.DelegatorAddr } func (d Delegation) GetValidator() sdk.ValAddress { return d.ValidatorAddr } -func (d Delegation) GetBondShares() sdk.Dec { return d.Shares } +func (d Delegation) GetShares() sdk.Dec { return d.Shares } // HumanReadableString returns a human readable string representation of a // Delegation. An error is returned if the Delegation's delegator or validator diff --git a/x/stake/types/errors.go b/x/stake/types/errors.go index 366012bbfb..541ad3d7b9 100644 --- a/x/stake/types/errors.go +++ b/x/stake/types/errors.go @@ -65,6 +65,14 @@ func ErrCommissionHuge(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than 100%") } +func ErrCommissionBeyondMax(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than preset commission maximum") +} + +func ErrCommissionPastRate(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidValidator, "commission change is greater than the commission rate, please wait before changing your commission more") +} + func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil") } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 6c5066a783..c15d43396c 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -470,12 +470,14 @@ func (v Validator) IsUnbonded(ctx sdk.Context) bool { var _ sdk.Validator = Validator{} // nolint - for sdk.Validator -func (v Validator) GetJailed() bool { return v.Jailed } -func (v Validator) GetMoniker() string { return v.Description.Moniker } -func (v Validator) GetStatus() sdk.BondStatus { return v.Status } -func (v Validator) GetOperator() sdk.ValAddress { return v.OperatorAddr } -func (v Validator) GetPubKey() crypto.PubKey { return v.ConsPubKey } -func (v Validator) GetPower() sdk.Dec { return v.BondedTokens() } -func (v Validator) GetTokens() sdk.Dec { return v.Tokens } -func (v Validator) GetDelegatorShares() sdk.Dec { return v.DelegatorShares } -func (v Validator) GetBondHeight() int64 { return v.BondHeight } +func (v Validator) GetJailed() bool { return v.Jailed } +func (v Validator) GetMoniker() string { return v.Description.Moniker } +func (v Validator) GetStatus() sdk.BondStatus { return v.Status } +func (v Validator) GetOperator() sdk.ValAddress { return v.OperatorAddr } +func (v Validator) GetPubKey() crypto.PubKey { return v.ConsPubKey } +func (v Validator) GetConsAddr() sdk.ConsAddress { return sdk.ConsAddress(v.ConsPubKey.Address()) } +func (v Validator) GetPower() sdk.Dec { return v.BondedTokens() } +func (v Validator) GetTokens() sdk.Dec { return v.Tokens } +func (v Validator) GetCommission() sdk.Dec { return v.Commission } +func (v Validator) GetDelegatorShares() sdk.Dec { return v.DelegatorShares } +func (v Validator) GetBondHeight() int64 { return v.BondHeight } From ab61695be97939cd5892de96aecf39cb60953cbe Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 20 Sep 2018 20:39:23 -0400 Subject: [PATCH 02/22] PENDING --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index e07319d49e..d9b94175f0 100644 --- a/PENDING.md +++ b/PENDING.md @@ -49,6 +49,7 @@ BREAKING CHANGES * [store] Change storeInfo within the root multistore to use tmhash instead of ripemd160 \#2308 * [codec] \#2324 All referrences to wire have been renamed to codec. Additionally, wire.NewCodec is now codec.New(). * [types] \#2343 Make sdk.Msg have a names field, to facilitate automatic tagging. + * [x/staking] \#2244 staking now holds a consensus-address-index instead of a consensus-pubkey-index * Tendermint From 0f903bdd52d6ef069b66599756595e723cf7e545 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 20 Sep 2018 21:17:50 -0400 Subject: [PATCH 03/22] finished pulling in, compiles --- types/stake.go | 38 +++++++++++++------------ x/gov/endblocker_test.go | 51 +++++++--------------------------- x/gov/genesis.go | 6 ++-- x/gov/handler.go | 10 +++---- x/gov/keeper.go | 19 +++++++------ x/gov/keeper_test.go | 9 +++--- x/gov/procedures.go | 8 ++---- x/gov/proposals.go | 27 +++++++++--------- x/gov/simulation/msgs.go | 5 ++-- x/gov/tally.go | 4 +-- x/gov/tally_test.go | 2 +- x/slashing/genesis.go | 2 +- x/slashing/handler.go | 2 +- x/slashing/hooks.go | 12 ++------ x/stake/genesis.go | 2 +- x/stake/handler.go | 8 ------ x/stake/keeper/delegation.go | 15 ---------- x/stake/keeper/hooks.go | 54 ------------------------------------ x/stake/keeper/keeper.go | 4 +-- x/stake/keeper/validator.go | 38 ------------------------- x/stake/types/validator.go | 2 +- 21 files changed, 80 insertions(+), 238 deletions(-) delete mode 100644 x/stake/keeper/hooks.go diff --git a/types/stake.go b/types/stake.go index 0b9f32b4b8..b8740a3cb9 100644 --- a/types/stake.go +++ b/types/stake.go @@ -37,22 +37,23 @@ func (b BondStatus) Equal(b2 BondStatus) bool { // validator for a delegated proof of stake system type Validator interface { - GetJailed() bool // whether the validator is jailed - GetMoniker() string // moniker of the validator - GetStatus() BondStatus // status of the validator - GetOperator() ValAddress // operator address to receive/return validators coins - GetPubKey() crypto.PubKey // validation pubkey - GetPower() Dec // validation power - GetTokens() Dec // validation tokens - GetDelegatorShares() Dec // Total out standing delegator shares - GetBondHeight() int64 // height in which the validator became active + GetJailed() bool // whether the validator is jailed + GetMoniker() string // moniker of the validator + GetStatus() BondStatus // status of the validator + GetOperator() ValAddress // operator address to receive/return validators coins + GetConsPubKey() crypto.PubKey // validation pubkey + GetConsAddr() ConsAddress // validation pubkey + GetPower() Dec // validation power + GetTokens() Dec // validation tokens + GetDelegatorShares() Dec // Total out standing delegator shares + GetBondHeight() int64 // height in which the validator became active } // validator which fulfills abci validator interface for use in Tendermint func ABCIValidator(v Validator) abci.Validator { return abci.Validator{ - PubKey: tmtypes.TM2PB.PubKey(v.GetPubKey()), - Address: v.GetPubKey().Address(), + PubKey: tmtypes.TM2PB.PubKey(v.GetConsPubKey()), + Address: v.GetConsPubKey().Address(), Power: v.GetPower().RoundInt64(), } } @@ -67,14 +68,15 @@ type ValidatorSet interface { IterateValidatorsBonded(Context, func(index int64, validator Validator) (stop bool)) - Validator(Context, ValAddress) Validator // get a particular validator by operator - ValidatorByPubKey(Context, crypto.PubKey) Validator // get a particular validator by signing PubKey - TotalPower(Context) Dec // total power of the validator set + Validator(Context, ValAddress) Validator // get a particular validator by operator address + ValidatorByConsPubKey(Context, crypto.PubKey) Validator // get a particular validator by consensus PubKey + ValidatorByConsAddr(Context, ConsAddress) Validator // get a particular validator by consensus address + TotalPower(Context) Dec // total power of the validator set // slash the validator and delegators of the validator, specifying offence height, offence power, and slash fraction - Slash(Context, crypto.PubKey, int64, int64, Dec) - Jail(Context, crypto.PubKey) // jail a validator - Unjail(Context, crypto.PubKey) // unjail a validator + Slash(Context, ConsAddress, int64, int64, Dec) + Jail(Context, ConsAddress) // jail a validator + Unjail(Context, ConsAddress) // unjail a validator // Delegation allows for getting a particular delegation for a given validator // and delegator outside the scope of the staking module. @@ -87,7 +89,7 @@ type ValidatorSet interface { type Delegation interface { GetDelegator() AccAddress // delegator AccAddress for the bond GetValidator() ValAddress // validator operator address - GetBondShares() Dec // amount of validator's shares + GetShares() Dec // amount of validator's shares held in this delegation } // properties for the set of all delegations for a particular diff --git a/x/gov/endblocker_test.go b/x/gov/endblocker_test.go index 4cbd1d7588..710ecb1dba 100644 --- a/x/gov/endblocker_test.go +++ b/x/gov/endblocker_test.go @@ -2,7 +2,6 @@ package gov import ( "testing" - "time" "github.com/stretchr/testify/require" @@ -29,18 +28,12 @@ func TestTickExpiredDepositPeriod(t *testing.T) { require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - newHeader := ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) - ctx = ctx.WithBlockHeader(newHeader) - + ctx = ctx.WithBlockHeight(10) EndBlocker(ctx, keeper) require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - newHeader = ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod) - ctx = ctx.WithBlockHeader(newHeader) - + ctx = ctx.WithBlockHeight(250) require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) EndBlocker(ctx, keeper) @@ -66,10 +59,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - newHeader := ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(2) * time.Second) - ctx = ctx.WithBlockHeader(newHeader) - + ctx = ctx.WithBlockHeight(10) EndBlocker(ctx, keeper) require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) @@ -78,20 +68,14 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { res = govHandler(ctx, newProposalMsg2) require.True(t, res.IsOK()) - newHeader = ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(time.Duration(-1) * time.Second) - ctx = ctx.WithBlockHeader(newHeader) - + ctx = ctx.WithBlockHeight(205) require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) EndBlocker(ctx, keeper) require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - newHeader = ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(5) * time.Second) - ctx = ctx.WithBlockHeader(newHeader) - + ctx = ctx.WithBlockHeight(215) require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) EndBlocker(ctx, keeper) @@ -121,10 +105,7 @@ func TestTickPassedDepositPeriod(t *testing.T) { require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - newHeader := ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) - ctx = ctx.WithBlockHeader(newHeader) - + ctx = ctx.WithBlockHeight(10) EndBlocker(ctx, keeper) require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) @@ -165,20 +146,14 @@ func TestTickPassedVotingPeriod(t *testing.T) { var proposalID int64 keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID) - newHeader := ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) - ctx = ctx.WithBlockHeader(newHeader) - + ctx = ctx.WithBlockHeight(10) newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin("steak", 5)}) res = govHandler(ctx, newDepositMsg) require.True(t, res.IsOK()) EndBlocker(ctx, keeper) - newHeader = ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod) - ctx = ctx.WithBlockHeader(newHeader) - + ctx = ctx.WithBlockHeight(215) require.True(t, shouldPopActiveProposalQueue(ctx, keeper)) depositsIterator := keeper.GetDeposits(ctx, proposalID) require.True(t, depositsIterator.Valid()) @@ -222,10 +197,7 @@ func TestSlashing(t *testing.T) { var proposalID int64 keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID) - newHeader := ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) - ctx = ctx.WithBlockHeader(newHeader) - + ctx = ctx.WithBlockHeight(10) require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus()) newVoteMsg := NewMsgVote(addrs[0], proposalID, OptionYes) @@ -234,10 +206,7 @@ func TestSlashing(t *testing.T) { EndBlocker(ctx, keeper) - newHeader = ctx.BlockHeader() - newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod) - ctx = ctx.WithBlockHeader(newHeader) - + ctx = ctx.WithBlockHeight(215) require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus()) EndBlocker(ctx, keeper) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 58273c8e84..15f952c000 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -1,8 +1,6 @@ package gov import ( - "time" - sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -29,10 +27,10 @@ func DefaultGenesisState() GenesisState { StartingProposalID: 1, DepositProcedure: DepositProcedure{ MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", 10)}, - MaxDepositPeriod: time.Duration(172800) * time.Second, + MaxDepositPeriod: 200, }, VotingProcedure: VotingProcedure{ - VotingPeriod: time.Duration(172800) * time.Second, + VotingPeriod: 200, }, TallyingProcedure: TallyingProcedure{ Threshold: sdk.NewDecWithPrec(5, 1), diff --git a/x/gov/handler.go b/x/gov/handler.go index e8cdf49aa5..84964b20f6 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -128,9 +128,9 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { for shouldPopActiveProposalQueue(ctx, keeper) { activeProposal := keeper.ActiveProposalQueuePop(ctx) - proposalStartTime := activeProposal.GetVotingStartTime() + proposalStartBlock := activeProposal.GetVotingStartBlock() votingPeriod := keeper.GetVotingProcedure(ctx).VotingPeriod - if ctx.BlockHeader().Time.Before(proposalStartTime.Add(votingPeriod)) { + if ctx.BlockHeight() < proposalStartBlock+votingPeriod { continue } @@ -155,7 +155,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { for _, valAddr := range nonVotingVals { val := keeper.ds.GetValidatorSet().Validator(ctx, valAddr) keeper.ds.GetValidatorSet().Slash(ctx, - val.GetPubKey(), + val.GetConsAddr(), ctx.BlockHeight(), val.GetPower().RoundInt64(), keeper.GetTallyingProcedure(ctx).GovernancePenalty) @@ -178,7 +178,7 @@ func shouldPopInactiveProposalQueue(ctx sdk.Context, keeper Keeper) bool { return false } else if peekProposal.GetStatus() != StatusDepositPeriod { return true - } else if !ctx.BlockHeader().Time.Before(peekProposal.GetSubmitTime().Add(depositProcedure.MaxDepositPeriod)) { + } else if ctx.BlockHeight() >= peekProposal.GetSubmitBlock()+depositProcedure.MaxDepositPeriod { return true } return false @@ -190,7 +190,7 @@ func shouldPopActiveProposalQueue(ctx sdk.Context, keeper Keeper) bool { if peekProposal == nil { return false - } else if !ctx.BlockHeader().Time.Before(peekProposal.GetVotingStartTime().Add(votingProcedure.VotingPeriod)) { + } else if ctx.BlockHeight() >= peekProposal.GetVotingStartBlock()+votingProcedure.VotingPeriod { return true } return false diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 8af2d1fd3a..bebcf51e78 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -66,14 +66,15 @@ func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description return nil } var proposal Proposal = &TextProposal{ - ProposalID: proposalID, - Title: title, - Description: description, - ProposalType: proposalType, - Status: StatusDepositPeriod, - TallyResult: EmptyTallyResult(), - TotalDeposit: sdk.Coins{}, - SubmitTime: ctx.BlockHeader().Time, + ProposalID: proposalID, + Title: title, + Description: description, + ProposalType: proposalType, + Status: StatusDepositPeriod, + TallyResult: EmptyTallyResult(), + TotalDeposit: sdk.Coins{}, + SubmitBlock: ctx.BlockHeight(), + VotingStartBlock: -1, // TODO: Make Time } keeper.SetProposal(ctx, proposal) keeper.InactiveProposalQueuePush(ctx, proposal) @@ -199,7 +200,7 @@ func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID int64, e } func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) { - proposal.SetVotingStartTime(ctx.BlockHeader().Time) + proposal.SetVotingStartBlock(ctx.BlockHeight()) proposal.SetStatus(StatusVotingPeriod) keeper.SetProposal(ctx, proposal) keeper.ActiveProposalQueuePush(ctx, proposal) diff --git a/x/gov/keeper_test.go b/x/gov/keeper_test.go index 91c41d7d7d..a61292b93e 100644 --- a/x/gov/keeper_test.go +++ b/x/gov/keeper_test.go @@ -2,7 +2,6 @@ package gov import ( "testing" - "time" "github.com/stretchr/testify/require" @@ -46,12 +45,12 @@ func TestActivateVotingPeriod(t *testing.T) { proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) - require.True(t, proposal.GetVotingStartTime().Equal(time.Time{})) + require.Equal(t, int64(-1), proposal.GetVotingStartBlock()) require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) keeper.activateVotingPeriod(ctx, proposal) - require.True(t, proposal.GetVotingStartTime().Equal(ctx.BlockHeader().Time)) + require.Equal(t, proposal.GetVotingStartBlock(), ctx.BlockHeight()) require.Equal(t, proposal.GetProposalID(), keeper.ActiveProposalQueuePeek(ctx).GetProposalID()) } @@ -78,7 +77,7 @@ func TestDeposits(t *testing.T) { // Check no deposits at beginning deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1]) require.False(t, found) - require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(time.Time{})) + require.Equal(t, keeper.GetProposal(ctx, proposalID).GetVotingStartBlock(), int64(-1)) require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) // Check first deposit @@ -115,7 +114,7 @@ func TestDeposits(t *testing.T) { require.Equal(t, addr1Initial.Minus(fourSteak), keeper.ck.GetCoins(ctx, addrs[1])) // Check that proposal moved to voting period - require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(ctx.BlockHeader().Time)) + require.Equal(t, ctx.BlockHeight(), keeper.GetProposal(ctx, proposalID).GetVotingStartBlock()) require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx)) require.Equal(t, proposalID, keeper.ActiveProposalQueuePeek(ctx).GetProposalID()) diff --git a/x/gov/procedures.go b/x/gov/procedures.go index e453add791..f74091c74f 100644 --- a/x/gov/procedures.go +++ b/x/gov/procedures.go @@ -1,15 +1,13 @@ package gov import ( - "time" - sdk "github.com/cosmos/cosmos-sdk/types" ) // Procedure around Deposits for governance type DepositProcedure struct { - MinDeposit sdk.Coins `json:"min_deposit"` // Minimum deposit for a proposal to enter voting period. - MaxDepositPeriod time.Duration `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months + MinDeposit sdk.Coins `json:"min_deposit"` // Minimum deposit for a proposal to enter voting period. + MaxDepositPeriod int64 `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months } // Procedure around Tallying votes in governance @@ -21,5 +19,5 @@ type TallyingProcedure struct { // Procedure around Voting in governance type VotingProcedure struct { - VotingPeriod time.Duration `json:"voting_period"` // Length of the voting period. + VotingPeriod int64 `json:"voting_period"` // Length of the voting period. } diff --git a/x/gov/proposals.go b/x/gov/proposals.go index e680699575..b4c6783673 100644 --- a/x/gov/proposals.go +++ b/x/gov/proposals.go @@ -3,7 +3,6 @@ package gov import ( "encoding/json" "fmt" - "time" "github.com/pkg/errors" @@ -31,14 +30,14 @@ type Proposal interface { GetTallyResult() TallyResult SetTallyResult(TallyResult) - GetSubmitTime() time.Time - SetSubmitTime(time.Time) + GetSubmitBlock() int64 + SetSubmitBlock(int64) GetTotalDeposit() sdk.Coins SetTotalDeposit(sdk.Coins) - GetVotingStartTime() time.Time - SetVotingStartTime(time.Time) + GetVotingStartBlock() int64 + SetVotingStartBlock(int64) } // checks if two proposals are equal @@ -49,9 +48,9 @@ func ProposalEqual(proposalA Proposal, proposalB Proposal) bool { proposalA.GetProposalType() == proposalB.GetProposalType() && proposalA.GetStatus() == proposalB.GetStatus() && proposalA.GetTallyResult().Equals(proposalB.GetTallyResult()) && - proposalA.GetSubmitTime().Equal(proposalB.GetSubmitTime()) && + proposalA.GetSubmitBlock() == proposalB.GetSubmitBlock() && proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit()) && - proposalA.GetVotingStartTime().Equal(proposalB.GetVotingStartTime()) { + proposalA.GetVotingStartBlock() == proposalB.GetVotingStartBlock() { return true } return false @@ -68,10 +67,10 @@ type TextProposal struct { Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected} TallyResult TallyResult `json:"tally_result"` // Result of Tallys - SubmitTime time.Time `json:"submit_block"` // Height of the block where TxGovSubmitProposal was included + SubmitBlock int64 `json:"submit_block"` // Height of the block where TxGovSubmitProposal was included TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit - VotingStartTime time.Time `json:"voting_start_block"` // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached + VotingStartBlock int64 `json:"voting_start_block"` // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached } // Implements Proposal Interface @@ -90,13 +89,13 @@ func (tp TextProposal) GetStatus() ProposalStatus { return tp.S func (tp *TextProposal) SetStatus(status ProposalStatus) { tp.Status = status } func (tp TextProposal) GetTallyResult() TallyResult { return tp.TallyResult } func (tp *TextProposal) SetTallyResult(tallyResult TallyResult) { tp.TallyResult = tallyResult } -func (tp TextProposal) GetSubmitTime() time.Time { return tp.SubmitTime } -func (tp *TextProposal) SetSubmitTime(submitTime time.Time) { tp.SubmitTime = submitTime } +func (tp TextProposal) GetSubmitBlock() int64 { return tp.SubmitBlock } +func (tp *TextProposal) SetSubmitBlock(submitBlock int64) { tp.SubmitBlock = submitBlock } func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit } func (tp *TextProposal) SetTotalDeposit(totalDeposit sdk.Coins) { tp.TotalDeposit = totalDeposit } -func (tp TextProposal) GetVotingStartTime() time.Time { return tp.VotingStartTime } -func (tp *TextProposal) SetVotingStartTime(votingStartTime time.Time) { - tp.VotingStartTime = votingStartTime +func (tp TextProposal) GetVotingStartBlock() int64 { return tp.VotingStartBlock } +func (tp *TextProposal) SetVotingStartBlock(votingStartBlock int64) { + tp.VotingStartBlock = votingStartBlock } //----------------------------------------------------------- diff --git a/x/gov/simulation/msgs.go b/x/gov/simulation/msgs.go index f46fe995e1..168081b188 100644 --- a/x/gov/simulation/msgs.go +++ b/x/gov/simulation/msgs.go @@ -4,7 +4,6 @@ import ( "fmt" "math" "math/rand" - "time" "github.com/tendermint/tendermint/crypto" @@ -69,8 +68,8 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe votingPeriod := k.GetVotingProcedure(ctx).VotingPeriod fops := make([]simulation.FutureOperation, numVotes+1) for i := 0; i < numVotes; i++ { - whenVote := ctx.BlockHeader().Time.Add(time.Duration(r.Int63n(int64(votingPeriod.Seconds()))) * time.Second) - fops[i] = simulation.FutureOperation{BlockTime: whenVote, Op: operationSimulateMsgVote(k, sk, keys[whoVotes[i]], proposalID)} + whenVote := ctx.BlockHeight() + r.Int63n(votingPeriod) + fops[i] = simulation.FutureOperation{BlockHeight: int(whenVote), Op: operationSimulateMsgVote(k, sk, keys[whoVotes[i]], proposalID)} } // 3) Make an operation to ensure slashes were done correctly. (Really should be a future invariant) // TODO: Find a way to check if a validator was slashed other than just checking their balance a block diff --git a/x/gov/tally.go b/x/gov/tally.go index a756eaf926..55fd81da24 100644 --- a/x/gov/tally.go +++ b/x/gov/tally.go @@ -53,10 +53,10 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall valAddrStr := delegation.GetValidator().String() if val, ok := currValidators[valAddrStr]; ok { - val.Minus = val.Minus.Add(delegation.GetBondShares()) + val.Minus = val.Minus.Add(delegation.GetShares()) currValidators[valAddrStr] = val - delegatorShare := delegation.GetBondShares().Quo(val.DelegatorShares) + delegatorShare := delegation.GetShares().Quo(val.DelegatorShares) votingPower := val.Power.Mul(delegatorShare) results[vote.Option] = results[vote.Option].Add(votingPower) diff --git a/x/gov/tally_test.go b/x/gov/tally_test.go index 6c6d64aa67..9c5348b2c7 100644 --- a/x/gov/tally_test.go +++ b/x/gov/tally_test.go @@ -440,7 +440,7 @@ func TestTallyJailedValidator(t *testing.T) { val2, found := sk.GetValidator(ctx, sdk.ValAddress(addrs[1])) require.True(t, found) - sk.Jail(ctx, val2.ConsPubKey) + sk.Jail(ctx, sdk.ConsAddress(val2.ConsPubKey.Address())) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() diff --git a/x/slashing/genesis.go b/x/slashing/genesis.go index 6e2809bfcb..43ae6b0d0a 100644 --- a/x/slashing/genesis.go +++ b/x/slashing/genesis.go @@ -8,7 +8,7 @@ import ( // InitGenesis initializes the keeper's address to pubkey map. func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) { for _, validator := range data.Validators { - keeper.addPubkey(ctx, validator.GetPubKey()) + keeper.addPubkey(ctx, validator.GetConsPubKey()) } return } diff --git a/x/slashing/handler.go b/x/slashing/handler.go index 4f342f62a0..740166d2af 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -34,7 +34,7 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result { return ErrValidatorNotJailed(k.codespace).Result() } - consAddr := sdk.ConsAddress(validator.GetPubKey().Address()) + consAddr := sdk.ConsAddress(validator.GetConsPubKey().Address()) info, found := k.getValidatorSigningInfo(ctx, consAddr) if !found { diff --git a/x/slashing/hooks.go b/x/slashing/hooks.go index 701a6b2cde..92c4cf85f8 100644 --- a/x/slashing/hooks.go +++ b/x/slashing/hooks.go @@ -29,10 +29,10 @@ type Hooks struct { k Keeper } -var _ sdk.StakingHooks = Hooks{} +var _ sdk.ValidatorHooks = Hooks{} // Return the wrapper struct -func (k Keeper) Hooks() Hooks { +func (k Keeper) ValidatorHooks() Hooks { return Hooks{k} } @@ -45,11 +45,3 @@ func (h Hooks) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) { func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) { h.k.onValidatorBeginUnbonding(ctx, address) } - -// nolint - unused hooks -func (h Hooks) OnValidatorCreated(_ sdk.Context, _ sdk.ValAddress) {} -func (h Hooks) OnValidatorCommissionChange(_ sdk.Context, _ sdk.ValAddress) {} -func (h Hooks) OnValidatorRemoved(_ sdk.Context, _ sdk.ValAddress) {} -func (h Hooks) OnDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} -func (h Hooks) OnDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} -func (h Hooks) OnDelegationRemoved(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} diff --git a/x/stake/genesis.go b/x/stake/genesis.go index a7f8493081..58b7ed1b4f 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -75,7 +75,7 @@ func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisValidator) { keeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { vals = append(vals, tmtypes.GenesisValidator{ - PubKey: validator.GetPubKey(), + PubKey: validator.GetConsPubKey(), Power: validator.GetPower().RoundInt64(), Name: validator.GetMoniker(), }) diff --git a/x/stake/handler.go b/x/stake/handler.go index 005b3af7d0..f4864a14a6 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -87,11 +87,6 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k return err.Result() } - // call the hook if present - k.OnValidatorCreated(ctx, validator.OperatorAddr) - accAddr := sdk.AccAddress(validator.OperatorAddr) - k.OnDelegationCreated(ctx, accAddr, validator.OperatorAddr) - tags := sdk.NewTags( tags.Action, tags.ActionCreateValidator, tags.DstValidator, []byte(msg.ValidatorAddr.String()), @@ -151,9 +146,6 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) return err.Result() } - // call the hook if present - k.OnDelegationCreated(ctx, msg.DelegatorAddr, validator.OperatorAddr) - tags := sdk.NewTags( tags.Action, tags.ActionDelegate, tags.Delegator, []byte(msg.DelegatorAddr.String()), diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 6ac51ac196..6efa4c8ed3 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -67,11 +67,6 @@ func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { // remove a delegation from store func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) { - // call the hook if present - if k.hooks != nil { - k.hooks.OnDelegationRemoved(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr) - } - store := ctx.KVStore(k.storeKey) store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr)) } @@ -281,11 +276,6 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co k.SetDelegation(ctx, delegation) k.UpdateValidator(ctx, validator) - // call the hook if present - if k.hooks != nil { - k.hooks.OnDelegationSharesModified(ctx, delegation.DelegatorAddr, validator.OperatorAddr) - } - return } @@ -344,11 +334,6 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA k.RemoveValidator(ctx, validator.OperatorAddr) } - // call the hook if present - if k.hooks != nil { - k.hooks.OnDelegationSharesModified(ctx, delegation.DelegatorAddr, validator.OperatorAddr) - } - return amount, nil } diff --git a/x/stake/keeper/hooks.go b/x/stake/keeper/hooks.go deleted file mode 100644 index 81bf5594ba..0000000000 --- a/x/stake/keeper/hooks.go +++ /dev/null @@ -1,54 +0,0 @@ -//nolint -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// Expose the hooks if present -func (k Keeper) OnValidatorCreated(ctx sdk.Context, address sdk.ValAddress) { - if k.hooks != nil { - k.hooks.OnValidatorCreated(ctx, address) - } -} -func (k Keeper) OnValidatorCommissionChange(ctx sdk.Context, address sdk.ValAddress) { - if k.hooks != nil { - k.hooks.OnValidatorCommissionChange(ctx, address) - } -} - -func (k Keeper) OnValidatorRemoved(ctx sdk.Context, address sdk.ValAddress) { - if k.hooks != nil { - k.hooks.OnValidatorRemoved(ctx, address) - } -} - -func (k Keeper) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) { - if k.hooks != nil { - k.hooks.OnValidatorBonded(ctx, address) - } -} - -func (k Keeper) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) { - if k.hooks != nil { - k.hooks.OnValidatorBeginUnbonding(ctx, address) - } -} - -func (k Keeper) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { - if k.hooks != nil { - k.hooks.OnDelegationCreated(ctx, delAddr, valAddr) - } -} - -func (k Keeper) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { - if k.hooks != nil { - k.hooks.OnDelegationSharesModified(ctx, delAddr, valAddr) - } -} - -func (k Keeper) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { - if k.hooks != nil { - k.hooks.OnDelegationRemoved(ctx, delAddr, valAddr) - } -} diff --git a/x/stake/keeper/keeper.go b/x/stake/keeper/keeper.go index 82170a4aed..0f700f9ab8 100644 --- a/x/stake/keeper/keeper.go +++ b/x/stake/keeper/keeper.go @@ -14,7 +14,7 @@ type Keeper struct { storeTKey sdk.StoreKey cdc *codec.Codec bankKeeper bank.Keeper - hooks sdk.StakingHooks + hooks sdk.ValidatorHooks // codespace codespace sdk.CodespaceType @@ -33,7 +33,7 @@ func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, ck bank.Keeper, codespa } // Set the validator hooks -func (k Keeper) WithHooks(sh sdk.StakingHooks) Keeper { +func (k Keeper) WithValidatorHooks(sh sdk.ValidatorHooks) Keeper { if k.hooks != nil { panic("cannot set validator hooks twice") } diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index af7d77e207..d4fe76b70e 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -681,11 +681,6 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. // remove the validator record and associated indexes func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { - // call the hook if present - if k.hooks != nil { - k.hooks.OnValidatorRemoved(ctx, address) - } - // first retrieve the old validator record validator, found := k.GetValidator(ctx, address) if !found { @@ -745,36 +740,3 @@ func ensureValidatorFound(found bool, ownerAddr []byte) { panic(fmt.Sprintf("validator record not found for address: %X\n", ownerAddr)) } } - -//__________________________________________________________________________ - -// XXX remove this code - this is should be superceded by commission work that bez is doing -// get a single validator -func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, addr sdk.ValAddress, newCommission sdk.Dec) sdk.Error { - - // call the hook if present - if k.hooks != nil { - k.hooks.OnValidatorCommissionChange(ctx, addr) - } - - validator, found := k.GetValidator(ctx, addr) - - // check for errors - switch { - case !found: - return types.ErrNoValidatorFound(k.Codespace()) - case newCommission.LT(sdk.ZeroDec()): - return types.ErrCommissionNegative(k.Codespace()) - case newCommission.GT(validator.CommissionMax): - return types.ErrCommissionBeyondMax(k.Codespace()) - //case rateChange(Commission) > CommissionMaxChange: // XXX XXX XXX TODO implementation - //return types.ErrCommissionPastRate(k.Codespace()) - } - - // TODO adjust all the commission terms appropriately - - validator.Commission = newCommission - - k.SetValidator(ctx, validator) - return nil -} diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index c15d43396c..38cc127b0b 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -474,7 +474,7 @@ func (v Validator) GetJailed() bool { return v.Jailed } func (v Validator) GetMoniker() string { return v.Description.Moniker } func (v Validator) GetStatus() sdk.BondStatus { return v.Status } func (v Validator) GetOperator() sdk.ValAddress { return v.OperatorAddr } -func (v Validator) GetPubKey() crypto.PubKey { return v.ConsPubKey } +func (v Validator) GetConsPubKey() crypto.PubKey { return v.ConsPubKey } func (v Validator) GetConsAddr() sdk.ConsAddress { return sdk.ConsAddress(v.ConsPubKey.Address()) } func (v Validator) GetPower() sdk.Dec { return v.BondedTokens() } func (v Validator) GetTokens() sdk.Dec { return v.Tokens } From 9e2b8e413d6bf6e3358ff04f3f5a3be9b6fe7257 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 20 Sep 2018 21:22:28 -0400 Subject: [PATCH 04/22] revert some gov changes --- types/stake.go | 4 ++-- x/gov/endblocker_test.go | 51 ++++++++++++++++++++++++++++++++-------- x/gov/genesis.go | 6 +++-- x/gov/handler.go | 8 +++---- x/gov/keeper.go | 19 +++++++-------- x/gov/keeper_test.go | 9 +++---- x/gov/procedures.go | 8 ++++--- x/gov/proposals.go | 27 +++++++++++---------- x/gov/simulation/msgs.go | 5 ++-- x/gov/tally_test.go | 2 +- 10 files changed, 88 insertions(+), 51 deletions(-) diff --git a/types/stake.go b/types/stake.go index b8740a3cb9..ade96843dd 100644 --- a/types/stake.go +++ b/types/stake.go @@ -41,8 +41,8 @@ type Validator interface { GetMoniker() string // moniker of the validator GetStatus() BondStatus // status of the validator GetOperator() ValAddress // operator address to receive/return validators coins - GetConsPubKey() crypto.PubKey // validation pubkey - GetConsAddr() ConsAddress // validation pubkey + GetConsPubKey() crypto.PubKey // validation consensus pubkey + GetConsAddr() ConsAddress // validation consensus address GetPower() Dec // validation power GetTokens() Dec // validation tokens GetDelegatorShares() Dec // Total out standing delegator shares diff --git a/x/gov/endblocker_test.go b/x/gov/endblocker_test.go index 710ecb1dba..4cbd1d7588 100644 --- a/x/gov/endblocker_test.go +++ b/x/gov/endblocker_test.go @@ -2,6 +2,7 @@ package gov import ( "testing" + "time" "github.com/stretchr/testify/require" @@ -28,12 +29,18 @@ func TestTickExpiredDepositPeriod(t *testing.T) { require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - ctx = ctx.WithBlockHeight(10) + newHeader := ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) + ctx = ctx.WithBlockHeader(newHeader) + EndBlocker(ctx, keeper) require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - ctx = ctx.WithBlockHeight(250) + newHeader = ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod) + ctx = ctx.WithBlockHeader(newHeader) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) EndBlocker(ctx, keeper) @@ -59,7 +66,10 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - ctx = ctx.WithBlockHeight(10) + newHeader := ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(2) * time.Second) + ctx = ctx.WithBlockHeader(newHeader) + EndBlocker(ctx, keeper) require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) @@ -68,14 +78,20 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { res = govHandler(ctx, newProposalMsg2) require.True(t, res.IsOK()) - ctx = ctx.WithBlockHeight(205) + newHeader = ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(time.Duration(-1) * time.Second) + ctx = ctx.WithBlockHeader(newHeader) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) EndBlocker(ctx, keeper) require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - ctx = ctx.WithBlockHeight(215) + newHeader = ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(5) * time.Second) + ctx = ctx.WithBlockHeader(newHeader) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) EndBlocker(ctx, keeper) @@ -105,7 +121,10 @@ func TestTickPassedDepositPeriod(t *testing.T) { require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - ctx = ctx.WithBlockHeight(10) + newHeader := ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) + ctx = ctx.WithBlockHeader(newHeader) + EndBlocker(ctx, keeper) require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) @@ -146,14 +165,20 @@ func TestTickPassedVotingPeriod(t *testing.T) { var proposalID int64 keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID) - ctx = ctx.WithBlockHeight(10) + newHeader := ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) + ctx = ctx.WithBlockHeader(newHeader) + newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin("steak", 5)}) res = govHandler(ctx, newDepositMsg) require.True(t, res.IsOK()) EndBlocker(ctx, keeper) - ctx = ctx.WithBlockHeight(215) + newHeader = ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod) + ctx = ctx.WithBlockHeader(newHeader) + require.True(t, shouldPopActiveProposalQueue(ctx, keeper)) depositsIterator := keeper.GetDeposits(ctx, proposalID) require.True(t, depositsIterator.Valid()) @@ -197,7 +222,10 @@ func TestSlashing(t *testing.T) { var proposalID int64 keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID) - ctx = ctx.WithBlockHeight(10) + newHeader := ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) + ctx = ctx.WithBlockHeader(newHeader) + require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus()) newVoteMsg := NewMsgVote(addrs[0], proposalID, OptionYes) @@ -206,7 +234,10 @@ func TestSlashing(t *testing.T) { EndBlocker(ctx, keeper) - ctx = ctx.WithBlockHeight(215) + newHeader = ctx.BlockHeader() + newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod) + ctx = ctx.WithBlockHeader(newHeader) + require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus()) EndBlocker(ctx, keeper) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 15f952c000..58273c8e84 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -1,6 +1,8 @@ package gov import ( + "time" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -27,10 +29,10 @@ func DefaultGenesisState() GenesisState { StartingProposalID: 1, DepositProcedure: DepositProcedure{ MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", 10)}, - MaxDepositPeriod: 200, + MaxDepositPeriod: time.Duration(172800) * time.Second, }, VotingProcedure: VotingProcedure{ - VotingPeriod: 200, + VotingPeriod: time.Duration(172800) * time.Second, }, TallyingProcedure: TallyingProcedure{ Threshold: sdk.NewDecWithPrec(5, 1), diff --git a/x/gov/handler.go b/x/gov/handler.go index 84964b20f6..00eaf37440 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -128,9 +128,9 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { for shouldPopActiveProposalQueue(ctx, keeper) { activeProposal := keeper.ActiveProposalQueuePop(ctx) - proposalStartBlock := activeProposal.GetVotingStartBlock() + proposalStartTime := activeProposal.GetVotingStartTime() votingPeriod := keeper.GetVotingProcedure(ctx).VotingPeriod - if ctx.BlockHeight() < proposalStartBlock+votingPeriod { + if ctx.BlockHeader().Time.Before(proposalStartTime.Add(votingPeriod)) { continue } @@ -178,7 +178,7 @@ func shouldPopInactiveProposalQueue(ctx sdk.Context, keeper Keeper) bool { return false } else if peekProposal.GetStatus() != StatusDepositPeriod { return true - } else if ctx.BlockHeight() >= peekProposal.GetSubmitBlock()+depositProcedure.MaxDepositPeriod { + } else if !ctx.BlockHeader().Time.Before(peekProposal.GetSubmitTime().Add(depositProcedure.MaxDepositPeriod)) { return true } return false @@ -190,7 +190,7 @@ func shouldPopActiveProposalQueue(ctx sdk.Context, keeper Keeper) bool { if peekProposal == nil { return false - } else if ctx.BlockHeight() >= peekProposal.GetVotingStartBlock()+votingProcedure.VotingPeriod { + } else if !ctx.BlockHeader().Time.Before(peekProposal.GetVotingStartTime().Add(votingProcedure.VotingPeriod)) { return true } return false diff --git a/x/gov/keeper.go b/x/gov/keeper.go index bebcf51e78..8af2d1fd3a 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -66,15 +66,14 @@ func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description return nil } var proposal Proposal = &TextProposal{ - ProposalID: proposalID, - Title: title, - Description: description, - ProposalType: proposalType, - Status: StatusDepositPeriod, - TallyResult: EmptyTallyResult(), - TotalDeposit: sdk.Coins{}, - SubmitBlock: ctx.BlockHeight(), - VotingStartBlock: -1, // TODO: Make Time + ProposalID: proposalID, + Title: title, + Description: description, + ProposalType: proposalType, + Status: StatusDepositPeriod, + TallyResult: EmptyTallyResult(), + TotalDeposit: sdk.Coins{}, + SubmitTime: ctx.BlockHeader().Time, } keeper.SetProposal(ctx, proposal) keeper.InactiveProposalQueuePush(ctx, proposal) @@ -200,7 +199,7 @@ func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID int64, e } func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) { - proposal.SetVotingStartBlock(ctx.BlockHeight()) + proposal.SetVotingStartTime(ctx.BlockHeader().Time) proposal.SetStatus(StatusVotingPeriod) keeper.SetProposal(ctx, proposal) keeper.ActiveProposalQueuePush(ctx, proposal) diff --git a/x/gov/keeper_test.go b/x/gov/keeper_test.go index a61292b93e..91c41d7d7d 100644 --- a/x/gov/keeper_test.go +++ b/x/gov/keeper_test.go @@ -2,6 +2,7 @@ package gov import ( "testing" + "time" "github.com/stretchr/testify/require" @@ -45,12 +46,12 @@ func TestActivateVotingPeriod(t *testing.T) { proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) - require.Equal(t, int64(-1), proposal.GetVotingStartBlock()) + require.True(t, proposal.GetVotingStartTime().Equal(time.Time{})) require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) keeper.activateVotingPeriod(ctx, proposal) - require.Equal(t, proposal.GetVotingStartBlock(), ctx.BlockHeight()) + require.True(t, proposal.GetVotingStartTime().Equal(ctx.BlockHeader().Time)) require.Equal(t, proposal.GetProposalID(), keeper.ActiveProposalQueuePeek(ctx).GetProposalID()) } @@ -77,7 +78,7 @@ func TestDeposits(t *testing.T) { // Check no deposits at beginning deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1]) require.False(t, found) - require.Equal(t, keeper.GetProposal(ctx, proposalID).GetVotingStartBlock(), int64(-1)) + require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(time.Time{})) require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) // Check first deposit @@ -114,7 +115,7 @@ func TestDeposits(t *testing.T) { require.Equal(t, addr1Initial.Minus(fourSteak), keeper.ck.GetCoins(ctx, addrs[1])) // Check that proposal moved to voting period - require.Equal(t, ctx.BlockHeight(), keeper.GetProposal(ctx, proposalID).GetVotingStartBlock()) + require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(ctx.BlockHeader().Time)) require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx)) require.Equal(t, proposalID, keeper.ActiveProposalQueuePeek(ctx).GetProposalID()) diff --git a/x/gov/procedures.go b/x/gov/procedures.go index f74091c74f..e453add791 100644 --- a/x/gov/procedures.go +++ b/x/gov/procedures.go @@ -1,13 +1,15 @@ package gov import ( + "time" + sdk "github.com/cosmos/cosmos-sdk/types" ) // Procedure around Deposits for governance type DepositProcedure struct { - MinDeposit sdk.Coins `json:"min_deposit"` // Minimum deposit for a proposal to enter voting period. - MaxDepositPeriod int64 `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months + MinDeposit sdk.Coins `json:"min_deposit"` // Minimum deposit for a proposal to enter voting period. + MaxDepositPeriod time.Duration `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months } // Procedure around Tallying votes in governance @@ -19,5 +21,5 @@ type TallyingProcedure struct { // Procedure around Voting in governance type VotingProcedure struct { - VotingPeriod int64 `json:"voting_period"` // Length of the voting period. + VotingPeriod time.Duration `json:"voting_period"` // Length of the voting period. } diff --git a/x/gov/proposals.go b/x/gov/proposals.go index b4c6783673..e680699575 100644 --- a/x/gov/proposals.go +++ b/x/gov/proposals.go @@ -3,6 +3,7 @@ package gov import ( "encoding/json" "fmt" + "time" "github.com/pkg/errors" @@ -30,14 +31,14 @@ type Proposal interface { GetTallyResult() TallyResult SetTallyResult(TallyResult) - GetSubmitBlock() int64 - SetSubmitBlock(int64) + GetSubmitTime() time.Time + SetSubmitTime(time.Time) GetTotalDeposit() sdk.Coins SetTotalDeposit(sdk.Coins) - GetVotingStartBlock() int64 - SetVotingStartBlock(int64) + GetVotingStartTime() time.Time + SetVotingStartTime(time.Time) } // checks if two proposals are equal @@ -48,9 +49,9 @@ func ProposalEqual(proposalA Proposal, proposalB Proposal) bool { proposalA.GetProposalType() == proposalB.GetProposalType() && proposalA.GetStatus() == proposalB.GetStatus() && proposalA.GetTallyResult().Equals(proposalB.GetTallyResult()) && - proposalA.GetSubmitBlock() == proposalB.GetSubmitBlock() && + proposalA.GetSubmitTime().Equal(proposalB.GetSubmitTime()) && proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit()) && - proposalA.GetVotingStartBlock() == proposalB.GetVotingStartBlock() { + proposalA.GetVotingStartTime().Equal(proposalB.GetVotingStartTime()) { return true } return false @@ -67,10 +68,10 @@ type TextProposal struct { Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected} TallyResult TallyResult `json:"tally_result"` // Result of Tallys - SubmitBlock int64 `json:"submit_block"` // Height of the block where TxGovSubmitProposal was included + SubmitTime time.Time `json:"submit_block"` // Height of the block where TxGovSubmitProposal was included TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit - VotingStartBlock int64 `json:"voting_start_block"` // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached + VotingStartTime time.Time `json:"voting_start_block"` // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached } // Implements Proposal Interface @@ -89,13 +90,13 @@ func (tp TextProposal) GetStatus() ProposalStatus { return tp.S func (tp *TextProposal) SetStatus(status ProposalStatus) { tp.Status = status } func (tp TextProposal) GetTallyResult() TallyResult { return tp.TallyResult } func (tp *TextProposal) SetTallyResult(tallyResult TallyResult) { tp.TallyResult = tallyResult } -func (tp TextProposal) GetSubmitBlock() int64 { return tp.SubmitBlock } -func (tp *TextProposal) SetSubmitBlock(submitBlock int64) { tp.SubmitBlock = submitBlock } +func (tp TextProposal) GetSubmitTime() time.Time { return tp.SubmitTime } +func (tp *TextProposal) SetSubmitTime(submitTime time.Time) { tp.SubmitTime = submitTime } func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit } func (tp *TextProposal) SetTotalDeposit(totalDeposit sdk.Coins) { tp.TotalDeposit = totalDeposit } -func (tp TextProposal) GetVotingStartBlock() int64 { return tp.VotingStartBlock } -func (tp *TextProposal) SetVotingStartBlock(votingStartBlock int64) { - tp.VotingStartBlock = votingStartBlock +func (tp TextProposal) GetVotingStartTime() time.Time { return tp.VotingStartTime } +func (tp *TextProposal) SetVotingStartTime(votingStartTime time.Time) { + tp.VotingStartTime = votingStartTime } //----------------------------------------------------------- diff --git a/x/gov/simulation/msgs.go b/x/gov/simulation/msgs.go index 168081b188..f46fe995e1 100644 --- a/x/gov/simulation/msgs.go +++ b/x/gov/simulation/msgs.go @@ -4,6 +4,7 @@ import ( "fmt" "math" "math/rand" + "time" "github.com/tendermint/tendermint/crypto" @@ -68,8 +69,8 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe votingPeriod := k.GetVotingProcedure(ctx).VotingPeriod fops := make([]simulation.FutureOperation, numVotes+1) for i := 0; i < numVotes; i++ { - whenVote := ctx.BlockHeight() + r.Int63n(votingPeriod) - fops[i] = simulation.FutureOperation{BlockHeight: int(whenVote), Op: operationSimulateMsgVote(k, sk, keys[whoVotes[i]], proposalID)} + whenVote := ctx.BlockHeader().Time.Add(time.Duration(r.Int63n(int64(votingPeriod.Seconds()))) * time.Second) + fops[i] = simulation.FutureOperation{BlockTime: whenVote, Op: operationSimulateMsgVote(k, sk, keys[whoVotes[i]], proposalID)} } // 3) Make an operation to ensure slashes were done correctly. (Really should be a future invariant) // TODO: Find a way to check if a validator was slashed other than just checking their balance a block diff --git a/x/gov/tally_test.go b/x/gov/tally_test.go index 9c5348b2c7..6c6d64aa67 100644 --- a/x/gov/tally_test.go +++ b/x/gov/tally_test.go @@ -440,7 +440,7 @@ func TestTallyJailedValidator(t *testing.T) { val2, found := sk.GetValidator(ctx, sdk.ValAddress(addrs[1])) require.True(t, found) - sk.Jail(ctx, sdk.ConsAddress(val2.ConsPubKey.Address())) + sk.Jail(ctx, val2.ConsPubKey) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() From 12435070989e253d3ac8c6e01bd1326c913bd8fd Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 20 Sep 2018 22:09:27 -0400 Subject: [PATCH 05/22] no more compile errors in tests --- examples/democoin/mock/validator.go | 22 ++++++++++++++++------ x/gov/tally_test.go | 2 +- x/mock/simulation/constants.go | 4 ++-- x/slashing/keeper_test.go | 6 +++--- x/stake/simulation/invariants.go | 2 +- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/examples/democoin/mock/validator.go b/examples/democoin/mock/validator.go index 9f84786adf..a54cdfedf6 100644 --- a/examples/democoin/mock/validator.go +++ b/examples/democoin/mock/validator.go @@ -24,7 +24,12 @@ func (v Validator) GetOperator() sdk.ValAddress { } // Implements sdk.Validator -func (v Validator) GetPubKey() crypto.PubKey { +func (v Validator) GetConsPubKey() crypto.PubKey { + return nil +} + +// Implements sdk.Validator +func (v Validator) GetConsAddr() sdk.ConsAddress { return nil } @@ -88,7 +93,12 @@ func (vs *ValidatorSet) Validator(ctx sdk.Context, addr sdk.ValAddress) sdk.Vali } // ValidatorByPubKey implements sdk.ValidatorSet -func (vs *ValidatorSet) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) sdk.Validator { +func (vs *ValidatorSet) ValidatorByConsPubKey(_ sdk.Context, _ crypto.PubKey) sdk.Validator { + panic("not implemented") +} + +// ValidatorByPubKey implements sdk.ValidatorSet +func (vs *ValidatorSet) ValidatorByConsAddr(_ sdk.Context, _ sdk.ConsAddress) sdk.Validator { panic("not implemented") } @@ -122,21 +132,21 @@ func (vs *ValidatorSet) RemoveValidator(addr sdk.AccAddress) { } // Implements sdk.ValidatorSet -func (vs *ValidatorSet) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, power int64, amt sdk.Dec) { +func (vs *ValidatorSet) Slash(_ sdk.Context, _ sdk.ConsAddress, _ int64, _ int64, _ sdk.Dec) { panic("not implemented") } // Implements sdk.ValidatorSet -func (vs *ValidatorSet) Jail(ctx sdk.Context, pubkey crypto.PubKey) { +func (vs *ValidatorSet) Jail(_ sdk.Context, _ sdk.ConsAddress) { panic("not implemented") } // Implements sdk.ValidatorSet -func (vs *ValidatorSet) Unjail(ctx sdk.Context, pubkey crypto.PubKey) { +func (vs *ValidatorSet) Unjail(_ sdk.Context, _ sdk.ConsAddress) { panic("not implemented") } // Implements sdk.ValidatorSet -func (vs *ValidatorSet) Delegation(ctx sdk.Context, addrDel sdk.AccAddress, addrVal sdk.ValAddress) sdk.Delegation { +func (vs *ValidatorSet) Delegation(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) sdk.Delegation { panic("not implemented") } diff --git a/x/gov/tally_test.go b/x/gov/tally_test.go index 6c6d64aa67..9c5348b2c7 100644 --- a/x/gov/tally_test.go +++ b/x/gov/tally_test.go @@ -440,7 +440,7 @@ func TestTallyJailedValidator(t *testing.T) { val2, found := sk.GetValidator(ctx, sdk.ValAddress(addrs[1])) require.True(t, found) - sk.Jail(ctx, val2.ConsPubKey) + sk.Jail(ctx, sdk.ConsAddress(val2.ConsPubKey.Address())) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() diff --git a/x/mock/simulation/constants.go b/x/mock/simulation/constants.go index 544da50e3e..985a22dcac 100644 --- a/x/mock/simulation/constants.go +++ b/x/mock/simulation/constants.go @@ -5,10 +5,10 @@ const ( pastEvidenceFraction float64 = 0.5 // Minimum time per block - minTimePerBlock int64 = 1000 / 2 + minTimePerBlock int64 = 86400 / 2 // Maximum time per block - maxTimePerBlock int64 = 1000 + maxTimePerBlock int64 = 86400 // Number of keys numKeys int = 250 diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 1d69f714f0..9a3ff537c2 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -27,7 +27,7 @@ func TestHandleDoubleSign(t *testing.T) { // initial setup ctx, ck, sk, _, keeper := createTestInput(t) - sk = sk.WithHooks(keeper.Hooks()) + sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) @@ -69,7 +69,7 @@ func TestSlashingPeriodCap(t *testing.T) { // initial setup ctx, ck, sk, _, keeper := createTestInput(t) - sk = sk.WithHooks(keeper.Hooks()) + sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) amtInt := int64(100) addr, amt := addrs[0], sdk.NewInt(amtInt) valConsPubKey, valConsAddr := pks[0], sdk.ConsAddress(pks[0].Address()) @@ -125,7 +125,7 @@ func TestHandleAbsentValidator(t *testing.T) { // initial setup ctx, ck, sk, _, keeper := createTestInput(t) - sk = sk.WithHooks(keeper.Hooks()) + sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) sh := stake.NewHandler(sk) diff --git a/x/stake/simulation/invariants.go b/x/stake/simulation/invariants.go index 2ab0717042..cdd80a8c41 100644 --- a/x/stake/simulation/invariants.go +++ b/x/stake/simulation/invariants.go @@ -80,7 +80,7 @@ func PositivePowerInvariant(k stake.Keeper) simulation.Invariant { var err error k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) bool { if !validator.GetPower().GT(sdk.ZeroDec()) { - err = fmt.Errorf("validator with non-positive power stored. (pubkey %v)", validator.GetPubKey()) + err = fmt.Errorf("validator with non-positive power stored. (pubkey %v)", validator.GetConsPubKey()) return true } return false From 787a2f990e596a3e5bb225412c384e938903121d Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 20 Sep 2018 22:36:33 -0400 Subject: [PATCH 06/22] fix using cons address, also remove old commented distr code --- x/distribution/keeper.go | 91 -------------------------- x/distribution/keeper_test.go | 31 --------- x/distribution/movement.go | 72 --------------------- x/distribution/types.go | 107 ------------------------------- x/stake/keeper/slash.go | 2 +- x/stake/keeper/slash_test.go | 1 + x/stake/keeper/validator.go | 2 +- x/stake/keeper/validator_test.go | 9 +++ 8 files changed, 12 insertions(+), 303 deletions(-) delete mode 100644 x/distribution/keeper.go delete mode 100644 x/distribution/keeper_test.go delete mode 100644 x/distribution/movement.go delete mode 100644 x/distribution/types.go diff --git a/x/distribution/keeper.go b/x/distribution/keeper.go deleted file mode 100644 index 937a4674cf..0000000000 --- a/x/distribution/keeper.go +++ /dev/null @@ -1,91 +0,0 @@ -package stake - -//// keeper of the staking store -//type Keeper struct { -//storeKey sdk.StoreKey -//cdc *codec.Codec -//bankKeeper bank.Keeper - -//// codespace -//codespace sdk.CodespaceType -//} - -//func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ck bank.Keeper, codespace sdk.CodespaceType) Keeper { -//keeper := Keeper{ -//storeKey: key, -//cdc: cdc, -//bankKeeper: ck, -//codespace: codespace, -//} -//return keeper -//} - -////_________________________________________________________________________ - -//// cummulative power of the non-absent prevotes -//func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Dec { -//store := ctx.KVStore(k.storeKey) - -//// get absent prevote indexes -//absents := ctx.AbsentValidators() - -//TotalPower := sdk.ZeroDec() -//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/distribution/keeper_test.go b/x/distribution/keeper_test.go deleted file mode 100644 index 8902680604..0000000000 --- a/x/distribution/keeper_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package stake - -//// test if is a gotValidator from the last update -//func TestGetTotalPrecommitVotingPower(t *testing.T) { -//ctx, _, keeper := createTestInput(t, false, 0) - -//amts := []int64{10000, 1000, 100, 10, 1} -//var candidatesIn [5]Candidate -//for i, amt := range amts { -//candidatesIn[i] = NewCandidate(addrVals[i], pks[i], Description{}) -//candidatesIn[i].BondedShares = sdk.NewDec(amt) -//candidatesIn[i].DelegatorShares = sdk.NewDec(amt) -//keeper.setCandidate(ctx, candidatesIn[i]) -//} - -//// test that an empty gotValidator set doesn't have any gotValidators -//gotValidators := keeper.GetValidators(ctx) -//require.Equal(t, 5, len(gotValidators)) - -//totPow := keeper.GetTotalPrecommitVotingPower(ctx) -//exp := sdk.NewDec(11111) -//require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) - -//// set absent gotValidators to be the 1st and 3rd record sorted by pubKey address -//ctx = ctx.WithAbsentValidators([]int32{1, 3}) -//totPow = keeper.GetTotalPrecommitVotingPower(ctx) - -//// XXX verify that this order should infact exclude these two records -//exp = sdk.NewDec(11100) -//require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) -//} diff --git a/x/distribution/movement.go b/x/distribution/movement.go deleted file mode 100644 index 399a25a681..0000000000 --- a/x/distribution/movement.go +++ /dev/null @@ -1,72 +0,0 @@ -package stake - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// burn burn burn -func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, 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) - -//// XXX determine -//candidate := NewCandidate(addrs[0], pks[0], Description{}) - -//// calculate the proposer reward -//precommitPower := k.GetTotalPrecommitVotingPower(ctx) -//toProposer := coinsMulRat(collectedFees, (sdk.NewDec(1, 100).Add(sdk.NewDec(4, 100).Mul(precommitPower).Quo(pool.BondedShares)))) -//candidate.ProposerRewardPool = candidate.ProposerRewardPool.Plus(toProposer) - -//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 - -//// lastly update the FeeRecent term -//pool.FeeRecent = collectedFees - -//k.setPool(ctx, pool) -//} - -//func coinsMulRat(coins sdk.Coins, rat sdk.Dec) sdk.Coins { -//var res sdk.Coins -//for _, coin := range coins { -//coinMulAmt := rat.Mul(sdk.NewDec(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) { - -//heightRat := sdk.NewDec(height) -//lastHeightRat := sdk.NewDec(height - 1) -//candidateFeeCount := candidate.BondedShares.Mul(heightRat) -//poolFeeCount := pool.BondedShares.Mul(heightRat) - -//for i, denom := range denoms { -//poolFeeSumReceived := sdk.NewDec(pool.FeeSumReceived.AmountOf(denom)) -//poolFeeRecent := sdk.NewDec(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) -//} - -//return candidate, pool -//} diff --git a/x/distribution/types.go b/x/distribution/types.go deleted file mode 100644 index 2234104717..0000000000 --- a/x/distribution/types.go +++ /dev/null @@ -1,107 +0,0 @@ -package stake - -//// GenesisState - all staking state that must be provided at genesis -//type GenesisState struct { -//Pool Pool `json:"pool"` -//Params Params `json:"params"` -//} - -//func NewGenesisState(pool Pool, params Params, candidates []Candidate, bonds []Delegation) GenesisState { -//return GenesisState{ -//Pool: pool, -//Params: params, -//} -//} - -//// 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.Dec `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms -//PrevBondedShares sdk.Dec `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.Dec `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) -//} - -//func defaultParams() Params { -//return Params{ -//FeeDenoms: []string{"steak"}, -//ReservePoolFee: sdk.NewDec(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.Dec `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms -//PrevBondedShares sdk.Dec `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.DecsEqual(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.Dec{sdk.ZeroDec()}, -//PrevBondedShares: sdk.ZeroDec(), -//} -//} - -////_________________________________________________________________________ - -//// 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.Dec `json:"power"` // total power at change -//PrevPower sdk.Dec `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 - -//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...) -//} diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index ea378678ae..29adec06a7 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -143,7 +143,7 @@ func (k Keeper) Unjail(ctx sdk.Context, consAddr sdk.ConsAddress) { // set the jailed flag on a validator func (k Keeper) setJailed(ctx sdk.Context, consAddr sdk.ConsAddress, isJailed bool) { - validator, found := k.GetValidatorByConsAddr(ctx, sdk.ConsAddress(consAddr)) + validator, found := k.GetValidatorByConsAddr(ctx, consAddr) if !found { panic(fmt.Errorf("validator with consensus-Address %s not found, cannot set jailed to %v", consAddr, isJailed)) } diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index c4a1edd415..7d2f2f785c 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -14,6 +14,7 @@ import ( // TODO integrate with test_common.go helper (CreateTestInput) // setup helper function - creates two validators func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { + // setup ctx, _, keeper := CreateTestInput(t, false, amt) params := keeper.GetParams(ctx) diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index d4fe76b70e..ef2256e083 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -90,7 +90,7 @@ func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { // TODO change to SetValidatorByConsAddr? used for retrieving from ConsPubkey as well- kinda confusing func (k Keeper) SetValidatorByConsAddr(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - consAddr := sdk.ConsAddress(validator.OperatorAddr.Bytes()) + consAddr := sdk.ConsAddress(validator.ConsPubKey.Address()) store.Set(GetValidatorByConsAddrKey(consAddr), validator.OperatorAddr) } diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index a541600d9f..356170189a 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -305,10 +305,19 @@ func TestValidatorBasics(t *testing.T) { // set and retrieve a record validators[0] = keeper.UpdateValidator(ctx, validators[0]) + keeper.SetValidatorByConsAddr(ctx, validators[0]) resVal, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) assert.True(ValEq(t, validators[0], resVal)) + // retrieve from consensus + resVal, found = keeper.GetValidatorByConsAddr(ctx, sdk.ConsAddress(PKs[0].Address())) + require.True(t, found) + assert.True(ValEq(t, validators[0], resVal)) + resVal, found = keeper.GetValidatorByConsPubKey(ctx, PKs[0]) + require.True(t, found) + assert.True(ValEq(t, validators[0], resVal)) + resVals = keeper.GetValidatorsBonded(ctx) require.Equal(t, 1, len(resVals)) assert.True(ValEq(t, validators[0], resVals[0])) From 72e302548102ef941dd9da29292ca52121c3cbab Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 20 Sep 2018 22:43:11 -0400 Subject: [PATCH 07/22] doc update --- docs/spec/staking/state.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/spec/staking/state.md b/docs/spec/staking/state.md index f2d6f98541..9d5e129237 100644 --- a/docs/spec/staking/state.md +++ b/docs/spec/staking/state.md @@ -43,12 +43,13 @@ type Params struct { Validators are identified according to the `OperatorAddr`, an SDK validator address for the operator of the validator. -Validators also have a `ConsPubKey`, the public key of the validator. - -Validators are indexed in the store using the following maps: +Validators also have a `ConsPubKey`, the public key of the validator. The +validator can be retrieved from it's `ConsPubKey` once it can be converted into +the corresponding `ConsAddr`. Validators are indexed in the store using the +following maps: - Validators: `0x02 | OperatorAddr -> amino(validator)` -- ValidatorsByPubKey: `0x03 | ConsPubKey -> OperatorAddr` +- ValidatorsByConsAddr: `0x03 | ConsAddr -> OperatorAddr` - ValidatorsByPower: `0x05 | power | blockHeight | blockTx -> OperatorAddr` `Validators` is the primary index - it ensures that each operator can have only one @@ -69,7 +70,7 @@ validator. ```golang type Validator struct { - ConsensusPubKey crypto.PubKey // Tendermint consensus pubkey of validator + ConsPubKey crypto.PubKey // Tendermint consensus pubkey of validator Jailed bool // has the validator been jailed? Status sdk.BondStatus // validator status (bonded/unbonding/unbonded) From b212470d31482607a0a5655f6810b5dd66e37fb6 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 20 Sep 2018 22:49:51 -0400 Subject: [PATCH 08/22] revert some accidental stuff --- x/mock/simulation/constants.go | 4 ++-- x/stake/types/errors.go | 8 -------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/x/mock/simulation/constants.go b/x/mock/simulation/constants.go index 985a22dcac..544da50e3e 100644 --- a/x/mock/simulation/constants.go +++ b/x/mock/simulation/constants.go @@ -5,10 +5,10 @@ const ( pastEvidenceFraction float64 = 0.5 // Minimum time per block - minTimePerBlock int64 = 86400 / 2 + minTimePerBlock int64 = 1000 / 2 // Maximum time per block - maxTimePerBlock int64 = 86400 + maxTimePerBlock int64 = 1000 // Number of keys numKeys int = 250 diff --git a/x/stake/types/errors.go b/x/stake/types/errors.go index 541ad3d7b9..366012bbfb 100644 --- a/x/stake/types/errors.go +++ b/x/stake/types/errors.go @@ -65,14 +65,6 @@ func ErrCommissionHuge(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than 100%") } -func ErrCommissionBeyondMax(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than preset commission maximum") -} - -func ErrCommissionPastRate(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission change is greater than the commission rate, please wait before changing your commission more") -} - func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil") } From 14792f2b23a33219c13bd7ea0c819caf14ae7baf Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 22 Sep 2018 13:50:26 -0400 Subject: [PATCH 09/22] val comments --- docs/spec/staking/state.md | 8 ++++---- x/stake/keeper/validator.go | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/spec/staking/state.md b/docs/spec/staking/state.md index 9d5e129237..9454aca7dd 100644 --- a/docs/spec/staking/state.md +++ b/docs/spec/staking/state.md @@ -43,10 +43,10 @@ type Params struct { Validators are identified according to the `OperatorAddr`, an SDK validator address for the operator of the validator. -Validators also have a `ConsPubKey`, the public key of the validator. The -validator can be retrieved from it's `ConsPubKey` once it can be converted into -the corresponding `ConsAddr`. Validators are indexed in the store using the -following maps: +Validators also have a `ConsPubKey`, the public key of the validator used in +Tendermint consensus. The validator can be retrieved from it's `ConsPubKey` +once it can be converted into the corresponding `ConsAddr`. Validators are +indexed in the store using the following maps: - Validators: `0x02 | OperatorAddr -> amino(validator)` - ValidatorsByConsAddr: `0x03 | ConsAddr -> OperatorAddr` diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index ef2256e083..f7c43757ff 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -87,7 +87,6 @@ func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { } // validator index -// TODO change to SetValidatorByConsAddr? used for retrieving from ConsPubkey as well- kinda confusing func (k Keeper) SetValidatorByConsAddr(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) consAddr := sdk.ConsAddress(validator.ConsPubKey.Address()) From d428317f91f0686f50f6fd45db668418a57087f3 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 22 Sep 2018 13:56:48 -0400 Subject: [PATCH 10/22] import decimal from fee-distr PR --- types/decimal.go | 26 ++++++++++++++++++++++++++ types/decimal_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/types/decimal.go b/types/decimal.go index 8e7db1340b..d6c93f617a 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -323,6 +323,32 @@ func (d Dec) RoundInt() Int { //___________________________________________________________________________________ +// similar to chopPrecisionAndRound, but always rounds down +func chopPrecisionAndTruncate(d *big.Int) *big.Int { + return d.Quo(d, precisionReuse) +} + +func chopPrecisionAndTruncateNonMutative(d *big.Int) *big.Int { + tmp := new(big.Int).Set(d) + return chopPrecisionAndTruncate(tmp) +} + +// RoundInt64 rounds the decimal using bankers rounding +func (d Dec) TruncateInt64() int64 { + chopped := chopPrecisionAndTruncateNonMutative(d.Int) + if !chopped.IsInt64() { + panic("Int64() out of bound") + } + return chopped.Int64() +} + +// RoundInt round the decimal using bankers rounding +func (d Dec) TruncateInt() Int { + return NewIntFromBigInt(chopPrecisionAndTruncateNonMutative(d.Int)) +} + +//___________________________________________________________________________________ + // reuse nil values var ( nilAmino string diff --git a/types/decimal_test.go b/types/decimal_test.go index 779460c253..161215467f 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -202,6 +202,32 @@ func TestBankerRoundChop(t *testing.T) { } } +func TestTruncate(t *testing.T) { + tests := []struct { + d1 Dec + exp int64 + }{ + {mustNewDecFromStr(t, "0"), 0}, + {mustNewDecFromStr(t, "0.25"), 0}, + {mustNewDecFromStr(t, "0.75"), 0}, + {mustNewDecFromStr(t, "1"), 1}, + {mustNewDecFromStr(t, "1.5"), 1}, + {mustNewDecFromStr(t, "7.5"), 7}, + {mustNewDecFromStr(t, "7.6"), 7}, + {mustNewDecFromStr(t, "7.4"), 7}, + {mustNewDecFromStr(t, "100.1"), 100}, + {mustNewDecFromStr(t, "1000.1"), 1000}, + } + + for tcIndex, tc := range tests { + resNeg := tc.d1.Neg().TruncateInt64() + require.Equal(t, -1*tc.exp, resNeg, "negative tc %d", tcIndex) + + resPos := tc.d1.TruncateInt64() + require.Equal(t, tc.exp, resPos, "positive tc %d", tcIndex) + } +} + func TestToLeftPadded(t *testing.T) { tests := []struct { dec Dec From 79cfee96236c00ed41bb9c4d005592a65547362b Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 22 Sep 2018 14:51:38 -0400 Subject: [PATCH 11/22] pending --- PENDING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PENDING.md b/PENDING.md index 4d494f3779..700abff649 100644 --- a/PENDING.md +++ b/PENDING.md @@ -89,6 +89,7 @@ FEATURES * [simulation] [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) allow operations to specify future operations * [simulation] [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) Add benchmarking capabilities, with makefile commands "test_sim_gaia_benchmark, test_sim_gaia_profile" * [simulation] [\#2349](https://github.com/cosmos/cosmos-sdk/issues/2349) Add time-based future scheduled operations to simulator + * [] [\#2349](https://github.com/cosmos/cosmos-sdk/issues/2349) Add time-based future scheduled operations to simulator * Tendermint @@ -125,6 +126,7 @@ IMPROVEMENTS * [simulation] Logs get written to file if large, and also get printed on panics \#2285 * [gaiad] \#1992 Add optional flag to `gaiad testnet` to make config directory of daemon (default `gaiad`) and cli (default `gaiacli`) configurable * [x/stake] Add stake `Queriers` for Gaia-lite endpoints. This increases the staking endpoints performance by reusing the staking `keeper` logic for queries. [#2249](https://github.com/cosmos/cosmos-sdk/pull/2149) + * [types/decimal] \#2378 - Added truncate functionality to decimal * Tendermint From 6012a252bbf0c5a04c08a517927bd914b3d255ba Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 22 Sep 2018 14:52:47 -0400 Subject: [PATCH 12/22] ... --- PENDING.md | 1 - 1 file changed, 1 deletion(-) diff --git a/PENDING.md b/PENDING.md index 700abff649..5cf80cd6f6 100644 --- a/PENDING.md +++ b/PENDING.md @@ -89,7 +89,6 @@ FEATURES * [simulation] [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) allow operations to specify future operations * [simulation] [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) Add benchmarking capabilities, with makefile commands "test_sim_gaia_benchmark, test_sim_gaia_profile" * [simulation] [\#2349](https://github.com/cosmos/cosmos-sdk/issues/2349) Add time-based future scheduled operations to simulator - * [] [\#2349](https://github.com/cosmos/cosmos-sdk/issues/2349) Add time-based future scheduled operations to simulator * Tendermint From 6f35822d7dc45c70e2e8a1b5579ff0f91ca14743 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 22 Sep 2018 16:29:42 -0400 Subject: [PATCH 13/22] import hook from fee-distr --- cmd/gaia/app/app.go | 2 +- types/stake.go | 25 +++++++++++++---- x/slashing/hooks.go | 12 ++++++-- x/slashing/keeper_test.go | 6 ++-- x/stake/handler.go | 8 ++++++ x/stake/keeper/delegation.go | 9 ++++++ x/stake/keeper/hooks.go | 54 ++++++++++++++++++++++++++++++++++++ x/stake/keeper/keeper.go | 4 +-- x/stake/keeper/validator.go | 30 ++++++++++++++------ 9 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 x/stake/keeper/hooks.go diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 353825121a..31b912a9de 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -91,7 +91,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams) app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.tkeyStake, app.bankKeeper, app.RegisterCodespace(stake.DefaultCodespace)) app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace)) - app.stakeKeeper = app.stakeKeeper.WithValidatorHooks(app.slashingKeeper.ValidatorHooks()) + app.stakeKeeper = app.stakeKeeper.WithHooks(app.slashingKeeper.Hooks()) app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper.Setter(), app.bankKeeper, app.stakeKeeper, app.RegisterCodespace(gov.DefaultCodespace)) app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(app.cdc, app.keyFeeCollection) diff --git a/types/stake.go b/types/stake.go index ade96843dd..03bf5e3bf3 100644 --- a/types/stake.go +++ b/types/stake.go @@ -102,12 +102,25 @@ type DelegationSet interface { fn func(index int64, delegation Delegation) (stop bool)) } -// validator event hooks -// These can be utilized to communicate between a staking keeper -// and another keeper which must take particular actions when -// validators are bonded and unbonded. The second keeper must implement -// this interface, which then the staking keeper can call. -type ValidatorHooks interface { +//_______________________________________________________________________________ +// Event Hooks +// These can be utilized to communicate between a staking keeper and another +// keeper which must take particular actions when validators/delegators change +// state. The second keeper must implement this interface, which then the +// staking keeper can call. + +// TODO refactor event hooks out to the receiver modules + +// event hooks for staking validator object +type StakingHooks interface { + OnValidatorCreated(ctx Context, address ValAddress) // Must be called when a validator is created + OnValidatorCommissionChange(ctx Context, address ValAddress) // Must be called when a validator's commission is modified + OnValidatorRemoved(ctx Context, address ValAddress) // Must be called when a validator is deleted + OnValidatorBonded(ctx Context, address ConsAddress) // Must be called when a validator is bonded OnValidatorBeginUnbonding(ctx Context, address ConsAddress) // Must be called when a validator begins unbonding + + OnDelegationCreated(ctx Context, delAddr AccAddress, valAddr ValAddress) // Must be called when a delegation is created + OnDelegationSharesModified(ctx Context, delAddr AccAddress, valAddr ValAddress) // Must be called when a delegation's shares are modified + OnDelegationRemoved(ctx Context, delAddr AccAddress, valAddr ValAddress) // Must be called when a delegation is removed } diff --git a/x/slashing/hooks.go b/x/slashing/hooks.go index 92c4cf85f8..701a6b2cde 100644 --- a/x/slashing/hooks.go +++ b/x/slashing/hooks.go @@ -29,10 +29,10 @@ type Hooks struct { k Keeper } -var _ sdk.ValidatorHooks = Hooks{} +var _ sdk.StakingHooks = Hooks{} // Return the wrapper struct -func (k Keeper) ValidatorHooks() Hooks { +func (k Keeper) Hooks() Hooks { return Hooks{k} } @@ -45,3 +45,11 @@ func (h Hooks) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) { func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) { h.k.onValidatorBeginUnbonding(ctx, address) } + +// nolint - unused hooks +func (h Hooks) OnValidatorCreated(_ sdk.Context, _ sdk.ValAddress) {} +func (h Hooks) OnValidatorCommissionChange(_ sdk.Context, _ sdk.ValAddress) {} +func (h Hooks) OnValidatorRemoved(_ sdk.Context, _ sdk.ValAddress) {} +func (h Hooks) OnDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} +func (h Hooks) OnDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} +func (h Hooks) OnDelegationRemoved(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 9a3ff537c2..1d69f714f0 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -27,7 +27,7 @@ func TestHandleDoubleSign(t *testing.T) { // initial setup ctx, ck, sk, _, keeper := createTestInput(t) - sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) + sk = sk.WithHooks(keeper.Hooks()) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) @@ -69,7 +69,7 @@ func TestSlashingPeriodCap(t *testing.T) { // initial setup ctx, ck, sk, _, keeper := createTestInput(t) - sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) + sk = sk.WithHooks(keeper.Hooks()) amtInt := int64(100) addr, amt := addrs[0], sdk.NewInt(amtInt) valConsPubKey, valConsAddr := pks[0], sdk.ConsAddress(pks[0].Address()) @@ -125,7 +125,7 @@ func TestHandleAbsentValidator(t *testing.T) { // initial setup ctx, ck, sk, _, keeper := createTestInput(t) - sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) + sk = sk.WithHooks(keeper.Hooks()) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) sh := stake.NewHandler(sk) diff --git a/x/stake/handler.go b/x/stake/handler.go index f4864a14a6..b3bf4c018b 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -87,6 +87,11 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k return err.Result() } + // call hooks + k.OnValidatorCreated(ctx, validator.OperatorAddr) + accAddr := sdk.AccAddress(validator.OperatorAddr) + k.OnDelegationCreated(ctx, accAddr, validator.OperatorAddr) + tags := sdk.NewTags( tags.Action, tags.ActionCreateValidator, tags.DstValidator, []byte(msg.ValidatorAddr.String()), @@ -146,6 +151,9 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) return err.Result() } + // call the hook if present + k.OnDelegationCreated(ctx, msg.DelegatorAddr, validator.OperatorAddr) + tags := sdk.NewTags( tags.Action, tags.ActionDelegate, tags.Delegator, []byte(msg.DelegatorAddr.String()), diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 6efa4c8ed3..a2392ac587 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -67,6 +67,9 @@ func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { // remove a delegation from store func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) { + // call hook + k.OnDelegationRemoved(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr) + store := ctx.KVStore(k.storeKey) store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr)) } @@ -283,6 +286,9 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, shares sdk.Dec) (amount sdk.Dec, err sdk.Error) { + // call hook + k.OnDelegationSharesModified(ctx, delAddr, valAddr) + // check if delegation has any shares in it unbond delegation, found := k.GetDelegation(ctx, delAddr, valAddr) if !found { @@ -334,6 +340,9 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA k.RemoveValidator(ctx, validator.OperatorAddr) } + // call hook + k.OnDelegationSharesModified(ctx, delegation.DelegatorAddr, validator.OperatorAddr) + return amount, nil } diff --git a/x/stake/keeper/hooks.go b/x/stake/keeper/hooks.go new file mode 100644 index 0000000000..81bf5594ba --- /dev/null +++ b/x/stake/keeper/hooks.go @@ -0,0 +1,54 @@ +//nolint +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Expose the hooks if present +func (k Keeper) OnValidatorCreated(ctx sdk.Context, address sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnValidatorCreated(ctx, address) + } +} +func (k Keeper) OnValidatorCommissionChange(ctx sdk.Context, address sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnValidatorCommissionChange(ctx, address) + } +} + +func (k Keeper) OnValidatorRemoved(ctx sdk.Context, address sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnValidatorRemoved(ctx, address) + } +} + +func (k Keeper) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) { + if k.hooks != nil { + k.hooks.OnValidatorBonded(ctx, address) + } +} + +func (k Keeper) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) { + if k.hooks != nil { + k.hooks.OnValidatorBeginUnbonding(ctx, address) + } +} + +func (k Keeper) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnDelegationCreated(ctx, delAddr, valAddr) + } +} + +func (k Keeper) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnDelegationSharesModified(ctx, delAddr, valAddr) + } +} + +func (k Keeper) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { + if k.hooks != nil { + k.hooks.OnDelegationRemoved(ctx, delAddr, valAddr) + } +} diff --git a/x/stake/keeper/keeper.go b/x/stake/keeper/keeper.go index 0f700f9ab8..82170a4aed 100644 --- a/x/stake/keeper/keeper.go +++ b/x/stake/keeper/keeper.go @@ -14,7 +14,7 @@ type Keeper struct { storeTKey sdk.StoreKey cdc *codec.Codec bankKeeper bank.Keeper - hooks sdk.ValidatorHooks + hooks sdk.StakingHooks // codespace codespace sdk.CodespaceType @@ -33,7 +33,7 @@ func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, ck bank.Keeper, codespa } // Set the validator hooks -func (k Keeper) WithValidatorHooks(sh sdk.ValidatorHooks) Keeper { +func (k Keeper) WithHooks(sh sdk.StakingHooks) Keeper { if k.hooks != nil { panic("cannot set validator hooks twice") } diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index f7c43757ff..69bab0f8ec 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -633,10 +633,8 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat // also remove from the Bonded types.Validators Store store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) - // call the unbond hook if present - if k.hooks != nil { - k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) - } + // call hook + k.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) // return updated validator return validator @@ -668,10 +666,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. tstore := ctx.TransientStore(k.storeTKey) tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) - // call the bond hook if present - if k.hooks != nil { - k.hooks.OnValidatorBonded(ctx, validator.ConsAddress()) - } + // call hook + k.OnValidatorBonded(ctx, validator.ConsAddress()) // return updated validator return validator @@ -680,6 +676,9 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. // remove the validator record and associated indexes func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { + // call hook + k.OnValidatorRemoved(ctx, address) + // first retrieve the old validator record validator, found := k.GetValidator(ctx, address) if !found { @@ -739,3 +738,18 @@ func ensureValidatorFound(found bool, ownerAddr []byte) { panic(fmt.Sprintf("validator record not found for address: %X\n", ownerAddr)) } } + +//__________________________________________________________________________ + +// XXX remove this code - this is should be superceded by commission work that bez is doing +// get a single validator +func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, addr sdk.ValAddress, newCommission sdk.Dec) sdk.Error { + + // call hook + k.OnValidatorCommissionChange(ctx, addr) + + validator, _ := k.GetValidator(ctx, addr) + validator.Commission = newCommission + k.SetValidator(ctx, validator) + return nil +} From 1b485bb3c851dafd9f10150d9ad64ad2aa04f9b2 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 22 Sep 2018 16:38:33 -0400 Subject: [PATCH 14/22] pending --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index 5cf80cd6f6..04b7b23f28 100644 --- a/PENDING.md +++ b/PENDING.md @@ -52,6 +52,7 @@ BREAKING CHANGES * [types] \#2343 Make sdk.Msg have a names field, to facilitate automatic tagging. * [baseapp] \#2366 Automatically add action tags to all messages * [x/staking] \#2244 staking now holds a consensus-address-index instead of a consensus-pubkey-index + * [x/staking] \#2236 more distribution hooks for distribution * Tendermint From df0d5825be5bb1d81a0b2e8cadb8069f6a4a3dca Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 22 Sep 2018 16:43:29 -0400 Subject: [PATCH 15/22] add staking hooks to staking spec --- docs/spec/staking/hooks.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 docs/spec/staking/hooks.md diff --git a/docs/spec/staking/hooks.md b/docs/spec/staking/hooks.md new file mode 100644 index 0000000000..bcc496e3d6 --- /dev/null +++ b/docs/spec/staking/hooks.md @@ -0,0 +1,19 @@ +## Receiver Hooks + +The staking module allow for the following hooks to be registered with staking events: + +``` golang +// event hooks for staking validator object +type StakingHooks interface { + OnValidatorCreated(ctx Context, address ValAddress) // called when a validator is created + OnValidatorCommissionChange(ctx Context, address ValAddress) // called when a validator's commission is modified + OnValidatorRemoved(ctx Context, address ValAddress) // called when a validator is deleted + + OnValidatorBonded(ctx Context, address ConsAddress) // called when a validator is bonded + OnValidatorBeginUnbonding(ctx Context, address ConsAddress) // called when a validator begins unbonding + + OnDelegationCreated(ctx Context, delAddr AccAddress, valAddr ValAddress) // called when a delegation is created + OnDelegationSharesModified(ctx Context, delAddr AccAddress, valAddr ValAddress) // called when a delegation's shares are modified + OnDelegationRemoved(ctx Context, delAddr AccAddress, valAddr ValAddress) // called when a delegation is removed +} +``` From 9dfeeb0d7bea7e5d6920db80eb0029240e44d4b4 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 24 Sep 2018 18:54:49 -0400 Subject: [PATCH 16/22] address bez comments --- x/stake/handler.go | 1 - x/stake/keeper/delegation.go | 6 ------ x/stake/keeper/validator.go | 8 -------- 3 files changed, 15 deletions(-) diff --git a/x/stake/handler.go b/x/stake/handler.go index b3bf4c018b..21800ffe2c 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -87,7 +87,6 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k return err.Result() } - // call hooks k.OnValidatorCreated(ctx, validator.OperatorAddr) accAddr := sdk.AccAddress(validator.OperatorAddr) k.OnDelegationCreated(ctx, accAddr, validator.OperatorAddr) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index a2392ac587..cc46646a73 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -66,10 +66,7 @@ func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { // remove a delegation from store func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) { - - // call hook k.OnDelegationRemoved(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr) - store := ctx.KVStore(k.storeKey) store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr)) } @@ -286,7 +283,6 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, shares sdk.Dec) (amount sdk.Dec, err sdk.Error) { - // call hook k.OnDelegationSharesModified(ctx, delAddr, valAddr) // check if delegation has any shares in it unbond @@ -340,9 +336,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA k.RemoveValidator(ctx, validator.OperatorAddr) } - // call hook k.OnDelegationSharesModified(ctx, delegation.DelegatorAddr, validator.OperatorAddr) - return amount, nil } diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 69bab0f8ec..6e9427d475 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -633,10 +633,7 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat // also remove from the Bonded types.Validators Store store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) - // call hook k.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) - - // return updated validator return validator } @@ -666,17 +663,13 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. tstore := ctx.TransientStore(k.storeTKey) tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) - // call hook k.OnValidatorBonded(ctx, validator.ConsAddress()) - - // return updated validator return validator } // remove the validator record and associated indexes func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { - // call hook k.OnValidatorRemoved(ctx, address) // first retrieve the old validator record @@ -745,7 +738,6 @@ func ensureValidatorFound(found bool, ownerAddr []byte) { // get a single validator func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, addr sdk.ValAddress, newCommission sdk.Dec) sdk.Error { - // call hook k.OnValidatorCommissionChange(ctx, addr) validator, _ := k.GetValidator(ctx, addr) From afe179ebb38657c3765dc74da9a459a4f1a5b139 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 24 Sep 2018 21:51:18 -0400 Subject: [PATCH 17/22] remove GetValidatorByConsPubKey --- types/address.go | 5 +++++ types/stake.go | 7 +++---- x/slashing/keeper_test.go | 16 ++++++++-------- x/slashing/tick_test.go | 2 +- x/stake/handler.go | 2 +- x/stake/keeper/sdk_types.go | 10 ---------- x/stake/keeper/slash_test.go | 4 ++-- x/stake/keeper/validator.go | 12 ------------ x/stake/keeper/validator_test.go | 2 +- 9 files changed, 21 insertions(+), 39 deletions(-) diff --git a/types/address.go b/types/address.go index 58b694f5da..ae13b2ad0a 100644 --- a/types/address.go +++ b/types/address.go @@ -292,6 +292,11 @@ func ConsAddressFromBech32(address string) (addr ConsAddress, err error) { return ConsAddress(bz), nil } +// get ConsAddress from pubkey +func GetConsAddress(pubkey crypto.PubKey) ConsAddress { + return ConsAddress(pubkey.Address()) +} + // Returns boolean for whether two ConsAddress are Equal func (ca ConsAddress) Equals(ca2 ConsAddress) bool { if ca.Empty() && ca2.Empty() { diff --git a/types/stake.go b/types/stake.go index ade96843dd..e794ea7349 100644 --- a/types/stake.go +++ b/types/stake.go @@ -68,10 +68,9 @@ type ValidatorSet interface { IterateValidatorsBonded(Context, func(index int64, validator Validator) (stop bool)) - Validator(Context, ValAddress) Validator // get a particular validator by operator address - ValidatorByConsPubKey(Context, crypto.PubKey) Validator // get a particular validator by consensus PubKey - ValidatorByConsAddr(Context, ConsAddress) Validator // get a particular validator by consensus address - TotalPower(Context) Dec // total power of the validator set + Validator(Context, ValAddress) Validator // get a particular validator by operator address + ValidatorByConsAddr(Context, ConsAddress) Validator // get a particular validator by consensus address + TotalPower(Context) Dec // total power of the validator set // slash the validator and delegators of the validator, specifying offence height, offence power, and slash fraction Slash(Context, ConsAddress, int64, int64, Dec) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 9a3ff537c2..d4b1af3d51 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -167,7 +167,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.SignedBlocksCounter) // validator should be bonded still - validator, _ := sk.GetValidatorByConsPubKey(ctx, val) + validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Bonded, validator.GetStatus()) pool := sk.GetPool(ctx) require.Equal(t, amtInt, pool.BondedTokens.RoundInt64()) @@ -181,7 +181,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter) // validator should have been jailed - validator, _ = sk.GetValidatorByConsPubKey(ctx, val) + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Unbonding, validator.GetStatus()) // unrevocation should fail prior to jail expiration @@ -194,7 +194,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, got.IsOK()) // validator should be rebonded now - validator, _ = sk.GetValidatorByConsPubKey(ctx, val) + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Bonded, validator.GetStatus()) // validator should have been slashed @@ -212,7 +212,7 @@ func TestHandleAbsentValidator(t *testing.T) { height++ ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) - validator, _ = sk.GetValidatorByConsPubKey(ctx, val) + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Bonded, validator.GetStatus()) // 500 signed blocks @@ -228,7 +228,7 @@ func TestHandleAbsentValidator(t *testing.T) { ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) } - validator, _ = sk.GetValidatorByConsPubKey(ctx, val) + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Unbonding, validator.GetStatus()) } @@ -263,7 +263,7 @@ func TestHandleNewValidator(t *testing.T) { require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) // validator should be bonded still, should not have been jailed or slashed - validator, _ := sk.GetValidatorByConsPubKey(ctx, val) + validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Bonded, validator.GetStatus()) pool := sk.GetPool(ctx) require.Equal(t, int64(100), pool.BondedTokens.RoundInt64()) @@ -297,7 +297,7 @@ func TestHandleAlreadyJailed(t *testing.T) { } // validator should have been jailed and slashed - validator, _ := sk.GetValidatorByConsPubKey(ctx, val) + validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Unbonding, validator.GetStatus()) // validator should have been slashed @@ -308,7 +308,7 @@ func TestHandleAlreadyJailed(t *testing.T) { keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) // validator should not have been slashed twice - validator, _ = sk.GetValidatorByConsPubKey(ctx, val) + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, amtInt-1, validator.GetTokens().RoundInt64()) } diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index fe273be5eb..8225c96347 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -78,7 +78,7 @@ func TestBeginBlocker(t *testing.T) { } // validator should be jailed - validator, found := sk.GetValidatorByConsPubKey(ctx, pk) + validator, found := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(pk)) require.True(t, found) require.Equal(t, sdk.Unbonding, validator.GetStatus()) } diff --git a/x/stake/handler.go b/x/stake/handler.go index f4864a14a6..4d74c8a7bf 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -68,7 +68,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k if found { return ErrValidatorOwnerExists(k.Codespace()).Result() } - _, found = k.GetValidatorByConsPubKey(ctx, msg.PubKey) + _, found = k.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(msg.PubKey)) if found { return ErrValidatorPubKeyExists(k.Codespace()).Result() } diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index 9872630a4e..d702e845da 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -5,7 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" - "github.com/tendermint/tendermint/crypto" ) // Implements ValidatorSet @@ -67,15 +66,6 @@ func (k Keeper) ValidatorByConsAddr(ctx sdk.Context, addr sdk.ConsAddress) sdk.V return val } -// get the sdk.validator for a particular pubkey -func (k Keeper) ValidatorByConsPubKey(ctx sdk.Context, consPubKey crypto.PubKey) sdk.Validator { - val, found := k.GetValidatorByConsPubKey(ctx, consPubKey) - if !found { - return nil - } - return val -} - // total power from the bond func (k Keeper) TotalPower(ctx sdk.Context) sdk.Dec { pool := k.GetPool(ctx) diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 7d2f2f785c..0a6cccac2a 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -473,7 +473,7 @@ func TestSlashBoth(t *testing.T) { // slash validator ctx = ctx.WithBlockHeight(12) oldPool := keeper.GetPool(ctx) - validator, found := keeper.GetValidatorByConsPubKey(ctx, PKs[0]) + validator, found := keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) require.True(t, found) consAddr0 := sdk.ConsAddress(PKs[0].Address()) keeper.Slash(ctx, consAddr0, 10, 10, fraction) @@ -490,7 +490,7 @@ func TestSlashBoth(t *testing.T) { // bonded tokens burned require.Equal(t, int64(3), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // read updated validator - validator, found = keeper.GetValidatorByConsPubKey(ctx, PKs[0]) + validator, found = keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) require.True(t, found) // power not decreased, all stake was bonded since require.Equal(t, sdk.NewDec(10), validator.GetPower()) diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index f7c43757ff..00d465cff1 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -6,7 +6,6 @@ import ( "fmt" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" @@ -68,17 +67,6 @@ func (k Keeper) GetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress return k.GetValidator(ctx, opAddr) } -// get a single validator by pubkey -func (k Keeper) GetValidatorByConsPubKey(ctx sdk.Context, consPubKey crypto.PubKey) (validator types.Validator, found bool) { - store := ctx.KVStore(k.storeKey) - consAddr := sdk.ConsAddress(consPubKey.Address()) - opAddr := store.Get(GetValidatorByConsAddrKey(consAddr)) - if opAddr == nil { - return validator, false - } - return k.GetValidator(ctx, opAddr) -} - // set the main record holding validator details func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 356170189a..c21336f9f3 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -314,7 +314,7 @@ func TestValidatorBasics(t *testing.T) { resVal, found = keeper.GetValidatorByConsAddr(ctx, sdk.ConsAddress(PKs[0].Address())) require.True(t, found) assert.True(ValEq(t, validators[0], resVal)) - resVal, found = keeper.GetValidatorByConsPubKey(ctx, PKs[0]) + resVal, found = keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0])) require.True(t, found) assert.True(ValEq(t, validators[0], resVal)) From dad4253957b943b1f0d742c223ef86f1f6177cae Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 24 Sep 2018 22:27:09 -0400 Subject: [PATCH 18/22] merge fix --- x/stake/types/validator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 30cf1f17c0..051ffa9e51 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -458,6 +458,6 @@ func (v Validator) GetConsPubKey() crypto.PubKey { return v.ConsPubKey } func (v Validator) GetConsAddr() sdk.ConsAddress { return sdk.ConsAddress(v.ConsPubKey.Address()) } func (v Validator) GetPower() sdk.Dec { return v.BondedTokens() } func (v Validator) GetTokens() sdk.Dec { return v.Tokens } -func (v Validator) GetCommission() sdk.Dec { return v.Commission } +func (v Validator) GetCommission() sdk.Dec { return v.Commission.Rate } func (v Validator) GetDelegatorShares() sdk.Dec { return v.DelegatorShares } func (v Validator) GetBondHeight() int64 { return v.BondHeight } From ca2fc77af7c1030ad9fa6889e236ff2298197205 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 24 Sep 2018 22:58:26 -0400 Subject: [PATCH 19/22] update commission hook for new commission work --- x/stake/keeper/validator.go | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 406093cbdf..b812e6a20a 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -699,6 +699,7 @@ func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Valid validator.Commission.UpdateTime = blockTime k.SetValidator(ctx, validator) + k.OnValidatorCommissionChange(ctx, addr) return nil } @@ -736,17 +737,3 @@ func ensureValidatorFound(found bool, ownerAddr []byte) { panic(fmt.Sprintf("validator record not found for address: %X\n", ownerAddr)) } } - -//__________________________________________________________________________ - -// XXX remove this code - this is should be superceded by commission work that bez is doing -// get a single validator -func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, addr sdk.ValAddress, newCommission sdk.Dec) sdk.Error { - - k.OnValidatorCommissionChange(ctx, addr) - - validator, _ := k.GetValidator(ctx, addr) - validator.Commission = newCommission - k.SetValidator(ctx, validator) - return nil -} From 5be5ea3b4cfb70f43e7034012daa80c6ffb6a4a8 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 24 Sep 2018 23:07:55 -0400 Subject: [PATCH 20/22] comment update --- types/decimal.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 79ada9559d..13a494ba0c 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -335,7 +335,7 @@ func chopPrecisionAndTruncateNonMutative(d *big.Int) *big.Int { return chopPrecisionAndTruncate(tmp) } -// RoundInt64 rounds the decimal using bankers rounding +// TruncateInt64 truncates the decimals from the number and returns an int64 func (d Dec) TruncateInt64() int64 { chopped := chopPrecisionAndTruncateNonMutative(d.Int) if !chopped.IsInt64() { @@ -344,7 +344,7 @@ func (d Dec) TruncateInt64() int64 { return chopped.Int64() } -// RoundInt round the decimal using bankers rounding +// TruncateInt truncates the decimals from the number and returns an Int func (d Dec) TruncateInt() Int { return NewIntFromBigInt(chopPrecisionAndTruncateNonMutative(d.Int)) } From 2fb3493ff57c32d13c3c20c6270d8dc694e03b54 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Tue, 25 Sep 2018 14:36:42 -0700 Subject: [PATCH 21/22] Merge PR #2223: Gaia CLI Config Command * Allow a gaia-cli config file to be created Closes #1613. Closes #1275. Closes #1956. * Add homedir to Gopkg.toml * Updates from code review * Post-rebase fixes * Update test * Code review refactor * Fixes from code review * Fix import * Fix broken test * Fixes from rebase * Fix formatting --- Gopkg.lock | 10 ++ Gopkg.toml | 4 + PENDING.md | 1 + client/config.go | 131 +++++++++++++++++++++++++++ client/flags.go | 9 ++ client/input.go | 18 ++++ client/lcd/root.go | 3 + client/rpc/block.go | 3 + client/rpc/root.go | 4 + client/rpc/status.go | 2 + client/rpc/validators.go | 4 + client/tx/query.go | 8 +- client/tx/search.go | 5 +- cmd/gaia/cli_test/cli_test.go | 43 +++++++++ cmd/gaia/cmd/gaiacli/main.go | 32 ++++++- types/utils.go | 25 ++++- x/auth/client/txbuilder/txbuilder.go | 2 +- x/auth/client/txbuilder/utils.go | 25 ----- 18 files changed, 298 insertions(+), 31 deletions(-) create mode 100644 client/config.go delete mode 100644 x/auth/client/txbuilder/utils.go diff --git a/Gopkg.lock b/Gopkg.lock index d64538d36b..00eafa4ade 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -229,6 +229,14 @@ revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" version = "v1.0.1" +[[projects]] + digest = "1:78bbb1ba5b7c3f2ed0ea1eab57bdd3859aec7e177811563edc41198a760b06af" + name = "github.com/mitchellh/go-homedir" + packages = ["."] + pruneopts = "UT" + revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4" + version = "v1.0.0" + [[projects]] digest = "1:645110e089152bd0f4a011a2648fbb0e4df5977be73ca605781157ac297f50c4" name = "github.com/mitchellh/mapstructure" @@ -630,6 +638,8 @@ "github.com/golang/protobuf/proto", "github.com/gorilla/mux", "github.com/mattn/go-isatty", + "github.com/mitchellh/go-homedir", + "github.com/pelletier/go-toml", "github.com/pkg/errors", "github.com/spf13/cobra", "github.com/spf13/pflag", diff --git a/Gopkg.toml b/Gopkg.toml index 2b5928a897..3080e3cd35 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -70,3 +70,7 @@ [prune] go-tests = true unused-packages = true + +[[constraint]] + name = "github.com/mitchellh/go-homedir" + version = "1.0.0" diff --git a/PENDING.md b/PENDING.md index 95dcc7c47d..a4abb336bd 100644 --- a/PENDING.md +++ b/PENDING.md @@ -81,6 +81,7 @@ FEATURES * [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add --generate-only flag to build an unsigned transaction and write it to STDOUT. * [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) New `sign` command to sign transactions generated with the --generate-only flag. * [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) New `broadcast` command to broadcast transactions generated offline and signed with the `sign` command. + * [cli] \#2220 Add `gaiacli config` feature to interactively create CLI config files to reduce the number of required flags * [stake][cli] [\#1672](https://github.com/cosmos/cosmos-sdk/issues/1672) Introduced new commission flags for validator commands `create-validator` and `edit-validator`. diff --git a/client/config.go b/client/config.go new file mode 100644 index 0000000000..fcb2523753 --- /dev/null +++ b/client/config.go @@ -0,0 +1,131 @@ +package client + +import ( + "github.com/spf13/cobra" + "github.com/mitchellh/go-homedir" + "bufio" + "path" + "os" + "io/ioutil" + "github.com/pelletier/go-toml" + "fmt" + "github.com/cosmos/cosmos-sdk/types" +) + +type cliConfig struct { + Home string `toml:"home"` + ChainID string `toml:"chain_id"` + TrustNode bool `toml:"trust_node"` + Encoding string `toml:"encoding"` + Output string `toml:"output"` + Node string `toml:"node"` + Trace bool `toml:"trace"` +} + +// ConfigCmd returns a CLI command to interactively create a +// Gaia CLI config file. +func ConfigCmd() *cobra.Command { + cfg := &cobra.Command{ + Use: "config", + Short: "Interactively creates a Gaia CLI config file", + RunE: runConfigCmd, + } + + return cfg +} + +func runConfigCmd(cmd *cobra.Command, args [] string) error { + home, err := homedir.Dir() + if err != nil { + return err + } + + stdin := BufferStdin() + gaiaCLIHome, err := handleGaiaCLIHome(home, stdin) + if err != nil { + return err + } + node, err := handleNode(stdin) + if err != nil { + return err + } + trustNode, err := handleTrustNode(stdin) + if err != nil { + return err + } + + encoding := "btc" + output := "text" + var chainID string + chainID, err = types.DefaultChainID() + if err != nil { + fmt.Println("Couldn't populate ChainID, so using an empty one.") + } + + cfg := &cliConfig{ + Home: gaiaCLIHome, + ChainID: chainID, + TrustNode: trustNode, + Encoding: encoding, + Output: output, + Node: node, + Trace: false, + } + + return createGaiaCLIConfig(cfg) +} + +func handleGaiaCLIHome(dir string, stdin *bufio.Reader) (string, error) { + dirName := ".gaiacli" + home, err := GetString(fmt.Sprintf("Where is your gaiacli home directory? (Default: ~/%s)", dirName), stdin) + if err != nil { + return "", err + } + + if home == "" { + home = path.Join(dir, dirName) + } + + return home, nil +} + +func handleNode(stdin *bufio.Reader) (string, error) { + defaultNode := "tcp://localhost:26657" + node, err := GetString(fmt.Sprintf("Where is your validator node running? (Default: %s)", defaultNode), stdin) + if err != nil { + return "", err + } + + if node == "" { + node = defaultNode + } + + return node, nil +} + +func handleTrustNode(stdin *bufio.Reader) (bool, error) { + return GetConfirmation("Do you trust this node?", stdin) +} + +func createGaiaCLIConfig(cfg *cliConfig) error { + cfgPath := path.Join(cfg.Home, "config") + err := os.MkdirAll(cfgPath, os.ModePerm) + if err != nil { + return err + } + + data, err := toml.Marshal(*cfg) + if err != nil { + return err + } + + cfgFile := path.Join(cfgPath, "config.toml") + if info, err := os.Stat(cfgFile); err == nil && !info.IsDir() { + err = os.Rename(cfgFile, path.Join(cfgPath, "config.toml-old")) + if err != nil { + return err + } + } + + return ioutil.WriteFile(cfgFile, data, os.ModePerm) +} diff --git a/client/flags.go b/client/flags.go index d0d783d3a7..ff93549370 100644 --- a/client/flags.go +++ b/client/flags.go @@ -5,6 +5,7 @@ import ( "strconv" "github.com/spf13/cobra" + "github.com/spf13/viper" ) // nolint @@ -51,6 +52,10 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command { c.Flags().String(FlagChainID, "", "Chain ID of tendermint node") c.Flags().String(FlagNode, "tcp://localhost:26657", ": to tendermint rpc interface for this chain") c.Flags().Int64(FlagHeight, 0, "block height to query, omit to get most recent provable block") + viper.BindPFlag(FlagTrustNode, c.Flags().Lookup(FlagTrustNode)) + viper.BindPFlag(FlagUseLedger, c.Flags().Lookup(FlagUseLedger)) + viper.BindPFlag(FlagChainID, c.Flags().Lookup(FlagChainID)) + viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode)) } return cmds } @@ -76,6 +81,10 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command { // --gas can accept integers and "simulate" c.Flags().Var(&GasFlagVar, "gas", fmt.Sprintf( "gas limit to set per-transaction; set to %q to calculate required gas automatically (default %d)", GasFlagSimulate, DefaultGasLimit)) + viper.BindPFlag(FlagTrustNode, c.Flags().Lookup(FlagTrustNode)) + viper.BindPFlag(FlagUseLedger, c.Flags().Lookup(FlagUseLedger)) + viper.BindPFlag(FlagChainID, c.Flags().Lookup(FlagChainID)) + viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode)) } return cmds } diff --git a/client/input.go b/client/input.go index b10f65ce62..a456f1b92a 100644 --- a/client/input.go +++ b/client/input.go @@ -100,6 +100,19 @@ func GetConfirmation(prompt string, buf *bufio.Reader) (bool, error) { } } +// GetString simply returns the trimmed string output of a given reader. +func GetString(prompt string, buf *bufio.Reader) (string, error) { + if inputIsTty() && prompt != "" { + PrintPrefixed(prompt) + } + + out, err := readLineFromBuf(buf) + if err != nil { + return "", err + } + return strings.TrimSpace(out), nil +} + // inputIsTty returns true iff we have an interactive prompt, // where we can disable echo and request to repeat the password. // If false, we can optimize for piped input from another command @@ -117,3 +130,8 @@ func readLineFromBuf(buf *bufio.Reader) (string, error) { } return strings.TrimSpace(pass), nil } + +// PrintPrefixed prints a string with > prefixed for use in prompts. +func PrintPrefixed(msg string) { + fmt.Printf("> %s\n", msg) +} diff --git a/client/lcd/root.go b/client/lcd/root.go index 36fbd42d0b..84d3e806c9 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -121,6 +121,9 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command { cmd.Flags().String(client.FlagNode, "tcp://localhost:26657", "Address of the node to connect to") cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections") cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)") + viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode)) + viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID)) + viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode)) return cmd } diff --git a/client/rpc/block.go b/client/rpc/block.go index 3824bc3e5c..44def2d323 100644 --- a/client/rpc/block.go +++ b/client/rpc/block.go @@ -10,6 +10,7 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" + "github.com/spf13/viper" tmliteProxy "github.com/tendermint/tendermint/lite/proxy" ) @@ -22,7 +23,9 @@ func BlockCommand() *cobra.Command { RunE: printBlock, } cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") + viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode)) cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)") + viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode)) cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node") return cmd } diff --git a/client/rpc/root.go b/client/rpc/root.go index a8171a293a..74c5a69a2e 100644 --- a/client/rpc/root.go +++ b/client/rpc/root.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/spf13/viper" ) const ( @@ -40,6 +41,9 @@ func initClientCommand() *cobra.Command { cmd.Flags().String(flagGenesis, "", "Genesis file to verify header validity") cmd.Flags().String(flagCommit, "", "File with trusted and signed header") cmd.Flags().String(flagValHash, "", "Hash of trusted validator set (hex-encoded)") + viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID)) + viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode)) + return cmd } diff --git a/client/rpc/status.go b/client/rpc/status.go index ea090d32f9..6c42701754 100644 --- a/client/rpc/status.go +++ b/client/rpc/status.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" ctypes "github.com/tendermint/tendermint/rpc/core/types" + "github.com/spf13/viper" ) func statusCommand() *cobra.Command { @@ -20,6 +21,7 @@ func statusCommand() *cobra.Command { } cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") + viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode)) return cmd } diff --git a/client/rpc/validators.go b/client/rpc/validators.go index 0583dc0545..d8572d5444 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" tmtypes "github.com/tendermint/tendermint/types" + "github.com/spf13/viper" ) // TODO these next two functions feel kinda hacky based on their placement @@ -26,8 +27,11 @@ func ValidatorCommand() *cobra.Command { RunE: printValidators, } cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") + viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode)) cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)") + viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode)) cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node") + viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID)) return cmd } diff --git a/client/tx/query.go b/client/tx/query.go index 732c11b659..f1d13b608a 100644 --- a/client/tx/query.go +++ b/client/tx/query.go @@ -3,8 +3,8 @@ package tx import ( "encoding/hex" "fmt" - "github.com/tendermint/tendermint/libs/common" "net/http" + "github.com/tendermint/tendermint/libs/common" "github.com/gorilla/mux" "github.com/spf13/cobra" @@ -16,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/spf13/viper" ) // QueryTxCmd implements the default command for a tx query. @@ -41,8 +42,11 @@ func QueryTxCmd(cdc *codec.Codec) *cobra.Command { } cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") - cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)") + viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode)) cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node") + viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID)) + cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)") + viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode)) return cmd } diff --git a/client/tx/search.go b/client/tx/search.go index 5bc8726db1..8d83c44b3e 100644 --- a/client/tx/search.go +++ b/client/tx/search.go @@ -62,8 +62,11 @@ $ gaiacli tendermint txs --tag test1,test2 --any } cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") - cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)") + viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode)) cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node") + viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID)) + cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)") + viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode)) cmd.Flags().StringSlice(flagTags, nil, "Comma-separated list of tags that must match") cmd.Flags().Bool(flagAny, false, "Return transactions that match ANY tag, rather than ALL") return cmd diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 3c847dc90e..8e31c664bc 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "os" "testing" + "path" "github.com/stretchr/testify/require" @@ -515,6 +516,48 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) { require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) } +func TestGaiaCLIConfig(t *testing.T) { + require.NoError(t, os.RemoveAll(gaiacliHome)) + require.NoError(t, os.RemoveAll(gaiadHome)) + servAddr, port, err := server.FreeTCPAddr() + require.NoError(t, err) + node := fmt.Sprintf("%s:%s", servAddr, port) + chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) + executeWrite(t, fmt.Sprintf("gaiacli --home=%s config", gaiadHome), gaiacliHome, node, "y") + config, err := ioutil.ReadFile(path.Join(gaiacliHome, "config", "config.toml")) + require.NoError(t, err) + expectedConfig := fmt.Sprintf(`chain_id = "%s" +encoding = "btc" +home = "%s" +node = "%s" +output = "text" +trace = false +trust_node = true +`, chainID, gaiacliHome, node) + require.Equal(t, expectedConfig, string(config)) + // ensure a backup gets created + executeWrite(t, "gaiacli config", gaiacliHome, node, "y", "y") + configBackup, err := ioutil.ReadFile(path.Join(gaiacliHome, "config", "config.toml-old")) + require.NoError(t, err) + require.Equal(t, expectedConfig, string(configBackup)) + + require.NoError(t, os.RemoveAll(gaiadHome)) + executeWrite(t, "gaiacli config", gaiacliHome, node, "y") + + // ensure it works without an initialized gaiad state + expectedConfig = fmt.Sprintf(`chain_id = "" +encoding = "btc" +home = "%s" +node = "%s" +output = "text" +trace = false +trust_node = true +`, gaiacliHome, node) + config, err = ioutil.ReadFile(path.Join(gaiacliHome, "config", "config.toml")) + require.NoError(t, err) + require.Equal(t, expectedConfig, string(config)) +} + //___________________________________________________________________________________ // helper methods diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index c61b30056f..fee43dc02b 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -18,6 +18,9 @@ import ( stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli" "github.com/cosmos/cosmos-sdk/cmd/gaia/app" + "path" + "os" + "github.com/spf13/viper" ) // rootCmd is the entry point for this binary @@ -35,6 +38,7 @@ func main() { // TODO: setup keybase, viper object, etc. to be passed into // the below functions and eliminate global vars, like we do // with the cdc + rootCmd.AddCommand(client.ConfigCmd()) // add standard rpc commands rpc.AddCommands(rootCmd) @@ -131,9 +135,35 @@ func main() { // prepare and add flags executor := cli.PrepareMainCmd(rootCmd, "GA", app.DefaultCLIHome) - err := executor.Execute() + err := initConfig(rootCmd) + if err != nil { + panic(err) + } + + err = executor.Execute() if err != nil { // handle with #870 panic(err) } } + +func initConfig(cmd *cobra.Command) error { + home, err := cmd.PersistentFlags().GetString(cli.HomeFlag) + if err != nil { + return err + } + + cfgFile := path.Join(home, "config", "config.toml") + if _, err := os.Stat(cfgFile); err == nil { + viper.SetConfigFile(cfgFile) + + if err := viper.ReadInConfig(); err != nil { + return err + } + } + + if err := viper.BindPFlag(cli.EncodingFlag, cmd.PersistentFlags().Lookup(cli.EncodingFlag)); err != nil { + return err + } + return viper.BindPFlag(cli.OutputFlag, cmd.PersistentFlags().Lookup(cli.OutputFlag)) +} diff --git a/types/utils.go b/types/utils.go index 2e027676a0..95fc779d73 100644 --- a/types/utils.go +++ b/types/utils.go @@ -1,6 +1,10 @@ package types -import "encoding/json" +import ( + "encoding/json" + tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" + tmtypes "github.com/tendermint/tendermint/types" +) // SortedJSON takes any JSON and returns it sorted by keys. Also, all white-spaces // are removed. @@ -29,3 +33,22 @@ func MustSortJSON(toSortJSON []byte) []byte { } return js } + +// DefaultChainID returns the chain ID from the genesis file if present. An +// error is returned if the file cannot be read or parsed. +// +// TODO: This should be removed and the chainID should always be provided by +// the end user. +func DefaultChainID() (string, error) { + cfg, err := tcmd.ParseConfig() + if err != nil { + return "", err + } + + doc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile()) + if err != nil { + return "", err + } + + return doc.ChainID, nil +} \ No newline at end of file diff --git a/x/auth/client/txbuilder/txbuilder.go b/x/auth/client/txbuilder/txbuilder.go index 030ddb72a4..642893b52f 100644 --- a/x/auth/client/txbuilder/txbuilder.go +++ b/x/auth/client/txbuilder/txbuilder.go @@ -30,7 +30,7 @@ func NewTxBuilderFromCLI() TxBuilder { // if chain ID is not specified manually, read default chain ID chainID := viper.GetString(client.FlagChainID) if chainID == "" { - defaultChainID, err := defaultChainID() + defaultChainID, err := sdk.DefaultChainID() if err != nil { chainID = defaultChainID } diff --git a/x/auth/client/txbuilder/utils.go b/x/auth/client/txbuilder/utils.go deleted file mode 100644 index 22cc8220bb..0000000000 --- a/x/auth/client/txbuilder/utils.go +++ /dev/null @@ -1,25 +0,0 @@ -package context - -import ( - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - tmtypes "github.com/tendermint/tendermint/types" -) - -// defaultChainID returns the chain ID from the genesis file if present. An -// error is returned if the file cannot be read or parsed. -// -// TODO: This should be removed and the chainID should always be provided by -// the end user. -func defaultChainID() (string, error) { - cfg, err := tcmd.ParseConfig() - if err != nil { - return "", err - } - - doc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile()) - if err != nil { - return "", err - } - - return doc.ChainID, nil -} From 4929b022ceb0ac1f4ec5cd6f1c7835e4c139f7b2 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 25 Sep 2018 19:59:46 -0400 Subject: [PATCH 22/22] mini-fix --- x/stake/keeper/validator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 9acdb67644..84a82dba5f 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -695,7 +695,7 @@ func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Valid validator.Commission.UpdateTime = blockTime k.SetValidator(ctx, validator) - k.OnValidatorCommissionChange(ctx, addr) + k.OnValidatorCommissionChange(ctx, validator.OperatorAddr) return nil }