1use core::ops::{Add, AddAssign};
2
3use crate::simple::{MaxImports, MaxWorkItems};
4
5use super::*;
6use simple::OpaqueBlsPublic;
7
8#[derive(Copy, Clone, Encode, Decode, Debug, Eq, PartialEq)]
11pub struct OpaqueValKeyset {
12 pub ed25519: OpaqueEd25519Public,
14 pub bandersnatch: OpaqueBandersnatchPublic,
16 pub bls: OpaqueBlsPublic,
18 pub metadata: OpaqueValidatorMetadata,
20}
21impl Default for OpaqueValKeyset {
22 fn default() -> Self {
23 Self {
24 ed25519: OpaqueEd25519Public::zero(),
25 bandersnatch: OpaqueBandersnatchPublic::zero(),
26 bls: OpaqueBlsPublic::zero(),
27 metadata: OpaqueValidatorMetadata::zero(),
28 }
29 }
30}
31
32pub type OpaqueValKeysets = FixedVec<OpaqueValKeyset, ValCount>;
34
35#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
38pub enum RootIdentifier {
39 Direct(SegmentTreeRoot),
41 Indirect(WorkPackageHash),
44}
45
46impl From<SegmentTreeRoot> for RootIdentifier {
47 fn from(root: SegmentTreeRoot) -> Self {
48 Self::Direct(root)
49 }
50}
51impl From<WorkPackageHash> for RootIdentifier {
52 fn from(hash: WorkPackageHash) -> Self {
53 Self::Indirect(hash)
54 }
55}
56impl TryFrom<RootIdentifier> for SegmentTreeRoot {
57 type Error = WorkPackageHash;
58 fn try_from(root: RootIdentifier) -> Result<Self, Self::Error> {
59 match root {
60 RootIdentifier::Direct(root) => Ok(root),
61 RootIdentifier::Indirect(hash) => Err(hash),
62 }
63 }
64}
65
66#[derive(Clone, Debug, Eq, PartialEq, Hash)]
68pub struct ImportSpec {
69 pub root: RootIdentifier,
71 pub index: u16,
73}
74
75impl Encode for ImportSpec {
76 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
77 let off = match &self.root {
78 RootIdentifier::Direct(root) => {
79 root.encode_to(dest);
80 0
81 },
82 RootIdentifier::Indirect(hash) => {
83 hash.encode_to(dest);
84 1 << 15
85 },
86 };
87 (self.index + off).encode_to(dest);
88 }
89}
90
91impl Decode for ImportSpec {
92 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
93 let h = Hash::decode(input)?;
94 let i = u16::decode(input)?;
95 let root = if i & (1 << 15) == 0 {
96 SegmentTreeRoot::from(h).into()
97 } else {
98 WorkPackageHash::from(h).into()
99 };
100 Ok(Self { root, index: i & !(1 << 15) })
101 }
102
103 fn encoded_fixed_size() -> Option<usize> {
104 Some(core::mem::size_of::<Hash>() + core::mem::size_of::<u16>())
105 }
106}
107
108#[derive(Clone, Encode, Decode, Debug)]
110pub struct ExtrinsicSpec {
111 pub hash: ExtrinsicHash,
113 pub len: u32,
115}
116
117pub type WorkItems = BoundedVec<WorkItem, MaxWorkItems>;
119
120#[derive(Clone, Encode, Decode, Debug)]
123pub struct WorkItem {
124 pub service: ServiceId,
126 pub code_hash: CodeHash,
129 pub payload: WorkPayload,
131 pub refine_gas_limit: UnsignedGas,
133 pub accumulate_gas_limit: UnsignedGas,
135 pub import_segments: WorkItemImportsVec,
137 pub extrinsics: Vec<ExtrinsicSpec>,
139 pub export_count: u16,
141}
142
143pub type WorkItemImportsVec = BoundedVec<ImportSpec, MaxImports>;
145
146#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
148pub struct RefineContext {
149 pub anchor: HeaderHash,
152 pub state_root: StateRootHash,
154 pub beefy_root: MmrPeakHash,
156 pub lookup_anchor: HeaderHash,
163 pub lookup_anchor_slot: Slot,
167 pub prerequisites: VecSet<WorkPackageHash>,
170}
171
172#[derive(Clone, Encode, Decode, Debug)]
176pub struct WorkPackage {
177 pub authorization: Authorization,
179 pub auth_code_host: ServiceId,
181 pub authorizer: Authorizer,
183 pub context: RefineContext,
185 pub items: WorkItems,
187}
188
189#[derive(Clone, Encode, Decode, Debug)]
192pub struct Authorizer {
193 pub code_hash: CodeHash,
195 pub config: AuthConfig,
197}
198
199impl Authorizer {
200 pub fn any() -> Self {
201 Self { code_hash: CodeHash::zero(), config: Default::default() }
202 }
203
204 pub fn with_concat<R>(&self, f: impl Fn(&[u8]) -> R) -> R {
205 f(&[&self.code_hash.0[..], &self.config[..]].concat()[..])
206 }
207}
208
209#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
216#[doc(hidden)]
217pub enum WorkError {
218 OutOfGas = 1,
220 Panic = 2,
222 BadExports = 3,
224 BadCode = 4,
228 CodeOversize = 5,
230}
231
232#[derive(Copy, Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
235#[doc(hidden)]
236pub struct RefineLoad {
237 #[codec(compact)]
239 pub gas_used: UnsignedGas,
240 #[codec(compact)]
242 pub imports: u16,
243 #[codec(compact)]
245 pub extrinsic_count: u16,
246 #[codec(compact)]
248 pub extrinsic_size: u32,
249 #[codec(compact)]
251 pub exports: u16,
252}
253
254impl Add for RefineLoad {
255 type Output = Self;
256 fn add(self, rhs: Self) -> Self {
257 Self {
258 gas_used: self.gas_used + rhs.gas_used,
259 imports: self.imports + rhs.imports,
260 extrinsic_count: self.extrinsic_count + rhs.extrinsic_count,
261 extrinsic_size: self.extrinsic_size + rhs.extrinsic_size,
262 exports: self.exports + rhs.exports,
263 }
264 }
265}
266
267impl AddAssign for RefineLoad {
268 fn add_assign(&mut self, rhs: Self) {
269 self.gas_used += rhs.gas_used;
270 self.imports += rhs.imports;
271 self.extrinsic_count += rhs.extrinsic_count;
272 self.extrinsic_size += rhs.extrinsic_size;
273 self.exports += rhs.exports;
274 }
275}
276
277#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
280#[doc(hidden)]
281pub struct WorkDigest {
282 pub service: ServiceId,
284 pub code_hash: CodeHash,
287 pub payload_hash: PayloadHash,
289 pub accumulate_gas: UnsignedGas,
291 #[codec(encoded_as = "CompactRefineResult")]
293 pub result: Result<WorkOutput, WorkError>,
294 pub refine_load: RefineLoad,
296}
297
298#[derive(Debug, Encode, Decode)]
301pub struct AccumulateItem {
302 pub package: WorkPackageHash,
304 pub exports_root: SegmentTreeRoot,
307 pub authorizer_hash: AuthorizerHash,
310 pub auth_output: AuthTrace,
313 pub payload: PayloadHash,
315 #[codec(compact)]
317 pub gas_limit: UnsignedGas,
318 #[codec(encoded_as = "CompactRefineResult")]
320 pub result: Result<WorkOutput, WorkError>,
321}
322
323#[derive(Debug, Encode, Decode)]
325#[doc(hidden)]
326pub struct AccumulateParams {
327 #[codec(compact)]
329 pub slot: Slot,
330 #[codec(compact)]
332 pub id: ServiceId,
333 pub results: Vec<AccumulateItem>,
335}
336
337#[derive(Debug, Clone, Encode, Decode, Default)]
339pub struct TransferRecord {
340 pub source: ServiceId,
342 pub destination: ServiceId,
344 pub amount: Balance,
346 pub memo: Memo,
348 pub gas_limit: UnsignedGas,
351}
352
353#[derive(Debug, Encode, Decode)]
355#[doc(hidden)]
356pub struct OnTransferParams {
357 #[codec(compact)]
359 pub slot: Slot,
360 #[codec(compact)]
362 pub id: ServiceId,
363 pub transfers: Vec<TransferRecord>,
365}
366
367#[derive(Debug, Encode)]
370#[doc(hidden)]
371pub struct OnTransferParamsRef<'a> {
372 #[codec(compact)]
374 pub slot: Slot,
375 #[codec(compact)]
377 pub id: ServiceId,
378 pub transfers: &'a [TransferRecord],
380}
381
382#[derive(Debug, Encode, Decode)]
384#[doc(hidden)]
385pub struct RefineParams {
386 #[codec(compact)]
388 pub id: ServiceId,
389 pub payload: WorkPayload,
391 pub package_hash: WorkPackageHash,
393 pub context: RefineContext,
395 pub auth_code_hash: CodeHash,
397}
398
399#[derive(Debug, Encode)]
402#[doc(hidden)]
403pub struct RefineParamsRef<'a> {
404 #[codec(compact)]
406 pub id: ServiceId,
407 pub payload: &'a WorkPayload,
409 pub package_hash: &'a WorkPackageHash,
411 pub context: &'a RefineContext,
413 pub auth_code_hash: &'a CodeHash,
415}
416
417#[derive(Debug, Clone, Encode, Decode, MaxEncodedLen)]
421pub struct ServiceInfo {
422 pub code_hash: CodeHash,
424 #[codec(compact)]
426 pub balance: Balance,
427 #[codec(compact)]
429 pub threshold: Balance,
430 #[codec(compact)]
433 pub min_item_gas: UnsignedGas,
434 #[codec(compact)]
437 pub min_memo_gas: UnsignedGas,
438 #[codec(compact)]
440 pub bytes: u64,
441 #[codec(compact)]
443 pub items: u32,
444}
445
446impl codec::ConstEncodedLen for ServiceInfo {}
447struct CompactRefineResult(Result<WorkOutput, WorkError>);
449struct CompactRefineResultRef<'a>(&'a Result<WorkOutput, WorkError>);
450
451impl From<CompactRefineResult> for Result<WorkOutput, WorkError> {
452 fn from(value: CompactRefineResult) -> Self {
453 value.0
454 }
455}
456
457impl<'a> From<&'a Result<WorkOutput, WorkError>> for CompactRefineResultRef<'a> {
458 fn from(value: &'a Result<WorkOutput, WorkError>) -> Self {
459 CompactRefineResultRef(value)
460 }
461}
462
463impl<'a> codec::EncodeAsRef<'a, Result<WorkOutput, WorkError>> for CompactRefineResult {
464 type RefType = CompactRefineResultRef<'a>;
465}
466
467impl Encode for CompactRefineResult {
468 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
469 CompactRefineResultRef(&self.0).encode_to(dest)
470 }
471}
472
473impl Encode for CompactRefineResultRef<'_> {
474 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
475 match &self.0 {
476 Ok(o) => {
477 dest.push_byte(0);
478 o.encode_to(dest)
479 },
480 Err(e) => e.encode_to(dest),
481 }
482 }
483}
484
485impl Decode for CompactRefineResult {
486 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
487 match input.read_byte()? {
488 0 => Ok(Self(Ok(WorkOutput::decode(input)?))),
489 e => Ok(Self(Err(WorkError::decode(&mut &[e][..])?))),
490 }
491 }
492}
493
494#[cfg(test)]
495mod tests {
496 use super::*;
497
498 #[test]
499 fn compact_refine_result_codec() {
500 let enc_dec = |exp_res, exp_buf: &[u8]| {
501 let buf = CompactRefineResultRef(&exp_res).encode();
502 assert_eq!(buf, exp_buf);
503 let res = CompactRefineResult::decode(&mut &buf[..]).unwrap();
504 assert_eq!(res.0, exp_res);
505 };
506
507 enc_dec(Ok(vec![1, 2, 3].into()), &[0, 3, 1, 2, 3]);
508 enc_dec(Err(WorkError::OutOfGas), &[1]);
509 enc_dec(Err(WorkError::Panic), &[2]);
510 enc_dec(Err(WorkError::BadExports), &[3]);
511 enc_dec(Err(WorkError::BadCode), &[4]);
512 enc_dec(Err(WorkError::CodeOversize), &[5]);
513 }
514}