Merge PR #3666: improve denom validation

This commit is contained in:
Alessio Treglia 2019-03-01 20:10:22 +00:00 committed by Jack Zampolin
parent bdf55d9610
commit b47032d280
3 changed files with 30 additions and 23 deletions

View File

@ -23,6 +23,7 @@
* [\#3669] Ensure consistency in message naming, codec registration, and JSON
tags.
* [\#3666] Improve coins denom validation.
* [\#3751] Disable (temporarily) support for ED25519 account key pairs.
### Tendermint

View File

@ -1,6 +1,7 @@
package types
import (
"errors"
"fmt"
"regexp"
"sort"
@ -27,10 +28,10 @@ type Coin struct {
// NewCoin returns a new coin with a denomination and amount. It will panic if
// the amount is negative.
func NewCoin(denom string, amount Int) Coin {
validateDenom(denom)
mustValidateDenom(denom)
if amount.LT(ZeroInt()) {
panic(fmt.Sprintf("negative coin amount: %v\n", amount))
panic(fmt.Errorf("negative coin amount: %v", amount))
}
return Coin{
@ -148,7 +149,7 @@ func (coins Coins) IsValid() bool {
case 0:
return true
case 1:
if strings.ToLower(coins[0].Denom) != coins[0].Denom {
if err := validateDenom(coins[0].Denom); err != nil {
return false
}
return coins[0].IsPositive()
@ -360,7 +361,7 @@ func (coins Coins) Empty() bool {
// Returns the amount of a denom from coins
func (coins Coins) AmountOf(denom string) Int {
validateDenom(denom)
mustValidateDenom(denom)
switch len(coins) {
case 0:
@ -477,20 +478,25 @@ func (coins Coins) Sort() Coins {
var (
// Denominations can be 3 ~ 16 characters long.
reDnm = `[[:alpha:]][[:alnum:]]{2,15}`
reAmt = `[[:digit:]]+`
reDecAmt = `[[:digit:]]*\.[[:digit:]]+`
reSpc = `[[:space:]]*`
reCoin = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, reAmt, reSpc, reDnm))
reDecCoin = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, reDecAmt, reSpc, reDnm))
reDnmString = `[a-z][a-z0-9]{2,15}`
reAmt = `[[:digit:]]+`
reDecAmt = `[[:digit:]]*\.[[:digit:]]+`
reSpc = `[[:space:]]*`
reDnm = regexp.MustCompile(fmt.Sprintf(`^%s$`, reDnmString))
reCoin = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, reAmt, reSpc, reDnmString))
reDecCoin = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, reDecAmt, reSpc, reDnmString))
)
func validateDenom(denom string) {
if len(denom) < 3 || len(denom) > 16 {
panic(fmt.Sprintf("invalid denom length: %s", denom))
func validateDenom(denom string) error {
if !reDnm.MatchString(denom) {
return errors.New("illegal characters")
}
if strings.ToLower(denom) != denom {
panic(fmt.Sprintf("denom cannot contain upper case characters: %s", denom))
return nil
}
func mustValidateDenom(denom string) {
if err := validateDenom(denom); err != nil {
panic(err)
}
}
@ -511,8 +517,8 @@ func ParseCoin(coinStr string) (coin Coin, err error) {
return Coin{}, fmt.Errorf("failed to parse coin amount: %s", amountStr)
}
if denomStr != strings.ToLower(denomStr) {
return Coin{}, fmt.Errorf("denom cannot contain upper case characters: %s", denomStr)
if err := validateDenom(denomStr); err != nil {
return Coin{}, fmt.Errorf("invalid denom cannot contain upper case characters or spaces: %s", err)
}
return NewCoin(denomStr, amount), nil

View File

@ -19,7 +19,7 @@ type DecCoin struct {
}
func NewDecCoin(denom string, amount Int) DecCoin {
validateDenom(denom)
mustValidateDenom(denom)
if amount.LT(ZeroInt()) {
panic(fmt.Sprintf("negative coin amount: %v\n", amount))
@ -32,7 +32,7 @@ func NewDecCoin(denom string, amount Int) DecCoin {
}
func NewDecCoinFromDec(denom string, amount Dec) DecCoin {
validateDenom(denom)
mustValidateDenom(denom)
if amount.LT(ZeroDec()) {
panic(fmt.Sprintf("negative decimal coin amount: %v\n", amount))
@ -366,7 +366,7 @@ func (coins DecCoins) Empty() bool {
// returns the amount of a denom from deccoins
func (coins DecCoins) AmountOf(denom string) Dec {
validateDenom(denom)
mustValidateDenom(denom)
switch len(coins) {
case 0:
@ -429,7 +429,7 @@ func (coins DecCoins) IsValid() bool {
return true
case 1:
if strings.ToLower(coins[0].Denom) != coins[0].Denom {
if err := validateDenom(coins[0].Denom); err != nil {
return false
}
return coins[0].IsPositive()
@ -529,8 +529,8 @@ func ParseDecCoin(coinStr string) (coin DecCoin, err error) {
return DecCoin{}, errors.Wrap(err, fmt.Sprintf("failed to parse decimal coin amount: %s", amountStr))
}
if denomStr != strings.ToLower(denomStr) {
return DecCoin{}, fmt.Errorf("denom cannot contain upper case characters: %s", denomStr)
if err := validateDenom(denomStr); err != nil {
return DecCoin{}, fmt.Errorf("invalid denom cannot contain upper case characters or spaces: %s", err)
}
return NewDecCoinFromDec(denomStr, amount), nil