-
Notifications
You must be signed in to change notification settings - Fork 352
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
Additional unit tests for Client State #1873
Changes from 2 commits
5884ff9
c67d426
6710408
d393cd6
08a631d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -330,18 +330,32 @@ impl From<ClientState> for RawClientState { | |
#[cfg(test)] | ||
mod tests { | ||
use crate::prelude::*; | ||
use crate::Height; | ||
use core::time::Duration; | ||
use test_log::test; | ||
|
||
use ibc_proto::ics23::ProofSpec as Ics23ProofSpec; | ||
use tendermint_rpc::endpoint::abci_query::AbciQuery; | ||
|
||
use crate::clients::ics07_tendermint::client_state::{AllowUpdate, ClientState}; | ||
use crate::core::ics02_client::trust_threshold::TrustThreshold; | ||
use crate::core::ics23_commitment::specs::ProofSpecs; | ||
use crate::core::ics24_host::identifier::ChainId; | ||
use crate::test::test_serialization_roundtrip; | ||
use crate::timestamp::ZERO_DURATION; | ||
use crate::Height; | ||
use crate::timestamp::{Timestamp, ZERO_DURATION}; | ||
|
||
#[derive(Clone, Debug, PartialEq)] | ||
struct ClientStateParams { | ||
id: ChainId, | ||
trust_level: TrustThreshold, | ||
trusting_period: Duration, | ||
unbonding_period: Duration, | ||
max_clock_drift: Duration, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ibc-go doesn't allow a zero |
||
latest_height: Height, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're also not checking if the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I took the liberty to document all the missing checks in a separate issue: #1893 |
||
proof_specs: ProofSpecs, | ||
upgrade_path: Vec<String>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apparently, each key in |
||
allow_update: AllowUpdate, | ||
} | ||
|
||
#[test] | ||
fn serialization_roundtrip_no_proof() { | ||
|
@@ -359,19 +373,6 @@ mod tests { | |
|
||
#[test] | ||
fn client_state_new() { | ||
#[derive(Clone, Debug, PartialEq)] | ||
struct ClientStateParams { | ||
id: ChainId, | ||
trust_level: TrustThreshold, | ||
trusting_period: Duration, | ||
unbonding_period: Duration, | ||
max_clock_drift: Duration, | ||
latest_height: Height, | ||
proof_specs: ProofSpecs, | ||
upgrade_path: Vec<String>, | ||
allow_update: AllowUpdate, | ||
} | ||
|
||
// Define a "default" set of parameters to reuse throughout these tests. | ||
let default_params: ClientStateParams = ClientStateParams { | ||
id: ChainId::default(), | ||
|
@@ -421,6 +422,30 @@ mod tests { | |
params: ClientStateParams { | ||
trusting_period: Duration::new(11, 0), | ||
unbonding_period: Duration::new(10, 0), | ||
..default_params.clone() | ||
}, | ||
want_pass: false, | ||
}, | ||
Test { | ||
name: "Invalid (too small) trusting trust threshold".to_string(), | ||
params: ClientStateParams { | ||
trust_level: TrustThreshold::ZERO, | ||
..default_params.clone() | ||
}, | ||
want_pass: false, | ||
}, | ||
Test { | ||
name: "Invalid (too small) latest height".to_string(), | ||
params: ClientStateParams { | ||
latest_height: Height::zero(), | ||
..default_params.clone() | ||
}, | ||
want_pass: false, | ||
}, | ||
Test { | ||
name: "Invalid (empty) proof specs".to_string(), | ||
params: ClientStateParams { | ||
proof_specs: ProofSpecs::from(Vec::<Ics23ProofSpec>::new()), | ||
..default_params | ||
}, | ||
want_pass: false, | ||
|
@@ -454,6 +479,164 @@ mod tests { | |
); | ||
} | ||
} | ||
|
||
#[test] | ||
fn client_state_verify_delay_passed() { | ||
use std::time::Duration; | ||
adizere marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#[derive(Debug, Clone)] | ||
struct Params { | ||
current_time: Timestamp, | ||
current_height: Height, | ||
processed_time: Timestamp, | ||
processed_height: Height, | ||
delay_period_time: Duration, | ||
delay_period_blocks: u64, | ||
} | ||
struct Test { | ||
name: String, | ||
params: Params, | ||
want_pass: bool, | ||
} | ||
let now = Timestamp::now(); | ||
|
||
let tests: Vec<Test> = vec![ | ||
Test { | ||
name: "Successful delay verification".to_string(), | ||
params: Params { | ||
current_time: (now + Duration::from_nanos(2000)).unwrap(), | ||
current_height: Height::new(0, 5), | ||
processed_time: (now + Duration::from_nanos(1000)).unwrap(), | ||
processed_height: Height::new(0, 3), | ||
delay_period_time: Duration::from_nanos(500), | ||
delay_period_blocks: 2, | ||
}, | ||
want_pass: true, | ||
}, | ||
Test { | ||
name: "Delay period(time) has not elapsed".to_string(), | ||
params: Params { | ||
current_time: (now + Duration::from_nanos(1200)).unwrap(), | ||
current_height: Height::new(0, 5), | ||
processed_time: (now + Duration::from_nanos(1000)).unwrap(), | ||
processed_height: Height::new(0, 3), | ||
delay_period_time: Duration::from_nanos(500), | ||
delay_period_blocks: 2, | ||
}, | ||
want_pass: false, | ||
}, | ||
Test { | ||
name: "Delay period(blocks) has not elapsed".to_string(), | ||
params: Params { | ||
current_time: (now + Duration::from_nanos(2000)).unwrap(), | ||
current_height: Height::new(0, 5), | ||
processed_time: (now + Duration::from_nanos(1000)).unwrap(), | ||
processed_height: Height::new(0, 4), | ||
delay_period_time: Duration::from_nanos(500), | ||
delay_period_blocks: 2, | ||
}, | ||
want_pass: false, | ||
}, | ||
]; | ||
adizere marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
for test in tests { | ||
let res = ClientState::verify_delay_passed( | ||
test.params.current_time, | ||
test.params.current_height, | ||
test.params.processed_time, | ||
test.params.processed_height, | ||
test.params.delay_period_time, | ||
test.params.delay_period_blocks, | ||
); | ||
|
||
assert_eq!( | ||
test.want_pass, | ||
res.is_ok(), | ||
"ClientState::verify_delay_passed() failed for test {}, \nmsg{:?} with error {:?}", | ||
test.name, | ||
test.params.clone(), | ||
res.err(), | ||
); | ||
} | ||
} | ||
|
||
#[test] | ||
fn client_state_verify_height() { | ||
// Define a "default" set of parameters to reuse throughout these tests. | ||
let default_params: ClientStateParams = ClientStateParams { | ||
id: ChainId::default(), | ||
trust_level: TrustThreshold::ONE_THIRD, | ||
trusting_period: Duration::new(64000, 0), | ||
unbonding_period: Duration::new(128000, 0), | ||
max_clock_drift: Duration::new(3, 0), | ||
latest_height: Height::new(1, 10), | ||
proof_specs: ProofSpecs::default(), | ||
upgrade_path: vec!["".to_string()], | ||
allow_update: AllowUpdate { | ||
after_expiry: false, | ||
after_misbehaviour: false, | ||
}, | ||
}; | ||
|
||
struct Test { | ||
name: String, | ||
height: Height, | ||
setup: Option<Box<dyn FnOnce(ClientState) -> ClientState>>, | ||
want_pass: bool, | ||
} | ||
|
||
let tests = vec![ | ||
Test { | ||
name: "Successful height verification".to_string(), | ||
height: Height::new(1, 8), | ||
setup: None, | ||
want_pass: true, | ||
}, | ||
Test { | ||
name: "Invalid (too large) client height".to_string(), | ||
height: Height::new(1, 12), | ||
setup: None, | ||
want_pass: false, | ||
}, | ||
Test { | ||
name: "Invalid, client is frozen below current height".to_string(), | ||
height: Height::new(1, 6), | ||
setup: Some(Box::new(|client_state| { | ||
client_state.with_frozen_height(Height::new(1, 5)).unwrap() | ||
})), | ||
want_pass: false, | ||
}, | ||
]; | ||
|
||
for test in tests { | ||
let p = default_params.clone(); | ||
let client_state = ClientState::new( | ||
p.id, | ||
p.trust_level, | ||
p.trusting_period, | ||
p.unbonding_period, | ||
p.max_clock_drift, | ||
p.latest_height, | ||
p.proof_specs, | ||
p.upgrade_path, | ||
p.allow_update, | ||
) | ||
.unwrap(); | ||
let client_state = match test.setup { | ||
Some(setup) => (setup)(client_state), | ||
adizere marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_ => client_state, | ||
}; | ||
let res = client_state.verify_height(test.height); | ||
|
||
assert_eq!( | ||
test.want_pass, | ||
res.is_ok(), | ||
"ClientState::verify_delay_height() failed for test {}, \nmsg{:?} with error {:?}", | ||
test.name, | ||
test.height, | ||
res.err(), | ||
); | ||
} | ||
} | ||
} | ||
|
||
#[cfg(any(test, feature = "mocks"))] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated to this issue, but I see that ibc-go restricts 07-tendermint
ChainId
s totendermint::MaxChainID
-> cosmos/ibc-go#177@adizere Should we add this check to our
ClientState::new
ctor as well?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, I think we should! Seems minor so we can do it in almost any module-related PR.I will capture the missing piece in a separate issue.