Skip to content

Commit

Permalink
feat: add IsAutoUnDelegate field to CrossStakeDistributeUndelegatedSy…
Browse files Browse the repository at this point in the history
…nPackage and prevent too many failed in auto refund (#377)

* feat: add IsAutoUnDelegate field to CrossStakeDistributeUndelegatedSynPackage

* fix: disable undelegate after SecondSunsetFork and prevent too many failed in auto refund

* chore: add more logs

* revert: cross stake changes

* fix: error handling in refund

* fix: transferPackage

* fix: CrossStakeDistributeUndelegatedSynPackageV2
  • Loading branch information
j75689 authored Jan 12, 2024
1 parent d893e87 commit f7b025f
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 9 deletions.
8 changes: 8 additions & 0 deletions x/stake/cross_stake/cross_stake.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ func (app *CrossStakeApp) ExecuteFailAckPackage(ctx sdk.Context, payload []byte)
Recipient: p.Recipient,
}
result, err = app.handleDistributeUndelegatedRefund(ctx, refundPackage)
case *types.CrossStakeDistributeUndelegatedSynPackageV2:
bcAmount := bsc.ConvertBSCAmountToBCAmount(p.Amount)
refundPackage := &types.CrossStakeRefundPackage{
EventType: types.CrossStakeTypeDistributeUndelegated,
Amount: big.NewInt(bcAmount),
Recipient: p.Recipient,
}
result, err = app.handleDistributeUndelegatedRefund(ctx, refundPackage)
default:
app.stakeKeeper.Logger(ctx).Error("unknown cross stake fail ack event type", "err", err.Error(), "package", string(payload))
return sdk.ExecuteResult{}
Expand Down
11 changes: 11 additions & 0 deletions x/stake/cross_stake/serialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ func DeserializeCrossStakeFailAckPackage(serializedPackage []byte) (interface{},
}
return &pack, nil
},
func(serializedPackage []byte) (interface{}, error) {
var pack types.CrossStakeDistributeUndelegatedSynPackageV2
err := rlp.DecodeBytes(serializedPackage, &pack)
if err != nil {
return nil, err
}
if pack.EventType != types.CrossStakeTypeDistributeUndelegated {
return nil, fmt.Errorf("wrong cross stake event type")
}
return &pack, nil
},
}

var pack interface{}
Expand Down
31 changes: 27 additions & 4 deletions x/stake/endblock.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,15 +279,17 @@ func handleMatureUnbondingDelegations(k keeper.Keeper, ctx sdk.Context) ([]types
}

const (
maxProcessedRefundCount = 10
maxProcessedRefundCount = 10
maxProcessedRefundFailed = 200
)

func handleRefundStake(ctx sdk.Context, sideChainPrefix []byte, k keeper.Keeper) sdk.Events {
sideChainCtx := ctx.WithSideChainKeyPrefix(sideChainPrefix)
iterator := k.IteratorAllDelegations(sideChainCtx)
defer iterator.Close()
var refundEvents sdk.Events
count := 0
succeedCount := 0
failedCount := 0
boundDenom := k.BondDenom(sideChainCtx)
bscSideChainId := k.ScKeeper.BscSideChainId(ctx)

Expand All @@ -304,15 +306,36 @@ func handleRefundStake(ctx sdk.Context, sideChainPrefix []byte, k keeper.Keeper)
SideChainId: bscSideChainId,
}, k)
refundEvents = refundEvents.AppendEvents(result.Events)
if !result.IsOK() {
ctx.Logger().Debug("handleRefundStake failed",
"delegator", delegation.DelegatorAddr.String(),
"validator", delegation.ValidatorAddr.String(),
"amount", delegation.GetShares().String(),
"sideChainId", bscSideChainId,
"result", fmt.Sprintf("%+v", result),
)
// this is to prevent too many delegation is in unbounded state
// if too many delegation is in unbounded state, it will cause too many iteration in the block
failedCount++
if failedCount >= maxProcessedRefundFailed {
break
}

continue
}

if result.IsOK() && delegation.CrossStake {
k.SetAutoUnDelegate(sideChainCtx, delegation.DelegatorAddr, delegation.ValidatorAddr)
}

