Skip to content

Commit a49bf94

Browse files
author
Naohiro Yoshida
committed
check strict
Signed-off-by: Naohiro Yoshida <naohiro.yoshida@datachain.jp>
1 parent 1f6c1df commit a49bf94

File tree

7 files changed

+158
-41
lines changed

7 files changed

+158
-41
lines changed

light-client/src/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,7 @@ mod test {
836836
consensus_state: mock_consensus_state,
837837
};
838838
let err = client.update_client(&ctx, client_id, any).unwrap_err();
839-
assert_err(err, "MissingForkHeightIntBoundaryCalculation");
839+
assert_err(err, "MissingForkHeightInBoundaryCalculation");
840840
}
841841

842842
#[rstest]

light-client/src/client_state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ impl ClientState {
129129
}
130130

131131
// Ensure satisfying fork specs
132-
header.verify_fork_rule(&self.fork_specs)?;
132+
header.assign_fork_spec(&self.fork_specs)?;
133133

134134
// Ensure header is valid
135135
header.verify(&self.chain_id, cs)

light-client/src/errors.rs

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ pub enum Error {
109109
MissingForkSpec(BlockNumber, u64),
110110
MissingForkSpecByHeight(BlockNumber),
111111
UnexpectedHeaderItemCount(BlockNumber, usize, u64),
112+
MissingEpochInfo(BlockNumber),
113+
UnexpectedEpochInfo(BlockNumber, BlockNumber),
112114

113115
// Vote attestation
114116
UnexpectedTooManyHeadersToFinalize(BlockNumber, usize),
@@ -132,9 +134,18 @@ pub enum Error {
132134
UnexpectedForkSpecTimestampOrder(u64, u64),
133135
UnexpectedForkSpecHeightOrder(u64, u64),
134136
MissingForkHeightIntPreviousEpochCalculation(u64, ForkSpec),
135-
MissingForkHeightIntBoundaryCalculation(ForkSpec),
136-
NotVerifiableHeader(BlockNumber),
137+
MissingForkHeightInBoundaryCalculation(ForkSpec),
138+
MissingBoundaryEpochs(BlockNumber),
137139
MissingPreviousForkSpec(ForkSpec),
140+
UnexpectedCurrentEpochInCalculatingNextEpoch(BlockNumber, BlockNumber, BlockNumber),
141+
UnexpectedMissingForkSpecInCurrentEpochCalculation(BlockNumber, alloc::boxed::Box<Error>),
142+
UnexpectedMissingForkSpecInPreviousEpochCalculation(BlockNumber, alloc::boxed::Box<Error>),
143+
UnexpectedPreviousEpochInCalculatingNextEpoch(
144+
BlockNumber,
145+
BlockNumber,
146+
BlockNumber,
147+
BlockNumber,
148+
),
138149

139150
// Misbehaviour
140151
MissingHeader1,
@@ -457,15 +468,49 @@ impl core::fmt::Display for Error {
457468
e1, e2
458469
)
459470
}
460-
Error::MissingForkHeightIntBoundaryCalculation(e1) => {
461-
write!(f, "MissingForkHeightIntBoundaryCalculation : {:?}", e1)
471+
Error::MissingForkHeightInBoundaryCalculation(e1) => {
472+
write!(f, "MissingForkHeightInBoundaryCalculation : {:?}", e1)
462473
}
463-
Error::NotVerifiableHeader(e1) => {
464-
write!(f, "NotVerifiableHeader : {}", e1)
474+
Error::MissingBoundaryEpochs(e1) => {
475+
write!(f, "MissingBoundaryEpochs : {}", e1)
465476
}
466477
Error::MissingPreviousForkSpec(e1) => {
467478
write!(f, "MissingPreviousForkSpec : {:?}", e1)
468479
}
480+
Error::UnexpectedCurrentEpochInCalculatingNextEpoch(e1, e2, e3) => {
481+
write!(
482+
f,
483+
"UnexpectedCurrentEpochInCalculatingNextEpoch : {} {} {}",
484+
e1, e2, e3
485+
)
486+
}
487+
Error::UnexpectedMissingForkSpecInCurrentEpochCalculation(e1, e2) => {
488+
write!(
489+
f,
490+
"UnexpectedMissingForkSpecInCurrentEpochCalculation : {} {:?} ",
491+
e1, e2
492+
)
493+
}
494+
Error::UnexpectedMissingForkSpecInPreviousEpochCalculation(e1, e2) => {
495+
write!(
496+
f,
497+
"UnexpectedMissingForkSpecInPreviousEpochCalculation : {} {:?} ",
498+
e1, e2
499+
)
500+
}
501+
Error::UnexpectedPreviousEpochInCalculatingNextEpoch(e1, e2, e3, e4) => {
502+
write!(
503+
f,
504+
"UnexpectedPreviousEpochInCalculatingNextEpoch : {} {} {} {} ",
505+
e1, e2, e3, e4
506+
)
507+
}
508+
Error::MissingEpochInfo(e1) => {
509+
write!(f, "MissingEpochInfo : {} ", e1)
510+
}
511+
Error::UnexpectedEpochInfo(e1, e2) => {
512+
write!(f, "UnexpectedEpochInfo : {} {}", e1, e2)
513+
}
469514
}
470515
}
471516
}

