use crate::{
Address, Digest, ProtocolTimelines, ToDigest,
ecdsa::{ContractSignature, VerifiedData},
gear::BatchCommitment,
validators::ValidatorsVec,
};
use alloc::vec::Vec;
use core::num::NonZeroUsize;
use gprimitives::{CodeId, H256};
use k256::sha2::Digest as _;
use parity_scale_codec::{Decode, Encode};
use sha3::Keccak256;
pub const MAX_BATCH_SIZE_LIMIT: u64 = 120 * 1024;
pub const DEFAULT_BATCH_SIZE_LIMIT: u64 = 100 * 1024;
pub type VerifiedValidationRequest = VerifiedData<BatchCommitmentValidationRequest>;
pub type VerifiedValidationReply = VerifiedData<BatchCommitmentValidationReply>;
pub const fn block_coordinator_index_for_slot(validators_amount: NonZeroUsize, slot: u64) -> usize {
(slot % validators_amount.get() as u64) as usize
}
impl ProtocolTimelines {
pub fn block_coordinator_at(
&self,
validators: &ValidatorsVec,
timestamp: u64,
) -> Option<Address> {
let idx = self.block_coordinator_index_at(validators.len_nonzero(), timestamp)?;
validators.get(idx).cloned()
}
pub fn block_coordinator_index_at(
&self,
validators_amount: NonZeroUsize,
timestamp: u64,
) -> Option<usize> {
let slot = self.slot_from_ts(timestamp)?;
Some(block_coordinator_index_for_slot(validators_amount, slot))
}
}
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, Hash)]
pub struct BatchCommitmentValidationRequest {
pub digest: Digest,
pub head: Option<H256>,
pub codes: Vec<CodeId>,
pub rewards: bool,
pub validators: bool,
}
impl BatchCommitmentValidationRequest {
pub fn new(batch: &BatchCommitment) -> Self {
let codes = batch
.code_commitments
.iter()
.map(|commitment| commitment.id)
.collect();
BatchCommitmentValidationRequest {
digest: batch.to_digest(),
head: batch.chain_commitment.as_ref().map(|cc| cc.head),
codes,
rewards: batch.rewards_commitment.is_some(),
validators: batch.validators_commitment.is_some(),
}
}
}
impl ToDigest for BatchCommitmentValidationRequest {
fn update_hasher(&self, hasher: &mut sha3::Keccak256) {
let Self {
digest,
head,
codes,
rewards,
validators,
} = self;
hasher.update(digest);
head.map(|h| hasher.update(h.0));
hasher.update(
codes
.iter()
.flat_map(|h| h.into_bytes())
.collect::<Vec<u8>>(),
);
hasher.update([*rewards as u8]);
hasher.update([*validators as u8]);
}
}
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, Hash)]
pub struct BatchCommitmentValidationReply {
pub digest: Digest,
pub signature: ContractSignature,
}
impl ToDigest for BatchCommitmentValidationReply {
fn update_hasher(&self, hasher: &mut Keccak256) {
let Self { digest, signature } = self;
hasher.update(digest.0);
hasher.update(signature.into_pre_eip155_bytes())
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::num::NonZeroU64;
#[test]
fn block_coordinator_index_calculates_correct_index() {
let validators_amount = NonZeroUsize::new(5).unwrap();
let slot = 7;
let index = block_coordinator_index_for_slot(validators_amount, slot);
assert_eq!(index, 2);
}
#[test]
fn block_coordinator_for_calculates_correct_coordinator() {
let validators: ValidatorsVec = vec![
Address::from([1; 20]),
Address::from([2; 20]),
Address::from([3; 20]),
]
.try_into()
.unwrap();
let coordinator = ProtocolTimelines {
slot: NonZeroU64::new(1).unwrap(),
genesis_ts: 0,
era: NonZeroU64::new(1).unwrap(),
election: 0,
}
.block_coordinator_at(&validators, 10);
assert_eq!(coordinator, Some(Address::from([2; 20])));
}
#[test]
fn block_coordinator_for_calculates_correct_coordinator_with_genesis_timestamp() {
let validators: ValidatorsVec = vec![
Address::from([1; 20]),
Address::from([2; 20]),
Address::from([3; 20]),
]
.try_into()
.unwrap();
let coordinator = ProtocolTimelines {
slot: NonZeroU64::new(2).unwrap(),
genesis_ts: 6,
era: NonZeroU64::new(1).unwrap(),
election: 0,
}
.block_coordinator_at(&validators, 16);
assert_eq!(coordinator, Some(Address::from([3; 20])));
}
#[test]
fn block_coordinator_at_returns_none_before_genesis() {
let validators: ValidatorsVec = vec![Address::from([1; 20])].try_into().unwrap();
let coordinator = ProtocolTimelines {
slot: NonZeroU64::new(1).unwrap(),
genesis_ts: 100,
era: NonZeroU64::new(1).unwrap(),
election: 0,
}
.block_coordinator_at(&validators, 50);
assert_eq!(coordinator, None);
}
}