Skip to content

Commit

Permalink
Merge branch 'master' into v2.0-testnet
Browse files Browse the repository at this point in the history
  • Loading branch information
peilun-conflux committed Oct 31, 2024
2 parents 22f63e3 + 6d5cca1 commit 5f8bbe4
Show file tree
Hide file tree
Showing 15 changed files with 656 additions and 16 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions bins/conflux/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ hex = "0.3.0"
base64ct = "=1.1.1"
parity-version = { workspace = true }
tokio = { version = "1", features = ["rt"] }
bls-signatures = { workspace = true }

[target.'cfg(not(target_env = "msvc"))'.dependencies.jemallocator]
version = "0.3.2"
Expand All @@ -85,3 +86,7 @@ default = ["jemalloc-global"]
deadlock-detection = ["parking_lot/deadlock_detection"]
jemalloc-global = ["jemallocator", "malloc_size_of/jemalloc-global"]
u64-mpt-db-key = ["client/u64_mpt_db_key"]
# According to Rust's feature unification, when a feature is enabled for a dependency in the root package,
# it will be enabled across all paths depending on that package.
# (https://doc.rust-lang.org/cargo/reference/features.html#feature-unification)
blst-portable = ["bls-signatures/blst-portable"]
1 change: 1 addition & 0 deletions crates/cfxcore/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ prometheus = { version = "0.7.0", default-features = false }
rand = { workspace = true }
rand_08 = {package = "rand", version = "0.8"}
rand_xorshift="0.2"
rangetools = "0.1.4"
random-crash = { workspace = true }
rayon = { workspace = true }
rlp = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{
consensus_executor::{ConsensusExecutor, EpochExecutionTask},
ConsensusGraphInner, NULL,
},
pivot_hint::PivotHint,
pos_handler::PosVerifier,
ConsensusConfig,
},
Expand Down Expand Up @@ -49,6 +50,8 @@ pub struct ConsensusNewBlockHandler {

/// The type of this node: Archive, Full, or Light.
node_type: NodeType,

pivot_hint: Option<Arc<PivotHint>>,
}

/// ConsensusNewBlockHandler contains all sub-routines for handling new arriving
Expand All @@ -60,6 +63,7 @@ impl ConsensusNewBlockHandler {
data_man: Arc<BlockDataManager>, executor: Arc<ConsensusExecutor>,
statistics: SharedStatistics, notifications: Arc<Notifications>,
node_type: NodeType, pos_verifier: Arc<PosVerifier>,
pivot_hint: Option<Arc<PivotHint>>,
) -> Self {
let epochs_sender = notifications.epochs_ordered.clone();
let blame_verifier =
Expand All @@ -75,6 +79,7 @@ impl ConsensusNewBlockHandler {
epochs_sender,
blame_verifier,
node_type,
pivot_hint,
}
}

Expand Down Expand Up @@ -1127,8 +1132,8 @@ impl ConsensusNewBlockHandler {
return;
} else {
debug!(
"Start activating block in ConsensusGraph: index = {:?} hash={:?}",
me, inner.arena[me].hash,
"Start activating block in ConsensusGraph: index = {:?} hash={:?} height={:?}",
me, inner.arena[me].hash, inner.arena[me].height,
);
}

