Skip to content

Commit

Permalink
Fix genesis supply handling (#8930)
Browse files Browse the repository at this point in the history
* Fix genesis supply handling

* Add test

* Fix nit

Co-authored-by: Amaury M <[email protected]>
Co-authored-by: Alessio Treglia <[email protected]>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Mar 22, 2021
1 parent 3361ea9 commit e9e978d
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 7 deletions.
3 changes: 2 additions & 1 deletion proto/cosmos/bank/v1beta1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ message GenesisState {
// balances is an array containing the balances of all the accounts.
repeated Balance balances = 2 [(gogoproto.nullable) = false];

// supply represents the total supply.
// supply represents the total supply. If it is left empty, then supply will be calculated based on the provided
// balances. Otherwise, it will be used to validate that the sum of the balances equals this amount.
repeated cosmos.base.v1beta1.Coin supply = 3
[(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (gogoproto.nullable) = false];

Expand Down
8 changes: 4 additions & 4 deletions x/bank/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
func (k BaseKeeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) {
k.SetParams(ctx, genState.Params)

var totalSupply sdk.Coins
totalSupply := sdk.Coins{}

genState.Balances = types.SanitizeGenesisBalances(genState.Balances)
for _, balance := range genState.Balances {
Expand All @@ -27,11 +27,11 @@ func (k BaseKeeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) {
totalSupply = totalSupply.Add(balance.Coins...)
}

if genState.Supply.Empty() {
genState.Supply = totalSupply
if !genState.Supply.Empty() && !genState.Supply.IsEqual(totalSupply) {
panic(fmt.Errorf("genesis supply is incorrect, expected %v, got %v", genState.Supply, totalSupply))
}

k.setSupply(ctx, genState.Supply)
k.setSupply(ctx, totalSupply)

for _, meta := range genState.DenomMetadata {
k.SetDenomMetaData(ctx, meta)
Expand Down
47 changes: 47 additions & 0 deletions x/bank/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,50 @@ func (suite *IntegrationTestSuite) TestInitGenesis() {
suite.Require().True(found)
suite.Require().Equal(m, m2)
}

func (suite *IntegrationTestSuite) TestTotalSupply() {
// Prepare some test data.
defaultGenesis := types.DefaultGenesisState()
balances := []types.Balance{
{Coins: sdk.NewCoins(sdk.NewCoin("foocoin", sdk.NewInt(1))), Address: "cosmos1f9xjhxm0plzrh9cskf4qee4pc2xwp0n0556gh0"},
{Coins: sdk.NewCoins(sdk.NewCoin("barcoin", sdk.NewInt(1))), Address: "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh"},
{Coins: sdk.NewCoins(sdk.NewCoin("foocoin", sdk.NewInt(10)), sdk.NewCoin("barcoin", sdk.NewInt(20))), Address: "cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q"},
}
totalSupply := sdk.NewCoins(sdk.NewCoin("foocoin", sdk.NewInt(11)), sdk.NewCoin("barcoin", sdk.NewInt(21)))

testcases := []struct {
name string
genesis *types.GenesisState
expSupply sdk.Coins
expPanic bool
expPanicMsg string
}{
{
"calculation NOT matching genesis Supply field",
types.NewGenesisState(defaultGenesis.Params, balances, sdk.NewCoins(sdk.NewCoin("wrongcoin", sdk.NewInt(1))), defaultGenesis.DenomMetadata),
nil, true, "genesis supply is incorrect, expected 1wrongcoin, got 21barcoin,11foocoin",
},
{
"calculation matches genesis Supply field",
types.NewGenesisState(defaultGenesis.Params, balances, totalSupply, defaultGenesis.DenomMetadata),
totalSupply, false, "",
},
{
"calculation is correct, empty genesis Supply field",
types.NewGenesisState(defaultGenesis.Params, balances, nil, defaultGenesis.DenomMetadata),
totalSupply, false, "",
},
}

for _, tc := range testcases {
tc := tc
suite.Run(tc.name, func() {
if tc.expPanic {
suite.PanicsWithError(tc.expPanicMsg, func() { suite.app.BankKeeper.InitGenesis(suite.ctx, tc.genesis) })
} else {
suite.app.BankKeeper.InitGenesis(suite.ctx, tc.genesis)
suite.Require().Equal(tc.expSupply, suite.app.BankKeeper.GetTotalSupply(suite.ctx))
}
})
}
}
19 changes: 17 additions & 2 deletions x/bank/types/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ func (gs GenesisState) Validate() error {
seenBalances := make(map[string]bool)
seenMetadatas := make(map[string]bool)

totalSupply := sdk.Coins{}

for _, balance := range gs.Balances {
if seenBalances[balance.Address] {
return fmt.Errorf("duplicate balance for address %s", balance.Address)
Expand All @@ -28,6 +30,8 @@ func (gs GenesisState) Validate() error {
}

seenBalances[balance.Address] = true

totalSupply = totalSupply.Add(balance.Coins...)
}

for _, metadata := range gs.DenomMetadata {
Expand All @@ -42,8 +46,19 @@ func (gs GenesisState) Validate() error {
seenMetadatas[metadata.Base] = true
}

// NOTE: this errors if supply for any given coin is zero
return gs.Supply.Validate()
if !gs.Supply.Empty() {
// NOTE: this errors if supply for any given coin is zero
err := gs.Supply.Validate()
if err != nil {
return err
}

if !gs.Supply.IsEqual(totalSupply) {
return fmt.Errorf("genesis supply is incorrect, expected %v, got %v", gs.Supply, totalSupply)
}
}

return nil
}

// NewGenesisState creates a new genesis state.
Expand Down

0 comments on commit e9e978d

Please sign in to comment.