Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Index supply by denom #8517

Merged
merged 16 commits into from
Mar 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (client/keys) [\#8500](https://github.com/cosmos/cosmos-sdk/pull/8500) `InfoImporter` interface is removed from legacy keybase.
* [\#8629](https://github.com/cosmos/cosmos-sdk/pull/8629) Deprecated `SetFullFundraiserPath` from `Config` in favor of `SetPurpose` and `SetCoinType`.
* (x/upgrade) [\#8673](https://github.com/cosmos/cosmos-sdk/pull/8673) Remove IBC logic from x/upgrade. Deprecates IBC fields in an Upgrade Plan. IBC upgrade logic moved to 02-client and an IBC UpgradeProposal is added.
* (x/bank) [\#8517](https://github.com/cosmos/cosmos-sdk/pull/8517) `SupplyI` interface and `Supply` are removed and uses `sdk.Coins` for supply tracking

### State Machine Breaking

Expand All @@ -61,7 +62,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/evidence) [\#8502](https://github.com/cosmos/cosmos-sdk/pull/8502) `HandleEquivocationEvidence` persists the evidence to state.
* (x/gov) [\#7733](https://github.com/cosmos/cosmos-sdk/pull/7733) ADR 037 Implementation: Governance Split Votes
* (x/bank) [\#8656](https://github.com/cosmos/cosmos-sdk/pull/8656) balance and supply are now correctly tracked via `coin_spent`, `coin_received`, `coinbase` and `burn` events.

* (x/bank) [\#8517](https://github.com/cosmos/cosmos-sdk/pull/8517) Supply is now stored and tracked as `sdk.Coins`
### Improvements

* (x/bank) [\#8614](https://github.com/cosmos/cosmos-sdk/issues/8614) Add `Name` and `Symbol` fields to denom metadata
Expand Down
13 changes: 0 additions & 13 deletions proto/cosmos/bank/v1beta1/bank.proto
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,6 @@ message Output {
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
}

// Supply represents a struct that passively keeps track of the total supply
// amounts in the network.
message Supply {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a proto-breaking change. I'm okay to remove it in the v1beta2 package but not here.

I'm adding it back in the migration PR, and adding a deprecated comment to it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can keep it in the proto files even though it's not used for now. Deprecated is the right step.

option (gogoproto.equal) = true;
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_stringer) = false;

option (cosmos_proto.implements_interface) = "*github.com/cosmos/cosmos-sdk/x/bank/exported.SupplyI";

repeated cosmos.base.v1beta1.Coin total = 1
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
}

// DenomUnit represents a struct that describes a given
// denomination unit of the basic token.
message DenomUnit {
Expand Down
17 changes: 0 additions & 17 deletions x/bank/exported/exported.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package exported

import (
"github.com/gogo/protobuf/proto"

sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand All @@ -12,18 +10,3 @@ type GenesisBalance interface {
GetAddress() sdk.AccAddress
GetCoins() sdk.Coins
}

// SupplyI defines an inflationary supply interface for modules that handle
// token supply.
type SupplyI interface {
proto.Message

GetTotal() sdk.Coins
SetTotal(total sdk.Coins)

Inflate(amount sdk.Coins)
Deflate(amount sdk.Coins)

String() string
ValidateBasic() error
}
4 changes: 2 additions & 2 deletions x/bank/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (k BaseKeeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) {
genState.Supply = totalSupply
}

k.setSupply(ctx, types.NewSupply(genState.Supply))
k.setSupply(ctx, genState.Supply)

for _, meta := range genState.DenomMetadata {
k.SetDenomMetaData(ctx, meta)
Expand All @@ -43,7 +43,7 @@ func (k BaseKeeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
return types.NewGenesisState(
k.GetParams(ctx),
k.GetAccountsBalances(ctx),
k.GetSupply(ctx).GetTotal(),
k.GetTotalSupply(ctx),
k.GetAllDenomMetaData(ctx),
)
}
8 changes: 4 additions & 4 deletions x/bank/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ func (suite *IntegrationTestSuite) TestExportGenesis() {

suite.Require().Len(exportGenesis.Params.SendEnabled, 0)
suite.Require().Equal(types.DefaultParams().DefaultSendEnabled, exportGenesis.Params.DefaultSendEnabled)
suite.Require().Equal(totalSupply.Total, exportGenesis.Supply)
suite.Require().Equal(totalSupply, exportGenesis.Supply)
// add mint module balance as nil
expectedBalances = append(expectedBalances, types.Balance{Address: "cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q", Coins: nil})
suite.Require().Equal(expectedBalances, exportGenesis.Balances)
suite.Require().Equal(expectedMetadata, exportGenesis.DenomMetadata)
}

func (suite *IntegrationTestSuite) getTestBalancesAndSupply() ([]types.Balance, *types.Supply) {
func (suite *IntegrationTestSuite) getTestBalancesAndSupply() ([]types.Balance, sdk.Coins) {
addr2, _ := sdk.AccAddressFromBech32("cosmos1f9xjhxm0plzrh9cskf4qee4pc2xwp0n0556gh0")
addr1, _ := sdk.AccAddressFromBech32("cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh")
addr1Balance := sdk.Coins{sdk.NewInt64Coin("testcoin3", 10)}
addr2Balance := sdk.Coins{sdk.NewInt64Coin("testcoin1", 32), sdk.NewInt64Coin("testcoin2", 34)}

totalSupply := types.NewSupply(addr1Balance)
totalSupply.Inflate(addr2Balance)
totalSupply := addr1Balance
totalSupply = totalSupply.Add(addr2Balance...)
return []types.Balance{
{Address: addr2.String(), Coins: addr2Balance},
{Address: addr1.String(), Coins: addr1Balance},
Expand Down
6 changes: 3 additions & 3 deletions x/bank/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (k BaseKeeper) AllBalances(ctx context.Context, req *types.QueryAllBalances
// TotalSupply implements the Query/TotalSupply gRPC method
func (k BaseKeeper) TotalSupply(ctx context.Context, _ *types.QueryTotalSupplyRequest) (*types.QueryTotalSupplyResponse, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
totalSupply := k.GetSupply(sdkCtx).GetTotal()
totalSupply := k.GetTotalSupply(sdkCtx)

return &types.QueryTotalSupplyResponse{Supply: totalSupply}, nil
}
Expand All @@ -95,9 +95,9 @@ func (k BaseKeeper) SupplyOf(c context.Context, req *types.QuerySupplyOfRequest)
}

ctx := sdk.UnwrapSDKContext(c)
supply := k.GetSupply(ctx).GetTotal().AmountOf(req.Denom)
supply := k.GetSupply(ctx, req.Denom)

return &types.QuerySupplyOfResponse{Amount: sdk.NewCoin(req.Denom, supply)}, nil
return &types.QuerySupplyOfResponse{Amount: sdk.NewCoin(req.Denom, supply.Amount)}, nil
}

// Params implements the gRPC service handler for querying x/bank parameters.
Expand Down
12 changes: 5 additions & 7 deletions x/bank/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// +build norace

package keeper_test

import (
Expand Down Expand Up @@ -90,27 +88,27 @@ func (suite *IntegrationTestSuite) TestQueryAllBalances() {

func (suite *IntegrationTestSuite) TestQueryTotalSupply() {
app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient
expectedTotalSupply := types.NewSupply(sdk.NewCoins(sdk.NewInt64Coin("test", 400000000)))
expectedTotalSupply := sdk.NewCoins(sdk.NewInt64Coin("test", 400000000))
suite.
Require().
NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, expectedTotalSupply.Total))
NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, expectedTotalSupply))

res, err := queryClient.TotalSupply(gocontext.Background(), &types.QueryTotalSupplyRequest{})
suite.Require().NoError(err)
suite.Require().NotNil(res)

suite.Require().Equal(expectedTotalSupply.Total, res.Supply)
suite.Require().Equal(expectedTotalSupply, res.Supply)
}

func (suite *IntegrationTestSuite) TestQueryTotalSupplyOf() {
app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient

test1Supply := sdk.NewInt64Coin("test1", 4000000)
test2Supply := sdk.NewInt64Coin("test2", 700000000)
expectedTotalSupply := types.NewSupply(sdk.NewCoins(test1Supply, test2Supply))
expectedTotalSupply := sdk.NewCoins(test1Supply, test2Supply)
suite.
Require().
NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, expectedTotalSupply.Total))
NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, expectedTotalSupply))

_, err := queryClient.SupplyOf(gocontext.Background(), &types.QuerySupplyOfRequest{})
suite.Require().Error(err)
Expand Down
6 changes: 3 additions & 3 deletions x/bank/keeper/invariants.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,19 @@ func NonnegativeBalanceInvariant(k ViewKeeper) sdk.Invariant {
func TotalSupply(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
expectedTotal := sdk.Coins{}
supply := k.GetSupply(ctx)
supply := k.GetTotalSupply(ctx)

k.IterateAllBalances(ctx, func(_ sdk.AccAddress, balance sdk.Coin) bool {
expectedTotal = expectedTotal.Add(balance)
return false
})

broken := !expectedTotal.IsEqual(supply.GetTotal())
broken := !expectedTotal.IsEqual(supply)

return sdk.FormatInvariant(types.ModuleName, "total supply",
fmt.Sprintf(
"\tsum of accounts coins: %v\n"+
"\tsupply.Total: %v\n",
expectedTotal, supply.GetTotal())), broken
expectedTotal, supply)), broken
}
}
93 changes: 65 additions & 28 deletions x/bank/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported"
"github.com/cosmos/cosmos-sdk/x/bank/exported"
"github.com/cosmos/cosmos-sdk/x/bank/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
)
Expand All @@ -22,7 +21,9 @@ type Keeper interface {
InitGenesis(sdk.Context, *types.GenesisState)
ExportGenesis(sdk.Context) *types.GenesisState

GetSupply(ctx sdk.Context) exported.SupplyI
GetSupply(ctx sdk.Context, denom string) sdk.Coin
GetTotalSupply(ctx sdk.Context) sdk.Coins
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
IterateTotalSupply(ctx sdk.Context, cb func(sdk.Coin) bool)

GetDenomMetaData(ctx sdk.Context, denom string) (types.Metadata, bool)
SetDenomMetaData(ctx sdk.Context, denomMetaData types.Metadata)
Expand All @@ -38,8 +39,6 @@ type Keeper interface {

DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error
UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error
MarshalSupply(supplyI exported.SupplyI) ([]byte, error)
UnmarshalSupply(bz []byte) (exported.SupplyI, error)

types.QueryServer
}
Expand All @@ -54,6 +53,16 @@ type BaseKeeper struct {
paramSpace paramtypes.Subspace
}

func (k BaseKeeper) GetTotalSupply(ctx sdk.Context) sdk.Coins {
balances := sdk.NewCoins()
k.IterateTotalSupply(ctx, func(balance sdk.Coin) bool {
balances = balances.Add(balance)
return false
})

return balances.Sort()
}

func NewBaseKeeper(
cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace,
blockedAddrs map[string]bool,
Expand Down Expand Up @@ -154,30 +163,52 @@ func (k BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAdd
}

// GetSupply retrieves the Supply from store
func (k BaseKeeper) GetSupply(ctx sdk.Context) exported.SupplyI {
func (k BaseKeeper) GetSupply(ctx sdk.Context, denom string) sdk.Coin {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.SupplyKey)
supplyStore := prefix.NewStore(store, types.SupplyKey)

bz := supplyStore.Get([]byte(denom))
if bz == nil {
panic("stored supply should not have been nil")
return sdk.Coin{
Denom: denom,
Amount: sdk.NewInt(0),
}
}

supply, err := k.UnmarshalSupply(bz)
var coin sdk.Coin
err := k.cdc.UnmarshalBinaryBare(bz, &coin)
if err != nil {
panic(err)
}

return supply
return coin
}

// setSupply sets the Supply to store
func (k BaseKeeper) setSupply(ctx sdk.Context, supply exported.SupplyI) {
// SetSupply sets the Supply to store
func (k BaseKeeper) setSupply(ctx sdk.Context, supply sdk.Coins) {
store := ctx.KVStore(k.storeKey)
bz, err := k.MarshalSupply(supply)
if err != nil {
panic(err)
supplyStore := prefix.NewStore(store, types.SupplyKey)

var newSupply []sdk.Coin
storeSupply := k.GetTotalSupply(ctx)

// update supply for coins which have non zero amount
for _, coin := range storeSupply {
if supply.AmountOf(coin.Denom).IsZero() {
zeroCoin := &sdk.Coin{
Denom: coin.Denom,
Amount: sdk.NewInt(0),
}
bz := k.cdc.MustMarshalBinaryBare(zeroCoin)
supplyStore.Set([]byte(coin.Denom), bz)
}
}
newSupply = append(newSupply, supply...)

store.Set(types.SupplyKey, bz)
for i := range newSupply {
bz := k.cdc.MustMarshalBinaryBare(&supply[i])
supplyStore.Set([]byte(supply[i].Denom), bz)
}
}

// GetDenomMetaData retrieves the denomination metadata
Expand Down Expand Up @@ -339,8 +370,8 @@ func (k BaseKeeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins)
}

// update total supply
supply := k.GetSupply(ctx)
supply.Inflate(amt)
supply := k.GetTotalSupply(ctx)
supply = supply.Add(amt...)

k.setSupply(ctx, supply)

Expand Down Expand Up @@ -373,8 +404,9 @@ func (k BaseKeeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins)
}

// update total supply
supply := k.GetSupply(ctx)
supply.Deflate(amt)
supply := k.GetTotalSupply(ctx)
supply = supply.Sub(amt)

k.setSupply(ctx, supply)

logger := k.Logger(ctx)
Expand Down Expand Up @@ -418,14 +450,19 @@ func (k BaseKeeper) trackUndelegation(ctx sdk.Context, addr sdk.AccAddress, amt
return nil
}

// MarshalSupply protobuf serializes a Supply interface
func (k BaseKeeper) MarshalSupply(supplyI exported.SupplyI) ([]byte, error) {
return k.cdc.MarshalInterface(supplyI)
}
func (k BaseViewKeeper) IterateTotalSupply(ctx sdk.Context, cb func(sdk.Coin) bool) {
store := ctx.KVStore(k.storeKey)
supplyStore := prefix.NewStore(store, types.SupplyKey)

iterator := supplyStore.Iterator(nil, nil)
defer iterator.Close()

// UnmarshalSupply returns a Supply interface from raw encoded supply
// bytes of a Proto-based Supply type
func (k BaseKeeper) UnmarshalSupply(bz []byte) (exported.SupplyI, error) {
var evi exported.SupplyI
return evi, k.cdc.UnmarshalInterface(bz, &evi)
for ; iterator.Valid(); iterator.Next() {
var balance sdk.Coin
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &balance)

if cb(balance) {
break
}
}
}
Loading