perf: reduce the number of ValidateDenom calls in bank.SendCoins (#20354)

This commit is contained in:
Tuan Tran 2024-05-29 03:20:54 +07:00 committed by GitHub
parent dac569c3a2
commit 6a07568e30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 28 additions and 18 deletions

View File

@ -64,7 +64,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i
* (debug) [#20328](https://github.com/cosmos/cosmos-sdk/pull/20328) Add consensus address for debug cmd.
### Improvements
* (bank) [#20354](https://github.com/cosmos/cosmos-sdk/pull/20354) Reduce the number of `ValidateDenom` calls in `bank.SendCoins`.
* (types) [#19869](https://github.com/cosmos/cosmos-sdk/pull/19869) Removed `Any` type from `codec/types` and replaced it with an alias for `cosmos/gogoproto/types/any`.
* (server) [#19854](https://github.com/cosmos/cosmos-sdk/pull/19854) Add customizability to start command.
* Add `StartCmdOptions` in `server.AddCommands` instead of `servertypes.ModuleInitFlags`. To set custom flags set them in the `StartCmdOptions` struct on the `AddFlags` field.

View File

@ -865,8 +865,6 @@ func SetCoinDenomRegex(reFn func() string) {
// ValidateDenom is the default validation function for Coin.Denom.
func ValidateDenom(denom string) error {
if reDnm == nil || reDecCoin == nil {
// Convert the string to a byte slice as required by the Ragel-generated function.
// Call the Ragel-generated function.
if !MatchDenom(denom) {
return fmt.Errorf("invalid denom: %s", denom)

View File

@ -360,6 +360,10 @@ func (k BaseKeeper) MintCoins(ctx context.Context, moduleName string, amounts sd
return errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to mint tokens", moduleName)
}
if !amounts.IsValid() {
return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, amounts.String())
}
err = k.addCoins(ctx, acc.GetAddress(), amounts)
if err != nil {
return err
@ -399,6 +403,9 @@ func (k BaseKeeper) BurnCoins(ctx context.Context, address []byte, amounts sdk.C
return errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "account %x does not have permissions to burn tokens", address)
}
}
if !amounts.IsValid() {
return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, amounts.String())
}
err := k.subUnlockedCoins(ctx, acc.GetAddress(), amounts)
if err != nil {

View File

@ -184,6 +184,10 @@ func (k BaseSendKeeper) InputOutputCoins(ctx context.Context, input types.Input,
// SendCoins transfers amt coins from a sending account to a receiving account.
// An error is returned upon failure.
func (k BaseSendKeeper) SendCoins(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) error {
if !amt.IsValid() {
return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, amt.String())
}
var err error
err = k.subUnlockedCoins(ctx, fromAddr, amt)
if err != nil {
@ -217,19 +221,21 @@ func (k BaseSendKeeper) SendCoins(ctx context.Context, fromAddr, toAddr sdk.AccA
)
}
// subUnlockedCoins removes the unlocked amt coins of the given account. An error is
// returned if the resulting balance is negative or the initial amount is invalid.
// A coin_spent event is emitted after.
// subUnlockedCoins removes the unlocked amt coins of the given account.
// An error is returned if the resulting balance is negative.
//
// CONTRACT: The provided amount (amt) must be valid, non-negative coins.
//
// A coin_spent event is emitted after the operation.
func (k BaseSendKeeper) subUnlockedCoins(ctx context.Context, addr sdk.AccAddress, amt sdk.Coins) error {
if !amt.IsValid() {
return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, amt.String())
}
lockedCoins := k.LockedCoins(ctx, addr)
for _, coin := range amt {
balance := k.GetBalance(ctx, addr, coin.Denom)
locked := sdk.NewCoin(coin.Denom, lockedCoins.AmountOf(coin.Denom))
ok, locked := lockedCoins.Find(coin.Denom)
if !ok {
locked = sdk.Coin{Denom: coin.Denom, Amount: math.ZeroInt()}
}
spendable, hasNeg := sdk.Coins{balance}.SafeSub(locked)
if hasNeg {
@ -239,7 +245,7 @@ func (k BaseSendKeeper) subUnlockedCoins(ctx context.Context, addr sdk.AccAddres
if _, hasNeg := spendable.SafeSub(coin); hasNeg {
if len(spendable) == 0 {
spendable = sdk.Coins{sdk.NewCoin(coin.Denom, math.ZeroInt())}
spendable = sdk.Coins{sdk.Coin{Denom: coin.Denom, Amount: math.ZeroInt()}}
}
return errorsmod.Wrapf(
sdkerrors.ErrInsufficientFunds,
@ -267,13 +273,12 @@ func (k BaseSendKeeper) subUnlockedCoins(ctx context.Context, addr sdk.AccAddres
)
}
// addCoins increase the addr balance by the given amt. Fails if the provided
// amt is invalid. It emits a coin received event.
// addCoins increases the balance of the given address by the specified amount.
//
// CONTRACT: The provided amount (amt) must be valid, non-negative coins.
//
// It emits a coin_received event after the operation.
func (k BaseSendKeeper) addCoins(ctx context.Context, addr sdk.AccAddress, amt sdk.Coins) error {
if !amt.IsValid() {
return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, amt.String())
}
for _, coin := range amt {
balance := k.GetBalance(ctx, addr, coin.Denom)
newBalance := balance.Add(coin)