light-client/src/fork_spec.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl ForkSpec {
7575
intermediates,
7676
});
7777
}
78-
Err(Error::MissingForkHeightIntBoundaryCalculation(self.clone()))
78+
Err(Error::MissingForkHeightInBoundaryCalculation(self.clone()))
7979
}
8080
}
8181

@@ -526,7 +526,7 @@ mod test {
526526
.boundary_epochs(&fork_spec_after_pascal())
527527
.unwrap_err()
528528
{
529-
Error::MissingForkHeightIntBoundaryCalculation(e1) => {
529+
Error::MissingForkHeightInBoundaryCalculation(e1) => {
530530
assert_eq!(current, e1);
531531
}
532532
_ => unreachable!("unexpected error"),

light-client/src/header/eth_header.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,15 +316,15 @@ impl ETHHeader {
316316
Ok(self
317317
.boundary_epochs
318318
.as_ref()
319-
.ok_or(Error::NotVerifiableHeader(self.number))?
319+
.ok_or(Error::MissingBoundaryEpochs(self.number))?
320320
.current_epoch_block_number(self.number))
321321
}
322322

323323
pub fn previous_epoch_block_number(&self) -> Result<BlockNumber, Error> {
324324
let boundary = self
325325
.boundary_epochs
326326
.as_ref()
327-
.ok_or(Error::NotVerifiableHeader(self.number))?;
327+
.ok_or(Error::MissingBoundaryEpochs(self.number))?;
328328
let current_epoch_block_number = boundary.current_epoch_block_number(self.number);
329329
Ok(boundary.previous_epoch_block_number(current_epoch_block_number))
330330
}
@@ -351,7 +351,7 @@ impl ETHHeader {
351351
Ok(())
352352
}
353353
HeightOrTimestamp::Time(_) => {
354-
Err(Error::MissingForkHeightIntBoundaryCalculation(fs.clone()))
354+
Err(Error::MissingForkHeightInBoundaryCalculation(fs.clone()))
355355
}
356356
}
357357
}

light-client/src/header/eth_headers.rs

Lines changed: 71 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ impl ETHHeaders {
3535
let current_epoch_block_number = self.target.current_epoch_block_number()?;
3636
let checkpoint = current_epoch_block_number + previous_epoch.checkpoint();
3737

38-
let (n_val, next_checkpoint) = self.verify_header_size(checkpoint, current_epoch)?;
38+
let (n_val, next_checkpoint) =
39+
self.verify_header_size(checkpoint, current_epoch, current_epoch_block_number)?;
3940

4041
// Ensure all the headers are successfully chained.
4142
self.verify_cascading_fields()?;
@@ -139,29 +140,73 @@ impl ETHHeaders {
139140
/// checkpoint range and ensures that they meet the size requirements for the current and next epochs.
140141
fn verify_header_size(
141142
&self,
142-
checkpoint: u64,
143+
current_checkpoint: u64,
143144
current_epoch: &EitherEpoch,
145+
current_epoch_block_number: BlockNumber,
144146
) -> Result<(Option<Epoch>, Option<BlockNumber>), Error> {
145-
let after_checkpoint: Vec<&ETHHeader> =
146-
self.all.iter().filter(|h| h.number >= checkpoint).collect();
147-
148-
let find_next_epoch = |hs: &Vec<&ETHHeader>, height_to_checkpoint: u64| {
149-
for h in hs.iter() {
150-
if let Ok(next_epoch) = get_validator_bytes_and_turn_length(&h.extra_data) {
151-
let next_epoch = Epoch::new(next_epoch.0.into(), next_epoch.1);
152-
let next_checkpoint = h.number + height_to_checkpoint;
153-
return (Some(next_epoch), Some(next_checkpoint));
147+
let after_checkpoint: Vec<&ETHHeader> = self
148+
.all
149+
.iter()
150+
.filter(|h| h.number >= current_checkpoint)
151+
.collect();
152+
153+
let find_next_epoch =
154+
|hs: &Vec<&ETHHeader>,
155+
height_to_checkpoint: u64,
156+
expected_prev_epoch_number: BlockNumber| {
157+
for h in hs.iter() {
158+
let self_current_epoch_number =
159+
h.current_epoch_block_number().map_err(|e| {
160+
Error::UnexpectedMissingForkSpecInCurrentEpochCalculation(
161+
h.number,
162+
alloc::boxed::Box::new(e),
163+
)
164+
})?;
165+
if self_current_epoch_number == h.number {
166+
return if let Some(next_epoch) = &h.epoch {
167+
let self_previous_epoch_number =
168+
h.previous_epoch_block_number().map_err(|e| {
169+
Error::UnexpectedMissingForkSpecInPreviousEpochCalculation(
170+
h.number,
171+
alloc::boxed::Box::new(e),
172+
)
173+
})?;
174+
if self_previous_epoch_number != expected_prev_epoch_number {
175+
return Err(Error::UnexpectedPreviousEpochInCalculatingNextEpoch(
176+
h.number,
177+
self_previous_epoch_number,
178+
expected_prev_epoch_number,
179+
current_epoch_block_number,
180+
));
181+
}
182+
let next_checkpoint = h.number + height_to_checkpoint;
183+
Ok((
184+
Some(next_epoch.clone()),
185+
Some(next_checkpoint),
186+
Some(self_current_epoch_number),
187+
))
188+
} else {
189+
Err(Error::MissingEpochInfo(h.number))
190+
};
191+
} else if h.is_epoch() {
192+
return Err(Error::UnexpectedEpochInfo(
193+
h.number,
194+
self_current_epoch_number,
195+
));
196+
}
154197
}
155-
}
156-
(None, None)
157-
};
198+
Ok((None, None, None))
199+
};
158200

159201
match current_epoch {
160202
// ex) t=200 then 200 <= h < 411 (at least 1 honest c_val(200)' can be in p_val)
161203
Untrusted(_) => {
162204
// Ensure headers are before the next_checkpoint
163-
let (next_epoch, next_checkpoint) =
164-
find_next_epoch(&after_checkpoint, current_epoch.checkpoint());
205+
let (next_epoch, next_checkpoint, _) = find_next_epoch(
206+
&after_checkpoint,
207+
current_epoch.checkpoint(),
208+
current_epoch_block_number,
209+
)?;
165210
if let Some(next_checkpoint) = next_checkpoint {
166211
if after_checkpoint.iter().any(|h| h.number >= next_checkpoint) {
167212
return Err(Error::UnexpectedNextCheckpointHeader(
@@ -175,28 +220,31 @@ impl ETHHeaders {
175220
// ex) t=201 then 201 <= h < 611 (at least 1 honest n_val(400) can be in c_val(200))
176221
Trusted(_) => {
177222
// Get next_epoch if epoch after checkpoint ex) 400
178-
let (next_epoch, next_checkpoint) =
179-
find_next_epoch(&after_checkpoint, current_epoch.checkpoint());
223+
let (next_epoch, next_checkpoint, next_epoch_block_number) = find_next_epoch(
224+
&after_checkpoint,
225+
current_epoch.checkpoint(),
226+
current_epoch_block_number,
227+
)?;
180228
let next_checkpoint = match next_checkpoint {
181229
None => return Ok((next_epoch, next_checkpoint)),
182230
Some(v) => v,
183231
};
184232

185233
// Finish if no headers over next checkpoint were found
186-
let after_next_checkpoint: Vec<&ETHHeader> = self
187-
.all
188-
.iter()
234+
let after_next_checkpoint: Vec<&ETHHeader> = after_checkpoint
235+
.into_iter()
189236
.filter(|h| h.number >= next_checkpoint)
190237
.collect();
191238
if after_next_checkpoint.is_empty() {
192239
return Ok((next_epoch, Some(next_checkpoint)));
193240
}
194241

195242
// Ensure headers are before the next_next_checkpoint
196-
let (_, next_next_checkpoint) = find_next_epoch(
243+
let (_, next_next_checkpoint, _) = find_next_epoch(
197244
&after_next_checkpoint,
198245
next_epoch.clone().unwrap().checkpoint(),
199-
);
246+
next_epoch_block_number.unwrap(),
247+
)?;
200248
if let Some(next_next_checkpoint) = next_next_checkpoint {
201249
if after_next_checkpoint
202250
.iter()

light-client/src/header/mod.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use parlia_ibc_proto::google::protobuf::Any as IBCAny;
55
use parlia_ibc_proto::ibc::lightclients::parlia::v1::Header as RawHeader;
66

77
use crate::consensus_state::ConsensusState;
8-
use crate::fork_spec::{find_target_fork_spec, get_boundary_epochs, ForkSpec};
8+
use crate::fork_spec::{find_target_fork_spec, get_boundary_epochs, ForkSpec, HeightOrTimestamp};
99
use crate::header::epoch::{EitherEpoch, Epoch, TrustedEpoch, UntrustedEpoch};
1010
use crate::header::eth_header::{validate_turn_length, ETHHeader};
1111

@@ -71,13 +71,37 @@ impl Header {
7171
&self.headers.target.hash
7272
}
7373

74-
pub fn verify_fork_rule(&mut self, fork_specs: &[ForkSpec]) -> Result<(), Error> {
74+
pub fn assign_fork_spec(&mut self, fork_specs: &[ForkSpec]) -> Result<(), Error> {
75+
let mut fork_specs = fork_specs.to_vec();
7576
for header in &mut self.headers.all {
76-
header.verify_fork_rule(fork_specs)?;
77+
header.verify_fork_rule(&fork_specs)?;
78+
}
79+
// Ensure HF height is required for target without seeking next headers
80+
self.headers.target.set_boundary_epochs(&fork_specs)?;
81+
82+
// Try to set HF height
83+
if !fork_specs.is_empty() {
84+
let last_index = fork_specs.len() - 1;
85+
let last = &mut fork_specs[last_index];
86+
match last.height_or_timestamp {
87+
HeightOrTimestamp::Time(time) => {
88+
for header in &mut self.headers.all {
89+
if header.milli_timestamp() >= time {
90+
last.height_or_timestamp = HeightOrTimestamp::Height(header.number);
91+
break;
92+
}
93+
}
94+
}
95+
_ => {}
96+
}
97+
}
98+
99+
// Set boundary epoch to verify header size.
100+
for header in &mut self.headers.all {
101+
header.set_boundary_epochs(&fork_specs)?
77102
}
78-
self.headers.target.set_boundary_epochs(fork_specs)?;
79103

80-
self.fork_specs = fork_specs.to_vec();
104+
self.fork_specs = fork_specs;
81105
Ok(())
82106
}
83107

0 commit comments

Comments
 (0)