ctx.Logger().Info("handleRefundStake after SecondSunsetFork",
"delegator", delegation.DelegatorAddr.String(),
"validator", delegation.ValidatorAddr.String(),
"amount", delegation.GetShares().String(),
"sideChainId", bscSideChainId,
)
count++
if count >= maxProcessedRefundCount {
succeedCount++
if succeedCount >= maxProcessedRefundCount {
break
}
}
Expand Down
3 changes: 3 additions & 0 deletions x/stake/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ func NewHandler(k keeper.Keeper, govKeeper gov.Keeper) sdk.Handler {
}
return handleMsgSideChainRedelegate(ctx, msg, k)
case types.MsgSideChainUndelegate:
if sdk.IsUpgrade(sdk.SecondSunsetFork) {
return sdk.ErrMsgNotSupported("").Result()
}
return handleMsgSideChainUndelegate(ctx, msg, k)
case types.MsgSideChainStakeMigration:
if !sdk.IsUpgrade(sdk.FirstSunsetFork) || sdk.IsUpgrade(sdk.SecondSunsetFork) {
Expand Down
36 changes: 31 additions & 5 deletions x/stake/keeper/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,20 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAd
return ubd, events, nil
}

func (k Keeper) IsAutoUnDelegate(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) bool {
store := ctx.KVStore(k.storeKey)
key := GetAutoUnDelegateIndexKey(delAddr, valAddr)

return store.Has(key)
}

func (k Keeper) SetAutoUnDelegate(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)

key := GetAutoUnDelegateIndexKey(delAddr, valAddr)
store.Set(key, []byte{}) // index, store empty bytes
}

// complete unbonding an unbonding record
func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) (types.Redelegation, sdk.Error) {
Expand Down Expand Up @@ -875,12 +889,24 @@ func (k Keeper) crossDistributeUndelegated(ctx sdk.Context, delAddr sdk.AccAddre
return sdk.Events{}, sdk.ErrInternal(err.Error())
}

transferPackage := types.CrossStakeDistributeUndelegatedSynPackage{
EventType: types.CrossStakeTypeDistributeUndelegated,
Amount: bscTransferAmount,
Recipient: recipient,
Validator: valAddr,
var transferPackage interface{}
if !sdk.IsUpgrade(sdk.SecondSunsetFork) {
transferPackage = types.CrossStakeDistributeUndelegatedSynPackage{
EventType: types.CrossStakeTypeDistributeUndelegated,
Amount: bscTransferAmount,
Recipient: recipient,
Validator: valAddr,
}
} else {
transferPackage = types.CrossStakeDistributeUndelegatedSynPackageV2{
EventType: types.CrossStakeTypeDistributeUndelegated,
Amount: bscTransferAmount,
Recipient: recipient,
Validator: valAddr,
IsAutoUnDelegate: k.IsAutoUnDelegate(ctx, delAddr, valAddr),
}
}

encodedPackage, err := rlp.EncodeToBytes(transferPackage)
if err != nil {
return sdk.Events{}, sdk.ErrInternal(err.Error())
Expand Down
13 changes: 13 additions & 0 deletions x/stake/keeper/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ var (
// Keys for reward store prefix
RewardBatchKey = []byte{0x01} // key for batch of rewards
RewardValDistAddrKey = []byte{0x02} // key for rewards' validator <-> distribution address mapping

AutoUndelegateIndexKey = []byte{0x61} // prefix for each key for an auto undelegate, by validator operator
)

const (
Expand Down Expand Up @@ -340,3 +342,14 @@ func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddr
func GetValLatestUpdateConsAddrTimeKey(valAddr sdk.ValAddress) []byte {
return append(ValLatestUpdateConsAddrTimeKey, valAddr.Bytes()...)
}

// gets the prefix keyspace for the indexes of auto unDelegate delegations for a validator
func GetAutoUnDelegateByValIndexKey(valAddr sdk.ValAddress) []byte {
return append(AutoUndelegateIndexKey, valAddr.Bytes()...)
}

// gets the index-key for an auto unDelegate delegation, stored by validator-index
// VALUE: none (key rearrangement used)
func GetAutoUnDelegateIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte {
return append(GetAutoUnDelegateByValIndexKey(valAddr), delAddr.Bytes()...)
}
8 changes: 8 additions & 0 deletions x/stake/types/cross_stake.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ type CrossStakeDistributeUndelegatedSynPackage struct {
Amount *big.Int
}

type CrossStakeDistributeUndelegatedSynPackageV2 struct {
EventType CrossStakeEventType
Recipient sdk.SmartChainAddress
Validator sdk.ValAddress
Amount *big.Int
IsAutoUnDelegate bool
}

type RefundError uint32

const (
Expand Down

0 comments on commit f7b025f

Please sign in to comment.