use rialo_s_pubkey::Pubkey;
use serde::{Deserialize, Serialize};
use super::{
BLAKE3_HASH_SIZE, ED25519_SIGNATURE_SIZE, READY_MESSAGE_INTENT_PREFIX,
READY_MESSAGE_SIGNING_SIZE,
};
use crate::{
consensus_crypto::{AuthorityPublicKey, NetworkPublicKey, ProtocolPublicKey},
Multiaddr,
};
#[derive(
Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize,
)]
#[repr(transparent)]
pub struct EpochIdentifier(u64);
impl EpochIdentifier {
pub const fn new(epoch: u64) -> Self {
Self(epoch)
}
pub const fn as_u64(self) -> u64 {
self.0
}
pub const fn to_le_bytes(self) -> [u8; 8] {
self.0.to_le_bytes()
}
}
impl From<u64> for EpochIdentifier {
fn from(epoch: u64) -> Self {
Self(epoch)
}
}
impl From<EpochIdentifier> for u64 {
fn from(epoch: EpochIdentifier) -> Self {
epoch.0
}
}
impl std::fmt::Display for EpochIdentifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct EpochChangeConfig {
pub current_epoch: EpochIdentifier,
pub new_epoch: EpochIdentifier,
pub validators: Vec<ValidatorInfo>,
pub consensus_config: Option<EpochConsensusConfig>,
}
impl EpochChangeConfig {
pub fn deterministic_hash(&self) -> [u8; BLAKE3_HASH_SIZE] {
let mut hasher = blake3::Hasher::new();
hasher.update(&self.current_epoch.to_le_bytes());
hasher.update(&self.new_epoch.to_le_bytes());
hasher.update(&(self.validators.len() as u64).to_le_bytes());
for validator in &self.validators {
hasher.update(&validator.stake.to_le_bytes());
let consensus_addr_bytes = validator.consensus_address.to_vec();
hasher.update(&(consensus_addr_bytes.len() as u64).to_le_bytes());
hasher.update(&consensus_addr_bytes);
let state_sync_addr_bytes = validator.state_sync_address.to_vec();
hasher.update(&(state_sync_addr_bytes.len() as u64).to_le_bytes());
hasher.update(&state_sync_addr_bytes);
hasher.update(&(validator.hostname.len() as u64).to_le_bytes());
hasher.update(validator.hostname.as_bytes());
hasher.update(&validator.authority_key.to_bytes());
hasher.update(&validator.protocol_key.to_bytes());
hasher.update(&validator.network_key.to_bytes());
hasher.update(validator.signing_key.as_ref());
}
match &self.consensus_config {
Some(config) => {
hasher.update(&[1u8]);
Self::hash_optional_usize(&mut hasher, config.num_leaders_per_round);
Self::hash_optional_u64(&mut hasher, config.max_transactions_in_block_bytes);
Self::hash_optional_u64(&mut hasher, config.max_num_transactions_in_block);
Self::hash_optional_u64(&mut hasher, config.max_transaction_size_bytes);
Self::hash_optional_u32(&mut hasher, config.gc_depth);
Self::hash_optional_bool(&mut hasher, config.zstd_compression);
}
None => {
hasher.update(&[0u8]); }
}
*hasher.finalize().as_bytes()
}
fn hash_optional_usize(hasher: &mut blake3::Hasher, value: Option<usize>) {
match value {
Some(v) => {
hasher.update(&[1u8]);
hasher.update(&(v as u64).to_le_bytes());
}
None => {
hasher.update(&[0u8]);
}
}
}
fn hash_optional_u64(hasher: &mut blake3::Hasher, value: Option<u64>) {
match value {
Some(v) => {
hasher.update(&[1u8]);
hasher.update(&v.to_le_bytes());
}
None => {
hasher.update(&[0u8]);
}
}
}
fn hash_optional_u32(hasher: &mut blake3::Hasher, value: Option<u32>) {
match value {
Some(v) => {
hasher.update(&[1u8]);
hasher.update(&v.to_le_bytes());
}
None => {
hasher.update(&[0u8]);
}
}
}
fn hash_optional_bool(hasher: &mut blake3::Hasher, value: Option<bool>) {
match value {
Some(v) => {
hasher.update(&[1u8]);
hasher.update(&[v as u8]);
}
None => {
hasher.update(&[0u8]);
}
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct ValidatorInfo {
pub stake: u64,
pub consensus_address: Multiaddr,
pub state_sync_address: Multiaddr,
pub hostname: String,
pub authority_key: AuthorityPublicKey,
pub protocol_key: ProtocolPublicKey,
pub network_key: NetworkPublicKey,
pub signing_key: Pubkey,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct EpochConsensusConfig {
pub num_leaders_per_round: Option<usize>,
pub max_transactions_in_block_bytes: Option<u64>,
pub max_num_transactions_in_block: Option<u64>,
pub max_transaction_size_bytes: Option<u64>,
pub gc_depth: Option<u32>,
pub zstd_compression: Option<bool>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct ValidatorReadyMessage {
pub current_epoch: EpochIdentifier,
pub epoch_config_hash: [u8; BLAKE3_HASH_SIZE],
pub authority_key: AuthorityPublicKey,
pub protocol_key: ProtocolPublicKey,
#[serde(with = "serde_big_array::BigArray")]
pub signature: [u8; ED25519_SIGNATURE_SIZE],
}
impl ValidatorReadyMessage {
pub fn signing_message(
current_epoch: EpochIdentifier,
epoch_config_hash: &[u8; BLAKE3_HASH_SIZE],
) -> [u8; READY_MESSAGE_SIGNING_SIZE] {
let mut msg = [0u8; READY_MESSAGE_SIGNING_SIZE];
msg[0..3].copy_from_slice(&READY_MESSAGE_INTENT_PREFIX);
msg[3..11].copy_from_slice(¤t_epoch.to_le_bytes());
msg[11..READY_MESSAGE_SIGNING_SIZE].copy_from_slice(epoch_config_hash);
msg
}
pub fn message_bytes(&self) -> [u8; READY_MESSAGE_SIGNING_SIZE] {
Self::signing_message(self.current_epoch, &self.epoch_config_hash)
}
}