diff --git a/light-client/src/client.rs b/light-client/src/client.rs index 5e10fd9..105e161 100644 --- a/light-client/src/client.rs +++ b/light-client/src/client.rs @@ -1372,6 +1372,7 @@ mod test { additional_header_item_count: 0, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }]; (client_state, cons_state) })); @@ -1385,6 +1386,7 @@ mod test { additional_header_item_count: 0, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }]; (client_state, cons_state) })); @@ -1399,6 +1401,7 @@ mod test { additional_header_item_count: 0, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }]; (client_state, cons_state) })) diff --git a/light-client/src/client_state.rs b/light-client/src/client_state.rs index f776eda..96b1b1c 100644 --- a/light-client/src/client_state.rs +++ b/light-client/src/client_state.rs @@ -325,6 +325,7 @@ mod test { additional_header_item_count: 1, // requestsHash epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, } } diff --git a/light-client/src/errors.rs b/light-client/src/errors.rs index 61b3a6a..7eb126c 100644 --- a/light-client/src/errors.rs +++ b/light-client/src/errors.rs @@ -82,6 +82,7 @@ pub enum Error { MissingSignerInValidator(BlockNumber, Address), UnexpectedGasDiff(BlockNumber, u64, u64), UnexpectedGasUsed(BlockNumber, u64, u64), + UnexpectedGasLimitDivider(BlockNumber), UnexpectedHeaderRelation(BlockNumber, BlockNumber, Hash, Vec, u64, u64), ProofRLPError(rlp::DecoderError), InvalidProofFormatError(Vec), @@ -509,6 +510,9 @@ impl core::fmt::Display for Error { Error::UnexpectedEpochInfo(e1, e2) => { write!(f, "UnexpectedEpochInfo : {} {}", e1, e2) } + Error::UnexpectedGasLimitDivider(e1) => { + write!(f, "UnexpectedGasLimitDivider : {}", e1) + } Error::UnexpectedEpochLength(e1, e2) => { write!(f, "UnexpectedEpochLength : {} {}", e1, e2) } diff --git a/light-client/src/fixture/mod.rs b/light-client/src/fixture/mod.rs index cf814bf..f9eb948 100644 --- a/light-client/src/fixture/mod.rs +++ b/light-client/src/fixture/mod.rs @@ -75,6 +75,7 @@ pub fn fork_spec_after_pascal() -> ForkSpec { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 64, + gas_limit_bound_divider: 256, } } @@ -84,6 +85,7 @@ pub fn fork_spec_after_lorentz() -> ForkSpec { additional_header_item_count: 1, epoch_length: 500, max_turn_length: 64, + gas_limit_bound_divider: 1024, } } @@ -93,5 +95,6 @@ pub fn fork_spec_after_maxwell() -> ForkSpec { additional_header_item_count: 1, epoch_length: 1000, max_turn_length: 64, + gas_limit_bound_divider: 1024, } } diff --git a/light-client/src/fork_spec.rs b/light-client/src/fork_spec.rs index 8c33649..0055c5a 100644 --- a/light-client/src/fork_spec.rs +++ b/light-client/src/fork_spec.rs @@ -28,6 +28,8 @@ pub struct ForkSpec { pub epoch_length: u64, /// Max turn length pub max_turn_length: u64, + /// Gas Limit bound diriver + pub gas_limit_bound_divider: u64, } impl ForkSpec { @@ -201,6 +203,7 @@ impl TryFrom for ForkSpec { additional_header_item_count: value.additional_header_item_count, epoch_length: value.epoch_length, max_turn_length: value.max_turn_length, + gas_limit_bound_divider: value.gas_limit_bound_divider, }) } } @@ -217,6 +220,7 @@ impl From for RawForkSpec { additional_header_item_count: value.additional_header_item_count, epoch_length: value.epoch_length, max_turn_length: value.max_turn_length, + gas_limit_bound_divider: value.gas_limit_bound_divider, } } } @@ -308,12 +312,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(20), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; let v = find_target_fork_spec(specs, 10, 0).unwrap(); @@ -334,12 +340,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Time(20), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; let v = find_target_fork_spec(specs, 0, 10).unwrap(); @@ -360,12 +368,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Time(10), additional_header_item_count: 20, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; // After value is primary @@ -387,12 +397,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(20), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; let v = find_target_fork_spec(specs, 9, 0).unwrap_err(); @@ -413,12 +425,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Time(20), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; let v = find_target_fork_spec(specs, 0, 9).unwrap_err(); @@ -439,12 +453,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Time(10), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; let v = find_target_fork_spec(specs, 9, 9).unwrap_err(); @@ -465,12 +481,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(11), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; verify_sorted_asc(specs).unwrap(); @@ -484,12 +502,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Time(11), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; verify_sorted_asc(specs).unwrap(); @@ -503,12 +523,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(10), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; let v = verify_sorted_asc(specs).unwrap_err(); @@ -526,12 +548,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(10), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; let v = verify_sorted_asc(specs).unwrap_err(); @@ -552,12 +576,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Time(10), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; let v = verify_sorted_asc(specs).unwrap_err(); @@ -575,12 +601,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Time(10), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; let v = verify_sorted_asc(specs).unwrap_err(); @@ -600,6 +628,7 @@ mod test { additional_header_item_count: 1, epoch_length: 500, max_turn_length: 64, + gas_limit_bound_divider: 256, }; match current .boundary_epochs(&fork_spec_after_pascal()) @@ -619,6 +648,7 @@ mod test { additional_header_item_count: 1, epoch_length: 0, max_turn_length: 64, + gas_limit_bound_divider: 256, }; match current .boundary_epochs(&fork_spec_after_pascal()) @@ -639,6 +669,7 @@ mod test { additional_header_item_count: 1, epoch_length: 0, max_turn_length: 64, + gas_limit_bound_divider: 256, }; match fork_spec_after_pascal() .boundary_epochs(&previous) @@ -763,12 +794,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(20), additional_header_item_count: 2, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; let v = get_boundary_epochs(&fork_spec_after_pascal(), specs).unwrap_err(); @@ -788,12 +821,14 @@ mod test { additional_header_item_count: 1, epoch_length: 200, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(20), additional_header_item_count: 2, epoch_length: 500, max_turn_length: 9, + gas_limit_bound_divider: 256, }, ]; let v = get_boundary_epochs(&specs[1], specs).unwrap(); diff --git a/light-client/src/header/eth_header.rs b/light-client/src/header/eth_header.rs index 9dc72a6..9fa7419 100644 --- a/light-client/src/header/eth_header.rs +++ b/light-client/src/header/eth_header.rs @@ -28,8 +28,6 @@ const VALIDATOR_NUM_SIZE: usize = 1; const TURN_LENGTH_SIZE: usize = 1; -const PARAMS_GAS_LIMIT_BOUND_DIVISOR: u64 = 256; - const EMPTY_UNCLE_HASH: Hash = hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); const EMPTY_NONCE: [u8; 8] = hex!("0000000000000000"); @@ -177,7 +175,16 @@ impl ETHHeader { } else { self.gas_limit - parent.gas_limit }; - let limit = parent.gas_limit / PARAMS_GAS_LIMIT_BOUND_DIVISOR; + let gas_limit_divider = self + .boundary_epochs + .as_ref() + .ok_or(Error::MissingBoundaryEpochs(self.number))? + .current_fork_spec() + .gas_limit_bound_divider; + if gas_limit_divider == 0 { + return Err(Error::UnexpectedGasLimitDivider(self.number)); + } + let limit = parent.gas_limit / gas_limit_divider; if diff >= limit { return Err(Error::UnexpectedGasDiff(self.number, diff, limit)); } @@ -533,13 +540,13 @@ pub(crate) mod test { use crate::errors::Error; use crate::header::eth_header::{ ETHHeader, DIFFICULTY_INTURN, DIFFICULTY_NOTURN, EXTRA_SEAL, EXTRA_VANITY, - PARAMS_GAS_LIMIT_BOUND_DIVISOR, VALIDATOR_BYTES_LENGTH_BEFORE_LUBAN, + VALIDATOR_BYTES_LENGTH_BEFORE_LUBAN, }; use rlp::RlpStream; use rstest::*; - use crate::fixture::{localnet, Network}; + use crate::fixture::{fork_spec_after_lorentz, fork_spec_after_pascal, localnet, Network}; use crate::header::epoch::Epoch; use crate::fork_spec::{ForkSpec, HeightOrTimestamp}; @@ -775,11 +782,30 @@ pub(crate) mod test { match result.unwrap_err() { Error::UnexpectedGasDiff(number, diff, limit) => { assert_eq!(block.number, number); - assert_eq!(parent.gas_limit / PARAMS_GAS_LIMIT_BOUND_DIVISOR, limit); + assert_eq!( + parent.gas_limit + / block + .boundary_epochs + .unwrap() + .current_fork_spec() + .gas_limit_bound_divider, + limit + ); assert_eq!(parent.gas_limit - block.gas_limit, diff); } err => unreachable!("{:?}", err), } + + let mut current = fork_spec_after_lorentz(); + current.gas_limit_bound_divider = 0; + block.boundary_epochs = Some(current.boundary_epochs(&fork_spec_after_pascal()).unwrap()); + let result = block.verify_cascading_fields(&parent); + match result.unwrap_err() { + Error::UnexpectedGasLimitDivider(number) => { + assert_eq!(block.number, number); + } + err => unreachable!("{:?}", err), + } } #[rstest] @@ -899,6 +925,7 @@ pub(crate) mod test { additional_header_item_count: header.additional_items.len() as u64, epoch_length: 500, max_turn_length: 64, + gas_limit_bound_divider: 1024, }]) .unwrap(); @@ -909,18 +936,21 @@ pub(crate) mod test { additional_header_item_count: header.additional_items.len() as u64, epoch_length: 500, max_turn_length: 64, + gas_limit_bound_divider: 1024, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(header.number), additional_header_item_count: header.additional_items.len() as u64, epoch_length: 500, max_turn_length: 64, + gas_limit_bound_divider: 1024, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(header.number + 1), additional_header_item_count: header.additional_items.len() as u64 + 1, epoch_length: 500, max_turn_length: 64, + gas_limit_bound_divider: 1024, }, ]) .unwrap(); @@ -937,6 +967,7 @@ pub(crate) mod test { additional_header_item_count: header.additional_items.len() as u64 - 1, epoch_length: 500, max_turn_length: 64, + gas_limit_bound_divider: 1024, }]) .unwrap_err(); match err { @@ -951,18 +982,21 @@ pub(crate) mod test { additional_header_item_count: header.additional_items.len() as u64, epoch_length: 500, max_turn_length: 64, + gas_limit_bound_divider: 1024, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(header.number), additional_header_item_count: header.additional_items.len() as u64 - 1, epoch_length: 500, max_turn_length: 64, + gas_limit_bound_divider: 1024, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(header.number + 1), additional_header_item_count: header.additional_items.len() as u64, epoch_length: 500, max_turn_length: 64, + gas_limit_bound_divider: 1024, }, ]) .unwrap_err(); @@ -985,6 +1019,7 @@ pub(crate) mod test { additional_header_item_count: header.additional_items.len() as u64, epoch_length: 500, max_turn_length: turn_length - 1, + gas_limit_bound_divider: 1024, }]) .unwrap_err(); match err { @@ -999,18 +1034,21 @@ pub(crate) mod test { additional_header_item_count: header.additional_items.len() as u64, epoch_length: 500, max_turn_length: turn_length, + gas_limit_bound_divider: 1024, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(header.number), additional_header_item_count: header.additional_items.len() as u64, epoch_length: 500, max_turn_length: turn_length - 1, + gas_limit_bound_divider: 1024, }, ForkSpec { height_or_timestamp: HeightOrTimestamp::Height(header.number + 1), additional_header_item_count: header.additional_items.len() as u64, epoch_length: 500, max_turn_length: turn_length, + gas_limit_bound_divider: 1024, }, ]) .unwrap_err(); diff --git a/light-client/src/header/eth_headers.rs b/light-client/src/header/eth_headers.rs index 7eb9468..3666dd4 100644 --- a/light-client/src/header/eth_headers.rs +++ b/light-client/src/header/eth_headers.rs @@ -922,6 +922,7 @@ mod test { epoch_length: 10, additional_header_item_count: 1, max_turn_length: 64, + gas_limit_bound_divider: 256, }; let invalid_current_fork_spec = ForkSpec { @@ -929,6 +930,7 @@ mod test { epoch_length: 500, additional_header_item_count: 1, max_turn_length: 64, + gas_limit_bound_divider: 1024, }; for _i in 0..1000 { let mut header = headers.all.last().unwrap().clone(); diff --git a/proto/definitions/ibc/lightclients/parlia/v1/parlia.proto b/proto/definitions/ibc/lightclients/parlia/v1/parlia.proto index e67d5e3..c91cfaa 100644 --- a/proto/definitions/ibc/lightclients/parlia/v1/parlia.proto +++ b/proto/definitions/ibc/lightclients/parlia/v1/parlia.proto @@ -15,6 +15,7 @@ message ForkSpec { uint64 additional_header_item_count = 3; uint64 epoch_length = 4; uint64 max_turn_length = 5; + uint64 gas_limit_bound_divider = 6; } message ClientState { diff --git a/proto/src/prost/ibc.lightclients.parlia.v1.rs b/proto/src/prost/ibc.lightclients.parlia.v1.rs index 62af31a..d557b6d 100644 --- a/proto/src/prost/ibc.lightclients.parlia.v1.rs +++ b/proto/src/prost/ibc.lightclients.parlia.v1.rs @@ -7,6 +7,8 @@ pub struct ForkSpec { pub epoch_length: u64, #[prost(uint64, tag = "5")] pub max_turn_length: u64, + #[prost(uint64, tag = "6")] + pub gas_limit_bound_divider: u64, #[prost(oneof = "fork_spec::HeightOrTimestamp", tags = "1, 2")] pub height_or_timestamp: ::core::option::Option, }