solana/core/src/voting_service.rs

106 lines
2.9 KiB
Rust

use {
crate::{
consensus::tower_storage::{SavedTowerVersions, TowerStorage},
next_leader::next_leader_tpu_vote,
},
crossbeam_channel::Receiver,
solana_gossip::cluster_info::ClusterInfo,
solana_measure::measure::Measure,
solana_poh::poh_recorder::PohRecorder,
solana_sdk::{clock::Slot, transaction::Transaction},
std::{
sync::{Arc, RwLock},
thread::{self, Builder, JoinHandle},
},
};
pub enum VoteOp {
PushVote {
tx: Transaction,
tower_slots: Vec<Slot>,
saved_tower: SavedTowerVersions,
},
RefreshVote {
tx: Transaction,
last_voted_slot: Slot,
},
}
impl VoteOp {
fn tx(&self) -> &Transaction {
match self {
VoteOp::PushVote { tx, .. } => tx,
VoteOp::RefreshVote { tx, .. } => tx,
}
}
}
pub struct VotingService {
thread_hdl: JoinHandle<()>,
}
impl VotingService {
pub fn new(
vote_receiver: Receiver<VoteOp>,
cluster_info: Arc<ClusterInfo>,
poh_recorder: Arc<RwLock<PohRecorder>>,
tower_storage: Arc<dyn TowerStorage>,
) -> Self {
let thread_hdl = Builder::new()
.name("solVoteService".to_string())
.spawn(move || {
for vote_op in vote_receiver.iter() {
Self::handle_vote(
&cluster_info,
&poh_recorder,
tower_storage.as_ref(),
vote_op,
);
}
})
.unwrap();
Self { thread_hdl }
}
pub fn handle_vote(
cluster_info: &ClusterInfo,
poh_recorder: &RwLock<PohRecorder>,
tower_storage: &dyn TowerStorage,
vote_op: VoteOp,
) {
if let VoteOp::PushVote { saved_tower, .. } = &vote_op {
let mut measure = Measure::start("tower_save-ms");
if let Err(err) = tower_storage.store(saved_tower) {
error!("Unable to save tower to storage: {:?}", err);
std::process::exit(1);
}
measure.stop();
inc_new_counter_info!("tower_save-ms", measure.as_ms() as usize);
}
let _ = cluster_info.send_transaction(
vote_op.tx(),
next_leader_tpu_vote(cluster_info, poh_recorder)
.map(|(_pubkey, target_addr)| target_addr),
);
match vote_op {
VoteOp::PushVote {
tx, tower_slots, ..
} => {
cluster_info.push_vote(&tower_slots, tx);
}
VoteOp::RefreshVote {
tx,
last_voted_slot,
} => {
cluster_info.refresh_vote(tx, last_voted_slot);
}
}
}
pub fn join(self) -> thread::Result<()> {
self.thread_hdl.join()
}
}