Summary
ValidatorSetFactory::create accepts an empty validator list and returns a validator set whose
total stake is zero.
Vulnerability details
fn create( &self, validators: Vec<(NodeId<Self::NodeIdPubKey>, Stake)>,) -> Result<Self::ValidatorSetType, Self::NodeIdPubKey> { let mut vmap = BTreeMap::new(); let mut total_stake = Stake::ZERO; for (node_id, stake) in validators.into_iter() { let duplicate = vmap.insert(node_id, stake); if duplicate.is_some() { return Err(ValidatorSetError::DuplicateValidator(node_id)); } total_stake += stake; }
Ok(ValidatorSet { validators: vmap, total_stake, })}Impact
Downstream quorum and threshold logic assumes meaningful stake totals. A zero-stake set can cause threshold checks to become unsatisfiable and create liveness issues.
Recommendation
Reject empty validator lists before constructing the validator set.