Skip to content

Commit

Permalink
SetPower unsafe option (30%VP),
Browse files Browse the repository at this point in the history
  • Loading branch information
Reecepbcups committed Oct 21, 2023
1 parent 6e938cd commit 32c99d8
Show file tree
Hide file tree
Showing 6 changed files with 370 additions and 178 deletions.
289 changes: 176 additions & 113 deletions api/v1/tx.pulsar.go

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func NewTxCmd(ac address.Codec) *cobra.Command {

func NewSetPowerCmd(ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "set-power [validator] [power]",
Use: "set-power [validator] [power] [--unsafe]",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
Expand All @@ -64,10 +64,16 @@ func NewSetPowerCmd(ac address.Codec) *cobra.Command {
return fmt.Errorf("strconv.ParseUint failed: %w", err)
}

unsafeAction, err := cmd.Flags().GetBool("unsafe")
if err != nil {
return fmt.Errorf("get unsafe flag failed: %w", err)
}

msg := &poa.MsgSetPower{
FromAddress: clientCtx.GetFromAddress().String(),
ValidatorAddress: validator,
Power: power,
Unsafe: unsafeAction,
}

if err := msg.Validate(ac); err != nil {
Expand All @@ -79,6 +85,7 @@ func NewSetPowerCmd(ac address.Codec) *cobra.Command {
}

flags.AddTxFlagsToCmd(cmd)
cmd.Flags().Bool("unsafe", false, "set power without checking if validator is in the validator set")

return cmd
}
Expand Down
102 changes: 93 additions & 9 deletions keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

"github.com/strangelove-ventures/poa"
Expand All @@ -33,6 +34,10 @@ func (ms msgServer) SetPower(ctx context.Context, msg *poa.MsgSetPower) (*poa.Ms
return nil, fmt.Errorf("not an authority")
}

if err := msg.Validate(ms.k.validatorAddressCodec); err != nil {
return nil, err
}

isPending, err := ms.k.IsValidatorPending(ctx, msg.ValidatorAddress)
if err != nil {
return nil, err
Expand All @@ -55,6 +60,18 @@ func (ms msgServer) SetPower(ctx context.Context, msg *poa.MsgSetPower) (*poa.Ms
return nil, fmt.Errorf("GetValidator failed: %w", err)
}

// if msg.Unsafe is true, we don't check the total power and set it.
if !msg.Unsafe {
totalPower, err := ms.getTotalChainPower(ctx)
if err != nil {
return nil, err
}

if msg.Power > totalPower.Mul(math.NewInt(30)).Quo(math.NewInt(100)).Uint64() {
return nil, fmt.Errorf("unsafe: msg.Power is >30%% of total power, set unsafe=true to override")
}
}

// clean delegations up
delegations, err := ms.k.stakingKeeper.GetValidatorDelegations(ctx, valAddr)
if err != nil {
Expand All @@ -72,8 +89,6 @@ func (ms msgServer) SetPower(ctx context.Context, msg *poa.MsgSetPower) (*poa.Ms
Shares: math.LegacyNewDec(int64(msg.Power)),
}

// TODO: Do not allow setting lower than 1_000_000 ?
// TODO: does this cause any invariance issues?
val.DelegatorShares = delegation.Shares
val.Tokens = math.NewIntFromUint64(msg.Power)
val.Status = stakingtypes.Bonded
Expand All @@ -85,6 +100,7 @@ func (ms msgServer) SetPower(ctx context.Context, msg *poa.MsgSetPower) (*poa.Ms
if err := ms.k.stakingKeeper.SetValidator(ctx, val); err != nil {
return nil, err
}
ms.k.stakingKeeper.SetLastValidatorPower(ctx, valAddr, int64(msg.Power))

delegations, err = ms.k.stakingKeeper.GetValidatorDelegations(ctx, valAddr)
if err != nil {
Expand All @@ -95,6 +111,13 @@ func (ms msgServer) SetPower(ctx context.Context, msg *poa.MsgSetPower) (*poa.Ms
return nil, fmt.Errorf("delegation error, expected 1, got %d", len(delegations))
}

// Update total power
totalPower, err := ms.getTotalChainPower(ctx)
if err != nil {
return nil, err
}
ms.k.stakingKeeper.SetLastTotalPower(ctx, totalPower)

return &poa.MsgSetPowerResponse{}, nil
}

Expand All @@ -110,6 +133,15 @@ func (ms msgServer) RemoveValidator(ctx context.Context, msg *poa.MsgRemoveValid
return nil, fmt.Errorf("ValAddressFromBech32 failed: %w", err)
}

// Ensure we do not remove the last validator in the set.
allValidators, err := ms.k.stakingKeeper.GetAllValidators(ctx)
if err != nil {
return nil, fmt.Errorf("GetAllValidators failed: %w", err)
}
if len(allValidators) == 1 {
return nil, fmt.Errorf("cannot remove the last validator")
}

if err := ms.clearValidator(ctx, valAddr); err != nil {
return nil, fmt.Errorf("clearValidator failed: %w", err)
}
Expand Down Expand Up @@ -195,7 +227,7 @@ func (ms msgServer) CreateValidator(ctx context.Context, msg *poa.MsgCreateValid
return nil, err
}

validator.MinSelfDelegation = msg.MinSelfDelegation
validator.MinSelfDelegation = math.NewInt(1)

// the validator is now pending approval to be let into the set.
// Until then, they are not apart of the set.
Expand All @@ -206,6 +238,16 @@ func (ms msgServer) CreateValidator(ctx context.Context, msg *poa.MsgCreateValid
return &poa.MsgCreateValidatorResponse{}, nil
}

func (ms msgServer) UpdateParams(ctx context.Context, msg *poa.MsgUpdateParams) (*poa.MsgUpdateParamsResponse, error) {
if ok, err := ms.isAdmin(ctx, msg.FromAddress); err != nil {
return nil, err
} else if !ok {
return nil, fmt.Errorf("not an authority")
}

return &poa.MsgUpdateParamsResponse{}, ms.k.SetParams(ctx, msg.Params)
}

// takes in a validator address & sees if they are pending approval.
// if so, we create them now.
// TODO: use stakingtypes.Validator in GetPendingValidator?
Expand Down Expand Up @@ -240,6 +282,23 @@ func (ms msgServer) acceptNewValidator(ctx context.Context, operatingAddress str
return err
}

cons, err := val.GetConsAddr()
if err != nil {
return err
}

err = ms.k.slashKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(cons), slashingtypes.ValidatorSigningInfo{
Address: sdk.ConsAddress(cons).String(),
StartHeight: sdkCtx.BlockHeight(),
IndexOffset: 0,
JailedUntil: sdkCtx.BlockHeader().Time,
Tombstoned: false,
MissedBlocksCounter: 0,
})
if err != nil {
return err
}

// call the after-creation hook
if err := ms.k.stakingKeeper.Hooks().AfterValidatorCreated(ctx, valAddr); err != nil {
return err
Expand All @@ -260,14 +319,18 @@ func (ms msgServer) acceptNewValidator(ctx context.Context, operatingAddress str
return nil
}

func (ms msgServer) UpdateParams(ctx context.Context, msg *poa.MsgUpdateParams) (*poa.MsgUpdateParamsResponse, error) {
if ok, err := ms.isAdmin(ctx, msg.FromAddress); err != nil {
return nil, err
} else if !ok {
return nil, fmt.Errorf("not an authority")
func (ms msgServer) getTotalChainPower(ctx context.Context) (math.Int, error) {
delSum := math.ZeroInt()
allDelegations, err := ms.k.stakingKeeper.GetAllDelegations(ctx)
if err != nil {
return math.ZeroInt(), err
}

return &poa.MsgUpdateParamsResponse{}, ms.k.SetParams(ctx, msg.Params)
for _, del := range allDelegations {
delSum = delSum.Add(del.Shares.TruncateInt())
}

return delSum, nil
}

func (ms msgServer) clearValidator(ctx context.Context, valAddr sdk.ValAddress) error {
Expand All @@ -294,12 +357,33 @@ func (ms msgServer) clearValidator(ctx context.Context, valAddr sdk.ValAddress)
return fmt.Errorf("SetValidator failed: %w", err)
}

if err := ms.k.stakingKeeper.DeleteLastValidatorPower(ctx, valAddr); err != nil {
return fmt.Errorf("DeleteLastValidatorPower failed: %w", err)
}

// Do we handle? or does the sdk do this (may need to wait until the next block?)
// validator record not found for address: 67AE8730FE9C4A8E67FB699F61EEA7F90627B34F\n
// if err := ms.k.stakingKeeper.RemoveValidator(ctx, valAddr); err != nil {
// return fmt.Errorf("removevalidator failed: %w", err)
// }

// remove from slashing keeper store?
cons, err := val.GetConsAddr()
if err != nil {
return fmt.Errorf("GetConsAddr failed: %w", err)
}
if err := ms.k.slashKeeper.DeleteMissedBlockBitmap(ctx, sdk.ConsAddress(cons)); err != nil {
return fmt.Errorf("DeleteMissedBlockBitmap failed: %w", err)
}

if err := ms.k.slashKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(cons), slashingtypes.ValidatorSigningInfo{}); err != nil {
return fmt.Errorf("SetValidatorSigningInfo failed: %w", err)
}

if err := ms.k.stakingKeeper.Jail(ctx, sdk.ConsAddress(cons)); err != nil {
return fmt.Errorf("jail failed: %w", err)
}

return nil
}

Expand Down
3 changes: 2 additions & 1 deletion proto/strangelove_ventures/poa/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ message MsgSetPower {

string from_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string validator_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
uint64 power = 3;
uint64 power = 3;
bool unsafe = 4;
}
// MsgSetPowerResponse
message MsgSetPowerResponse {}
Expand Down
8 changes: 5 additions & 3 deletions simapp/test_node.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# cd simapp
# BINARY="poad" CHAIN_ID="poa-1" HOME_DIR="$HOME/.poad" TIMEOUT_COMMIT="500ms" CLEAN=true sh test_node.sh
#
# poad tx poa set-power $(poad q staking validators --output=json | jq .validators[0].operator_address -r) 1230000 --home=$HOME_DIR --yes --from=acc1
# this is actually safe since its only 12 validator
# poad tx poa set-power $(poad q staking validators --output=json | jq .validators[0].operator_address -r) 111222333444 --home=$HOME_DIR --yes --from=acc1 --unsafe
# poad q staking validators
# poad tx poa remove $(poad q staking validators --output=json | jq .validators[0].operator_address -r) --home=$HOME_DIR --yes --from=acc1
#
Expand All @@ -14,7 +15,8 @@
# Create a validator
# poad tx poa create-validator simapp/validator_file.json --from acc3 --yes --home=$HOME_DIR # no genesis amount
# poad q poa pending-validators --output json
# poad tx poa set-power $(poad q poa pending-validators --output=json | jq .pending[0].operator_address -r) 123 --home=$HOME_DIR --yes --from=acc1
# poad tx poa set-power $(poad q poa pending-validators --output=json | jq .pending[0].operator_address -r) 1000000 --home=$HOME_DIR --yes --from=acc1
# poad q slashing signing-infos
# poad tx poa remove $(poad q staking validators --output=json | jq .validators[1].operator_address -r) --home=$HOME_DIR --yes --from=acc1

export KEY="acc1" # validator
Expand Down Expand Up @@ -95,7 +97,7 @@ from_scratch () {

# Allocate genesis accounts
# stake should ONLY be as much as they gentx with. No more.
BINARY genesis add-genesis-account $KEY 1000000stake,1000utest --keyring-backend $KEYRING
BINARY genesis add-genesis-account $KEY 100000000000000stake,1000utest --keyring-backend $KEYRING
BINARY genesis add-genesis-account $KEY2 1000000stake,1000utest --keyring-backend $KEYRING

# 1 power (these rates will be overwriten)
Expand Down
Loading

0 comments on commit 32c99d8

Please sign in to comment.