From 481fd95b825f181ce04b92b11b5506dade55cabf Mon Sep 17 00:00:00 2001 From: Cashmaney Date: Wed, 10 Aug 2022 12:34:14 +0300 Subject: [PATCH 1/2] Parallelization of crisis "can-withdraw" check which was taking quite a long time running sequentially for each validator --- x/distribution/keeper/invariants.go | 49 +++++++++++++++++++---------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/x/distribution/keeper/invariants.go b/x/distribution/keeper/invariants.go index 50300b97737..9b30d581710 100644 --- a/x/distribution/keeper/invariants.go +++ b/x/distribution/keeper/invariants.go @@ -2,6 +2,7 @@ package keeper import ( "fmt" + "sync" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/distribution/types" @@ -67,36 +68,50 @@ func CanWithdrawInvariant(k Keeper) sdk.Invariant { // cache, we don't want to write changes ctx, _ = ctx.CacheContext() - var remaining sdk.DecCoins - valDelegationAddrs := make(map[string][]sdk.AccAddress) for _, del := range k.stakingKeeper.GetAllSDKDelegations(ctx) { valAddr := del.GetValidatorAddr().String() valDelegationAddrs[valAddr] = append(valDelegationAddrs[valAddr], del.GetDelegatorAddr()) } - // iterate over all validators + // get all validators so that we can iterate concurrently + // there might be a more elegant way to do this, but this seems to work pretty well + // and compared to the time the whole thing takes this iteration is negligible + var valList []stakingtypes.ValidatorI k.stakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { - _, _ = k.WithdrawValidatorCommission(ctx, val.GetOperator()) + valList = append(valList, val) + return false + }) - delegationAddrs, ok := valDelegationAddrs[val.GetOperator().String()] - if ok { - for _, delAddr := range delegationAddrs { - if _, err := k.WithdrawDelegationRewards(ctx, delAddr, val.GetOperator()); err != nil { - panic(err) + broken := false + var remaining sdk.DecCoins + wg := new(sync.WaitGroup) + for _, val := range valList { + wg.Add(1) + go func(val stakingtypes.ValidatorI, wg *sync.WaitGroup) { + defer wg.Done() + + _, _ = k.WithdrawValidatorCommission(ctx, val.GetOperator()) + + delegationAddrs, ok := valDelegationAddrs[val.GetOperator().String()] + if ok { + for _, delAddr := range delegationAddrs { + if _, err := k.WithdrawDelegationRewards(ctx, delAddr, val.GetOperator()); err != nil { + panic(err) + } } } - } - remaining = k.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator()) - if len(remaining) > 0 && remaining[0].Amount.IsNegative() { - return true - } + remainingRewards := k.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator()) + if len(remainingRewards) > 0 && remainingRewards[0].Amount.IsNegative() { + broken = true + remaining = k.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator()) + } + }(val, wg) + } - return false - }) + wg.Wait() - broken := len(remaining) > 0 && remaining[0].Amount.IsNegative() return sdk.FormatInvariant(types.ModuleName, "can withdraw", fmt.Sprintf("remaining coins: %v\n", remaining)), broken } From c79c97921ef4e0cd2be8518300122f9777787249 Mon Sep 17 00:00:00 2001 From: Cashmaney Date: Sat, 20 Aug 2022 23:25:55 +0300 Subject: [PATCH 2/2] Update invariants.go --- x/distribution/keeper/invariants.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x/distribution/keeper/invariants.go b/x/distribution/keeper/invariants.go index 9b30d581710..7334dc340b2 100644 --- a/x/distribution/keeper/invariants.go +++ b/x/distribution/keeper/invariants.go @@ -74,17 +74,17 @@ func CanWithdrawInvariant(k Keeper) sdk.Invariant { valDelegationAddrs[valAddr] = append(valDelegationAddrs[valAddr], del.GetDelegatorAddr()) } - // get all validators so that we can iterate concurrently - // there might be a more elegant way to do this, but this seems to work pretty well - // and compared to the time the whole thing takes this iteration is negligible var valList []stakingtypes.ValidatorI k.stakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { valList = append(valList, val) return false }) - broken := false - var remaining sdk.DecCoins + var ( + broken bool + remaining sdk.DecCoins + ) + wg := new(sync.WaitGroup) for _, val := range valList { wg.Add(1)