Skip to content

Commit

Permalink
fix zero coins (#9229)
Browse files Browse the repository at this point in the history
* fix zero coins issue

* fix tests

* udpate tests

* Review change

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* add change log

* review changes

* review changes

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
(cherry picked from commit f04b5dc)

# Conflicts:
#	CHANGELOG.md
#	x/bank/keeper/genesis_test.go
#	x/bank/keeper/keeper.go
#	x/bank/keeper/keeper_test.go
#	x/bank/keeper/send.go
  • Loading branch information
atheeshp authored and mergify-bot committed Apr 30, 2021
1 parent 75f84b5 commit 9e18396
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 73 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,20 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Bug Fixes

<<<<<<< HEAD
* [\#9108](https://github.com/cosmos/cosmos-sdk/pull/9108) Fixed the bug with querying multisig account, which is not showing threshold and public_keys.
=======
* (gRPC) [\#8945](https://github.com/cosmos/cosmos-sdk/pull/8945) gRPC reflection now works correctly.
* (keyring) [#\8635](https://github.com/cosmos/cosmos-sdk/issues/8635) Remove hardcoded default passphrase value on `NewMnemonic`
* (x/bank) [\#8434](https://github.com/cosmos/cosmos-sdk/pull/8434) Fix legacy REST API `GET /bank/total` and `GET /bank/total/{denom}` in swagger
* (x/slashing) [\#8427](https://github.com/cosmos/cosmos-sdk/pull/8427) Fix query signing infos command
* (server) [\#8399](https://github.com/cosmos/cosmos-sdk/pull/8399) fix gRPC-web flag default value
* (x/bank) [\#9229](https://github.com/cosmos/cosmos-sdk/pull/9229) Now zero coin balances cannot be added to balances & supply stores. If any denom becomes zero corresponding key gets deleted from store.

### Deprecated

* (grpc) [\#8926](https://github.com/cosmos/cosmos-sdk/pull/8926) The `tx` field in `SimulateRequest` has been deprecated, prefer to pass `tx_bytes` instead.
>>>>>>> f04b5dcb9... fix zero coins (#9229)
## [v0.42.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.42.4) - 2021-04-08

Expand Down
4 changes: 4 additions & 0 deletions x/bank/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ func (suite *IntegrationTestSuite) TestExportGenesis() {

suite.Require().Len(exportGenesis.Params.SendEnabled, 0)
suite.Require().Equal(types.DefaultParams().DefaultSendEnabled, exportGenesis.Params.DefaultSendEnabled)
<<<<<<< HEAD
suite.Require().Equal(totalSupply.GetTotal(), exportGenesis.Supply)
=======
suite.Require().Equal(totalSupply, exportGenesis.Supply)
>>>>>>> f04b5dcb9... fix zero coins (#9229)
suite.Require().Equal(expectedBalances, exportGenesis.Balances)
suite.Require().Equal(expectedMetadata, exportGenesis.DenomMetadata)
}
Expand Down
57 changes: 56 additions & 1 deletion x/bank/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,40 @@ type BaseKeeper struct {
paramSpace paramtypes.Subspace
}

<<<<<<< HEAD
=======
func (k BaseKeeper) GetPaginatedTotalSupply(ctx sdk.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error) {
store := ctx.KVStore(k.storeKey)
supplyStore := prefix.NewStore(store, types.SupplyKey)

supply := sdk.NewCoins()

pageRes, err := query.Paginate(supplyStore, pagination, func(key, value []byte) error {
var amount sdk.Int
err := amount.Unmarshal(value)
if err != nil {
return fmt.Errorf("unable to convert amount string to Int %v", err)
}

// `Add` omits the 0 coins addition to the `supply`.
supply = supply.Add(sdk.NewCoin(string(key), amount))
return nil
})

if err != nil {
return nil, nil, err
}

return supply, pageRes, nil
}

// NewBaseKeeper returns a new BaseKeeper object with a given codec, dedicated
// store key, an AccountKeeper implementation, and a parameter Subspace used to
// store and fetch module parameters. The BaseKeeper also accepts a
// blocklist map. This blocklist describes the set of addresses that are not allowed
// to receive funds through direct and explicit actions, for example, by using a MsgSend or
// by using a SendCoinsFromModuleToAccount execution.
>>>>>>> f04b5dcb9... fix zero coins (#9229)
func NewBaseKeeper(
cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace,
blockedAddrs map[string]bool,
Expand Down Expand Up @@ -94,7 +128,7 @@ func (k BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr
balances := sdk.NewCoins()

for _, coin := range amt {
balance := k.GetBalance(ctx, delegatorAddr, coin.Denom)
balance := k.GetBalance(ctx, delegatorAddr, coin.GetDenom())
if balance.IsLT(coin) {
return sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFunds, "failed to delegate; %s is smaller than %s", balance, amt,
Expand Down Expand Up @@ -382,7 +416,28 @@ func (k BaseKeeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins)
return nil
}

<<<<<<< HEAD
func (k BaseKeeper) trackDelegation(ctx sdk.Context, addr sdk.AccAddress, blockTime time.Time, balance, amt sdk.Coins) error {
=======
func (k BaseKeeper) setSupply(ctx sdk.Context, coin sdk.Coin) {
intBytes, err := coin.Amount.Marshal()
if err != nil {
panic(fmt.Errorf("unable to marshal amount value %v", err))
}

store := ctx.KVStore(k.storeKey)
supplyStore := prefix.NewStore(store, types.SupplyKey)

// Bank invariants and IBC requires to remove zero coins.
if coin.IsZero() {
supplyStore.Delete([]byte(coin.GetDenom()))
} else {
supplyStore.Set([]byte(coin.GetDenom()), intBytes)
}
}

func (k BaseKeeper) trackDelegation(ctx sdk.Context, addr sdk.AccAddress, balance, amt sdk.Coins) error {
>>>>>>> f04b5dcb9... fix zero coins (#9229)
acc := k.ak.GetAccount(ctx, addr)
if acc == nil {
return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr)
Expand Down
138 changes: 66 additions & 72 deletions x/bank/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,28 @@ type IntegrationTestSuite struct {
queryClient types.QueryClient
}

func (suite *IntegrationTestSuite) initKeepersWithmAccPerms(blockedAddrs map[string]bool) (authkeeper.AccountKeeper, keeper.BaseKeeper) {
app := suite.app
maccPerms := simapp.GetMaccPerms()
appCodec := simapp.MakeTestEncodingConfig().Marshaler

maccPerms[holder] = nil
maccPerms[authtypes.Burner] = []string{authtypes.Burner}
maccPerms[authtypes.Minter] = []string{authtypes.Minter}
maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking}
maccPerms[randomPerm] = []string{"random"}
authKeeper := authkeeper.NewAccountKeeper(
appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName),
authtypes.ProtoBaseAccount, maccPerms,
)
keeper := keeper.NewBaseKeeper(
appCodec, app.GetKey(types.StoreKey), authKeeper,
app.GetSubspace(types.ModuleName), blockedAddrs,
)

return authKeeper, keeper
}

func (suite *IntegrationTestSuite) SetupTest() {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
Expand All @@ -83,41 +105,51 @@ func (suite *IntegrationTestSuite) SetupTest() {
}

func (suite *IntegrationTestSuite) TestSupply() {
app, ctx := suite.app, suite.ctx
_, ctx := suite.app, suite.ctx

require := suite.Require()

// add module accounts to supply keeper
authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool))

initialPower := int64(100)
<<<<<<< HEAD
initTokens := sdk.TokensFromConsensusPower(initialPower)

totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))
app.BankKeeper.SetSupply(ctx, types.NewSupply(totalSupply))

total := app.BankKeeper.GetSupply(ctx).GetTotal()
suite.Require().Equal(totalSupply, total)
=======
initTokens := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, initialPower)
totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))

// set burnerAcc balance
authKeeper.SetModuleAccount(ctx, burnerAcc)
require.NoError(keeper.MintCoins(ctx, authtypes.Minter, totalSupply))
require.NoError(keeper.SendCoinsFromModuleToAccount(ctx, authtypes.Minter, burnerAcc.GetAddress(), totalSupply))

total, _, err := keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
require.NoError(err)
require.Equal(totalSupply, total)

// burning all supplied tokens
err = keeper.BurnCoins(ctx, authtypes.Burner, totalSupply)
require.NoError(err)

total, _, err = keeper.GetPaginatedTotalSupply(ctx, &query.PageRequest{})
require.NoError(err)
require.Equal(total.String(), "")
>>>>>>> f04b5dcb9... fix zero coins (#9229)
}

func (suite *IntegrationTestSuite) TestSendCoinsFromModuleToAccount_Blacklist() {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{Height: 1})
appCodec := app.AppCodec()
ctx := suite.ctx

// add module accounts to supply keeper
maccPerms := simapp.GetMaccPerms()
maccPerms[holder] = nil
maccPerms[authtypes.Burner] = []string{authtypes.Burner}
maccPerms[authtypes.Minter] = []string{authtypes.Minter}
maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking}
maccPerms[randomPerm] = []string{"random"}

addr1 := sdk.AccAddress([]byte("addr1_______________"))

authKeeper := authkeeper.NewAccountKeeper(
appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName),
authtypes.ProtoBaseAccount, maccPerms,
)
keeper := keeper.NewBaseKeeper(
appCodec, app.GetKey(types.StoreKey), authKeeper,
app.GetSubspace(types.ModuleName), map[string]bool{addr1.String(): true},
)
_, keeper := suite.initKeepersWithmAccPerms(map[string]bool{addr1.String(): true})

baseAcc := authKeeper.NewAccountWithAddress(ctx, authtypes.NewModuleAddress("baseAcc"))
suite.Require().NoError(keeper.SetBalances(ctx, holderAcc.GetAddress(), initCoins))
Expand All @@ -130,26 +162,10 @@ func (suite *IntegrationTestSuite) TestSendCoinsFromModuleToAccount_Blacklist()
}

func (suite *IntegrationTestSuite) TestSupply_SendCoins() {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{Height: 1})
appCodec := app.AppCodec()
ctx := suite.ctx

// add module accounts to supply keeper
maccPerms := simapp.GetMaccPerms()
maccPerms[holder] = nil
maccPerms[authtypes.Burner] = []string{authtypes.Burner}
maccPerms[authtypes.Minter] = []string{authtypes.Minter}
maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking}
maccPerms[randomPerm] = []string{"random"}

authKeeper := authkeeper.NewAccountKeeper(
appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName),
authtypes.ProtoBaseAccount, maccPerms,
)
keeper := keeper.NewBaseKeeper(
appCodec, app.GetKey(types.StoreKey), authKeeper,
app.GetSubspace(types.ModuleName), make(map[string]bool),
)
authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool))

baseAcc := authKeeper.NewAccountWithAddress(ctx, authtypes.NewModuleAddress("baseAcc"))
suite.Require().NoError(keeper.SetBalances(ctx, holderAcc.GetAddress(), initCoins))
Expand Down Expand Up @@ -193,26 +209,10 @@ func (suite *IntegrationTestSuite) TestSupply_SendCoins() {
}

func (suite *IntegrationTestSuite) TestSupply_MintCoins() {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{Height: 1})
appCodec := app.AppCodec()
ctx := suite.ctx

// add module accounts to supply keeper
maccPerms := simapp.GetMaccPerms()
maccPerms[holder] = nil
maccPerms[authtypes.Burner] = []string{authtypes.Burner}
maccPerms[authtypes.Minter] = []string{authtypes.Minter}
maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking}
maccPerms[randomPerm] = []string{"random"}

authKeeper := authkeeper.NewAccountKeeper(
appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName),
authtypes.ProtoBaseAccount, maccPerms,
)
keeper := keeper.NewBaseKeeper(
appCodec, app.GetKey(types.StoreKey), authKeeper,
app.GetSubspace(types.ModuleName), make(map[string]bool),
)
authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool))

