diff --git a/x/staking/genesis.go b/x/staking/genesis.go index 51ae11a25..e298bec7a 100644 --- a/x/staking/genesis.go +++ b/x/staking/genesis.go @@ -138,7 +138,12 @@ func InitGenesis( panic(fmt.Sprintf("validator %s not found", lv.Address)) } - update := validator.ABCIValidatorUpdate(keeper.PowerReduction(ctx)) + var update abci.ValidatorUpdate + if validator.IsGuardian() { + update = validator.ABCIValidatorUpdate() + } else { + update = validator.ABCIValidatorUpdateZero() + } update.Power = lv.Power // keep the next-val-set offset, use the last power for the first block res = append(res, update) } diff --git a/x/staking/keeper/msg_server.go b/x/staking/keeper/msg_server.go index 3642cef1e..d30535c40 100644 --- a/x/staking/keeper/msg_server.go +++ b/x/staking/keeper/msg_server.go @@ -160,10 +160,6 @@ func (k msgServer) EditValidator(goCtx context.Context, msg *types.MsgEditValida return nil, types.ErrMinSelfDelegationDecreased } - if msg.MinSelfDelegation.GT(validator.Tokens) { - return nil, types.ErrSelfDelegationBelowMinimum - } - validator.MinSelfDelegation = (*msg.MinSelfDelegation) } diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index 22f699366..9144f3d68 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -105,6 +105,7 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { // CONTRACT: Only validators with non-zero power or zero-power that were bonded // at the previous block height or were removed from the validator set entirely // are returned to Tendermint. +// TODO(csongor): review this func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate, err error) { params := k.GetParams(ctx) maxValidators := params.MaxValidators @@ -112,6 +113,8 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab totalPower := sdk.ZeroInt() amtFromBondedToNotBonded, amtFromNotBondedToBonded := sdk.ZeroInt(), sdk.ZeroInt() + // TODO(csongor): add new guardians that were not here before (from gov) + // Retrieve the last validator set. // The persistent set is updated later in this function. // (see LastValidatorPowerKey). @@ -134,10 +137,10 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab panic("should never retrieve a jailed validator from the power store") } - // if we get to a zero-power validator (which we don't bond), - // there are no more possible bonded validators - if validator.PotentialConsensusPower(k.PowerReduction(ctx)) == 0 { - break + // if we get to a validator that's not a guardian (after a guardian set + // update), we kick it out + if !validator.IsGuardian() { + continue } // apply the appropriate state change if necessary @@ -169,10 +172,11 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab newPower := validator.ConsensusPower(powerReduction) newPowerBytes := k.cdc.MustMarshal(&gogotypes.Int64Value{Value: newPower}) - // update the validator set if power has changed - if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) { - updates = append(updates, validator.ABCIValidatorUpdate(powerReduction)) + // TODO(csongor): is this expensive to do in each block? we can cache + updates = append(updates, validator.ABCIValidatorUpdate()) + // update the validator set if governance power has changed + if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) { k.SetLastValidatorPower(ctx, valAddr, newPower) } @@ -194,8 +198,8 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab return } amtFromBondedToNotBonded = amtFromBondedToNotBonded.Add(validator.GetTokens()) - k.DeleteLastValidatorPower(ctx, validator.GetOperator()) - updates = append(updates, validator.ABCIValidatorUpdateZero()) + k.DeleteLastValidatorPower(ctx, validator.GetOperator()) // remove from gov validators + updates = append(updates, validator.ABCIValidatorUpdateZero()) // remove from tendermint validators } // Update the pools based on the recent updates in the validator set: diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index af60ac370..0f59cb42d 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -113,7 +113,7 @@ func (msg MsgCreateValidator) ValidateBasic() error { return ErrEmptyValidatorPubKey } - if !msg.Value.IsValid() || !msg.Value.Amount.IsPositive() { + if !msg.Value.IsValid() || msg.Value.Amount.IsNegative() { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid delegation amount") } @@ -129,17 +129,6 @@ func (msg MsgCreateValidator) ValidateBasic() error { return err } - if !msg.MinSelfDelegation.IsPositive() { - return sdkerrors.Wrap( - sdkerrors.ErrInvalidRequest, - "minimum self delegation must be a positive integer", - ) - } - - if msg.Value.Amount.LT(msg.MinSelfDelegation) { - return ErrSelfDelegationBelowMinimum - } - return nil } diff --git a/x/staking/types/staking.pb.go b/x/staking/types/staking.pb.go index 618599edb..bec159787 100644 --- a/x/staking/types/staking.pb.go +++ b/x/staking/types/staking.pb.go @@ -336,6 +336,12 @@ type Validator struct { MinSelfDelegation github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,11,opt,name=min_self_delegation,json=minSelfDelegation,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"min_self_delegation" yaml:"min_self_delegation"` } +func (*Validator) IsGuardian() bool { + // TODO(csongor): write logic to work out if this is a guardian + // This will require the staking module to use the wormhole module's state keeper + return true +} + func (m *Validator) Reset() { *m = Validator{} } func (*Validator) ProtoMessage() {} func (*Validator) Descriptor() ([]byte, []int) { diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index ed394acf4..e4dd25dc6 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -56,7 +56,7 @@ func NewValidator(operator sdk.ValAddress, pubKey cryptotypes.PubKey, descriptio UnbondingHeight: int64(0), UnbondingTime: time.Unix(0, 0).UTC(), Commission: NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), - MinSelfDelegation: sdk.OneInt(), + MinSelfDelegation: sdk.ZeroInt(), }, nil } @@ -255,7 +255,9 @@ func (d Description) EnsureLength() (Description, error) { // ABCIValidatorUpdate returns an abci.ValidatorUpdate from a staking validator type // with the full validator power -func (v Validator) ABCIValidatorUpdate(r sdk.Int) abci.ValidatorUpdate { +// Implements Proof of Authority, which can be thought of as a binary staking +// model (either have consensus power, or not) +func (v Validator) ABCIValidatorUpdate() abci.ValidatorUpdate { tmProtoPk, err := v.TmConsPublicKey() if err != nil { panic(err) @@ -263,7 +265,7 @@ func (v Validator) ABCIValidatorUpdate(r sdk.Int) abci.ValidatorUpdate { return abci.ValidatorUpdate{ PubKey: tmProtoPk, - Power: v.ConsensusPower(r), + Power: 1, } } @@ -307,12 +309,18 @@ func (v Validator) TokensFromShares(shares sdk.Dec) sdk.Dec { // calculate the token worth of provided shares, truncated func (v Validator) TokensFromSharesTruncated(shares sdk.Dec) sdk.Dec { + if (v.DelegatorShares.IsZero()) { + return sdk.Dec(sdk.ZeroInt()) + } return (shares.MulInt(v.Tokens)).QuoTruncate(v.DelegatorShares) } // TokensFromSharesRoundUp returns the token worth of provided shares, rounded // up. func (v Validator) TokensFromSharesRoundUp(shares sdk.Dec) sdk.Dec { + if (v.DelegatorShares.IsZero()) { + return sdk.Dec(sdk.ZeroInt()) + } return (shares.MulInt(v.Tokens)).QuoRoundUp(v.DelegatorShares) }