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

[backport/v0.41.x]: bank: additional client metadata validation #8486

Merged
merged 1 commit into from
Feb 2, 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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ Ref: https://keepachangelog.com/en/1.0.0/

# Changelog

## Unreleased

### Improvements

* (x/bank) [\#8479](https://github.com/cosmos/cosmos-sdk/pull/8479) Aditional client denom metadata validation for `base` and `display` denoms.

## [v0.41.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.41.0) - 2021-01-26

### State Machine Breaking
Expand Down
39 changes: 37 additions & 2 deletions x/bank/types/metadata.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package types

import (
"errors"
"fmt"
"strings"

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

// Validate performs a basic validation of the coin metadata fields
// Validate performs a basic validation of the coin metadata fields. It checks:
// - Base and Display denominations are valid coin denominations
// - Base and Display denominations are present in the DenomUnit slice
// - Base denomination has exponent 0
// - Denomination units are sorted in ascending order
// - Denomination units not duplicated
func (m Metadata) Validate() error {
if err := sdk.ValidateDenom(m.Base); err != nil {
return fmt.Errorf("invalid metadata base denom: %w", err)
Expand All @@ -17,19 +23,48 @@ func (m Metadata) Validate() error {
return fmt.Errorf("invalid metadata display denom: %w", err)
}

var (
hasDisplay bool
currentExponent uint32 // check that the exponents are increasing
)

seenUnits := make(map[string]bool)
for _, denomUnit := range m.DenomUnits {

for i, denomUnit := range m.DenomUnits {
// The first denomination unit MUST be the base
if i == 0 {
// validate denomination and exponent
if denomUnit.Denom != m.Base {
return fmt.Errorf("metadata's first denomination unit must be the one with base denom '%s'", m.Base)
}
if denomUnit.Exponent != 0 {
return fmt.Errorf("the exponent for base denomination unit %s must be 0", m.Base)
}
} else if currentExponent >= denomUnit.Exponent {
return errors.New("denom units should be sorted asc by exponent")
}

currentExponent = denomUnit.Exponent

if seenUnits[denomUnit.Denom] {
return fmt.Errorf("duplicate denomination unit %s", denomUnit.Denom)
}

if denomUnit.Denom == m.Display {
hasDisplay = true
}

if err := denomUnit.Validate(); err != nil {
return err
}

seenUnits[denomUnit.Denom] = true
}

if !hasDisplay {
return fmt.Errorf("metadata must contain a denomination unit with display denom '%s'", m.Display)
}

return nil
}

Expand Down
55 changes: 54 additions & 1 deletion x/bank/types/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func TestMetadataValidate(t *testing.T) {
Description: "The native staking token of the Cosmos Hub.",
DenomUnits: []*types.DenomUnit{
{"uatom", uint32(0), []string{"microatom"}},
{"uatom", uint32(0), []string{"microatom"}},
{"uatom", uint32(1), []string{"microatom"}},
},
Base: "uatom",
Display: "atom",
Expand Down Expand Up @@ -94,6 +94,59 @@ func TestMetadataValidate(t *testing.T) {
},
true,
},
{
"no base denom unit",
types.Metadata{
Description: "The native staking token of the Cosmos Hub.",
DenomUnits: []*types.DenomUnit{
{"matom", uint32(3), []string{"milliatom"}},
{"atom", uint32(6), nil},
},
Base: "uatom",
Display: "atom",
},
true,
},
{
"base denom exponent not zero",
types.Metadata{
Description: "The native staking token of the Cosmos Hub.",
DenomUnits: []*types.DenomUnit{
{"uatom", uint32(1), []string{"microatom"}},
{"matom", uint32(3), []string{"milliatom"}},
{"atom", uint32(6), nil},
},
Base: "uatom",
Display: "atom",
},
true,
},
{
"no display denom unit",
types.Metadata{
Description: "The native staking token of the Cosmos Hub.",
DenomUnits: []*types.DenomUnit{
{"uatom", uint32(0), []string{"microatom"}},
},
Base: "uatom",
Display: "atom",
},
true,
},
{
"denom units not sorted",
types.Metadata{
Description: "The native staking token of the Cosmos Hub.",
DenomUnits: []*types.DenomUnit{
{"uatom", uint32(0), []string{"microatom"}},
{"atom", uint32(6), nil},
{"matom", uint32(3), []string{"milliatom"}},
},
Base: "uatom",
Display: "atom",
},
true,
},
}

for _, tc := range testCases {
Expand Down