Proof of Authority for tendermint consensus

allows validators to have 0 delegated tokens
This commit is contained in:
Csongor Kiss 2022-02-11 18:47:22 +00:00 committed by Conor Patrick
parent f2d94445c0
commit 0700b0b1bb
6 changed files with 37 additions and 29 deletions

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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:

View File

@ -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
}

View File

@ -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) {

View File

@ -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)
}