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

imp(ics23): fallible conversion for ProofSpec, LeafOp, InnerSpec #1160

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f9fc039
feat(ics23): add conversion checks
tuantran1702 Apr 8, 2024
9dd0569
fix compiler error
tuantran1702 Apr 8, 2024
84f3122
comment out depth range tests
tuantran1702 Apr 8, 2024
c921a7c
Update ibc-core/ics23-commitment/types/src/specs.rs
tuantran1702 Apr 9, 2024
b182566
Update ibc-core/ics23-commitment/types/src/specs.rs
tuantran1702 Apr 9, 2024
db28ff2
Merge branch 'main' into tuan/add-specs-conversion-check
tuantran1702 Apr 11, 2024
53f8915
add tests and linting
tuantran1702 Apr 11, 2024
303377c
Merge branch 'tuan/add-specs-conversion-check' of github.com:notional…
tuantran1702 Apr 11, 2024
c8f6efa
refactor loop
tuantran1702 Apr 12, 2024
75947b1
Update ibc-core/ics23-commitment/types/src/specs.rs
tuantran1702 Apr 13, 2024
6608bb9
Update ibc-core/ics23-commitment/types/src/specs.rs
tuantran1702 Apr 13, 2024
4047f6f
add parameterized test
tuantran1702 Apr 13, 2024
206c366
Merge branch 'main' into tuan/add-specs-conversion-check
tuantran1702 Apr 13, 2024
a055cfd
Merge branch 'tuan/add-specs-conversion-check' of github.com:notional…
tuantran1702 Apr 13, 2024
35bb2f0
Update ibc-core/ics23-commitment/types/src/specs.rs
tuantran1702 Apr 13, 2024
696072e
update err comment
tuantran1702 Apr 13, 2024
0183fcb
Merge branch 'tuan/add-specs-conversion-check' of github.com:notional…
tuantran1702 Apr 13, 2024
b370f70
update tests
rnbguy Apr 13, 2024
c9b2454
add rstest in dev-deps
rnbguy Apr 13, 2024
6c465d5
code opt
rnbguy Apr 13, 2024
3a035c5
add HashOp and LengthOp validations
rnbguy Apr 15, 2024
6928051
code opt
rnbguy Apr 15, 2024
c39de0d
update the range validation predicates and comments
rnbguy Apr 15, 2024
519f65b
empty proof specs are disallowed
rnbguy Apr 15, 2024
53ac059
rename test fn
rnbguy Apr 15, 2024
3fb22e3
update test cases
rnbguy Apr 15, 2024
061a032
Merge branch 'main' into tuan/add-specs-conversion-check
tuantran1702 Apr 16, 2024
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
48 changes: 24 additions & 24 deletions ibc-clients/ics07-tendermint/types/src/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ impl TryFrom<RawTmClientState> for ClientState {
unbonding_period,
max_clock_drift,
latest_height,
raw.proof_specs.into(),
raw.proof_specs.try_into()?,
raw.upgrade_path,
frozen_height,
allow_update,
Expand Down Expand Up @@ -411,7 +411,7 @@ pub(crate) mod serde_tests {

#[cfg(test)]
mod tests {
use ibc_core_commitment_types::proto::ics23::ProofSpec as Ics23ProofSpec;
// use ibc_core_commitment_types::proto::ics23::ProofSpec as Ics23ProofSpec;

use super::*;

Expand Down Expand Up @@ -556,28 +556,28 @@ mod tests {
},
want_pass: false,
},
Test {
name: "Invalid (empty) proof specs".to_string(),
params: ClientStateParams {
proof_specs: Vec::<Ics23ProofSpec>::new().into(),
..default_params.clone()
},
want_pass: false,
},
Comment on lines -559 to -566
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, we can leave this test here, no?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove it after disallowing empty proof specs in Vec<RawProofSpec>::try_from.

Test {
name: "Invalid (empty) proof specs depth range".to_string(),
params: ClientStateParams {
proof_specs: vec![Ics23ProofSpec {
leaf_spec: None,
inner_spec: None,
min_depth: 2,
max_depth: 1,
prehash_key_before_comparison: false,
}].into(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm - this test is removed because min_depth: 2 and max_depth: 1 is not a valid Ics23ProofSpec after deserialization from protobuf?

I think, it's still ok to leave them here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update: this will fail when unwrapping. so this must be removed.

..default_params
},
want_pass: false,
},
// Test {
// name: "Invalid (empty) proof specs".to_string(),
// params: ClientStateParams {
// proof_specs: Vec::<Ics23ProofSpec>::new(),
// ..default_params.clone()
// },
// want_pass: false,
// },
// Test {
// name: "Invalid (empty) proof specs depth range".to_string(),
// params: ClientStateParams {
// proof_specs: vec![Ics23ProofSpec {
// leaf_spec: None,
// inner_spec: None,
// min_depth: 2,
// max_depth: 1,
// prehash_key_before_comparison: false,
// }],
// ..default_params
// },
// want_pass: false,
// },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add these tests? I guess that these failed to be created - because of try_from. In that case, add them as unit tests for your new TryFrom implementations.

]
.into_iter()
.collect();
Expand Down
6 changes: 6 additions & 0 deletions ibc-core/ics23-commitment/types/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ pub enum CommitmentError {
EncodingFailure(String),
/// decoding commitment proof bytes failed: `{0}`
DecodingFailure(String),
/// invalid length: `{0}`
tuantran1702 marked this conversation as resolved.
Show resolved Hide resolved
InvalidPrefixLengthRange(i32, i32),
/// invalid child size: `{0}`
InvalidChildSize(i32),


}

#[cfg(feature = "std")]
Expand Down
62 changes: 47 additions & 15 deletions ibc-core/ics23-commitment/types/src/specs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ impl ProofSpecs {
vec![
ics23::iavl_spec(), // Format of proofs-iavl (iavl merkle proofs)
ics23::tendermint_spec(), // Format of proofs-tendermint (crypto/ merkle SimpleProof)
]
.into()
].try_into().expect("should convert successfully")
}

pub fn is_empty(&self) -> bool {
Expand All @@ -45,9 +44,15 @@ impl ProofSpecs {
}
}

impl From<Vec<RawProofSpec>> for ProofSpecs {
fn from(ics23_specs: Vec<RawProofSpec>) -> Self {
Self(ics23_specs.into_iter().map(Into::into).collect())
impl TryFrom<Vec<RawProofSpec>> for ProofSpecs {
type Error = CommitmentError;
fn try_from(ics23_specs: Vec<RawProofSpec>) -> Result<Self, CommitmentError> {
let mut specs = Vec::new();
for raw_spec in ics23_specs {
let spec = ProofSpec::try_from(raw_spec)?;
specs.push(spec);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use

let specs = ics23_specs
  .into_iter()
  .map(ProofSpec::try_from)
  .collect::<Result<Vec<_>, _>>()?;

Ok(ProofSpecs(specs))
}
}

Expand All @@ -61,15 +66,29 @@ impl From<ProofSpecs> for Vec<RawProofSpec> {
#[derive(Clone, Debug, PartialEq)]
struct ProofSpec(RawProofSpec);

impl From<RawProofSpec> for ProofSpec {
fn from(spec: RawProofSpec) -> Self {
Self(RawProofSpec {
leaf_spec: spec.leaf_spec.map(|lop| LeafOp::from(lop).0),
inner_spec: spec.inner_spec.map(|ispec| InnerSpec::from(ispec).0),
impl TryFrom<RawProofSpec> for ProofSpec {
type Error = CommitmentError;
fn try_from(spec: RawProofSpec) -> Result<Self, CommitmentError> {
if spec.max_depth < spec.min_depth
|| spec.min_depth < 0
|| spec.max_depth < 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add comments about the failure case.

example: why 0 is case is allowed.

Copy link
Contributor Author

@tuantran1702 tuantran1702 Apr 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I am not certain about this, given some thought, I guess when min_depth or max_depth is negative, it specify that no lower or upper bound is enforced on the number of allowed InnerOps(proof specs) As a result something like min_depth=2, max_depth=-1 is perfectly fine.
Would love to hear your opinion @rnbguy, I think the failure case should be limited to only if spec.max_depth>0 && spec.min_depth>0 && spec.max_depth < spec.min_depth

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey sorry for not explaining myself 😅 I know the logic. I suggested adding them in the comments.

You can refer to the comments in protobuf definitions.

Copy link
Contributor Author

@tuantran1702 tuantran1702 Apr 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rnbguy yes but do you think

spec.max_depth < spec.min_depth
            || spec.min_depth < 0
            || spec.max_depth < 0

is correct or it should be as I mention?

Copy link
Collaborator

@rnbguy rnbguy Apr 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last comment is not right. The error case should be following, as you mentioned already,

0 < spec.min_depth && 0 < spec.max_depth && spec.max_depth < spec.min_depth

So, if both of min_depth and max_depth are greater than zero, min_depth <= max_depth. Add the logic in the comment to avoid confusion.

{
return Err(CommitmentError::InvalidDepthRange(spec.min_depth, spec.max_depth));
}

let leaf_spec = spec.leaf_spec.map(|lop| LeafOp::from(lop)).map(|lop| lop.0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let leaf_spec = spec.leaf_spec.map(|lop| LeafOp::from(lop)).map(|lop| lop.0);
let leaf_spec = spec.leaf_spec.map(LeafOp::from).map(|lop| lop.0);

let inner_spec = spec.inner_spec
.map(|ispec| InnerSpec::try_from(ispec))
tuantran1702 marked this conversation as resolved.
Show resolved Hide resolved
.transpose()?
.map(|ispec| ispec.0);

Ok(Self(RawProofSpec {
leaf_spec,
inner_spec,
max_depth: spec.max_depth,
min_depth: spec.min_depth,
prehash_key_before_comparison: spec.prehash_key_before_comparison,
})
}))
}
}

Expand Down Expand Up @@ -119,16 +138,29 @@ impl From<LeafOp> for RawLeafOp {
#[derive(Clone, Debug, PartialEq)]
struct InnerSpec(RawInnerSpec);

impl From<RawInnerSpec> for InnerSpec {
fn from(inner_spec: RawInnerSpec) -> Self {
Self(RawInnerSpec {
impl TryFrom<RawInnerSpec> for InnerSpec {
type Error = CommitmentError;
fn try_from(inner_spec: RawInnerSpec) -> Result<Self, CommitmentError> {
if inner_spec.child_size <= 0 {
return Err(CommitmentError::InvalidChildSize(inner_spec.child_size));
}
if inner_spec.min_prefix_length > inner_spec.max_prefix_length
tuantran1702 marked this conversation as resolved.
Show resolved Hide resolved
|| inner_spec.min_prefix_length < 0
|| inner_spec.max_prefix_length < 0 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add comments about the failure cases.

return Err(CommitmentError::InvalidPrefixLengthRange(
inner_spec.min_prefix_length,
inner_spec.max_prefix_length,
));
}

Ok(Self(RawInnerSpec {
child_order: inner_spec.child_order,
child_size: inner_spec.child_size,
min_prefix_length: inner_spec.min_prefix_length,
max_prefix_length: inner_spec.max_prefix_length,
empty_child: inner_spec.empty_child,
hash: inner_spec.hash,
})
}))
}
}

Expand Down
Loading