Skip to content

Commit cd3d4ac

Browse files
author
Naohiro Yoshida
committed
fix conflict
Signed-off-by: Naohiro Yoshida <[email protected]>
2 parents 5d752c6 + bd83fed commit cd3d4ac

File tree

10 files changed

+473
-130
lines changed

10 files changed

+473
-130
lines changed

.github/workflows/ci.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,11 @@ jobs:
4141
with:
4242
command: test
4343
args: --release --features=std --manifest-path light-client/Cargo.toml
44+
- uses: actions-rs/cargo@v1
45+
name: unit-test-dev-test
46+
with:
47+
command: test
48+
args: --release --features=dev --manifest-path light-client/Cargo.toml --lib test::dev_test
49+
env:
50+
MINIMUM_TIMESTAMP_SUPPORTED: 1731495592
51+
MINIMUM_HEIGHT_SUPPORTED: 100

light-client/build.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,23 @@ fn main() {
88
writeln!(
99
file,
1010
"pub const BLOCKS_PER_EPOCH: u64 = {};",
11-
blocks_per_epoch
11+
blocks_per_epoch,
12+
)
13+
.unwrap();
14+
}
15+
16+
{
17+
use std::io::Write;
18+
let mut file = std::fs::File::create("src/header/hardfork.rs").unwrap();
19+
let minimum_time_stamp_supported =
20+
std::env::var("MINIMUM_TIMESTAMP_SUPPORTED").unwrap_or_else(|_| "0".to_string());
21+
let minimum_height_supported =
22+
std::env::var("MINIMUM_HEIGHT_SUPPORTED").unwrap_or_else(|_| "0".to_string());
23+
writeln!(
24+
file,
25+
"pub const MINIMUM_TIMESTAMP_SUPPORTED: u64 = {};\npub const MINIMUM_HEIGHT_SUPPORTED: u64 = {};",
26+
minimum_time_stamp_supported,
27+
minimum_height_supported
1228
)
1329
.unwrap();
1430
}

light-client/src/client.rs

