Fix genesis supply handling (#8930)
* Fix genesis supply handling * Add test * Fix nit Co-authored-by: Amaury M <1293565+amaurym@users.noreply.github.com> Co-authored-by: Alessio Treglia <alessio@tendermint.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
3361ea989c
commit
e9e978d543
|
@ -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];
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
@ -28,6 +30,8 @@ func (gs GenesisState) Validate() error {
|
|||
}
|
||||
|
||||
seenBalances[balance.Address] = true
|
||||
|
||||
totalSupply = totalSupply.Add(balance.Coins...)
|
||||
}
|
||||
|
||||
for _, metadata := range gs.DenomMetadata {
|
||||
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue