前序博客有:
- Solana代码解析
- Solana中的PoH
let (verified_vote_packets_sender, verified_vote_packets_receiver) = unbounded();
let cluster_info_vote_listener = ClusterInfoVoteListener::new(
exit,
cluster_info.clone(),
verified_vote_packets_sender,
poh_recorder,
vote_tracker,
bank_forks.clone(),
subscriptions.clone(),
verified_vote_sender,
gossip_verified_vote_hash_sender,
replay_vote_receiver,
blockstore.clone(),
bank_notification_sender,
cluster_confirmed_slot_sender,
);
TPU中的监听投票流程与banking_stage是并行进行的。
投票的维度有2种,分别为:
- vote for label packets
- vote for transactions
let (verified_vote_label_packets_sender, verified_vote_label_packets_receiver) =
unbounded();
let (verified_vote_transactions_sender, verified_vote_transactions_receiver) = unbounded();
并行处理的流程有:
- 1)recv_loop():通过gossip协议收集投票信息 -》 验证投票中的交易和label信息-》分别发送transactions vote和label packets vote
let (labels, votes) = cluster_info.get_votes(&mut cursor);
.....
let (vote_txs, packets) = Self::verify_votes(votes, labels);
verified_vote_transactions_sender.send(vote_txs)?;
verified_vote_label_packets_sender.send(packets)?;
- 2)bank_send_loop(): 2.1)借助
receive_and_process_vote_packets()
,若当前Validator为leader,则将相应的packets插入到VerifiedVotePackets中;若不是leader,则清空VerifiedVotePackets。 2.2)为leader时,借助get_latest_votes()
,过滤VerifiedVotePackets中,version版本大于last_version的packets。 2.3)将过滤后的packets通过verified_packets_sender发出,并更新bank中记录的最新version。 - 3)process_votes_loop():
verify_for_unrooted_optimistic_slots()
:Returns any optimistic slots that were not rootedlog_unrooted_optimistic_slots()
:progress_leader_schedule_epoch()
:Update with any newly calculated epoch state about future epochspurge_stale_state()
:Purge any outdated slot datalisten_and_confirm_votes()
:add_new_optimistic_confirmed_slots()
:只对confirmed slots进行处理。
【重点看replay_stage,有is_partition_detected().】 Replay_stage::new()->handle_votable_bank->push_vote->generate_vote_tx。 Solana中有维护skipped slot:是指由于leader下线 或 the fork containing the slot was abandoned for a better alternative by cluster consensus 原因,导致的slot中未产块的情况,称为skipped slot。 A skipped slot: 不会作为an ancestor for blocks at subsequent slots 不会increment the block height 决定一个slot是否为skipped slot的标准是:其 becomes older than the latest rooted (thus not-skipped) slot。 root:A block or slot that has reached maximum lockout on a validator. The root is the highest block that is an ancestor of all active forks on a validator. All ancestor blocks of a root are also transitively a root. Blocks that are not an ancestor and not a descendant of the root are excluded from consideration for consensus and can be discarded. lockout:The duration of time for which a validator is unable to vote on another fork.
// The number of slots for which this vote is locked
pub fn lockout(&self) -> u64 {
(INITIAL_LOCKOUT as u64).pow(self.confirmation_count)
}
// The last slot at which a vote is still locked out. Validators should not
// vote on a slot in another fork which is less than or equal to this slot
// to avoid having their stake slashed.
pub fn last_locked_out_slot(&self) -> Slot {
self.slot + self.lockout()
}