#[cfg(feature = "serde")]
mod serde;
#[cfg(feature = "serde")]
pub use self::serde::*;
use crate::{Config, Error};
use crate::primitives::*;
use core::cmp::max;
use primitive_types::H256;
pub fn to_bytes(v: Uint) -> H256 {
let bytes = v.to_le_bytes();
let mut ret = H256::default();
(&mut ret[0..bytes.len()]).copy_from_slice(&bytes);
ret
}
pub fn to_uint(v: &[u8]) -> Uint {
let mut ret = 0u64.to_le_bytes();
(&mut ret[..]).copy_from_slice(&v[..v.len()]);
u64::from_le_bytes(ret)
}
pub fn integer_squareroot(n: Uint) -> Uint {
let mut x = n;
let mut y = (x + 1) / 2;
while y < x {
x = y;
y = (x + n / x) / 2
}
x
}
pub fn compare_hash(a: &H256, b: &H256) -> core::cmp::Ordering {
for i in 0..32 {
if a[i] > b[i] {
return core::cmp::Ordering::Greater
} else if a[i] < b[i] {
return core::cmp::Ordering::Less
}
}
core::cmp::Ordering::Equal
}
pub fn shuffled_index<C: Config>(
mut index: Uint,
index_count: Uint,
seed: H256
) -> Result<ValidatorIndex, Error> {
if !(index < index_count && index_count <= 2u64.pow(40)) {
return Err(Error::IndexOutOfRange)
}
for round in 0..C::shuffle_round_count() {
let pivot = to_uint(
&C::hash(&[
&seed[..],
&round.to_le_bytes()[..1]
])[..8]
) % index_count;
let flip = (pivot + index_count - index) % index_count;
let position = max(index, flip);
let source = C::hash(&[
&seed[..],
&round.to_le_bytes()[..1],
&(position / 256).to_le_bytes()[..4]
]);
let byte = source[((position % 256) / 8) as usize];
let bit = (byte >> (position % 8)) % 2;
index = if bit != 0 { flip } else { index };
}
Ok(index)
}
pub fn compute_committee<C: Config>(
indices: &[ValidatorIndex],
seed: H256,
index: Uint,
count: Uint,
) -> Result<Vec<ValidatorIndex>, Error> {
let start = (indices.len() as u64 * index) / count;
let end = (indices.len() as u64 * (index + 1)) / count;
(start..end).into_iter().map(move |i| {
Ok(indices[
shuffled_index::<C>(i, indices.len() as u64, seed)? as usize
])
}).collect::<Result<Vec<_>, Error>>()
}
pub fn epoch_of_slot<C: Config>(slot: Uint) -> Uint {
slot / C::slots_per_epoch()
}
pub fn start_slot_of_epoch<C: Config>(epoch: Uint) -> Uint {
epoch * C::slots_per_epoch()
}
pub fn activation_exit_epoch<C: Config>(epoch: Uint) -> Uint {
epoch + 1 + C::activation_exit_delay()
}
pub fn is_valid_merkle_branch<C: Config>(
leaf: H256, proof: &[H256], depth: u64, index: u64, root: H256
) -> bool {
if proof.len() as u64 != depth {
return false
}
let mut value = leaf;
for i in 0..depth {
if index / 2u64.pow(i as u32) % 2 != 0 {
value = C::hash(&[&proof[i as usize][..], &value[..]]);
} else {
value = C::hash(&[&value[..], &proof[i as usize][..]]);
}
}
value == root
}
pub fn bls_domain(domain_type: u64, fork_version: Version) -> u64 {
let mut bytes = [0u8; 8];
(&mut bytes[0..4]).copy_from_slice(&domain_type.to_le_bytes()[0..4]);
(&mut bytes[4..8]).copy_from_slice(fork_version.as_ref());
u64::from_le_bytes(bytes)
}