Skip to content

Commit

Permalink
increased validator bond shares during redelegation
Browse files Browse the repository at this point in the history
  • Loading branch information
sampocs committed Aug 11, 2023
1 parent e633749 commit 846943c
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 17 deletions.
21 changes: 15 additions & 6 deletions x/staking/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRed
return nil, err
}

delegation, found := k.GetDelegation(ctx, delegatorAddress, valSrcAddr)
srcDelegation, found := k.GetDelegation(ctx, delegatorAddress, valSrcAddr)
if !found {
return nil, status.Errorf(
codes.NotFound,
Expand All @@ -312,7 +312,7 @@ func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRed

// If this is a validator self-bond, the new liquid delegation cannot fall below the self-bond * bond factor
// The delegation on the new validator will not a validator bond
if delegation.ValidatorBond {
if srcDelegation.ValidatorBond {
if err := k.SafelyDecreaseValidatorBond(ctx, srcValidator, srcShares); err != nil {
return nil, err
}
Expand Down Expand Up @@ -344,10 +344,6 @@ func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRed
if !found {
return nil, types.ErrNoValidatorFound
}
dstValidator, found = k.GetValidator(ctx, valDstAddr)
if !found {
return nil, types.ErrNoValidatorFound
}
}

bondDenom := k.BondDenom(ctx)
Expand All @@ -364,6 +360,19 @@ func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRed
return nil, err
}

// If the redelegation adds to a validator bond delegation, update the validator's bond shares
dstDelegation, found := k.GetDelegation(ctx, delegatorAddress, valDstAddr)
if !found {
return nil, types.ErrNoDelegation
}
if dstDelegation.ValidatorBond {
dstShares, err := dstValidator.SharesFromTokensTruncated(msg.Amount.Amount)
if err != nil {
return nil, err
}
k.IncreaseValidatorBondShares(ctx, dstValidator, dstShares)
}

if msg.Amount.Amount.IsInt64() {
defer func() {
telemetry.IncrCounter(1, types.ModuleName, "redelegate")
Expand Down
79 changes: 68 additions & 11 deletions x/staking/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1003,27 +1003,33 @@ func TestChangeValidatorBond(t *testing.T) {
require.Equal(t, expectedShares.Int64(), validator.ValidatorBondShares.TruncateInt64(), "validator bond shares")
}

// Create a delegator and 2 validators
addresses := simapp.AddTestAddrs(app, ctx, 3, sdk.NewInt(1_000_000))
pubKeys := simapp.CreateTestPubKeys(3)
// Create a delegator and 3 validators
addresses := simapp.AddTestAddrs(app, ctx, 4, sdk.NewInt(1_000_000))
pubKeys := simapp.CreateTestPubKeys(4)

validatorAPubKey := pubKeys[1]
validatorBPubKey := pubKeys[2]
validatorCPubKey := pubKeys[3]

delegatorAddress := addresses[0]
validatorAAddress := sdk.ValAddress(validatorAPubKey.Address())
validatorBAddress := sdk.ValAddress(validatorBPubKey.Address())
validatorCAddress := sdk.ValAddress(validatorCPubKey.Address())

validatorA := teststaking.NewValidator(t, validatorAAddress, validatorAPubKey)
validatorB := teststaking.NewValidator(t, validatorBAddress, validatorBPubKey)
validatorC := teststaking.NewValidator(t, validatorCAddress, validatorCPubKey)

validatorA.Tokens = sdk.NewInt(1_000_000)
validatorB.Tokens = sdk.NewInt(1_000_000)
validatorC.Tokens = sdk.NewInt(1_000_000)
validatorA.DelegatorShares = sdk.NewDec(1_000_000)
validatorB.DelegatorShares = sdk.NewDec(1_000_000)
validatorC.DelegatorShares = sdk.NewDec(1_000_000)

app.StakingKeeper.SetValidator(ctx, validatorA)
app.StakingKeeper.SetValidator(ctx, validatorB)
app.StakingKeeper.SetValidator(ctx, validatorC)

// The test will go through Delegate/Redelegate/Undelegate messages with the following
delegation1Amount := sdk.NewInt(1000)
Expand All @@ -1036,28 +1042,44 @@ func TestChangeValidatorBond(t *testing.T) {
redelegateCoin := sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), redelegateAmount)
undelegateCoin := sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), undelegateAmount)

// Delegate to validator A - validator bond shares should not change
// Delegate to validator's A and C - validator bond shares should not change
_, err := msgServer.Delegate(sdk.WrapSDKContext(ctx), &types.MsgDelegate{
DelegatorAddress: delegatorAddress.String(),
ValidatorAddress: validatorAAddress.String(),
Amount: delegate1Coin,
})
require.NoError(t, err, "no error expected during first delegation")

_, err = msgServer.Delegate(sdk.WrapSDKContext(ctx), &types.MsgDelegate{
DelegatorAddress: delegatorAddress.String(),
ValidatorAddress: validatorCAddress.String(),
Amount: delegate1Coin,
})
require.NoError(t, err, "no error expected during first delegation")

checkValidatorBondShares(validatorAAddress, sdk.ZeroInt())
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())
checkValidatorBondShares(validatorCAddress, sdk.ZeroInt())

