Skip to content

Commit

Permalink
Problem: no efficient bank api to support evm add/sub balances
Browse files Browse the repository at this point in the history
fix

Update CHANGELOG.md

Signed-off-by: yihuang <[email protected]>

don't change interface
  • Loading branch information
yihuang committed Mar 28, 2024
1 parent 9ef65ec commit f3146d3
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 30 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features

* (baseapp) [#205](https://github.com/crypto-org-chain/cosmos-sdk/pull/205) Add `TxExecutor` baseapp option, add `TxIndex`/`TxCount`/`MsgIndex`/`BlockGasUsed` fields to `Context, to support tx parallel execution.
* (baseapp) [#206](https://github.com/crypto-org-chain/cosmos-sdk/pull/206) Support mount object store in baseapp, add `ObjectStore` api in context..
* (baseapp) [#206](https://github.com/crypto-org-chain/cosmos-sdk/pull/206) Support mount object store in baseapp, add `ObjectStore` api in context.
* (bank) [#237](https://github.com/crypto-org-chain/cosmos-sdk/pull/237) Support virtual accounts in sending coins.
* (x/bank) [#239](https://github.com/crypto-org-chain/cosmos-sdk/pull/239) Add low level `AddBalance`,`SubBalance` APIs to bank keeper.

## [Unreleased-Upstream]

Expand Down
27 changes: 27 additions & 0 deletions x/bank/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,33 @@ func (k BaseKeeper) BurnCoins(ctx context.Context, moduleName string, amounts sd
return nil
}

// AddBalance is low level api to update balance directly, mainly used by evm integration,
// caller should make sure the total supply of the denom not changed and the account exists.
// it's for evm integration, call at your own risk.
// it emits mint event.
func (k BaseKeeper) AddBalance(ctx context.Context, addr sdk.AccAddress, coin sdk.Coin) error {
sdkCtx := sdk.UnwrapSDKContext(ctx)
// emit mint event
sdkCtx.EventManager().EmitEvent(
types.NewCoinMintEvent(addr, sdk.NewCoins(coin)),
)
return k.addCoin(ctx, addr, coin)
}

// SubBalance is low level api to update balance directly, mainly used by evm integration,
// caller should make sure the total supply of the denom not changed.
// it's for evm integration, call at your own risk.
// it emits burn event.
func (k BaseKeeper) SubBalance(ctx context.Context, addr sdk.AccAddress, coin sdk.Coin) error {
sdkCtx := sdk.UnwrapSDKContext(ctx)
// emit burn event
sdkCtx.EventManager().EmitEvent(
types.NewCoinBurnEvent(addr, sdk.NewCoins(coin)),
)
lockedCoins := k.LockedCoins(ctx, addr)
return k.subCoin(ctx, addr, coin, lockedCoins)
}

// setSupply sets the supply for the given coin
func (k BaseKeeper) setSupply(ctx context.Context, coin sdk.Coin) {
// Bank invariants and IBC requires to remove zero coins.
Expand Down
63 changes: 34 additions & 29 deletions x/bank/keeper/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"cosmossdk.io/core/store"
errorsmod "cosmossdk.io/errors"
"cosmossdk.io/log"
"cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"

"github.com/cosmos/cosmos-sdk/codec"
Expand Down Expand Up @@ -273,29 +272,7 @@ func (k BaseSendKeeper) subUnlockedCoins(ctx context.Context, addr sdk.AccAddres
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))

spendable, hasNeg := sdk.Coins{balance}.SafeSub(locked)
if hasNeg {
return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds,
"locked amount exceeds account balance funds: %s > %s", locked, balance)
}

if _, hasNeg := spendable.SafeSub(coin); hasNeg {
if len(spendable) == 0 {
spendable = sdk.Coins{sdk.NewCoin(coin.Denom, math.ZeroInt())}
}
return errorsmod.Wrapf(
sdkerrors.ErrInsufficientFunds,
"spendable balance %s is smaller than %s",
spendable, coin,
)
}

newBalance := balance.Sub(coin)

if err := k.setBalance(ctx, addr, newBalance); err != nil {
if err := k.subCoin(ctx, addr, coin, lockedCoins); err != nil {
return err
}
}
Expand All @@ -308,6 +285,32 @@ func (k BaseSendKeeper) subUnlockedCoins(ctx context.Context, addr sdk.AccAddres
return nil
}

func (k BaseSendKeeper) subCoin(ctx context.Context, addr sdk.AccAddress, coin sdk.Coin, lockedCoins sdk.Coins) error {
var (
spendable sdk.Coin
err error
)
balance := k.GetBalance(ctx, addr, coin.Denom)
locked := sdk.NewCoin(coin.Denom, lockedCoins.AmountOf(coin.Denom))
if locked.IsZero() {
spendable = balance
} else {
spendable, err = balance.SafeSub(locked)
if err != nil {
return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds,
"locked amount exceeds account balance funds: %s > %s", locked, balance)
}
}
if spendable.Amount.LT(coin.Amount) {
return errorsmod.Wrapf(
sdkerrors.ErrInsufficientFunds,
"spendable balance %s is smaller than %s",
spendable, coin,
)
}
return k.setBalance(ctx, addr, balance.Sub(coin))
}

// addCoins increase the addr balance by the given amt. Fails if the provided
// amt is invalid. It emits a coin received event.
func (k BaseSendKeeper) addCoins(ctx context.Context, addr sdk.AccAddress, amt sdk.Coins) error {
Expand All @@ -316,11 +319,7 @@ func (k BaseSendKeeper) addCoins(ctx context.Context, addr sdk.AccAddress, amt s
}

for _, coin := range amt {
balance := k.GetBalance(ctx, addr, coin.Denom)
newBalance := balance.Add(coin)

err := k.setBalance(ctx, addr, newBalance)
if err != nil {
if err := k.addCoin(ctx, addr, coin); err != nil {
return err
}
}
Expand All @@ -334,6 +333,12 @@ func (k BaseSendKeeper) addCoins(ctx context.Context, addr sdk.AccAddress, amt s
return nil
}

func (k BaseSendKeeper) addCoin(ctx context.Context, addr sdk.AccAddress, coin sdk.Coin) error {
balance := k.GetBalance(ctx, addr, coin.Denom)
newBalance := balance.Add(coin)
return k.setBalance(ctx, addr, newBalance)
}

// setBalance sets the coin balance for an account by address.
func (k BaseSendKeeper) setBalance(ctx context.Context, addr sdk.AccAddress, balance sdk.Coin) error {
if !balance.IsValid() {
Expand Down

0 comments on commit f3146d3

Please sign in to comment.