use std::{
collections::BTreeMap,
sync::mpsc::Sender,
time::{Duration, Instant, SystemTime},
};
use ed25519_dalek::VerifyingKey;
use crate::{
block_tree::{
accessors::internal::{BlockTreeError, BlockTreeSingleton, BlockTreeWriteBatch},
pluggables::KVStore,
},
events::{
AdvanceViewEvent, CollectTCEvent, Event, ReceiveAdvanceViewEvent, ReceiveTimeoutVoteEvent,
TimeoutVoteEvent, UpdateHighestTCEvent, ViewTimeoutEvent,
},
hotstuff::roles::is_validator,
networking::{messages::Message, network::Network, sending::SenderHandle},
pacemaker::{
messages::{AdvanceView, PacemakerMessage, ProgressCertificate, TimeoutVote},
types::TimeoutVoteCollector,
},
types::{
crypto_primitives::Keypair,
data_types::{ChainID, EpochLength, ViewNumber},
signed_messages::{ActiveCollectorPair, Certificate, SignedMessage},
validator_set::{ValidatorSet, ValidatorSetState},
},
};
pub(crate) struct Pacemaker<N: Network> {
config: PacemakerConfiguration,
state: PacemakerState,
view_info: ViewInfo,
sender: SenderHandle<N>,
event_publisher: Option<Sender<Event>>,
}
impl<N: Network> Pacemaker<N> {
pub(crate) fn new(
config: PacemakerConfiguration,
sender: SenderHandle<N>,
init_view: ViewNumber,
init_validator_set_state: &ValidatorSetState,
event_publisher: Option<Sender<Event>>,
) -> Result<Self, PacemakerError> {
let state = PacemakerState::initialize(&config, init_view, init_validator_set_state);
let timeout = state
.timeouts
.get(&init_view)
.clone()
.ok_or(UpdateViewError::GetViewTimeoutError { view: init_view })?;
let view_info = ViewInfo::new(init_view, *timeout);
Ok(Self {
config,
state,
view_info,
sender,
event_publisher,
})
}
pub(crate) fn query(&self) -> &ViewInfo {
&self.view_info
}
pub(crate) fn tick<K: KVStore>(
&mut self,
block_tree: &BlockTreeSingleton<K>,
) -> Result<(), PacemakerError> {
let cur_view = self.view_info.view;
let validator_set_state = block_tree.validator_set_state()?;
if Instant::now() > self.view_info.deadline {
Event::ViewTimeout(ViewTimeoutEvent {
timestamp: SystemTime::now(),
view: cur_view,
})
.publish(&self.event_publisher);
if is_epoch_change_view(&cur_view, self.config.epoch_length) {
if is_validator(&self.config.keypair.public(), &validator_set_state) {
let pacemaker_message = PacemakerMessage::timeout_vote(
&self.config.keypair,
self.config.chain_id,
cur_view,
block_tree.highest_tc()?,
);
self.sender
.broadcast(Message::from(pacemaker_message.clone()));
if let PacemakerMessage::TimeoutVote(timeout_vote) = pacemaker_message {
Event::TimeoutVote(TimeoutVoteEvent {
timestamp: SystemTime::now(),
timeout_vote,
})
.publish(&self.event_publisher)
}
}
self.extend_view()?
} else {
self.update_view(cur_view + 1, &validator_set_state)?;
}
return Ok(());
}
let _ = self
.state
.timeout_vote_collectors
.update_validator_sets(&validator_set_state);
if block_tree.highest_pc()?.view >= cur_view
&& !block_tree.highest_pc()?.is_genesis_pc()
&& is_validator(&self.config.keypair.public(), &validator_set_state)
&& (self.state.last_advance_view.is_none()
|| self.state.last_advance_view.is_some_and(|v| v < cur_view))
{
let pacemaker_message = PacemakerMessage::advance_view(
ProgressCertificate::PhaseCertificate(block_tree.highest_pc()?),
);
self.sender
.broadcast(Message::from(pacemaker_message.clone()));
if let PacemakerMessage::AdvanceView(advance_view) = pacemaker_message {
Event::AdvanceView(AdvanceViewEvent {
timestamp: SystemTime::now(),
advance_view,
})
.publish(&self.event_publisher)
}
self.state.last_advance_view = Some(self.view_info.view);
}
Ok(())
}
pub(crate) fn on_receive_msg<K: KVStore>(
&mut self,
msg: PacemakerMessage,
origin: &VerifyingKey,
block_tree: &mut BlockTreeSingleton<K>,
) -> Result<(), PacemakerError> {
match msg {
PacemakerMessage::TimeoutVote(timeout_vote) => {
self.on_receive_timeout_vote(timeout_vote, origin, block_tree)?
}
PacemakerMessage::AdvanceView(advance_view) => {
self.on_receive_advance_view(advance_view, origin, block_tree)?
}
}
Ok(())
}
fn on_receive_timeout_vote<K: KVStore>(
&mut self,
timeout_vote: TimeoutVote,
origin: &VerifyingKey,
block_tree: &mut BlockTreeSingleton<K>,
) -> Result<(), PacemakerError> {
Event::ReceiveTimeoutVote(ReceiveTimeoutVoteEvent {
timestamp: SystemTime::now(),
origin: origin.clone(),
timeout_vote: timeout_vote.clone(),
})
.publish(&self.event_publisher);
let validator_set_state = block_tree.validator_set_state()?;
if !is_validator(origin, &validator_set_state) {
return Ok(());
};
if timeout_vote.is_correct(origin)
&& is_epoch_change_view(&timeout_vote.view, self.config.epoch_length)
{
let fallback_tc = match &timeout_vote.highest_tc {
Some(tc) if tc.is_correct(block_tree)? => Some(tc.clone()),
_ => None,
};
if let Some(new_tc) = self
.state
.timeout_vote_collectors
.collect(origin, timeout_vote)
{
Event::CollectTC(CollectTCEvent {
timestamp: SystemTime::now(),
timeout_certificate: new_tc.clone(),
})
.publish(&self.event_publisher);
if block_tree.highest_tc()?.is_none()
|| new_tc.view > block_tree.highest_tc()?.unwrap().view
{
let mut wb = BlockTreeWriteBatch::new();
wb.set_highest_tc(&new_tc)?;
block_tree.write(wb);
Event::UpdateHighestTC(UpdateHighestTCEvent {
timestamp: SystemTime::now(),
highest_tc: new_tc.clone(),
})
.publish(&self.event_publisher);
if is_validator(&self.config.keypair.public(), &validator_set_state)
&& self.state.last_advance_view.is_none()
|| self
.state
.last_advance_view
.is_some_and(|v| v < self.view_info.view)
{
let pacemaker_message = PacemakerMessage::advance_view(
ProgressCertificate::TimeoutCertificate(new_tc),
);
self.sender
.broadcast(Message::from(pacemaker_message.clone()));
if let PacemakerMessage::AdvanceView(advance_view) = pacemaker_message {
Event::AdvanceView(AdvanceViewEvent {
timestamp: SystemTime::now(),
advance_view,
})
.publish(&self.event_publisher)
}
self.state.last_advance_view = Some(self.view_info.view);
}
}
} else if let Some(tc) = fallback_tc {
if block_tree.highest_tc()?.is_none()
|| tc.view > block_tree.highest_tc()?.unwrap().view
{
block_tree.set_highest_tc(&tc)?;
Event::UpdateHighestTC(UpdateHighestTCEvent {
timestamp: SystemTime::now(),
highest_tc: tc.clone(),
})
.publish(&self.event_publisher);
let next_view = tc.view + 1;
self.update_view(next_view, &validator_set_state)?
}
}
}
Ok(())
}
fn on_receive_advance_view<K: KVStore>(
&mut self,
advance_view: AdvanceView,
origin: &VerifyingKey,
block_tree: &mut BlockTreeSingleton<K>,
) -> Result<(), PacemakerError> {
Event::ReceiveAdvanceView(ReceiveAdvanceViewEvent {
timestamp: SystemTime::now(),
origin: origin.clone(),
advance_view: advance_view.clone(),
})
.publish(&self.event_publisher);
let validator_set_state = block_tree.validator_set_state()?;
if !is_validator(origin, &validator_set_state) {
return Ok(());
}
let progress_certificate = advance_view.progress_certificate.clone();
let is_valid = match &progress_certificate {
ProgressCertificate::PhaseCertificate(pc) => pc.is_correct(block_tree)?,
ProgressCertificate::TimeoutCertificate(tc) => {
tc.is_correct(&block_tree)?
&& is_epoch_change_view(&tc.view, self.config.epoch_length)
}
};
if is_valid {
if let ProgressCertificate::TimeoutCertificate(tc) = &progress_certificate {
if block_tree.highest_tc()?.is_none()
|| tc.view > block_tree.highest_tc()?.unwrap().view
{
block_tree.set_highest_tc(&tc)?;
Event::UpdateHighestTC(UpdateHighestTCEvent {
timestamp: SystemTime::now(),
highest_tc: tc.clone(),
})
.publish(&self.event_publisher);
}
};
if is_validator(
&self.config.keypair.public(),
&block_tree.validator_set_state()?,
) && (self.state.last_advance_view.is_none()
|| self
.state
.last_advance_view
.is_some_and(|v| v < self.view_info.view))
{
self.sender
.broadcast(Message::from(PacemakerMessage::AdvanceView(
advance_view.clone(),
)));
Event::AdvanceView(AdvanceViewEvent {
timestamp: SystemTime::now(),
advance_view,
})
.publish(&self.event_publisher);
self.state.last_advance_view = Some(self.view_info.view);
}
let next_view = progress_certificate.view() + 1;
self.update_view(next_view, &validator_set_state)?
}
Ok(())
}
fn update_view(
&mut self,
next_view: ViewNumber,
validator_set_state: &ValidatorSetState,
) -> Result<(), PacemakerError> {
let cur_view = self.view_info.view;
if next_view <= cur_view {
return Err(UpdateViewError::NonIncreasingViewError {
cur_view,
next_view,
}
.into());
}
if epoch(cur_view, self.config.epoch_length) != epoch(next_view, self.config.epoch_length) {
self.state.update_timeouts(next_view, &self.config);
}
self.view_info = ViewInfo::new(
next_view,
*self
.state
.timeouts
.get(&next_view)
.ok_or(UpdateViewError::GetViewTimeoutError { view: next_view })?,
);
self.state.timeout_vote_collectors = <ActiveCollectorPair<TimeoutVoteCollector>>::new(
self.config.chain_id,
next_view,
validator_set_state,
);
Ok(())
}
fn extend_view(&mut self) -> Result<(), ExtendViewError> {
let cur_view = self.view_info.view;
if !is_epoch_change_view(&cur_view, self.config.epoch_length) {
return Err(ExtendViewError::TriedToExtendNonEpochView {
view: cur_view.clone(),
});
};
self.state
.extend_epoch_change_view_timeout(self.view_info.view, &self.config);
let new_timeout = self
.state
.timeouts
.get(&cur_view)
.ok_or(ExtendViewError::GetViewTimeoutError { view: cur_view })?;
self.view_info = self.view_info.with_new_timeout(*new_timeout);
Ok(())
}
}
#[derive(Clone)]
pub(crate) struct PacemakerConfiguration {
pub(crate) chain_id: ChainID,
pub(crate) keypair: Keypair,
pub(crate) epoch_length: EpochLength,
pub(crate) max_view_time: Duration,
}
struct PacemakerState {
timeouts: BTreeMap<ViewNumber, Instant>,
timeout_vote_collectors: ActiveCollectorPair<TimeoutVoteCollector>,
last_advance_view: Option<ViewNumber>,
}
impl PacemakerState {
fn initialize(
config: &PacemakerConfiguration,
init_view: ViewNumber,
validator_set_state: &ValidatorSetState,
) -> Self {
fn initial_timeouts(
start_view: ViewNumber,
config: &PacemakerConfiguration,
) -> BTreeMap<ViewNumber, Instant> {
let mut timeouts = BTreeMap::new();
let epoch = epoch(start_view, config.epoch_length);
let epoch_view = epoch * config.epoch_length.int() as u64;
let start_time = Instant::now();
for view in start_view.int()..=epoch_view {
let time_to_view_deadline = Duration::from_secs(
config.max_view_time.as_secs() * (view - start_view.int() + 1),
);
timeouts.insert(ViewNumber::new(view), start_time + time_to_view_deadline);
}
timeouts
}
Self {
timeouts: initial_timeouts(init_view, config),
timeout_vote_collectors: <ActiveCollectorPair<TimeoutVoteCollector>>::new(
config.chain_id,
init_view,
validator_set_state,
),
last_advance_view: None,
}
}
fn update_timeouts(&mut self, epoch_start_view: ViewNumber, config: &PacemakerConfiguration) {
self.timeouts = self.timeouts.split_off(&epoch_start_view);
let epoch_change_view = {
let epoch_num = epoch(epoch_start_view, config.epoch_length);
epoch_num * config.epoch_length.int() as u64
};
let epoch_start_time = Instant::now();
for view in epoch_start_view.int()..=epoch_change_view {
let time_to_view_deadline = Duration::from_secs(
config.max_view_time.as_secs() * (view - epoch_start_view.int() + 1),
);
self.timeouts.insert(
ViewNumber::new(view),
epoch_start_time + time_to_view_deadline,
);
}
}
fn extend_epoch_change_view_timeout(
&mut self,
epoch_change_view: ViewNumber,
config: &PacemakerConfiguration,
) {
self.timeouts
.insert(epoch_change_view, Instant::now() + config.max_view_time);
}
}
#[derive(Debug)]
pub enum PacemakerError {
UpdateViewError(UpdateViewError),
ExtendViewError(ExtendViewError),
BlockTreeError(BlockTreeError),
}
impl From<BlockTreeError> for PacemakerError {
fn from(value: BlockTreeError) -> Self {
PacemakerError::BlockTreeError(value)
}
}
impl From<UpdateViewError> for PacemakerError {
fn from(value: UpdateViewError) -> Self {
PacemakerError::UpdateViewError(value)
}
}
impl From<ExtendViewError> for PacemakerError {
fn from(value: ExtendViewError) -> Self {
PacemakerError::ExtendViewError(value)
}
}
#[derive(Debug)]
pub enum UpdateViewError {
NonIncreasingViewError {
cur_view: ViewNumber,
next_view: ViewNumber,
},
GetViewTimeoutError { view: ViewNumber },
}
#[derive(Debug)]
pub enum ExtendViewError {
TriedToExtendNonEpochView { view: ViewNumber },
GetViewTimeoutError { view: ViewNumber },
}
#[derive(PartialEq, Eq, Clone)]
pub(crate) struct ViewInfo {
pub(crate) view: ViewNumber,
pub(crate) deadline: Instant,
}
impl ViewInfo {
pub(crate) fn new(view: ViewNumber, deadline: Instant) -> Self {
Self { view, deadline }
}
pub(crate) fn with_new_timeout(&self, new_deadline: Instant) -> Self {
Self {
view: self.view,
deadline: new_deadline,
}
}
}
pub fn select_leader(view: ViewNumber, validator_set: &ValidatorSet) -> VerifyingKey {
let p_total = validator_set.total_power();
let n = validator_set.len();
let index = view.int() % (p_total.int() as u64);
let p_max = validator_set
.validators_and_powers()
.iter()
.map(|(_, power)| power.int())
.max()
.expect("The validator set cannot be empty!")
.clone();
let mut counter = 0;
for threshold in 1..=p_max {
for k in 0..=(n - 1) {
let validator = validator_set.validators().nth(k).unwrap();
if validator_set.power(validator).unwrap().int() >= threshold {
if counter == index {
return *validator;
}
counter += 1
}
}
}
unreachable!("Cannot select a leader: index not found!")
}
fn is_epoch_change_view(view: &ViewNumber, epoch_length: EpochLength) -> bool {
view.int() % (epoch_length.int() as u64) == 0
}
fn epoch(view: ViewNumber, epoch_length: EpochLength) -> u64 {
view.int().div_ceil(epoch_length.int() as u64)
}
#[test]
fn select_leader_fairness_test() {
use crate::types::{data_types::Power, update_sets::ValidatorSetUpdates};
use ed25519_dalek::{SigningKey, VerifyingKey};
use rand_core::OsRng;
let mut csprg = OsRng {};
let n = 20;
let keypairs: Vec<SigningKey> = (0..n).map(|_| SigningKey::generate(&mut csprg)).collect();
let public_keys: Vec<VerifyingKey> = keypairs
.iter()
.map(|keypair| keypair.verifying_key())
.collect();
let mut validator_set = ValidatorSet::new();
let mut validator_set_updates = ValidatorSetUpdates::new();
public_keys
.iter()
.zip(0..n)
.for_each(|(validator, power)| validator_set_updates.insert(*validator, Power::new(power)));
validator_set.apply_updates(&validator_set_updates);
let total_power = validator_set.total_power().int() as u64;
let leader_sequence: Vec<VerifyingKey> = (0..total_power)
.into_iter()
.map(|v| select_leader(ViewNumber::new(v), &validator_set))
.collect();
validator_set.validators().for_each(|validator| {
assert_eq!(
leader_sequence
.iter()
.filter(|leader| leader == &validator)
.count(),
validator_set.power(validator).unwrap().int() as usize
)
})
}