Lines changed: 107 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::commitment::{
1919
};
2020
use crate::consensus_state::ConsensusState;
2121
use crate::errors::{ClientError, Error};
22-
22+
use crate::header::hardfork::{MINIMUM_HEIGHT_SUPPORTED, MINIMUM_TIMESTAMP_SUPPORTED};
2323
use crate::header::Header;
2424
use crate::message::ClientMessage;
2525
use crate::misbehaviour::Misbehaviour;
@@ -165,6 +165,18 @@ impl InnerLightClient {
165165
let height = client_state.latest_height;
166166
let timestamp = consensus_state.timestamp;
167167

168+
#[allow(clippy::absurd_extreme_comparisons)]
169+
if timestamp.as_unix_timestamp_secs() < MINIMUM_TIMESTAMP_SUPPORTED {
170+
return Err(Error::UnsupportedMinimumTimestamp(timestamp));
171+
}
172+
#[allow(clippy::absurd_extreme_comparisons)]
173+
if height.revision_height() < MINIMUM_HEIGHT_SUPPORTED {
174+
return Err(Error::UnsupportedMinimumHeight(height));
175+
}
176+
if height.revision_height() == 0 {
177+
return Err(Error::UnexpectedRevisionHeight(height.revision_height()));
178+
}
179+
168180
Ok(CreateClientResult {
169181
height,
170182
message: UpdateStateProxyMessage {
@@ -559,7 +571,7 @@ mod test {
559571
fn test_success_create_client() {
560572
let client_state = hex!("0a272f6962632e6c69676874636c69656e74732e7061726c69612e76312e436c69656e745374617465124d08381214151f3951fa218cac426edfe078fa9e5c6dcea5001a2000000000000000000000000000000000000000000000000000000000000000002205109b9ea90f2a040880a305320410c0843d").to_vec();
561573
let consensus_state = hex!("0a2a2f6962632e6c69676874636c69656e74732e7061726c69612e76312e436f6e73656e7375735374617465126c0a2056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b42110de82d5a8061a209c59cf0b5717cb6e2bd8620b7f3481605c8abcd45636bdf45c86db06338f0c5e22207a1dede35f5c835fecdc768324928cd0d9d9161e8529e1ba1e60451f3a9d088a").to_vec();
562-
let client = ParliaLightClient::default();
574+
let client = ParliaLightClient;
563575
let mock_consensus_state = BTreeMap::new();
564576
let ctx = MockClientReader {
565577
client_state: None,
@@ -590,6 +602,26 @@ mod test {
590602
_ => unreachable!("invalid commitment"),
591603
}
592604
}
605+
#[test]
606+
fn test_error_create_client() {
607+
let client_state = hex!("0a272f6962632e6c69676874636c69656e74732e7061726c69612e76312e436c69656e745374617465124d08381214151f3951fa218cac426edfe078fa9e5c6dcea5001a2000000000000000000000000000000000000000000000000000000000000000002205109b9ea90f2a040880a305320410c0843d").to_vec();
608+
let consensus_state = hex!("0a2a2f6962632e6c69676874636c69656e74732e7061726c69612e76312e436f6e73656e7375735374617465126c0a2056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b42110de82d5a8061a209c59cf0b5717cb6e2bd8620b7f3481605c8abcd45636bdf45c86db06338f0c5e22207a1dede35f5c835fecdc768324928cd0d9d9161e8529e1ba1e60451f3a9d088a").to_vec();
609+
let client = ParliaLightClient::default();
610+
let mock_consensus_state = BTreeMap::new();
611+
let ctx = MockClientReader {
612+
client_state: None,
613+
consensus_state: mock_consensus_state,
614+
};
615+
let mut any_client_state: Any = client_state.try_into().unwrap();
616+
let mut client_state = ClientState::try_from(any_client_state.clone()).unwrap();
617+
client_state.latest_height = Height::new(0, 0);
618+
any_client_state = client_state.try_into().unwrap();
619+
let any_consensus_state: Any = consensus_state.try_into().unwrap();
620+
let result = client
621+
.create_client(&ctx, any_client_state.clone(), any_consensus_state.clone())
622+
.unwrap_err();
623+
assert_err(result, "UnexpectedRevisionHeight");
624+
}
593625

594626
#[rstest]
595627
#[case::localnet(localnet())]
@@ -641,7 +673,7 @@ mod test {
641673
) {
642674
let any: Any = header.try_into().unwrap();
643675
let header = Header::try_from(any.clone()).unwrap();
644-
let client = ParliaLightClient::default();
676+
let client = ParliaLightClient;
645677
let client_id = ClientId::new(&client.client_type(), 1).unwrap();
646678
let mut mock_consensus_state = BTreeMap::new();
647679
let trusted_cs = ConsensusState {
@@ -711,7 +743,7 @@ mod test {
711743
#[rstest]
712744
#[case::localnet(localnet())]
713745
fn test_success_update_state_continuous(#[case] hp: Box<dyn Network>) {
714-
let client = ParliaLightClient::default();
746+
let client = ParliaLightClient;
715747
let client_id = ClientId::new(&client.client_type(), 1).unwrap();
716748
let header_groups = hp.success_update_client_continuous_input();
717749

@@ -768,7 +800,7 @@ mod test {
768800
let header = input.header;
769801
let any: Any = header.try_into().unwrap();
770802

771-
let client = ParliaLightClient::default();
803+
let client = ParliaLightClient;
772804
let client_id = ClientId::new(&client.client_type(), 1).unwrap();
773805
let mut mock_consensus_state = BTreeMap::new();
774806

@@ -845,7 +877,7 @@ mod test {
845877
let header = Header::try_from(input.clone()).unwrap();
846878
let trusted_height = header.trusted_height();
847879

848-
let client = ParliaLightClient::default();
880+
let client = ParliaLightClient;
849881
let client_id = ClientId::new(&client.client_type(), 1).unwrap();
850882
let mut mock_consensus_state = BTreeMap::new();
851883
mock_consensus_state.insert(trusted_height, ConsensusState::default());
@@ -945,7 +977,7 @@ mod test {
945977
latest_height: Height,
946978
frozen: bool,
947979
) -> Result<VerifyMembershipResult, light_client::Error> {
948-
let client = ParliaLightClient::default();
980+
let client = ParliaLightClient;
949981
let client_id = ClientId::new(client.client_type().as_str(), 0).unwrap();
950982
let mut mock_consensus_state = BTreeMap::new();
951983
mock_consensus_state.insert(
@@ -976,7 +1008,7 @@ mod test {
9761008

9771009
#[test]
9781010
fn test_success_submit_misbehavior() {
979-
let client = ParliaLightClient::default();
1011+
let client = ParliaLightClient;
9801012
let client_id = ClientId::new(client.client_type().as_str(), 1).unwrap();
9811013

9821014
// Detect misbehavior
@@ -1039,7 +1071,7 @@ mod test {
10391071
consensus_state: BTreeMap::new(),
10401072
};
10411073

1042-
let client = ParliaLightClient::default();
1074+
let client = ParliaLightClient;
10431075
let client_id = ClientId::new(client.client_type().as_str(), 1).unwrap();
10441076

10451077
// fail: exactly same block
@@ -1119,4 +1151,70 @@ mod test {
11191151
fn assert_err(err: light_client::Error, contains: &str) {
11201152
assert!(format!("{:?}", err).contains(contains), "{}", err);
11211153
}
1154+
1155+
#[cfg(feature = "dev")]
1156+
mod dev_test {
1157+
use crate::client::test::MockClientReader;
1158+
use crate::client::ParliaLightClient;
1159+
use crate::client_state::ClientState;
1160+
use crate::consensus_state::ConsensusState;
1161+
use crate::header::hardfork::{MINIMUM_HEIGHT_SUPPORTED, MINIMUM_TIMESTAMP_SUPPORTED};
1162+
use crate::misc::{new_height, new_timestamp};
1163+
use hex_literal::hex;
1164+
use light_client::{types::Any, LightClient};
1165+
use std::collections::BTreeMap;
1166+
1167+
#[test]
1168+
fn test_supported_timestamp() {
1169+
let client_state = hex!("0a272f6962632e6c69676874636c69656e74732e7061726c69612e76312e436c69656e745374617465124d08381214151f3951fa218cac426edfe078fa9e5c6dcea5001a2000000000000000000000000000000000000000000000000000000000000000002205109b9ea90f2a040880a305320410c0843d").to_vec();
1170+
let consensus_state = hex!("0a2a2f6962632e6c69676874636c69656e74732e7061726c69612e76312e436f6e73656e7375735374617465126c0a2056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b42110de82d5a8061a209c59cf0b5717cb6e2bd8620b7f3481605c8abcd45636bdf45c86db06338f0c5e22207a1dede35f5c835fecdc768324928cd0d9d9161e8529e1ba1e60451f3a9d088a").to_vec();
1171+
let client = ParliaLightClient::default();
1172+
let mock_consensus_state = BTreeMap::new();
1173+
let ctx = MockClientReader {
1174+
client_state: None,
1175+
consensus_state: mock_consensus_state,
1176+
};
1177+
let any_client_state: Any = client_state.try_into().unwrap();
1178+
let any_consensus_state: Any = consensus_state.try_into().unwrap();
1179+
let err = client
1180+
.create_client(&ctx, any_client_state.clone(), any_consensus_state.clone())
1181+
.unwrap_err();
1182+
assert!(
1183+
format!("{:?}", err).contains("UnsupportedMinimumTimestamp"),
1184+
"{}",
1185+
err
1186+
);
1187+
}
1188+
1189+
#[test]
1190+
fn test_supported_height() {
1191+
let client_state = hex!("0a272f6962632e6c69676874636c69656e74732e7061726c69612e76312e436c69656e745374617465124d08381214151f3951fa218cac426edfe078fa9e5c6dcea5001a2000000000000000000000000000000000000000000000000000000000000000002205109b9ea90f2a040880a305320410c0843d").to_vec();
1192+
let consensus_state = hex!("0a2a2f6962632e6c69676874636c69656e74732e7061726c69612e76312e436f6e73656e7375735374617465126c0a2056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b42110de82d5a8061a209c59cf0b5717cb6e2bd8620b7f3481605c8abcd45636bdf45c86db06338f0c5e22207a1dede35f5c835fecdc768324928cd0d9d9161e8529e1ba1e60451f3a9d088a").to_vec();
1193+
let client = ParliaLightClient::default();
1194+
let mock_consensus_state = BTreeMap::new();
1195+
let ctx = MockClientReader {
1196+
client_state: None,
1197+
consensus_state: mock_consensus_state,
1198+
};
1199+
let any_client_state: Any = client_state.try_into().unwrap();
1200+
let any_consensus_state: Any = consensus_state.try_into().unwrap();
1201+
1202+
let mut client_state: ClientState = any_client_state.try_into().unwrap();
1203+
client_state.latest_height = new_height(0, MINIMUM_HEIGHT_SUPPORTED - 1);
1204+
let mut consensus_state: ConsensusState = any_consensus_state.try_into().unwrap();
1205+
consensus_state.timestamp = new_timestamp(MINIMUM_TIMESTAMP_SUPPORTED).unwrap();
1206+
1207+
let any_client_state: Any = client_state.try_into().unwrap();
1208+
let any_consensus_state: Any = consensus_state.try_into().unwrap();
1209+
1210+
let err = client
1211+
.create_client(&ctx, any_client_state.clone(), any_consensus_state.clone())
1212+
.unwrap_err();
1213+
assert!(
1214+
format!("{:?}", err).contains("UnsupportedMinimumHeight"),
1215+
"{}",
1216+
err
1217+
);
1218+
}
1219+
}
11221220
}

light-client/src/client_state.rs

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use parlia_ibc_proto::ibc::lightclients::parlia::v1::ClientState as RawClientSta
1111
use crate::commitment::resolve_account;
1212
use crate::consensus_state::ConsensusState;
1313
use crate::errors::Error;
14+
use crate::header::hardfork::{MINIMUM_HEIGHT_SUPPORTED, MINIMUM_TIMESTAMP_SUPPORTED};
1415
use crate::header::Header;
1516
use crate::misbehaviour::Misbehaviour;
1617
use crate::misc::{new_height, Address, ChainId, Hash};
@@ -97,12 +98,23 @@ impl ClientState {
9798
}
9899

99100
fn check_header(&self, now: Time, cs: &ConsensusState, header: &Header) -> Result<(), Error> {
101+
// Ensure header has supported timestamp
102+
let ts = header.timestamp()?;
103+
104+
#[allow(clippy::absurd_extreme_comparisons)]
105+
if ts.as_unix_timestamp_secs() < MINIMUM_TIMESTAMP_SUPPORTED {
106+
return Err(Error::UnsupportedMinimumTimestamp(ts));
107+
}
108+
#[allow(clippy::absurd_extreme_comparisons)]
109+
if header.height().revision_height() < MINIMUM_HEIGHT_SUPPORTED {
110+
return Err(Error::UnsupportedMinimumHeight(header.height()));
111+
}
100112
// Ensure last consensus state is within the trusting period
101113
validate_within_trusting_period(
102114
now,
103115
self.trusting_period,
104116
self.max_clock_drift,
105-
header.timestamp()?,
117+
ts,
106118
cs.timestamp,
107119
)?;
108120

@@ -159,6 +171,13 @@ impl TryFrom<RawClientState> for ClientState {
159171

160172
let chain_id = ChainId::new(value.chain_id);
161173

174+
if chain_id.version() != raw_latest_height.revision_number {
175+
return Err(Error::UnexpectedLatestHeightRevision(
176+
chain_id.version(),
177+
raw_latest_height.revision_number,
178+
));
179+
}
180+
162181
let latest_height = new_height(
163182
raw_latest_height.revision_number,
164183
raw_latest_height.revision_height,
@@ -489,6 +508,19 @@ mod test {
489508
err => unreachable!("{:?}", err),
490509
}
491510

511+
cs.latest_height = Some(Height {
512+
revision_number: 1,
513+
revision_height: 0,
514+
});
515+
let err = ClientState::try_from(cs.clone()).unwrap_err();
516+
match err {
517+
Error::UnexpectedLatestHeightRevision(e1, e2) => {
518+
assert_eq!(e1, 0);
519+
assert_eq!(e2, 1);
520+
}
521+
err => unreachable!("{:?}", err),
522+
}
523+
492524
cs.latest_height = Some(Height::default());
493525
let err = ClientState::try_from(cs.clone()).unwrap_err();
494526
match err {
@@ -673,4 +705,69 @@ mod test {
673705
panic!("expected error");
674706
}
675707
}
708+
#[cfg(feature = "dev")]
709+
mod dev_test {
710+
use crate::client_state::ClientState;
711+
use crate::consensus_state::ConsensusState;
712+
use crate::errors::Error;
713+
use crate::fixture::localnet;
714+
use crate::header::eth_headers::ETHHeaders;
715+
use crate::header::hardfork::{MINIMUM_HEIGHT_SUPPORTED, MINIMUM_TIMESTAMP_SUPPORTED};
716+
use crate::header::Header;
717+
use crate::misc::new_timestamp;
718+
use parlia_ibc_proto::ibc::core::client::v1::Height;
719+
720+
#[test]
721+
fn test_supported_timestamp() {
722+
let header = Header::new(
723+
vec![1],
724+
ETHHeaders {
725+
target: localnet().previous_epoch_header(),
726+
all: vec![],
727+
},
728+
Height::default(),
729+
localnet().previous_epoch_header().epoch.unwrap(),
730+
localnet().epoch_header().epoch.unwrap(),
731+
);
732+
let cs = ClientState::default();
733+
let cons_state = ConsensusState::default();
734+
let err = cs
735+
.check_header(new_timestamp(0).unwrap(), &cons_state, &header)
736+
.unwrap_err();
737+
match err {
738+
Error::UnsupportedMinimumTimestamp(e1) => {
739+
assert_eq!(e1, header.timestamp().unwrap());
740+
}
741+
err => unreachable!("{:?}", err),
742+
}
743+
}
744+
745+
#[test]
746+
fn test_supported_height() {
747+
let mut header = Header::new(
748+
vec![1],
749+
ETHHeaders {
750+
target: localnet().previous_epoch_header(),
751+
all: vec![],
752+
},
753+
Height::default(),
754+
localnet().previous_epoch_header().epoch.unwrap(),
755+
localnet().epoch_header().epoch.unwrap(),
756+
);
757+
header.eth_header_mut().target.timestamp = MINIMUM_TIMESTAMP_SUPPORTED;
758+
header.eth_header_mut().target.number = MINIMUM_HEIGHT_SUPPORTED - 1;
759+
760+
let cs = ClientState::default();
761+
let cons_state = ConsensusState::default();
762+
let err = cs
763+
.check_header(new_timestamp(0).unwrap(), &cons_state, &header)
764+
.unwrap_err();
765+
match err {
766+
Error::UnsupportedMinimumHeight(e1) => {
767+
assert_eq!(e1, header.height());
768+
}
769+
err => unreachable!("{:?}", err),
770+
}
771+
}
772+
}
676773
}

0 commit comments

Comments
 (0)