diff --git a/core/src/client/client.rs b/core/src/client/client.rs index 29a24c92fd..c5dbf07bdb 100644 --- a/core/src/client/client.rs +++ b/core/src/client/client.rs @@ -780,11 +780,19 @@ impl TermInfo for Client { } fn term_common_params(&self, id: BlockId) -> Option { - let block_number = self.last_term_finished_block_num(id).expect("The block of the parent hash should exist"); - if block_number == 0 { - None + let state = self.state_at(id)?; + let metadata = state.metadata().unwrap().expect("Metadata always exist"); + + if let Some(term_params) = metadata.term_params() { + Some(*term_params) } else { - Some(self.common_params((block_number).into()).expect("Common params should exist")) + let block_number = + self.last_term_finished_block_num(id).expect("The block of the parent hash should exist"); + if block_number == 0 { + None + } else { + Some(self.common_params((block_number).into()).expect("Common params should exist")) + } } } } diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index a1d0566834..6276b90348 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -24,7 +24,7 @@ use std::sync::{Arc, Weak}; use ckey::{public_to_address, Address}; use cnetwork::NetworkService; use crossbeam_channel as crossbeam; -use cstate::{ActionHandler, TopStateView}; +use cstate::{ActionHandler, TopState, TopStateView}; use ctypes::{BlockHash, CommonParams, Header}; use num_rational::Ratio; @@ -232,6 +232,7 @@ impl ConsensusEngine for Tendermint { stake::on_term_close(block.state_mut(), block_number, &inactive_validators)?; + block.state_mut().update_term_params()?; Ok(()) } diff --git a/state/src/impls/top_level.rs b/state/src/impls/top_level.rs index 2ecfb32209..f726f606ea 100644 --- a/state/src/impls/top_level.rs +++ b/state/src/impls/top_level.rs @@ -999,6 +999,12 @@ impl TopState for TopLevelState { metadata.increase_seq(); Ok(()) } + + fn update_term_params(&mut self) -> StateResult<()> { + let mut metadata = self.get_metadata_mut()?; + metadata.update_term_params(); + Ok(()) + } } fn is_active_account(state: &dyn TopStateView, address: &Address) -> TrieResult { diff --git a/state/src/item/metadata.rs b/state/src/item/metadata.rs index 41db37278b..c6f1123028 100644 --- a/state/src/item/metadata.rs +++ b/state/src/item/metadata.rs @@ -34,6 +34,7 @@ pub struct Metadata { term: TermMetadata, seq: u64, params: Option, + term_params: Option, } impl Metadata { @@ -45,6 +46,7 @@ impl Metadata { term: Default::default(), seq: 0, params: None, + term_params: None, } } @@ -93,6 +95,14 @@ impl Metadata { self.params = Some(params); } + pub fn term_params(&self) -> Option<&CommonParams> { + self.term_params.as_ref() + } + + pub fn update_term_params(&mut self) { + self.term_params = self.params; + } + pub fn increase_term_id(&mut self, last_term_finished_block_num: u64) { assert!(self.term.last_term_finished_block_num < last_term_finished_block_num); self.term.last_term_finished_block_num = last_term_finished_block_num; @@ -124,25 +134,31 @@ impl CacheableItem for Metadata { const PREFIX: u8 = super::METADATA_PREFIX; +const INITIAL_LEN: usize = 4; +const TERM_LEN: usize = INITIAL_LEN + 2; +const PARAMS_LEN: usize = TERM_LEN + 2; +const TERM_PARAMS_LEN: usize = PARAMS_LEN + 1; +const VALID_LEN: &[usize] = &[INITIAL_LEN, TERM_LEN, PARAMS_LEN, TERM_PARAMS_LEN]; + impl Encodable for Metadata { fn rlp_append(&self, s: &mut RlpStream) { - const INITIAL_LEN: usize = 4; - const TERM_LEN: usize = 2; - const PARAMS_LEN: usize = 2; - let mut len = INITIAL_LEN; - let term_changed = self.term != Default::default(); - if term_changed { - len += TERM_LEN; - } - let params_changed = self.seq != 0; - if params_changed { - if !term_changed { - len += TERM_LEN; + let term_params_exist = self.term_params.is_some(); + + let len = if term_params_exist { + if !params_changed { + panic!("Term params only can be changed if params changed"); } - len += PARAMS_LEN; - } + TERM_PARAMS_LEN + } else if params_changed { + PARAMS_LEN + } else if term_changed { + TERM_LEN + } else { + INITIAL_LEN + }; + s.begin_list(len) .append(&PREFIX) .append(&self.number_of_shards) @@ -159,48 +175,63 @@ impl Encodable for Metadata { } s.append(&self.seq).append(self.params.as_ref().unwrap()); } + if term_params_exist { + if !params_changed { + unreachable!("Term params only can be changed if params changed"); + } + s.append(self.term_params.as_ref().unwrap()); + } } } impl Decodable for Metadata { fn decode(rlp: &Rlp<'_>) -> Result { - let (term, seq, params) = match rlp.item_count()? { - 4 => (TermMetadata::default(), 0, None), - 6 => ( - TermMetadata { - last_term_finished_block_num: rlp.val_at(4)?, - current_term_id: rlp.val_at(5)?, - }, - 0, - None, - ), - 8 => ( - TermMetadata { - last_term_finished_block_num: rlp.val_at(4)?, - current_term_id: rlp.val_at(5)?, - }, - rlp.val_at(6)?, - Some(rlp.val_at(7)?), - ), - item_count => { - return Err(DecoderError::RlpInvalidLength { - got: item_count, - expected: 4, - }) - } - }; + let item_count = rlp.item_count()?; + if !VALID_LEN.contains(&item_count) { + return Err(DecoderError::RlpInvalidLength { + got: item_count, + expected: 4, + }) + } + let prefix = rlp.val_at::(0)?; if PREFIX != prefix { cdebug!(STATE, "{} is not an expected prefix for asset", prefix); return Err(DecoderError::Custom("Unexpected prefix")) } + let number_of_shards = rlp.val_at(1)?; + let number_of_initial_shards = rlp.val_at(2)?; + let hashes = rlp.list_at(3)?; + + let term = if item_count >= TERM_LEN { + TermMetadata { + last_term_finished_block_num: rlp.val_at(4)?, + current_term_id: rlp.val_at(5)?, + } + } else { + TermMetadata::default() + }; + + let (seq, params) = if item_count >= PARAMS_LEN { + (rlp.val_at(6)?, Some(rlp.val_at(7)?)) + } else { + Default::default() + }; + + let term_params = if item_count >= TERM_PARAMS_LEN { + Some(rlp.val_at(8)?) + } else { + Default::default() + }; + Ok(Self { - number_of_shards: rlp.val_at(1)?, - number_of_initial_shards: rlp.val_at(2)?, - hashes: rlp.list_at(3)?, + number_of_shards, + number_of_initial_shards, + hashes, term, seq, params, + term_params, }) } } @@ -266,6 +297,7 @@ mod tests { term: Default::default(), seq: 0, params: None, + term_params: None, }; let mut rlp = RlpStream::new_list(4); rlp.append(&PREFIX).append(&10u16).append(&1u16).append_list::(&[]); @@ -281,6 +313,7 @@ mod tests { term: Default::default(), seq: 3, params: Some(CommonParams::default_for_test()), + term_params: Some(CommonParams::default_for_test()), }; rlp_encode_and_decode_test!(metadata); } @@ -297,6 +330,7 @@ mod tests { }, seq: 0, params: None, + term_params: None, }; rlp_encode_and_decode_test!(metadata); } @@ -313,6 +347,7 @@ mod tests { }, seq: 3, params: Some(CommonParams::default_for_test()), + term_params: Some(CommonParams::default_for_test()), }; rlp_encode_and_decode_test!(metadata); } diff --git a/state/src/traits.rs b/state/src/traits.rs index 40d94688f7..f56ef405d1 100644 --- a/state/src/traits.rs +++ b/state/src/traits.rs @@ -183,6 +183,7 @@ pub trait TopState { fn remove_action_data(&mut self, key: &H256); fn update_params(&mut self, metadata_seq: u64, params: CommonParams) -> StateResult<()>; + fn update_term_params(&mut self) -> StateResult<()>; } pub trait StateWithCache {