// Flag the delegation as a validator bond
// Flag the the delegations to validator A and C validator bond's
// Their bond shares should increase
_, err = msgServer.ValidatorBond(sdk.WrapSDKContext(ctx), &types.MsgValidatorBond{
DelegatorAddress: delegatorAddress.String(),
ValidatorAddress: validatorAAddress.String(),
})
require.NoError(t, err, "no error expected during validator bond")

_, err = msgServer.ValidatorBond(sdk.WrapSDKContext(ctx), &types.MsgValidatorBond{
DelegatorAddress: delegatorAddress.String(),
ValidatorAddress: validatorCAddress.String(),
})
require.NoError(t, err, "no error expected during validator bond")

checkValidatorBondShares(validatorAAddress, delegation1Amount)
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())
checkValidatorBondShares(validatorCAddress, delegation1Amount)

// Delegate more - it should increase the validator bond shares
// Delegate more to validator A - it should increase the validator bond shares
_, err = msgServer.Delegate(sdk.WrapSDKContext(ctx), &types.MsgDelegate{
DelegatorAddress: delegatorAddress.String(),
ValidatorAddress: validatorAAddress.String(),
Expand All @@ -1067,8 +1089,10 @@ func TestChangeValidatorBond(t *testing.T) {

checkValidatorBondShares(validatorAAddress, delegation1Amount.Add(delegation2Amount))
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())
checkValidatorBondShares(validatorCAddress, delegation1Amount)

// Redelegate partially from A to B - it should remove the bond shares from the source validator
// Redelegate partially from A to B (where A is a validator bond and B is not)
// It should remove the bond shares from A, and B's validator bond shares should not change
_, err = msgServer.BeginRedelegate(sdk.WrapSDKContext(ctx), &types.MsgBeginRedelegate{
DelegatorAddress: delegatorAddress.String(),
ValidatorSrcAddress: validatorAAddress.String(),
Expand All @@ -1077,20 +1101,53 @@ func TestChangeValidatorBond(t *testing.T) {
})
require.NoError(t, err, "no error expected during redelegation")

checkValidatorBondShares(validatorAAddress, delegation1Amount.Add(delegation2Amount).Sub(redelegateAmount))
expectedBondSharesA := delegation1Amount.Add(delegation2Amount).Sub(redelegateAmount)
checkValidatorBondShares(validatorAAddress, expectedBondSharesA)
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())
checkValidatorBondShares(validatorCAddress, delegation1Amount)

// Now redelegate from B to C (where B is not a validator bond, but C is)
// Validator B's bond shares should remain at zero, but C's bond shares should increase
_, err = msgServer.BeginRedelegate(sdk.WrapSDKContext(ctx), &types.MsgBeginRedelegate{
DelegatorAddress: delegatorAddress.String(),
ValidatorSrcAddress: validatorBAddress.String(),
ValidatorDstAddress: validatorCAddress.String(),
Amount: redelegateCoin,
})
require.NoError(t, err, "no error expected during redelegation")

checkValidatorBondShares(validatorAAddress, expectedBondSharesA)
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())
checkValidatorBondShares(validatorCAddress, delegation1Amount.Add(redelegateAmount))

// Redelegate partially from A to C (where C is a validator bond delegation)
// It should remove the bond shares from A, and increase the bond shares on validator C
_, err = msgServer.BeginRedelegate(sdk.WrapSDKContext(ctx), &types.MsgBeginRedelegate{
DelegatorAddress: delegatorAddress.String(),
ValidatorSrcAddress: validatorAAddress.String(),
ValidatorDstAddress: validatorCAddress.String(),
Amount: redelegateCoin,
})
require.NoError(t, err, "no error expected during redelegation")

expectedBondSharesA = expectedBondSharesA.Sub(redelegateAmount)
expectedBondSharesC := delegation1Amount.Add(redelegateAmount).Add(redelegateAmount)
checkValidatorBondShares(validatorAAddress, expectedBondSharesA)
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())
checkValidatorBondShares(validatorCAddress, expectedBondSharesC)

// Undelegate from validator A - it should have removed the shares
// Undelegate from validator A - it should remove shares
_, err = msgServer.Undelegate(sdk.WrapSDKContext(ctx), &types.MsgUndelegate{
DelegatorAddress: delegatorAddress.String(),
ValidatorAddress: validatorAAddress.String(),
Amount: undelegateCoin,
})
require.NoError(t, err, "no error expected during undelegation")

expectedBondShares := delegation1Amount.Add(delegation2Amount).Sub(redelegateAmount).Sub(undelegateAmount)
checkValidatorBondShares(validatorAAddress, expectedBondShares)
expectedBondSharesA = expectedBondSharesA.Sub(undelegateAmount)
checkValidatorBondShares(validatorAAddress, expectedBondSharesA)
checkValidatorBondShares(validatorBAddress, sdk.ZeroInt())
checkValidatorBondShares(validatorCAddress, expectedBondSharesC)
}

func TestEnableDisableTokenizeShares(t *testing.T) {
Expand Down

0 comments on commit 846943c

Please sign in to comment.