use crate::{
hash_encoded, header::OffendersMark, AvailabilityAssurance, CoreCount, EpochIndex, ErasureRoot,
MaxTicketsPerBlock, TicketEnvelope, MAX_REPORT_ELECTIVE_DATA, VALS_PER_CORE,
};
use bounded_collections::ConstU32;
use jam_types::{
AuthOutput, AuthorizerHash, BoundedVec, CoreIndex, ExtrinsicHash, FixedVec, MaxWorkItems,
RefineContext, SegmentTreeRoot, ServiceId, Slot, UnsignedGas, ValIndex, ValSuperMajority,
VecMap, WorkPackageHash, WorkReportHash, WorkResult,
};
use scale::{ConstEncodedLen, Decode, Encode, MaxEncodedLen};
pub const MAX_VERDICTS_COUNT: usize = 16;
pub const MAX_OFFENSES_COUNT: usize = 16;
pub type PreimagesXt = Vec<Preimage>;
pub type TicketsXt = BoundedVec<TicketEnvelope, MaxTicketsPerBlock>;
pub type AssurancesXt = BoundedVec<AvailabilityAssurance, jam_types::ValCount>;
pub type GuaranteesXt = BoundedVec<ReportGuarantee, CoreCount>;
#[derive(Clone, Encode, Decode, Debug, Default)]
pub struct DisputesXt {
pub verdicts: BoundedVec<Verdict, ConstU32<{ MAX_VERDICTS_COUNT as u32 }>>,
pub culprits: BoundedVec<CulpritProof, ConstU32<{ MAX_OFFENSES_COUNT as u32 }>>,
pub faults: BoundedVec<FaultProof, ConstU32<{ MAX_OFFENSES_COUNT as u32 }>>,
}
impl DisputesXt {
pub fn offenders_mark(&self) -> OffendersMark {
let offenders: Vec<_> = self
.culprits
.iter()
.map(|v| v.key)
.chain(self.faults.iter().map(|v| v.key))
.collect();
offenders.try_into().expect("OffendersMark bounds equal culprits + faults")
}
pub fn implies_offenders_mark(&self, offenders_mark: &OffendersMark) -> bool {
self.culprits
.iter()
.map(|v| v.key)
.chain(self.faults.iter().map(|v| v.key))
.zip(offenders_mark.iter())
.all(|(a, b)| a == *b)
}
}
pub type VerdictVotes = FixedVec<Judgement, ValSuperMajority>;
#[derive(Clone, Encode, Decode, Debug)]
pub struct Verdict {
pub target: WorkReportHash,
pub age: EpochIndex,
pub votes: VerdictVotes,
}
#[derive(Clone, Encode, Decode, Debug)]
pub struct Judgement {
pub vote: bool,
pub index: ValIndex,
pub signature: super::ed25519::Signature,
}
#[derive(Clone, Encode, Decode, Debug)]
pub struct CulpritProof {
pub report_hash: WorkReportHash,
pub key: super::ed25519::Public,
pub signature: super::ed25519::Signature,
}
#[derive(Clone, Encode, Decode, Debug)]
pub struct FaultProof {
pub report_hash: WorkReportHash,
pub vote: bool,
pub key: super::ed25519::Public,
pub signature: super::ed25519::Signature,
}
#[derive(Clone, Encode, Decode, Debug, Default)]
pub struct Extrinsic {
pub tickets: TicketsXt,
pub preimages: PreimagesXt,
pub guarantees: GuaranteesXt,
pub assurances: AssurancesXt,
pub disputes: DisputesXt,
}
impl Extrinsic {
pub fn guarantees_prehashed(&self) -> Vec<(WorkReportHash, Slot, &GuaranteeSignatures)> {
self.guarantees
.iter()
.map(|r| (r.report.hash(), r.slot, &r.signatures))
.collect()
}
pub fn hash(&self) -> ExtrinsicHash {
let tickets_hash = hash_encoded(&self.tickets);
let disputes_hash = hash_encoded(&self.disputes);
let preimages_hash = hash_encoded(&self.preimages);
let assurances_hash = hash_encoded(&self.assurances);
let guarantees_hash = hash_encoded(&self.guarantees_prehashed());
let top = (tickets_hash, preimages_hash, guarantees_hash, assurances_hash, disputes_hash);
hash_encoded(&top).into()
}
}
#[derive(Clone, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Preimage {
pub requester: ServiceId,
pub blob: Vec<u8>,
}
impl Preimage {
pub fn new(requester: ServiceId, blob: impl Into<Vec<u8>>) -> Self {
Self { requester, blob: blob.into() }
}
}
#[derive(Clone, Encode, Decode, Debug, MaxEncodedLen)]
#[cfg_attr(test, derive(PartialEq, Eq))]
pub struct ReportGuarantee {
pub report: WorkReport,
pub slot: Slot,
pub signatures: GuaranteeSignatures,
}
pub type GuaranteeSignatures = BoundedVec<ValSignature, ConstU32<{ VALS_PER_CORE as u32 }>>;
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, MaxEncodedLen)]
pub struct ValSignature {
pub val_index: ValIndex,
pub signature: super::ed25519::Signature,
}
impl ConstEncodedLen for ValSignature {}
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, MaxEncodedLen)]
pub struct WorkPackageSpec {
pub hash: WorkPackageHash,
pub len: u32,
pub erasure_root: ErasureRoot,
pub exports_root: SegmentTreeRoot,
pub exports_count: u16,
}
impl WorkPackageSpec {
pub fn wp_srl(&self) -> (WorkPackageHash, SegmentTreeRoot) {
(self.hash, self.exports_root)
}
}
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
pub struct WorkReport {
pub package_spec: WorkPackageSpec,
pub context: RefineContext,
pub core_index: CoreIndex,
pub authorizer_hash: AuthorizerHash,
pub auth_output: AuthOutput,
pub sr_lookup: VecMap<WorkPackageHash, SegmentTreeRoot>,
pub results: BoundedVec<WorkResult, MaxWorkItems>,
#[codec(compact)]
pub auth_gas_used: UnsignedGas,
}
impl WorkReport {
pub fn hash(&self) -> WorkReportHash {
hash_encoded(self).into()
}
pub fn gas(&self) -> UnsignedGas {
self.results.iter().map(|r| r.accumulate_gas).sum()
}
pub fn deps(&self) -> impl Iterator<Item = &WorkPackageHash> {
self.sr_lookup.keys().chain(self.context.prerequisites.iter())
}
pub fn dep_count(&self) -> usize {
self.sr_lookup.len() + self.context.prerequisites.len()
}
pub fn check_size(&self) -> bool {
let total: usize =
self.results.iter().filter_map(|r| Some(r.result.as_ref().ok()?.len())).sum();
total + self.auth_output.len() <= MAX_REPORT_ELECTIVE_DATA
}
}
impl MaxEncodedLen for WorkReport {
fn max_encoded_len() -> usize {
MAX_REPORT_ELECTIVE_DATA + 1024
}
}