diff --git a/src/blockchain/mod.rs b/src/blockchain/mod.rs index e74321b89..27a400904 100644 --- a/src/blockchain/mod.rs +++ b/src/blockchain/mod.rs @@ -193,11 +193,11 @@ impl Blockchain { } /// Retrieve last finalized block slot offset - pub fn get_last_offset(&self) -> Result { - let (_, hash) = self.last().unwrap(); + pub fn get_last_offset(&self) -> Result<(u64, u64)> { + let (slot, hash) = self.last().unwrap(); let blocks = self.blocks.get(&[hash], true)?; // Since we used strict get, its safe to unwrap here let block = blocks[0].clone().unwrap(); - Ok(block.lead_info.offset) + Ok((slot, block.lead_info.offset)) } } diff --git a/src/consensus/constants.rs b/src/consensus/constants.rs index c2696e496..12ec29ba9 100644 --- a/src/consensus/constants.rs +++ b/src/consensus/constants.rs @@ -64,6 +64,9 @@ pub const EPOCH_LENGTH: usize = 10; /// Slot time in seconds pub const SLOT_TIME: u64 = 20; +/// Finalization sync period duration (should be >=1/4 of slot time) +pub const FINAL_SYNC_DUR: u64 = 5; + /// Block leader reward pub const REWARD: u64 = 420; diff --git a/src/consensus/proto/protocol_proposal.rs b/src/consensus/proto/protocol_proposal.rs index 13f2c4924..181be839b 100644 --- a/src/consensus/proto/protocol_proposal.rs +++ b/src/consensus/proto/protocol_proposal.rs @@ -18,7 +18,7 @@ use async_std::sync::Arc; use async_trait::async_trait; -use log::{debug, error, info}; +use log::{debug, error, trace}; use smol::Executor; use url::Url; @@ -75,8 +75,8 @@ impl ProtocolProposal { } }; - info!("ProtocolProposal::handle_receive_proposal(): recv: {}", proposal); - debug!("ProtocolProposal::handle_receive_proposal(): Full proposal: {:?}", proposal); + debug!("ProtocolProposal::handle_receive_proposal(): recv: {}", proposal); + trace!("ProtocolProposal::handle_receive_proposal(): Full proposal: {:?}", proposal); let proposal_copy = (*proposal).clone(); diff --git a/src/consensus/state.rs b/src/consensus/state.rs index 00740545d..4ce1603a1 100644 --- a/src/consensus/state.rs +++ b/src/consensus/state.rs @@ -432,9 +432,9 @@ impl ValidatorState { // Generate sigmas let mut total_stake = self.total_stake(); // Only used for fine-tuning - // at genesis epoch first slot, of absolute index 0, - // the total stake would be 0, to avoid division by zero, - // we asume total stake at first division is GENESIS_TOTAL_STAKE. + // at genesis epoch first slot, of absolute index 0, + // the total stake would be 0, to avoid division by zero, + // we asume total stake at first division is GENESIS_TOTAL_STAKE. if total_stake == 0 { total_stake = constants::GENESIS_TOTAL_STAKE; } @@ -519,13 +519,14 @@ impl ValidatorState { /// Auxillary function to receive current slot offset. /// If offset is None, its setted up as last block slot offset. - fn get_current_offset(&mut self) -> u64 { + fn get_current_offset(&mut self, current_slot: u64) -> u64 { // This is the case were we restarted our node, didn't receive offset from other nodes, - // so we need to find offset from last block + // so we need to find offset from last block, exluding network dead period. if self.consensus.offset.is_none() { - let last = self.blockchain.get_last_offset().unwrap(); - info!("get_current_offset(): Setting slot offset: {}", last); - self.consensus.offset = Some(last); + let (last_slot, last_offset) = self.blockchain.get_last_offset().unwrap(); + let offset = last_offset + (current_slot - last_slot); + info!("get_current_offset(): Setting slot offset: {}", offset); + self.consensus.offset = Some(offset); } self.consensus.offset.unwrap() @@ -545,8 +546,10 @@ impl ValidatorState { ); self.consensus.offset = Some(current_slot); } + // Retrieve longest fork length, to also those proposals in the calculation + let max_fork_length = self.longest_chain_length() as u64; - current_slot - blocks - self.get_current_offset() + current_slot - blocks - self.get_current_offset(current_slot) - max_fork_length } /// total stake @@ -617,6 +620,7 @@ impl ValidatorState { one.clone() / constants::TI.clone() * i.clone() + constants::TD.clone() * d.clone()); while f <= zero.clone() || f >= one.clone() { + info!("Consensus::win_prob_with_full_stake(): f: {}", f); let mut clipped_f = f; if clipped_f >= one { clipped_f = one.clone() - constants::PID_OUT_STEP.clone(); @@ -632,7 +636,6 @@ impl ValidatorState { (p.clone() + one.clone() / constants::TI.clone() * i.clone() + constants::TD.clone() * d.clone()); - info!("Consensus::win_prob_with_full_stake(): f: {}", f); } info!("Consensus::win_prob_with_full_stake(): last f: {}", f); f @@ -719,7 +722,7 @@ impl ValidatorState { coin.public_inputs(sigma1, sigma2), eta.to_repr(), LeadProof::from(proof), - self.get_current_offset(), + self.get_current_offset(slot), self.consensus.leaders_history.last().unwrap().clone(), ); // Replacing old coin with the derived coin @@ -780,6 +783,18 @@ impl ValidatorState { Ok((hash, index)) } + /// Finds the length of longest fork chain the node holds. + pub fn longest_chain_length(&self) -> usize { + let mut max = 0; + for proposal in &self.consensus.proposals { + if proposal.proposals.len() > max { + max = proposal.proposals.len(); + } + } + + max + } + /// Given a proposal, the node verify its sender (slot leader) and finds which blockchain /// it extends. If the proposal extends the canonical blockchain, a new fork chain is created. pub async fn receive_proposal(&mut self, proposal: &BlockProposal) -> Result<()> { @@ -831,7 +846,7 @@ impl ValidatorState { } // Verify proposal offset - let offset = self.get_current_offset(); + let offset = self.get_current_offset(current); if offset != lf.offset { warn!( "receive_proposal(): Received proposal contains different offset: {} - {}", diff --git a/src/consensus/task/proposal.rs b/src/consensus/task/proposal.rs index f035e807b..0fa438006 100644 --- a/src/consensus/task/proposal.rs +++ b/src/consensus/task/proposal.rs @@ -21,18 +21,22 @@ use std::time::Duration; use log::{debug, error, info}; use super::consensus_sync_task; -use crate::{consensus::ValidatorStatePtr, net::P2pPtr, util::async_util::sleep}; +use crate::{ + consensus::{constants, ValidatorStatePtr}, + net::P2pPtr, + util::async_util::sleep, +}; /// async task used for participating in the consensus protocol pub async fn proposal_task(consensus_p2p: P2pPtr, sync_p2p: P2pPtr, state: ValidatorStatePtr) { // Node waits just before the current or next epoch last finalization syncing period, so it can // start syncing latest state. let mut seconds_until_next_epoch = state.read().await.next_n_epoch_start(1); - let three_secs = Duration::new(3, 0); + let sync_offset = Duration::new(constants::FINAL_SYNC_DUR + 1, 0); loop { - if seconds_until_next_epoch > three_secs { - seconds_until_next_epoch -= three_secs; + if seconds_until_next_epoch > sync_offset { + seconds_until_next_epoch -= sync_offset; break } @@ -60,8 +64,9 @@ pub async fn proposal_task(consensus_p2p: P2pPtr, sync_p2p: P2pPtr, state: Valid loop { // Node sleeps until finalization sync period start (2 seconds before next slot) - let seconds_sync_period = - (state.read().await.next_n_slot_start(1) - Duration::new(2, 0)).as_secs(); + let seconds_sync_period = (state.read().await.next_n_slot_start(1) - + Duration::new(constants::FINAL_SYNC_DUR, 0)) + .as_secs(); info!("consensus: Waiting for finalization sync period ({} sec)", seconds_sync_period); sleep(seconds_sync_period).await;