Skip to content

Commit fe6b5b0

Browse files
mina86rnbguy
andauthored
refactor: simplify identifier length validation (informalsystems#960)
* refactor: simplify identifier length validation Firstly, remove asserts from the validate_identifier_length and validate_prefix_length functions. Instead, let the regular checks handle cases where min and max constraints don’t allow for a valid prefix to exist. Secondly, ensure minimum length constraints is at least one. This makes sure that the validation functions will check for empty identifiers and prefixes. This makes empty identifier check in validate_channel_identifier as well as Error::Empty variant unnecessary so get rid of those too. Lastly, collapse all checks in validate_prefix_length into a single call to validate_identifier_length with correctly adjusted min and max constraints. Issue: informalsystems#959 * log * Update 960-simplify-length-validation.md Signed-off-by: Michal Nazarewicz <[email protected]> * tests * Update and rename 960-simplify-length-validation.md to 961-simplify-length-validation.md Signed-off-by: Michal Nazarewicz <[email protected]> * update changelog entry * revert error variant deletion * refactor id validation tests * use numeral consistently --------- Signed-off-by: Michal Nazarewicz <[email protected]> Co-authored-by: Ranadeep Biswas <[email protected]>
1 parent 318c284 commit fe6b5b0

File tree

2 files changed

+38
-54
lines changed

2 files changed

+38
-54
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Simplify and refactor ICS-24 identifier validation logic.
2+
([\#961](https://github.com/cosmos/ibc-rs/issues/961))

crates/ibc/src/core/ics24_host/identifier/validate.rs

Lines changed: 36 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ const VALID_SPECIAL_CHARS: &str = "._+-#[]<>";
99
/// [`ICS-24`](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements#paths-identifiers-separators)]
1010
/// spec.
1111
pub fn validate_identifier_chars(id: &str) -> Result<(), Error> {
12-
// Check identifier is not empty
13-
if id.is_empty() {
14-
return Err(Error::Empty);
15-
}
16-
1712
// Check identifier does not contain path separators
1813
if id.contains(PATH_SEPARATOR) {
1914
return Err(Error::ContainSeparator { id: id.into() });
@@ -38,19 +33,19 @@ pub fn validate_identifier_chars(id: &str) -> Result<(), Error> {
3833
/// [`ICS-24`](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements#paths-identifiers-separators)]
3934
/// spec.
4035
pub fn validate_identifier_length(id: &str, min: u64, max: u64) -> Result<(), Error> {
41-
assert!(max >= min);
42-
43-
// Check identifier length is between given min/max
44-
if (id.len() as u64) < min || id.len() as u64 > max {
45-
return Err(Error::InvalidLength {
36+
// Make sure min is at least one so we reject empty identifiers.
37+
let min = min.max(1);
38+
let length = id.len() as u64;
39+
if (min..=max).contains(&length) {
40+
Ok(())
41+
} else {
42+
Err(Error::InvalidLength {
4643
id: id.into(),
47-
length: id.len() as u64,
44+
length,
4845
min,
4946
max,
50-
});
47+
})
5148
}
52-
53-
Ok(())
5449
}
5550

5651
/// Checks if a prefix forms a valid identifier with the given min/max identifier's length.
@@ -61,42 +56,16 @@ pub fn validate_prefix_length(
6156
min_id_length: u64,
6257
max_id_length: u64,
6358
) -> Result<(), Error> {
64-
assert!(max_id_length >= min_id_length);
65-
66-
if prefix.is_empty() {
67-
return Err(Error::InvalidPrefix {
68-
prefix: prefix.into(),
69-
});
70-
}
71-
72-
// Statically checks if the prefix forms a valid identifier length when constructed with `u64::MAX`
73-
// len(prefix + '-' + u64::MAX) <= max_id_length (minimum prefix length is 1)
74-
if max_id_length < 22 {
75-
return Err(Error::InvalidLength {
76-
id: prefix.into(),
77-
length: prefix.len() as u64,
78-
min: 0,
79-
max: 0,
80-
});
81-
}
82-
83-
// Checks if the prefix forms a valid identifier length when constructed with `u64::MIN`
84-
// len('-' + u64::MIN) = 2
85-
validate_identifier_length(
86-
prefix,
87-
min_id_length.saturating_sub(2),
88-
max_id_length.saturating_sub(2),
89-
)?;
90-
91-
// Checks if the prefix forms a valid identifier length when constructed with `u64::MAX`
92-
// len('-' + u64::MAX) = 21
93-
validate_identifier_length(
94-
prefix,
95-
min_id_length.saturating_sub(21),
96-
max_id_length.saturating_sub(21),
97-
)?;
98-
99-
Ok(())
59+
// Prefix must be at least `min_id_length - 2` characters long since the
60+
// shortest identifier we can construct is `{prefix}-0` which extends prefix
61+
// by 2 characters.
62+
let min = min_id_length.saturating_sub(2);
63+
// Prefix must be at most `max_id_length - 21` characters long since the
64+
// longest identifier we can construct is `{prefix}-{u64::MAX}` which
65+
// extends prefix by 21 characters.
66+
let max = max_id_length.saturating_sub(21);
67+
68+
validate_identifier_length(prefix, min, max)
10069
}
10170

10271
/// Default validator function for the Client types.
@@ -220,10 +189,21 @@ mod tests {
220189
}
221190

222191
#[test]
223-
fn parse_invalid_id_empty() {
224-
// invalid id empty
225-
let id = validate_identifier_chars("");
226-
assert!(id.is_err())
192+
fn validate_chars_empty_id() {
193+
// validate_identifier_chars allows empty identifiers
194+
assert!(validate_identifier_chars("").is_ok());
195+
}
196+
197+
#[test]
198+
fn validate_length_empty_id() {
199+
// validate_identifier_length does not allow empty identifiers
200+
assert!(validate_identifier_length("", 0, 64).is_err());
201+
}
202+
203+
#[test]
204+
fn validate_min_gt_max_constraints() {
205+
// validate_identifier_length rejects the id if min > max.
206+
assert!(validate_identifier_length("foobar", 5, 3).is_err());
227207
}
228208

229209
#[test]
@@ -252,8 +232,10 @@ mod tests {
252232
}
253233

254234
#[rstest]
235+
#[case::zero_min_length("", 0, 64, false)]
255236
#[case::empty_prefix("", 1, 64, false)]
256237
#[case::max_is_low("a", 1, 10, false)]
238+
#[case::min_greater_than_max("foobar", 5, 3, false)]
257239
#[case::u64_max_is_too_big("a", 3, 21, false)]
258240
#[case::u64_min_is_too_small("a", 4, 22, false)]
259241
#[case::u64_min_max_boundary("a", 3, 22, true)]

0 commit comments

Comments
 (0)