use crate::SignerBitmapError;
use serde::{Deserialize, Serialize};
pub const MAX_VALIDATORS: u32 = 65_536;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SignerBitmap {
bits: Vec<u8>,
validator_count: u32,
}
impl SignerBitmap {
#[must_use]
pub fn new(validator_count: u32) -> Self {
assert!(
validator_count <= MAX_VALIDATORS,
"SignerBitmap::new: validator_count {validator_count} exceeds MAX_VALIDATORS ({MAX_VALIDATORS})"
);
let byte_count = (validator_count as usize).div_ceil(8);
Self {
bits: vec![0u8; byte_count],
validator_count,
}
}
#[must_use]
pub fn from_bytes(bytes: &[u8], validator_count: u32) -> Self {
assert!(
validator_count <= MAX_VALIDATORS,
"SignerBitmap::from_bytes: validator_count {validator_count} exceeds MAX_VALIDATORS ({MAX_VALIDATORS})"
);
Self {
bits: bytes.to_vec(),
validator_count,
}
}
#[must_use]
pub fn has_signed(&self, index: u32) -> bool {
if index >= self.validator_count {
return false;
}
let byte_index = (index / 8) as usize;
let bit_index = index % 8;
let Some(&byte) = self.bits.get(byte_index) else {
return false;
};
byte & (1 << bit_index) != 0
}
pub fn set_signed(&mut self, index: u32) -> Result<(), SignerBitmapError> {
if index >= self.validator_count {
return Err(SignerBitmapError::IndexOutOfBounds {
index,
max: self.validator_count,
});
}
let byte_index = (index / 8) as usize;
let bit_index = index % 8;
let canonical_len = (self.validator_count as usize).div_ceil(8);
if self.bits.len() < canonical_len {
self.bits.resize(canonical_len, 0);
}
self.bits[byte_index] |= 1 << bit_index;
Ok(())
}
#[must_use]
pub fn signer_count(&self) -> u32 {
self.bits.iter().map(|b| b.count_ones()).sum()
}
#[must_use]
pub fn signing_percentage(&self) -> u64 {
if self.validator_count == 0 {
return 0;
}
(u64::from(self.signer_count()) * 100) / u64::from(self.validator_count)
}
#[must_use]
pub fn has_threshold(&self, threshold_pct: u64) -> bool {
self.signing_percentage() >= threshold_pct
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.bits
}
#[must_use]
pub fn validator_count(&self) -> u32 {
self.validator_count
}
pub fn merge(&mut self, other: &SignerBitmap) -> Result<(), SignerBitmapError> {
if self.validator_count != other.validator_count {
return Err(SignerBitmapError::ValidatorCountMismatch {
expected: self.validator_count,
got: other.validator_count,
});
}
let n = (self.validator_count as usize).div_ceil(8);
self.bits.resize(n, 0);
for i in 0..n {
let ob = other.bits.get(i).copied().unwrap_or(0);
self.bits[i] |= ob;
}
Ok(())
}
#[must_use]
pub fn signer_indices(&self) -> Vec<u32> {
(0..self.validator_count)
.filter(|&i| self.has_signed(i))
.collect()
}
}