From cb1940705d7274909feaf6ccfd719915ad1b3a8f Mon Sep 17 00:00:00 2001 From: Naohiro Yoshida Date: Wed, 29 Nov 2023 20:24:03 +0900 Subject: [PATCH] should error if next checkpoint found Signed-off-by: Naohiro Yoshida --- light-client/src/header/eth_header.rs | 6 +- light-client/src/header/eth_headers.rs | 42 ++- light-client/src/header/mod.rs | 28 +- light-client/src/header/validator_set.rs | 385 +---------------------- 4 files changed, 61 insertions(+), 400 deletions(-) diff --git a/light-client/src/header/eth_header.rs b/light-client/src/header/eth_header.rs index 9ec674b..3de6ce7 100644 --- a/light-client/src/header/eth_header.rs +++ b/light-client/src/header/eth_header.rs @@ -11,7 +11,7 @@ use parlia_ibc_proto::ibc::lightclients::parlia::v1::EthHeader as RawETHHeader; use crate::errors::Error; -use crate::header::vote_attestation::{VoteAttestation, BLS_PUBKEY_LENGTH}; +use crate::header::vote_attestation::VoteAttestation; use crate::misc::{Address, BlockNumber, ChainId, Hash, RlpIterator, Validators}; use super::BLOCKS_PER_EPOCH; @@ -22,8 +22,8 @@ const DIFFICULTY_NOTURN: u64 = 1; pub(crate) const EXTRA_VANITY: usize = 32; pub(crate) const EXTRA_SEAL: usize = 65; const VALIDATOR_BYTES_LENGTH_BEFORE_LUBAN: usize = 20; -pub(crate) const VALIDATOR_BYTES_LENGTH: usize = - VALIDATOR_BYTES_LENGTH_BEFORE_LUBAN + BLS_PUBKEY_LENGTH; +const BLS_PUBKEY_LENGTH: usize = 48; +const VALIDATOR_BYTES_LENGTH: usize = VALIDATOR_BYTES_LENGTH_BEFORE_LUBAN + BLS_PUBKEY_LENGTH; const VALIDATOR_NUM_SIZE: usize = 1; const PARAMS_GAS_LIMIT_BOUND_DIVISOR: u64 = 256; diff --git a/light-client/src/header/eth_headers.rs b/light-client/src/header/eth_headers.rs index f222a93..4aae435 100644 --- a/light-client/src/header/eth_headers.rs +++ b/light-client/src/header/eth_headers.rs @@ -3,11 +3,12 @@ use alloc::vec::Vec; use parlia_ibc_proto::ibc::lightclients::parlia::v1::EthHeader; use crate::errors::Error; -use crate::header::validator_set::{ValidatorRanges, ValidatorSet}; +use crate::header::validator_set::ValidatorSet; -use crate::misc::ChainId; +use crate::misc::{ChainId, Validators}; use super::eth_header::ETHHeader; +use super::BLOCKS_PER_EPOCH; #[derive(Clone, Debug, PartialEq)] pub struct ETHHeaders { @@ -30,23 +31,31 @@ impl ETHHeaders { } } - let validator_ranges = - ValidatorRanges::new(&self.all, previous_validators, current_validators)?; - // Ensure valid seals - for h in &self.all { - let val = validator_ranges.get_to_verify_seal(h.number)?; - h.verify_seal(val, chain_id)?; + let epoch = self.target.number / BLOCKS_PER_EPOCH; + let checkpoint = epoch * BLOCKS_PER_EPOCH + previous_validators.checkpoint(); + let previous_validators = previous_validators.validators()?; + for h in self.all.iter() { + if h.number >= checkpoint { + //TODO error if h.number reaches next checkpoint + h.verify_seal(current_validators.validators()?, chain_id)?; + } else { + h.verify_seal(previous_validators, chain_id)?; + } } // Ensure target is finalized let headers_for_finalize = self.verify_finalized()?; // Ensure BLS signature is collect + // At the just checkpoint BLS signature uses previous validator set. for h in headers_for_finalize { - let val = validator_ranges.get_to_verify_vote(h.number)?; let vote = h.get_vote_attestation()?; - vote.verify(h.number, val)?; + if h.number > checkpoint { + vote.verify(h.number, current_validators.validators()?)?; + } else { + vote.verify(h.number, previous_validators)?; + } } Ok(()) } @@ -286,7 +295,7 @@ mod test { } #[test] - fn test_error_verify_untrusted_current_validators() { + fn test_error_verify_too_many_headers_to_seal() { let v = vec![ header_31297200(), header_31297201(), @@ -307,8 +316,8 @@ mod test { // success ( untrusted validator not used ) let p_val = trust(validators_in_31297000().into()); - let c_val = empty(); - let result = headers.verify(&mainnet(), &c_val, &p_val); + let untrusted_c_val = validators_in_31297000().into(); + let result = headers.verify(&mainnet(), &untrusted_c_val, &p_val); match result.unwrap_err() { Error::UnexpectedTooManyHeadersToFinalize(e1, e2) => { assert_eq!(e1, headers.target.number, "block error"); @@ -317,13 +326,12 @@ mod test { e => unreachable!("{:?}", e), } - // error (c_val doesn't contains any p_val) + // error headers.all.push(header_31297211()); - let c_val = vec![vec![1]].into(); - let result = headers.verify(&mainnet(), &c_val, &p_val); + let result = headers.verify(&mainnet(), &untrusted_c_val, &p_val); match result.unwrap_err() { Error::ValidatorNotTrusted(e1) => { - assert_eq!(e1, c_val.hash); + assert_eq!(e1, untrusted_c_val.hash); } e => unreachable!("{:?}", e), } diff --git a/light-client/src/header/mod.rs b/light-client/src/header/mod.rs index edbda7c..20a0a2d 100644 --- a/light-client/src/header/mod.rs +++ b/light-client/src/header/mod.rs @@ -119,6 +119,9 @@ fn verify_validator_set( consensus_state.current_validators_hash, )); } + + // Try set trust by previous trusted validators + current_validators.trust(previous_validators.validators()?) } else { if header_epoch != trusted_epoch { return Err(Error::UnexpectedTrustedHeight( @@ -406,12 +409,18 @@ pub(crate) mod test { } fn to_validator_set(h: Hash) -> ValidatorSet { - let validators: Validators = vec![]; + let validators: Validators = vec![vec![1]]; let mut v: ValidatorSet = validators.into(); v.hash = h; v } + fn to_validator_set_with_validators(h: Hash, v: Validators) -> ValidatorSet { + let mut v: ValidatorSet = v.into(); + v.hash = h; + v + } + #[test] fn test_success_verify_validator_set() { let cs = ConsensusState { @@ -423,6 +432,8 @@ pub(crate) mod test { let height = new_height(0, 400); let trusted_height = new_height(0, 201); + + // Same validator set as previous let current_validators = &mut to_validator_set([3u8; 32]); let previous_validators = &mut to_validator_set(cs.current_validators_hash); verify_validator_set( @@ -434,6 +445,21 @@ pub(crate) mod test { current_validators, ) .unwrap(); + assert!(current_validators.trusted); + + let current_validators = &mut to_validator_set([3u8; 32]); + let previous_validators = + &mut to_validator_set_with_validators(cs.current_validators_hash, vec![vec![2]]); + verify_validator_set( + &cs, + true, + height, + trusted_height, + previous_validators, + current_validators, + ) + .unwrap(); + assert!(!current_validators.trusted); let height = new_height(0, 599); let trusted_height = new_height(0, 400); diff --git a/light-client/src/header/validator_set.rs b/light-client/src/header/validator_set.rs index b708b6b..b73c6fa 100644 --- a/light-client/src/header/validator_set.rs +++ b/light-client/src/header/validator_set.rs @@ -1,9 +1,7 @@ use crate::errors::Error; -use crate::header::constant::BLOCKS_PER_EPOCH; -use crate::header::eth_header::ETHHeader; use alloc::vec::Vec; -use crate::misc::{ceil_div, keccak_256_vec, BlockNumber, Hash, Validators}; +use crate::misc::{ceil_div, keccak_256_vec, Hash, Validators}; #[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] pub struct ValidatorSet { @@ -32,11 +30,11 @@ impl ValidatorSet { if self.trusted { return; } - let (trusted, _, _) = self.is_trustable(trusted_validators); + let (trusted, _, _) = self.trustable(trusted_validators); self.trusted = trusted } - fn is_trustable(&self, trusted_validators: &Validators) -> (bool, usize, usize) { + fn trustable(&self, trusted_validators: &Validators) -> (bool, usize, usize) { let mut trusted_validator_count = 0; for x1 in &self.validators { if trusted_validators.contains(x1) { @@ -63,383 +61,12 @@ impl From>> for ValidatorSet { } } -#[derive(Clone, Debug)] -struct ValidatorRange { - min_number_to_verify_seal: BlockNumber, - min_number_to_verify_vote: BlockNumber, - validators: Validators, -} - -impl ValidatorRange { - fn new( - min_number_to_verify_seal: BlockNumber, - min_number_to_verify_vote: BlockNumber, - validators: Validators, - ) -> Self { - Self { - min_number_to_verify_seal, - min_number_to_verify_vote, - validators, - } - } -} - -#[derive(Clone, Debug)] -pub struct ValidatorRanges { - inner: Vec, -} - -impl ValidatorRanges { - pub fn new( - hs: &[ETHHeader], - p_val: &ValidatorSet, - c_val: &ValidatorSet, - ) -> Result { - let first = &hs[0]; - let mut validators = vec![]; - let mut p_val = p_val.clone(); - let mut c_val = c_val.clone(); - let mut epoch = (first.number / BLOCKS_PER_EPOCH) * BLOCKS_PER_EPOCH; - let mut checkpoint = epoch + p_val.checkpoint(); - if first.number < checkpoint { - // Default validators before checkpoint - validators.push(ValidatorRange::new( - first.number, - first.number, - p_val.validators()?.clone(), - )); - } - let mut is_first_header_in_checkpoint = true; - for h in hs { - if h.number >= checkpoint { - if is_first_header_in_checkpoint { - c_val.trust(p_val.validators()?); - validators.push(ValidatorRange::new( - checkpoint, - // At the just checkpoint BLS signature uses previous validator set. - checkpoint + 1, - c_val.validators()?.clone(), - )); - is_first_header_in_checkpoint = false; - } - - let next_epoch = epoch + BLOCKS_PER_EPOCH; - if h.number == next_epoch { - let n_val: ValidatorSet = h - .get_validator_bytes() - .ok_or_else(|| Error::MissingValidatorInEpochBlock(h.number))? - .into(); - epoch = next_epoch; - checkpoint = next_epoch + c_val.checkpoint(); - is_first_header_in_checkpoint = true; - p_val = c_val; - c_val = n_val; - } - } - } - validators.reverse(); - // ex) when target = 201 then - // 611, 612, nn_val - // 411, 412, n_val - // 211, 212, c_val - // 201, 201, p_val - // ex) when target = 215 - // 611, 612, nn_val - // 411, 412, n_val - // 211, 212, c_val - Ok(Self { inner: validators }) - } - - pub fn get_to_verify_seal(&self, number: BlockNumber) -> Result<&Validators, Error> { - for range in &self.inner { - if number >= range.min_number_to_verify_seal { - return Ok(&range.validators); - } - } - Err(Error::MissingValidatorToVerifySeal(number)) - } - - pub fn get_to_verify_vote(&self, number: BlockNumber) -> Result<&Validators, Error> { - for range in &self.inner { - if number >= range.min_number_to_verify_vote { - return Ok(&range.validators); - } - } - Err(Error::MissingValidatorToVerifyVote(number)) - } -} - #[cfg(test)] mod test { - use crate::errors::Error; - use crate::header::constant::BLOCKS_PER_EPOCH; - use crate::header::eth_header::{ETHHeader, EXTRA_SEAL, EXTRA_VANITY, VALIDATOR_BYTES_LENGTH}; - use crate::header::testdata::header_31297200; - use crate::header::validator_set::{ValidatorRange, ValidatorRanges, ValidatorSet}; - use crate::misc::{ceil_div, Validators}; - use alloc::vec::Vec; - - #[test] - pub fn test_get_to_verify_seal() { - let v1 = vec![vec![1]]; - let r1 = ValidatorRange::new(2, 2, v1.clone()); - let ranges = ValidatorRanges { inner: vec![r1] }; - - // success - let result = ranges.get_to_verify_seal(2).unwrap(); - assert_eq!(*result, v1); - - // error - match ranges.get_to_verify_seal(1).unwrap_err() { - Error::MissingValidatorToVerifySeal(n) => { - assert_eq!(n, 1); - } - err => unreachable!("err {:?}", err), - } - } - - #[test] - pub fn test_get_to_verify_vote() { - let v1 = vec![vec![1]]; - let r1 = ValidatorRange::new(2, 2, v1.clone()); - let ranges = ValidatorRanges { inner: vec![r1] }; - - // success - let result = ranges.get_to_verify_vote(2).unwrap(); - assert_eq!(*result, v1); - - // error - match ranges.get_to_verify_vote(1).unwrap_err() { - Error::MissingValidatorToVerifyVote(n) => { - assert_eq!(n, 1); - } - err => unreachable!("err {:?}", err), - } - } - - #[test] - pub fn test_success_new_validator_sets() { - let base = header_31297200(); - let verify = |start, mut p_val: ValidatorSet, c_val| { - p_val.trusted = true; - let hs = create_headers(start, base.clone(), &p_val); - let mut verify_result = ValidatorRanges::new(&hs, &p_val, &c_val).unwrap(); - verify_result.inner.reverse(); - verify_result - }; - - let assert_before_checkpoint = - |result: ValidatorRanges, start: u64, p_val: ValidatorSet, c_val: ValidatorSet| { - let first = base.number + start; - let epoch = (first / BLOCKS_PER_EPOCH) * BLOCKS_PER_EPOCH; - assert_eq!(6, result.inner.len()); - assert_eq!(result.inner[0].min_number_to_verify_seal, first, "0-min"); - assert_eq!(result.inner[0].validators, p_val.validators, "0-val"); - assert_eq!( - result.inner[1].min_number_to_verify_seal, - epoch + p_val.checkpoint() - ); - assert_eq!(result.inner[1].validators, c_val.validators, "1-val"); - assert_eq!( - result.inner[2].min_number_to_verify_seal, - epoch + BLOCKS_PER_EPOCH + c_val.checkpoint() - ); - assert_eq!(result.inner[2].validators, p_val.validators, "2-val"); - assert_eq!( - result.inner[3].min_number_to_verify_seal, - epoch + 2 * BLOCKS_PER_EPOCH + p_val.checkpoint() - ); - assert_eq!(result.inner[3].validators, p_val.validators, "3-val"); - assert_eq!( - result.inner[4].min_number_to_verify_seal, - epoch + 3 * BLOCKS_PER_EPOCH + p_val.checkpoint() - ); - assert_eq!(result.inner[4].validators, p_val.validators, "4-val"); - assert_eq!( - result.inner[5].min_number_to_verify_seal, - epoch + 4 * BLOCKS_PER_EPOCH + p_val.checkpoint() - ); - assert_eq!(result.inner[5].validators, p_val.validators, "5-val"); - }; - - let assert_eq_checkpoint = - |result: ValidatorRanges, start: u64, p_val: ValidatorSet, c_val: ValidatorSet| { - let first = base.number + start; - let epoch = (first / BLOCKS_PER_EPOCH) * BLOCKS_PER_EPOCH; - assert_eq!(5, result.inner.len()); - assert_eq!( - result.inner[0].min_number_to_verify_seal, - epoch + p_val.checkpoint(), - "0-min" - ); - assert_eq!(result.inner[0].validators, c_val.validators, "0-val"); - assert_eq!( - result.inner[1].min_number_to_verify_seal, - epoch + BLOCKS_PER_EPOCH + c_val.checkpoint() - ); - assert_eq!(result.inner[1].validators, p_val.validators, "1-val"); - assert_eq!( - result.inner[2].min_number_to_verify_seal, - epoch + 2 * BLOCKS_PER_EPOCH + p_val.checkpoint() - ); - assert_eq!(result.inner[2].validators, p_val.validators, "2-val"); - assert_eq!( - result.inner[3].min_number_to_verify_seal, - epoch + 3 * BLOCKS_PER_EPOCH + p_val.checkpoint() - ); - assert_eq!(result.inner[3].validators, p_val.validators, "3-val"); - assert_eq!( - result.inner[4].min_number_to_verify_seal, - epoch + 4 * BLOCKS_PER_EPOCH + p_val.checkpoint() - ); - assert_eq!(result.inner[4].validators, p_val.validators, "4-val"); - }; - - let assert_after_checkpoint = - |result: ValidatorRanges, start: u64, p_val: ValidatorSet, c_val: ValidatorSet| { - let first = base.number + start; - let epoch = (first / BLOCKS_PER_EPOCH) * BLOCKS_PER_EPOCH; - assert_eq!(6, result.inner.len(), "block={}", first); - assert_eq!( - result.inner[0].min_number_to_verify_seal, - epoch + p_val.checkpoint(), - "0-min" - ); - assert_eq!(result.inner[0].validators, c_val.validators, "0-val"); - assert_eq!( - result.inner[1].min_number_to_verify_seal, - epoch + BLOCKS_PER_EPOCH + c_val.checkpoint() - ); - assert_eq!(result.inner[1].validators, p_val.validators, "1-val"); - assert_eq!( - result.inner[2].min_number_to_verify_seal, - epoch + 2 * BLOCKS_PER_EPOCH + p_val.checkpoint() - ); - assert_eq!(result.inner[2].validators, p_val.validators, "2-val"); - assert_eq!( - result.inner[3].min_number_to_verify_seal, - epoch + 3 * BLOCKS_PER_EPOCH + p_val.checkpoint() - ); - assert_eq!(result.inner[3].validators, p_val.validators, "3-val"); - assert_eq!( - result.inner[4].min_number_to_verify_seal, - epoch + 4 * BLOCKS_PER_EPOCH + p_val.checkpoint() - ); - assert_eq!(result.inner[4].validators, p_val.validators, "4-val"); - assert_eq!( - result.inner[5].min_number_to_verify_seal, - epoch + 5 * BLOCKS_PER_EPOCH + p_val.checkpoint() - ); - assert_eq!(result.inner[5].validators, p_val.validators, "5-val"); - }; - - let gen = |p, c| { - let mut p_val: Validators = vec![]; - for i in 0..p { - p_val.push([i + 1_u8; VALIDATOR_BYTES_LENGTH].to_vec()) - } - let mut c_val: Validators = vec![]; - for i in 0..c { - if i <= ceil_div(p as usize, 3) as u8 { - c_val.push([i + 1_u8; VALIDATOR_BYTES_LENGTH].to_vec()) - } else { - c_val.push([i + 50_u8; VALIDATOR_BYTES_LENGTH].to_vec()) - } - } - (ValidatorSet::from(p_val), ValidatorSet::from(c_val)) - }; - - let simple = gen(1, 3); - let result = verify(0, simple.0.clone(), simple.1.clone()); - assert_before_checkpoint(result, 0, simple.0.clone(), simple.1.clone()); - let result = verify(1, simple.0.clone(), simple.1.clone()); - assert_eq_checkpoint(result, 1, simple.0.clone(), simple.1.clone()); - for i in 2..199 { - let result = verify(i, simple.0.clone(), simple.1.clone()); - assert_after_checkpoint(result, i, simple.0.clone(), simple.1.clone()); - } - - let testnet = gen(7, 8); - for i in 0..3 { - let result = verify(i, testnet.0.clone(), testnet.1.clone()); - assert_before_checkpoint(result, i, testnet.0.clone(), testnet.1.clone()); - } - let result = verify(4, testnet.0.clone(), testnet.1.clone()); - assert_eq_checkpoint(result, 4, testnet.0.clone(), testnet.1.clone()); - for i in 5..199 { - let result = verify(i, testnet.0.clone(), testnet.1.clone()); - assert_after_checkpoint(result, i, testnet.0.clone(), testnet.1.clone()); - } - - let mainnet = gen(21, 21); - for i in 0..11 { - let result = verify(i, mainnet.0.clone(), mainnet.1.clone()); - assert_before_checkpoint(result, i, mainnet.0.clone(), mainnet.1.clone()); - } - let result = verify(11, mainnet.0.clone(), mainnet.1.clone()); - assert_eq_checkpoint(result, 11, mainnet.0.clone(), mainnet.1.clone()); - for i in 12..199 { - let result = verify(i, mainnet.0.clone(), mainnet.1.clone()); - assert_after_checkpoint(result, i, mainnet.0.clone(), mainnet.1.clone()); - } - } - - #[test] - pub fn test_error_new_validator_sets() { - let gen = |p, c| { - let mut p_val: Validators = vec![]; - for i in 0..p { - p_val.push([i + 1_u8; VALIDATOR_BYTES_LENGTH].to_vec()) - } - let mut c_val: Validators = vec![]; - for i in 0..c { - c_val.push([i + 50_u8; VALIDATOR_BYTES_LENGTH].to_vec()) - } - let mut p_val = ValidatorSet::from(p_val); - p_val.trusted = true; - (p_val, ValidatorSet::from(c_val)) - }; - - let base = header_31297200(); - let (p_val, c_val) = gen(21, 21); - let hs = create_headers(0, base, &p_val); - let result = ValidatorRanges::new(&hs, &p_val, &c_val).unwrap_err(); - match result { - Error::ValidatorNotTrusted(h) => { - assert_eq!(h, c_val.hash); - } - err => unreachable!("err {:?}", err), - } - } - - fn create_extra_data(val: Validators) -> Vec { - let mut extra_data = Vec::new(); - extra_data.extend([0u8; EXTRA_VANITY]); - extra_data.extend([val.len() as u8; 1]); - for v in val { - extra_data.extend(v); - } - extra_data.extend([10; EXTRA_SEAL]); - extra_data - } - - fn create_headers(start: u64, base: ETHHeader, p_val: &ValidatorSet) -> Vec { - let mut hs: Vec = vec![]; - for i in start..start + 1000 { - let mut target = base.clone(); - target.number = base.number + i; - if target.is_epoch() { - target.extra_data = create_extra_data(p_val.clone().validators) - } else { - target.extra_data = vec![]; - } - hs.push(target); - } - hs - } + use crate::header::validator_set::ValidatorSet; #[test] - fn test_trustable() { + pub fn test_trustable() { let mut _assert_trusted = |x, y, _trusted| { let trusted_validators = vec![ vec![1], @@ -455,7 +82,7 @@ mod test { hash: [0; 32], trusted: false, }; - let (trusted, count, required) = untrusted_validators.is_trustable(&trusted_validators); + let (trusted, count, required) = untrusted_validators.trustable(&trusted_validators); assert_eq!(trusted, trusted); assert_eq!(count, y); assert_eq!(required, 3);