diff --git a/src/consensus/parlia/consensus.rs b/src/consensus/parlia/consensus.rs index efed86d2..d4d8ab6b 100644 --- a/src/consensus/parlia/consensus.rs +++ b/src/consensus/parlia/consensus.rs @@ -31,8 +31,6 @@ use super::{ }; use crate::consensus::parlia::go_rng::{RngSource, Shuffle}; use tracing::{trace, debug, warn}; -use crate::consensus::parlia::constants::K_ANCESTOR_GENERATION_DEPTH; -use crate::consensus::parlia::provider::SnapshotProvider; const RECOVERED_PROPOSER_CACHE_NUM: usize = 4096; const ADDRESS_LENGTH: usize = 20; // Ethereum address length in bytes @@ -535,7 +533,7 @@ where ChainSpec: EthChainSpec + BscHardforks + 'static, let mut time_for_mining_ms = period_ms / 2; let last_block_in_turn = snap.last_block_in_one_turn(header.number); if !last_block_in_turn { - time_for_mining_ms = period_ms; + time_for_mining_ms = period_ms * 4 / 5; } if delay_ms > time_for_mining_ms { delay_ms = time_for_mining_ms; @@ -632,56 +630,27 @@ where ChainSpec: EthChainSpec + BscHardforks + 'static, SYSTEM_TXS_GAS_HARD_LIMIT } - pub fn assemble_vote_attestation(&self, parent_snap: &Snapshot, parent_header: &Header, current_header: &mut Header, snapshot_provider: &Arc) -> Result<(), ParliaConsensusError> { - if !self.spec.is_luban_active_at_block(current_header.number()) || current_header.number() < 3 { + pub fn assemble_vote_attestation(&self, parent_snap: &Snapshot, parent_header: &Header, current_header: &mut Header) -> Result<(), ParliaConsensusError> { + if !self.spec.is_luban_active_at_block(current_header.number()) || current_header.number() < 2 { return Ok(()); } - // get justified number and hash from parent snapshot - let (justified_number, justified_hash) = (parent_snap.vote_data.target_number, parent_snap.vote_data.target_hash); - let mut times = 1; - if self.spec.is_fermi_active_at_timestamp(current_header.number(), current_header.timestamp()) { - times = K_ANCESTOR_GENERATION_DEPTH; - } - let mut votes = Vec::new(); - let mut target_header = parent_header.clone(); - let mut target_header_parent_snap = None; - for _ in 0..times { - let snap = snapshot_provider.snapshot_by_hash(&target_header.parent_hash()). - ok_or(ParliaConsensusError::SnapshotNotFound { - block_hash: target_header.parent_hash(), - })?; - votes = fetch_vote_by_block_hash(target_header.hash_slow()); - let quorum = usize::div_ceil(snap.validators.len() * 2, 3); - if votes.len() >= quorum { - target_header_parent_snap = Some(snap); - break; - } + let votes = fetch_vote_by_block_hash(current_header.parent_hash()); + if votes.len() < usize::div_ceil(parent_snap.validators.len() * 2, 3) { tracing::debug!(target: "parlia::consensus", "vote count is less than 2/3 of validators, skip assemble vote attestation, number={}, parent ={:?}, vote count={}, validators count={}", - target_header.number(), target_header.hash_slow(), votes.len(), parent_snap.validators.len()); - let block_hash = target_header.parent_hash(); - if let Some(header) = crate::shared::get_canonical_header_by_hash_from_provider(&block_hash) { - target_header = header; - } else { - return Err(ParliaConsensusError::HeaderNotFound { - block_hash, - }); - } - if target_header.number() <= justified_number { - break; - } - } - if target_header_parent_snap.is_none() { - tracing::warn!(target: "parlia::consensus", "cannot collect enough votes, current_block={}, target_header_number={}, justified_number={}", - current_header.number(), target_header.number(), justified_number); + current_header.number(), current_header.parent_hash(), votes.len(), parent_snap.validators.len()); return Ok(()); } + tracing::debug!(target: "parlia::consensus", "assemble vote attestation, number={}, parent ={:?}, vote count={}, validators count={}", + current_header.number(), current_header.parent_hash(), votes.len(), parent_snap.validators.len()); + // get justified number and hash from parent snapshot + let (justified_number, justified_hash) = (parent_snap.vote_data.target_number, parent_snap.vote_data.target_hash); let mut attestation = VoteAttestation::new_with_vote_data(VoteData { source_number: justified_number, source_hash: justified_hash, - target_number: target_header.number(), - target_hash: target_header.hash_slow(), + target_number: parent_header.number, + target_hash: parent_header.hash_slow(), }); // Check vote data from votes for vote in votes.iter() { diff --git a/src/consensus/parlia/constants.rs b/src/consensus/parlia/constants.rs index 26e71553..df4fa21d 100644 --- a/src/consensus/parlia/constants.rs +++ b/src/consensus/parlia/constants.rs @@ -32,8 +32,7 @@ pub const SYSTEM_TXS_GAS_SOFT_LIMIT: u64 = 1_000_000; // Maximum gas reserved fo // Ramanujan HF constants pub const FIXED_BACKOFF_TIME_BEFORE_FORK_MILLIS: u64 = 200; // 200 ms pub const WIGGLE_TIME_BEFORE_FORK_MILLIS: u64 = 500; // 500 ms -pub const MILLISECONDS_UNIT: u64 = 50; // 50 ms -pub const K_ANCESTOR_GENERATION_DEPTH: u64 = 3; +pub const MILLISECONDS_UNIT: u64 = 250; // 250 ms // miner config default values pub const DEFAULT_MIN_GAS_TIP: u128 = 50_000_000; // 0.05 Gwei diff --git a/src/consensus/parlia/error.rs b/src/consensus/parlia/error.rs index 3ba11eda..2985f5a2 100644 --- a/src/consensus/parlia/error.rs +++ b/src/consensus/parlia/error.rs @@ -2,7 +2,6 @@ use alloy_primitives::{BlockHash, BlockNumber}; use crate::consensus::parlia::VoteAddress; - /// Parlia consensus error. #[derive(thiserror::Error, Debug, PartialEq, Eq, Clone)] pub enum ParliaConsensusError { @@ -34,20 +33,6 @@ pub enum ParliaConsensusError { #[error("invalid header extra")] InvalidHeaderExtra, - /// Error for invalid header extra - #[error("header not found: {block_hash}")] - HeaderNotFound { - /// The block hash - block_hash: BlockHash, - }, - - /// Error when the snapshot is not found - #[error("snapshot not found: {block_hash}")] - SnapshotNotFound { - /// The block hash - block_hash: BlockHash, - }, - /// Error when the header is not in epoch #[error("{block_number} is not in epoch")] NotInEpoch { diff --git a/src/hardforks/mod.rs b/src/hardforks/mod.rs index 6cc6c4af..3c29d4c2 100644 --- a/src/hardforks/mod.rs +++ b/src/hardforks/mod.rs @@ -256,7 +256,7 @@ pub trait BscHardforks: EthereumHardforks { self.bsc_fork_activation(BscHardfork::Maxwell).active_at_timestamp(timestamp) } - /// Convenience method to check if [`BscHardfork::Fermi`] is active at a given timestamp. + /// Convenience method to check if [`BscHardfork::Maxwell`] is active at a given timestamp. fn is_fermi_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { self.is_london_active_at_block(block_number) && self.bsc_fork_activation(BscHardfork::Fermi).active_at_timestamp(timestamp) diff --git a/src/node/evm/assembler.rs b/src/node/evm/assembler.rs index 65d0ddd4..897dd0dc 100644 --- a/src/node/evm/assembler.rs +++ b/src/node/evm/assembler.rs @@ -168,8 +168,7 @@ where self.parlia.clone(), &parent_snap, &parent_header, - &mut header, - &snapshot_provider, + &mut header ).map_err(|e| BlockExecutionError::msg(format!("Failed to finalize header: {}", e)))?; let header_hash = keccak256(alloy_rlp::encode(&header)); @@ -292,8 +291,7 @@ where self.parlia.clone(), &parent_snap, &parent_header, - &mut header, - &snapshot_provider, + &mut header ).map_err(|e| BlockExecutionError::msg(format!("Failed to finalize header: {}", e)))?; let header_hash = keccak256(alloy_rlp::encode(&header)); diff --git a/src/node/evm/pre_execution.rs b/src/node/evm/pre_execution.rs index 9357e686..27c1d00e 100644 --- a/src/node/evm/pre_execution.rs +++ b/src/node/evm/pre_execution.rs @@ -25,10 +25,11 @@ use blst::{ BLST_ERROR, }; use bit_set::BitSet; -use crate::consensus::parlia::constants::K_ANCESTOR_GENERATION_DEPTH; const BLST_DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; +const K_ANCESTOR_GENERATION_DEPTH: u64 = 3; + type ValidatorCache = LruMap, Vec), ByLength>; type TurnLengthCache = LruMap; @@ -277,12 +278,7 @@ where let target_hash = attestation.data.target_hash; let mut is_match = false; let mut ancestor = parent.clone(); - let depth = if self.spec.is_fermi_active_at_timestamp(header.number(), header.timestamp) { - K_ANCESTOR_GENERATION_DEPTH - } else { - 1 - }; - for _ in 0..depth { + for _ in 0..self.get_ancestor_generation_depth(header) { if ancestor.number() == target_block && ancestor.hash_slow() == target_hash { is_match = true; break; @@ -298,8 +294,8 @@ where if !is_match { return Err(BscBlockExecutionError::Validation( BscBlockValidationError::InvalidAttestationTarget { - block_number: GotExpected { got: target_block, expected: ancestor.number() }, - block_hash: GotExpected { got: target_hash, expected: ancestor.hash_slow() } + block_number: GotExpected { got: target_block, expected: parent.number() }, + block_hash: GotExpected { got: target_hash, expected: parent.hash_slow() } .into(), } ).into()); @@ -390,6 +386,14 @@ where Ok(()) } + + fn get_ancestor_generation_depth(&self, header: &Header) -> u64 { + if self.spec.is_fermi_active_at_timestamp(header.number(),header.timestamp) { + return K_ANCESTOR_GENERATION_DEPTH; + } + 1 + } + fn verify_seal( &self, diff --git a/src/node/miner/util.rs b/src/node/miner/util.rs index 5729f4ee..ae34ea2d 100644 --- a/src/node/miner/util.rs +++ b/src/node/miner/util.rs @@ -10,9 +10,8 @@ use reth::payload::EthPayloadBuilderAttributes; use crate::hardforks::BscHardforks; use reth_chainspec::EthChainSpec; use crate::node::evm::pre_execution::VALIDATOR_CACHE; -use crate::node::miner::signer::{SignerError, seal_header_with_global_signer}; +use crate::node::miner::signer::{seal_header_with_global_signer, SignerError}; use crate::node::miner::bsc_miner::MiningContext; -use crate::consensus::parlia::provider::SnapshotProvider; pub fn prepare_new_attributes(ctx: &mut MiningContext, parlia: Arc>, parent_header: &Header, signer: Address) -> EthPayloadBuilderAttributes { let mut new_header = prepare_new_header(parlia.clone(), parent_header, signer); @@ -62,9 +61,7 @@ pub fn finalize_new_header( parlia: Arc>, parent_snap: &Snapshot, parent_header: &Header, - new_header: &mut Header, - snapshot_provider: &Arc, -) -> Result<(), crate::node::miner::signer::SignerError> + new_header: &mut Header) -> Result<(), crate::node::miner::signer::SignerError> where ChainSpec: EthChainSpec + crate::hardforks::BscHardforks + 'static, { @@ -100,8 +97,16 @@ where parlia.prepare_turn_length(parent_snap, new_header). map_err(|e| SignerError::SigningFailed(format!("Failed to prepare turn length: {}", e)))?; - parlia.assemble_vote_attestation(parent_snap, parent_header, new_header, snapshot_provider). - map_err(|e| SignerError::SigningFailed(format!("Failed to assemble vote attestation: {}", e)))?; + // TODO: add BEP-590 changes in fermi hardfork later, it changes the assemble and verify logic. + if let Err(e) = parlia.assemble_vote_attestation(parent_snap, parent_header, new_header) { + tracing::warn!( + target: "parlia::assemble_vote_attestation", + block_number = new_header.number, + parent_hash = ?new_header.parent_hash, + error = ?e, + "Failed to assemble vote attestation, skipping" + ); + } { // seal header let mut extra_data = new_header.extra_data.to_vec(); diff --git a/src/node/vote_producer.rs b/src/node/vote_producer.rs index 00f9a855..50fdc08f 100644 --- a/src/node/vote_producer.rs +++ b/src/node/vote_producer.rs @@ -10,7 +10,6 @@ use crate::hardforks::BscHardforks; use crate::consensus::parlia::util::calculate_millisecond_timestamp; use crate::node::evm::util::get_cannonical_header_from_cache; use crate::node::vote_journal; -use crate::consensus::parlia::constants::K_ANCESTOR_GENERATION_DEPTH; /// Number of blocks to wait after mining becomes enabled before producing votes. /// This mirrors geth's VoteManager warm-up (blocksNumberSinceMining = 40) to avoid @@ -160,12 +159,7 @@ pub fn maybe_produce_and_broadcast_for_head( // Too-late-to-vote guard: ensure we have time to broadcast before next block assembly let cur_ms = calculate_millisecond_timestamp(head); - let count = if chain_spec.is_fermi_active_at_timestamp(head.number(), head.timestamp()) { - K_ANCESTOR_GENERATION_DEPTH - } else { - 1 - }; - let vote_assemble_ms = cur_ms.saturating_add(snap.block_interval * count); + let vote_assemble_ms = cur_ms.saturating_add(snap.block_interval); let now_ms = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .map(|d| d.as_millis() as u64) @@ -225,4 +219,4 @@ pub fn maybe_produce_and_broadcast_for_head( tracing::warn!(target: "bsc::vote", error=%e, "Failed to sign vote"); } } -} \ No newline at end of file +}