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

x/ibc ICS24 #5588

Merged
merged 15 commits into from
Feb 19, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ Ref: https://keepachangelog.com/en/1.0.0/

* (modules) [\#5555](https://github.com/cosmos/cosmos-sdk/pull/5555) Move x/auth/client/utils/ types and functions to x/auth/client/.

### Features

* (x/ibc) [\#5588](https://github.com/cosmos/cosmos-sdk/pull/5588) Add [ICS 024 - Host State Machine Requirements](https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements) subpackage to `x/ibc` module.

### Bug Fixes

* (x/bank) [\#5531](https://github.com/cosmos/cosmos-sdk/issues/5531) Added missing amount event to MsgMultiSend, emitted for each output.
Expand Down
15 changes: 15 additions & 0 deletions x/ibc/24-host/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package host

import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

// SubModuleName defines the ICS 24 host
const SubModuleName = "host"

// IBC client sentinel errors
var (
ErrInvalidID = sdkerrors.Register(SubModuleName, 1, "invalid identifier")
ErrInvalidPath = sdkerrors.Register(SubModuleName, 2, "invalid path")
ErrInvalidPacket = sdkerrors.Register(SubModuleName, 3, "invalid packet")
)
11 changes: 11 additions & 0 deletions x/ibc/24-host/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package host

// RemovePath is an util function to remove a path from a set.
func RemovePath(paths []string, path string) ([]string, bool) {
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
for i, p := range paths {
if p == path {
return append(paths[:i], paths[i+1:]...), true
}
}
return paths, false
}
102 changes: 102 additions & 0 deletions x/ibc/24-host/validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package host

import (
"regexp"
"strings"

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

// ICS 024 Identifier and Path Validation Implementation
//
// This file defines ValidateFn to validate identifier and path strings
// The spec for ICS 024 can be located here:
// https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements

// regular expression to check string is lowercase alphabetic characters only
var isAlphaLower = regexp.MustCompile(`^[a-z]+$`).MatchString

// regular expression to check string is alphanumeric
var isAlphaNumeric = regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString
fedekunze marked this conversation as resolved.
Show resolved Hide resolved

// ValidateFn function type to validate path and identifier bytestrings
type ValidateFn func(string) error

func defaultIdentifierValidator(id string, min, max int) error {
// valid id MUST NOT contain "/" separator
if strings.Contains(id, "/") {
return sdkerrors.Wrapf(ErrInvalidID, "identifier %s cannot contain separator '/'", id)
}
// valid id must be between 10 and 20 characters
if len(id) < min || len(id) > max {
return sdkerrors.Wrapf(ErrInvalidID, "identifier %s has invalid length: %d, must be between %d-%d characters", id, len(id), min, max)
}
// valid id must contain only lower alphabetic characters
if !isAlphaLower(id) {
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
return sdkerrors.Wrapf(ErrInvalidID, "identifier %s must contain only lowercase alphabetic characters", id)
}
return nil
}

// DefaultClientIdentifierValidator is the default validator function for Client identifiers
// A valid Identifier must be between 10-20 characters and only contain lowercase
// alphabetic characters,
func DefaultClientIdentifierValidator(id string) error {
return defaultIdentifierValidator(id, 10, 20)
}

// DefaultConnectionIdentifierValidator is the default validator function for Connection identifiers
// A valid Identifier must be between 10-20 characters and only contain lowercase
// alphabetic characters,
func DefaultConnectionIdentifierValidator(id string) error {
return defaultIdentifierValidator(id, 10, 20)
}

// DefaultChannelIdentifierValidator is the default validator function for Channel identifiers
// A valid Identifier must be between 10-20 characters and only contain lowercase
// alphabetic characters,
func DefaultChannelIdentifierValidator(id string) error {
return defaultIdentifierValidator(id, 10, 20)
}

// DefaultPortIdentifierValidator is the default validator function for Port identifiers
// A valid Identifier must be between 2-20 characters and only contain lowercase
// alphabetic characters,
func DefaultPortIdentifierValidator(id string) error {
return defaultIdentifierValidator(id, 2, 20)
}

// NewPathValidator takes in a Identifier Validator function and returns
// a Path Validator function which requires path only has valid identifiers
// alphanumeric character strings, and "/" separators
func NewPathValidator(idValidator ValidateFn) ValidateFn {
return func(path string) error {
pathArr := strings.Split(path, "/")
for _, p := range pathArr {
// Each path element must either be valid identifier or alphanumeric
err := idValidator(p)
if err != nil && !isAlphaNumeric(p) {
return sdkerrors.Wrapf(ErrInvalidPath, "path %s contains invalid identifier or non-alphanumeric path element: %s", path, p)
}
}
return nil
}
}

// DefaultPathValidator takes in path string and validates
// with default identifier rules. This is optimized by simply
// checking that all path elements are alphanumeric
func DefaultPathValidator(path string) error {
pathArr := strings.Split(path, "/")
if pathArr[0] == path {
return sdkerrors.Wrapf(ErrInvalidPath, "path %s doesn't contain any separator '/'", path)
}

for _, p := range pathArr {
// Each path element must be alphanumeric and non-blank
if strings.TrimSpace(p) == "" || !isAlphaNumeric(p) {
return sdkerrors.Wrapf(ErrInvalidPath, "path %s contains an invalid non-alphanumeric character: '%s'", path, p)
}
}
return nil
}