Expand Down Expand Up @@ -1221,19 +1226,39 @@ impl ConsensusNewBlockHandler {
let force_lca = inner.lca(force_confirm, last);

if force_lca == force_confirm && inner.arena[me].parent == last {
inner.pivot_chain.push(me);
inner.set_epoch_number_in_epoch(
me,
inner.pivot_index_to_height(inner.pivot_chain.len()) - 1,
);
inner.pivot_chain_metadata.push(Default::default());
extend_pivot = true;
pivot_changed = true;
fork_at = inner.pivot_index_to_height(old_pivot_chain_len)
let me_height = inner.arena[me].height;
let me_hash = inner.arena[me].hash;
let allow_extend = self
.pivot_hint
.as_ref()
.map_or(true, |hint| hint.allow_extend(me_height, me_hash));
if allow_extend {
inner.pivot_chain.push(me);
inner.set_epoch_number_in_epoch(
me,
inner.pivot_index_to_height(inner.pivot_chain.len()) - 1,
);
inner.pivot_chain_metadata.push(Default::default());
extend_pivot = true;
pivot_changed = true;
fork_at = inner.pivot_index_to_height(old_pivot_chain_len);
} else {
debug!("Chain extend rejected by pivot hint: height={me_height}, hash={me_hash:?}");
fork_at = inner.pivot_index_to_height(old_pivot_chain_len);
}
} else {
let lca = inner.lca(last, me);
let new;
if force_confirm != force_lca {
if self.pivot_hint.is_some() && lca == last {
// If pivot hint is enabled, `me` could be an extend of the
// pivot chain, but its parent block is not on the pivot chain.
// This special case can only happen
debug!("Chain extend rejected by pivot hint because parent is rejected.");
fork_at = inner.pivot_index_to_height(old_pivot_chain_len);
// In this case, `pivot_changed` is false. So `new` can be
// aribitrary value.
new = 0;
} else if force_confirm != force_lca {
debug!(
"pivot chain switch to force_confirm={} force_height={}",
force_confirm, force_height
Expand All @@ -1248,6 +1273,10 @@ impl ConsensusNewBlockHandler {
new = inner.ancestor_at(me, fork_at);
let new_weight = inner.weight_tree.get(new);

let me_height = inner.arena[me].height;
let me_ancestor_hash_at =
|height| inner.arena[inner.ancestor_at(me, height)].hash;

// Note that for properly set consensus parameters, fork_at will
// always after the force_height (i.e., the
// force confirmation is always stable).
Expand All @@ -1259,6 +1288,13 @@ impl ConsensusNewBlockHandler {
(new_weight, &inner.arena[new].hash),
(prev_weight, &inner.arena[prev].hash),
)
&& self.pivot_hint.as_ref().map_or(true, |hint| {
hint.allow_switch(
fork_at,
me_height,
me_ancestor_hash_at,
)
})
{
pivot_changed = true;
} else {
Expand Down
14 changes: 12 additions & 2 deletions crates/cfxcore/core/src/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ pub mod consensus_inner;
pub mod consensus_trait;
pub mod debug_recompute;
mod pastset_cache;
pub mod pivot_hint;
pub mod pos_handler;

use self::pivot_hint::{PivotHint, PivotHintConfig};

use super::consensus::consensus_inner::{
confirmation_meter::ConfirmationMeter,
consensus_executor::ConsensusExecutor,
Expand Down Expand Up @@ -152,6 +155,9 @@ pub struct ConsensusConfig {
/// The number of extra epochs that we want to keep
/// states/receipts/transactions.
pub sync_state_epoch_gap: Option<u64>,

/// The file path and checksum for `PivotHint`
pub pivot_hint_conf: Option<PivotHintConfig>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -250,7 +256,8 @@ impl ConsensusGraph {
notifications: Arc<Notifications>,
execution_conf: ConsensusExecutionConfiguration,
verification_config: VerificationConfig, node_type: NodeType,
pos_verifier: Arc<PosVerifier>, params: CommonParams,
pos_verifier: Arc<PosVerifier>, pivot_hint: Option<Arc<PivotHint>>,
params: CommonParams,
) -> Self {
let inner =
Arc::new(RwLock::new(ConsensusGraphInner::with_era_genesis(
Expand Down Expand Up @@ -288,6 +295,7 @@ impl ConsensusGraph {
notifications,
node_type,
pos_verifier,
pivot_hint,
),
confirmation_meter,
best_info: RwLock::new(Arc::new(Default::default())),
Expand Down Expand Up @@ -315,7 +323,8 @@ impl ConsensusGraph {
notifications: Arc<Notifications>,
execution_conf: ConsensusExecutionConfiguration,
verification_conf: VerificationConfig, node_type: NodeType,
pos_verifier: Arc<PosVerifier>, params: CommonParams,
pos_verifier: Arc<PosVerifier>, pivot_hint: Option<Arc<PivotHint>>,
params: CommonParams,
) -> Self {
let genesis_hash = data_man.get_cur_consensus_era_genesis_hash();
let stable_hash = data_man.get_cur_consensus_era_stable_hash();
Expand All @@ -333,6 +342,7 @@ impl ConsensusGraph {
verification_conf,
node_type,
pos_verifier,
pivot_hint,
params,
)
}
Expand Down
20 changes: 20 additions & 0 deletions crates/cfxcore/core/src/consensus/pivot_hint/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use hash::H256;

/// Configuration for initializing PivotHint.
#[derive(Clone)]
pub struct PivotHintConfig {
/// Path to the pivot hint file
pub file_path: String,

/// Expected keccak hash of the Page Digests Part
pub checksum: H256,
}

impl PivotHintConfig {
pub fn new(file_path: &str, checksum: H256) -> Self {
Self {
file_path: file_path.to_string(),
checksum,
}
}
}
125 changes: 125 additions & 0 deletions crates/cfxcore/core/src/consensus/pivot_hint/header.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use rangetools::Rangetools;
use std::io::Read;

pub const HEADER_LENGTH: usize = 28;

#[derive(Clone, Copy, Debug)]
pub(super) struct PivotHintHeader {
pub minor_interval: u64,
pub major_interval: u64,
pub page_interval: u64,
pub range_max: u64,
pub minor_hash_length: usize,
}

fn read_u32(mut reader: impl Read) -> Result<u32, String> {
let mut raw = [0u8; 4];
reader
.read_exact(&mut raw)
.map_err(|e| format!("Cannot load number {:?}", e))?;
Ok(u32::from_le_bytes(raw))
}

fn read_u64(mut reader: impl Read) -> Result<u64, String> {
let mut raw = [0u8; 8];
reader
.read_exact(&mut raw)
.map_err(|e| format!("Cannot load number {:?}", e))?;
Ok(u64::from_le_bytes(raw))
}

impl PivotHintHeader {
pub fn from_raw(raw_header: [u8; HEADER_LENGTH]) -> Result<Self, String> {
let mut reader = &raw_header[..];

let minor_interval = read_u32(&mut reader).unwrap() as u64;
let major_interval = read_u32(&mut reader).unwrap() as u64;
let page_interval = read_u32(&mut reader).unwrap() as u64;
let range_max = read_u64(&mut reader).unwrap();
let minor_hash_length = read_u32(&mut reader).unwrap() as usize;

if major_interval % minor_interval != 0 {
return Err("Inconsistent header params: major_interval".into());
}

if page_interval % major_interval != 0 {
return Err("Inconsistent header params: page_interval".into());
}

if range_max % page_interval != 0 {
return Err("Inconsistent header params: range_max".into());
}

let header = PivotHintHeader {
major_interval,
minor_interval,
minor_hash_length,
range_max,
page_interval,
};

let page_bytes = read_u32(&mut reader).unwrap() as usize;
if header.page_bytes() != page_bytes {
return Err("Inconsistent page bytes".into());
}
assert!(reader.is_empty());

Ok(header)
}

pub fn major_section_bytes(&self) -> usize {
(32 * (self.page_interval / self.major_interval)) as usize
}

pub fn minor_section_bytes(&self) -> usize {
self.minor_hash_length
* (self.page_interval / self.minor_interval) as usize
}

pub fn page_bytes(&self) -> usize {
self.major_section_bytes() + self.minor_section_bytes()
}

pub fn page_number(&self) -> usize {
(self.range_max / self.page_interval) as usize
}

pub fn compute_check_height(
&self, fork_at: u64, me_height: u64,
) -> Option<u64> {
let major_ticks = ((fork_at - 1) / self.major_interval + 1)
..=(me_height / self.major_interval);
let availd_major_ticks = 0..(self.range_max / self.major_interval);
let last_valid_major_tick = major_ticks
.intersection(availd_major_ticks)
.into_iter()
.next_back();
let major_height =
last_valid_major_tick.map(|x| x * self.major_interval);

if cfg!(test) {
assert!(major_height.map_or(true, |h| h >= fork_at
&& h <= me_height
&& h % self.major_interval == 0
&& h < self.range_max));
}

let minor_ticks = ((fork_at - 1) / self.minor_interval + 1)
..=(me_height / self.minor_interval);
let availd_minor_ticks = 0..(self.range_max / self.minor_interval);
let last_valid_minor_tick = minor_ticks
.intersection(availd_minor_ticks)
.into_iter()
.next_back();
let minor_height =
last_valid_minor_tick.map(|x| x * self.minor_interval);
if cfg!(test) {
assert!(minor_height.map_or(true, |h| h >= fork_at
&& h <= me_height
&& h % self.minor_interval == 0
&& h < self.range_max));
}

major_height.or(minor_height)
}
}
Loading

0 comments on commit 5f8bbe4

Please sign in to comment.