Skip to content

Commit f97baa3

Browse files
author
Naohiro Yoshida
committed
fix conflict
Signed-off-by: Naohiro Yoshida <naohiro.yoshida@datachain.jp>
2 parents b0c92af + bd83fed commit f97baa3

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_misbehaviour() {
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 misbehaviour
@@ -1042,7 +1074,7 @@ mod test {
10421074
consensus_state: BTreeMap::new(),
10431075
};
10441076

1045-
let client = ParliaLightClient::default();
1077+
let client = ParliaLightClient;
10461078
let client_id = ClientId::new(client.client_type().as_str(), 1).unwrap();
10471079

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

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)