authKeeper.SetModuleAccount(ctx, burnerAcc)
authKeeper.SetModuleAccount(ctx, minterAcc)
Expand Down Expand Up @@ -247,26 +247,16 @@ func (suite *IntegrationTestSuite) TestSupply_MintCoins() {
}

func (suite *IntegrationTestSuite) TestSupply_BurnCoins() {
<<<<<<< HEAD
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{Height: 1})
appCodec, _ := simapp.MakeCodecs()

=======
ctx := suite.ctx
>>>>>>> f04b5dcb9... fix zero coins (#9229)
// add module accounts to supply keeper
maccPerms := simapp.GetMaccPerms()
maccPerms[holder] = nil
maccPerms[authtypes.Burner] = []string{authtypes.Burner}
maccPerms[authtypes.Minter] = []string{authtypes.Minter}
maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking}
maccPerms[randomPerm] = []string{"random"}

authKeeper := authkeeper.NewAccountKeeper(
appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName),
authtypes.ProtoBaseAccount, maccPerms,
)
keeper := keeper.NewBaseKeeper(
appCodec, app.GetKey(types.StoreKey), authKeeper,
app.GetSubspace(types.ModuleName), make(map[string]bool),
)
authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool))

suite.Require().NoError(keeper.SetBalances(ctx, burnerAcc.GetAddress(), initCoins))
keeper.SetSupply(ctx, types.NewSupply(initCoins))
Expand Down Expand Up @@ -319,11 +309,15 @@ func (suite *IntegrationTestSuite) TestSendCoinsNewAccount() {
app.BankKeeper.GetAllBalances(ctx, addr2)
suite.Require().Empty(app.BankKeeper.GetAllBalances(ctx, addr2))

sendAmt := sdk.NewCoins(newFooCoin(50), newBarCoin(25))
sendAmt := sdk.NewCoins(newFooCoin(50), newBarCoin(50))
suite.Require().NoError(app.BankKeeper.SendCoins(ctx, addr1, addr2, sendAmt))

acc2Balances := app.BankKeeper.GetAllBalances(ctx, addr2)
acc1Balances = app.BankKeeper.GetAllBalances(ctx, addr1)
suite.Require().Equal(sendAmt, acc2Balances)
updatedAcc1Bal := balances.Sub(sendAmt)
suite.Require().Len(acc1Balances, len(updatedAcc1Bal))
suite.Require().Equal(acc1Balances, updatedAcc1Bal)
suite.Require().NotNil(app.AccountKeeper.GetAccount(ctx, addr2))
}

Expand Down
10 changes: 10 additions & 0 deletions x/bank/keeper/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,18 @@ func (k BaseSendKeeper) SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance
balancesStore := prefix.NewStore(store, types.BalancesPrefix)
accountStore := prefix.NewStore(balancesStore, addr.Bytes())

<<<<<<< HEAD
bz := k.cdc.MustMarshalBinaryBare(&balance)
accountStore.Set([]byte(balance.Denom), bz)
=======
// Bank invariants require to not store zero balances.
if balance.IsZero() {
accountStore.Delete([]byte(balance.Denom))
} else {
bz := k.cdc.MustMarshal(&balance)
accountStore.Set([]byte(balance.Denom), bz)
}
>>>>>>> f04b5dcb9... fix zero coins (#9229)

return nil
}
Expand Down

0 comments on commit 9e18396

Please sign in to comment.