1use crate::{
2 hash_encoded, header::OffendersMark, AvailabilityAssurance, CoreCount, EpochIndex, ErasureRoot,
3 MaxTicketsPerBlock, TicketEnvelope, MAX_REPORT_ELECTIVE_DATA, VALS_PER_CORE,
4};
5use bounded_collections::ConstU32;
6use jam_types::{
7 AuthOutput, AuthorizerHash, BoundedVec, CoreIndex, ExtrinsicHash, FixedVec, MaxWorkItems,
8 RefineContext, SegmentTreeRoot, ServiceId, Slot, UnsignedGas, ValIndex, ValSuperMajority,
9 VecMap, WorkPackageHash, WorkReportHash, WorkResult,
10};
11use scale::{ConstEncodedLen, Decode, Encode, MaxEncodedLen};
12
13pub const MAX_VERDICTS_COUNT: usize = 16;
14pub const MAX_OFFENSES_COUNT: usize = 16;
15
16pub type PreimagesXt = Vec<Preimage>;
18pub type TicketsXt = BoundedVec<TicketEnvelope, MaxTicketsPerBlock>;
20pub type AssurancesXt = BoundedVec<AvailabilityAssurance, jam_types::ValCount>;
22pub type GuaranteesXt = BoundedVec<ReportGuarantee, CoreCount>;
24#[derive(Clone, Encode, Decode, Debug, Default)]
26pub struct DisputesXt {
27 pub verdicts: BoundedVec<Verdict, ConstU32<{ MAX_VERDICTS_COUNT as u32 }>>,
29 pub culprits: BoundedVec<CulpritProof, ConstU32<{ MAX_OFFENSES_COUNT as u32 }>>,
31 pub faults: BoundedVec<FaultProof, ConstU32<{ MAX_OFFENSES_COUNT as u32 }>>,
33}
34
35impl DisputesXt {
36 pub fn offenders_mark(&self) -> OffendersMark {
37 let offenders: Vec<_> = self
38 .culprits
39 .iter()
40 .map(|v| v.key)
41 .chain(self.faults.iter().map(|v| v.key))
42 .collect();
43 offenders.try_into().expect("OffendersMark bounds equal culprits + faults")
44 }
45 pub fn implies_offenders_mark(&self, offenders_mark: &OffendersMark) -> bool {
46 self.culprits
47 .iter()
48 .map(|v| v.key)
49 .chain(self.faults.iter().map(|v| v.key))
50 .zip(offenders_mark.iter())
51 .all(|(a, b)| a == *b)
52 }
53}
54
55pub type VerdictVotes = FixedVec<Judgement, ValSuperMajority>;
58
59#[derive(Clone, Encode, Decode, Debug)]
61pub struct Verdict {
62 pub target: WorkReportHash,
64 pub age: EpochIndex,
67 pub votes: VerdictVotes,
69}
70
71#[derive(Clone, Encode, Decode, Debug)]
72pub struct Judgement {
73 pub vote: bool,
74 pub index: ValIndex,
75 pub signature: super::ed25519::Signature,
76}
77
78#[derive(Clone, Encode, Decode, Debug)]
79pub struct CulpritProof {
80 pub report_hash: WorkReportHash,
81 pub key: super::ed25519::Public,
82 pub signature: super::ed25519::Signature,
83}
84
85#[derive(Clone, Encode, Decode, Debug)]
86pub struct FaultProof {
87 pub report_hash: WorkReportHash,
88 pub vote: bool,
89 pub key: super::ed25519::Public,
90 pub signature: super::ed25519::Signature,
91}
92
93#[derive(Clone, Encode, Decode, Debug, Default)]
94pub struct Extrinsic {
95 pub tickets: TicketsXt,
96 pub preimages: PreimagesXt,
97 pub guarantees: GuaranteesXt,
98 pub assurances: AssurancesXt,
99 pub disputes: DisputesXt,
100}
101
102impl Extrinsic {
103 pub fn guarantees_prehashed(&self) -> Vec<(WorkReportHash, Slot, &GuaranteeSignatures)> {
104 self.guarantees
105 .iter()
106 .map(|r| (r.report.hash(), r.slot, &r.signatures))
107 .collect()
108 }
109
110 pub fn hash(&self) -> ExtrinsicHash {
111 let tickets_hash = hash_encoded(&self.tickets);
112 let disputes_hash = hash_encoded(&self.disputes);
113 let preimages_hash = hash_encoded(&self.preimages);
114 let assurances_hash = hash_encoded(&self.assurances);
115 let guarantees_hash = hash_encoded(&self.guarantees_prehashed());
116 let top = (tickets_hash, preimages_hash, guarantees_hash, assurances_hash, disputes_hash);
117 hash_encoded(&top).into()
118 }
119}
120
121#[derive(Clone, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord)]
122pub struct Preimage {
123 pub requester: ServiceId,
124 pub blob: Vec<u8>,
125}
126impl Preimage {
127 pub fn new(requester: ServiceId, blob: impl Into<Vec<u8>>) -> Self {
128 Self { requester, blob: blob.into() }
129 }
130}
131
132#[derive(Clone, Encode, Decode, Debug, MaxEncodedLen)]
134#[cfg_attr(test, derive(PartialEq, Eq))]
135pub struct ReportGuarantee {
136 pub report: WorkReport,
138 pub slot: Slot,
142 pub signatures: GuaranteeSignatures,
146}
147
148pub type GuaranteeSignatures = BoundedVec<ValSignature, ConstU32<{ VALS_PER_CORE as u32 }>>;
149
150#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, MaxEncodedLen)]
151pub struct ValSignature {
152 pub val_index: ValIndex,
153 pub signature: super::ed25519::Signature,
154}
155
156impl ConstEncodedLen for ValSignature {}
157
158#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, MaxEncodedLen)]
160pub struct WorkPackageSpec {
161 pub hash: WorkPackageHash,
163 pub len: u32,
165 pub erasure_root: ErasureRoot,
167 pub exports_root: SegmentTreeRoot,
169 pub exports_count: u16,
171}
172
173impl WorkPackageSpec {
174 pub fn wp_srl(&self) -> (WorkPackageHash, SegmentTreeRoot) {
175 (self.hash, self.exports_root)
176 }
177}
178
179#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
182pub struct WorkReport {
183 pub package_spec: WorkPackageSpec,
185 pub context: RefineContext,
187 pub core_index: CoreIndex,
189 pub authorizer_hash: AuthorizerHash,
192 pub auth_output: AuthOutput,
194 pub sr_lookup: VecMap<WorkPackageHash, SegmentTreeRoot>,
196 pub results: BoundedVec<WorkResult, MaxWorkItems>,
198 #[codec(compact)]
200 pub auth_gas_used: UnsignedGas,
201}
202
203impl WorkReport {
204 pub fn hash(&self) -> WorkReportHash {
206 hash_encoded(self).into()
207 }
208
209 pub fn gas(&self) -> UnsignedGas {
211 self.results.iter().map(|r| r.accumulate_gas).sum()
212 }
213
214 pub fn deps(&self) -> impl Iterator<Item = &WorkPackageHash> {
217 self.sr_lookup.keys().chain(self.context.prerequisites.iter())
218 }
219
220 pub fn dep_count(&self) -> usize {
223 self.sr_lookup.len() + self.context.prerequisites.len()
224 }
225
226 pub fn check_size(&self) -> bool {
228 let total: usize =
229 self.results.iter().filter_map(|r| Some(r.result.as_ref().ok()?.len())).sum();
230 total + self.auth_output.len() <= MAX_REPORT_ELECTIVE_DATA
231 }
232}
233
234impl MaxEncodedLen for WorkReport {
235 fn max_encoded_len() -> usize {
236 MAX_REPORT_ELECTIVE_DATA + 1024
237 }
238}