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: scale::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: scale::Input>(input: &mut I) -> Result<Self, scale::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
104#[derive(Clone, Encode, Decode, Debug)]
106pub struct ExtrinsicSpec {
107 pub hash: ExtrinsicHash,
109 pub len: u32,
111}
112
113pub type WorkItems = BoundedVec<WorkItem, MaxWorkItems>;
115
116#[derive(Clone, Encode, Decode, Debug)]
119pub struct WorkItem {
120 pub service: ServiceId,
122 pub code_hash: CodeHash,
125 pub payload: WorkPayload,
127 pub refine_gas_limit: UnsignedGas,
129 pub accumulate_gas_limit: UnsignedGas,
131 pub import_segments: WorkItemImportsVec,
133 pub extrinsics: Vec<ExtrinsicSpec>,
135 pub export_count: u16,
137}
138
139pub type WorkItemImportsVec = BoundedVec<ImportSpec, MaxImports>;
141
142#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
144pub struct RefineContext {
145 pub anchor: HeaderHash,
148 pub state_root: StateRootHash,
150 pub beefy_root: MmrPeakHash,
152 pub lookup_anchor: HeaderHash,
159 pub lookup_anchor_slot: Slot,
163 pub prerequisites: VecSet<WorkPackageHash>,
166}
167
168#[derive(Clone, Encode, Decode, Debug)]
172pub struct WorkPackage {
173 pub authorization: Authorization,
175 pub auth_code_host: ServiceId,
177 pub authorizer: Authorizer,
179 pub context: RefineContext,
181 pub items: WorkItems,
183}
184
185#[derive(Clone, Encode, Decode, Debug)]
188pub struct Authorizer {
189 pub code_hash: CodeHash,
191 pub param: AuthParam,
193}
194
195impl Authorizer {
196 pub fn any() -> Self {
197 Self { code_hash: CodeHash::zero(), param: Default::default() }
198 }
199
200 pub fn with_concat<R>(&self, f: impl Fn(&[u8]) -> R) -> R {
201 f(&[&self.code_hash.0[..], &self.param[..]].concat()[..])
202 }
203}
204
205#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
212#[doc(hidden)]
213pub enum WorkError {
214 OutOfGas = 1,
216 Panic = 2,
218 BadExports = 3,
220 BadCode = 4,
224 CodeOversize = 5,
226}
227
228#[derive(Copy, Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
231#[doc(hidden)]
232pub struct RefineLoad {
233 #[codec(compact)]
235 pub gas_used: UnsignedGas,
236 #[codec(compact)]
238 pub imports: u16,
239 #[codec(compact)]
241 pub extrinsic_count: u16,
242 #[codec(compact)]
244 pub extrinsic_size: u32,
245 #[codec(compact)]
247 pub exports: u16,
248}
249
250impl Add for RefineLoad {
251 type Output = Self;
252 fn add(self, rhs: Self) -> Self {
253 Self {
254 gas_used: self.gas_used + rhs.gas_used,
255 imports: self.imports + rhs.imports,
256 extrinsic_count: self.extrinsic_count + rhs.extrinsic_count,
257 extrinsic_size: self.extrinsic_size + rhs.extrinsic_size,
258 exports: self.exports + rhs.exports,
259 }
260 }
261}
262
263impl AddAssign for RefineLoad {
264 fn add_assign(&mut self, rhs: Self) {
265 self.gas_used += rhs.gas_used;
266 self.imports += rhs.imports;
267 self.extrinsic_count += rhs.extrinsic_count;
268 self.extrinsic_size += rhs.extrinsic_size;
269 self.exports += rhs.exports;
270 }
271}
272
273#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
276#[doc(hidden)]
277pub struct WorkResult {
278 pub service: ServiceId,
280 pub code_hash: CodeHash,
283 pub payload_hash: PayloadHash,
285 pub accumulate_gas: UnsignedGas,
287 #[codec(encoded_as = "CompactRefineResult")]
289 pub result: Result<WorkOutput, WorkError>,
290 pub refine_load: RefineLoad,
292}
293
294#[derive(Debug, Encode, Decode)]
297pub struct AccumulateItem {
298 pub package: WorkPackageHash,
300 pub exports_root: SegmentTreeRoot,
303 pub authorizer_hash: AuthorizerHash,
306 pub auth_output: AuthOutput,
309 pub payload: PayloadHash,
311 #[codec(encoded_as = "CompactRefineResult")]
313 pub result: Result<WorkOutput, WorkError>,
314}
315
316#[derive(Debug, Encode, Decode)]
318#[doc(hidden)]
319pub struct AccumulateParams {
320 pub slot: Slot,
322 pub id: ServiceId,
324 pub results: Vec<AccumulateItem>,
326}
327
328#[derive(Debug, Clone, Encode, Decode, Default)]
330pub struct TransferRecord {
331 pub source: ServiceId,
333 pub destination: ServiceId,
335 pub amount: Balance,
337 pub memo: Memo,
339 pub gas_limit: UnsignedGas,
342}
343
344#[derive(Debug, Encode, Decode)]
346#[doc(hidden)]
347pub struct OnTransferParams {
348 pub slot: Slot,
350 pub id: ServiceId,
352 pub transfers: Vec<TransferRecord>,
354}
355
356#[derive(Debug, Encode, Decode)]
358#[doc(hidden)]
359pub struct RefineParams {
360 pub id: ServiceId,
362 pub payload: WorkPayload,
364 pub package_hash: WorkPackageHash,
366 pub context: RefineContext,
368 pub auth_code_hash: CodeHash,
370}
371
372#[derive(Debug, Encode)]
375#[doc(hidden)]
376pub struct RefineParamsRef<'a> {
377 pub id: ServiceId,
379 pub payload: &'a WorkPayload,
381 pub package_hash: &'a WorkPackageHash,
383 pub context: &'a RefineContext,
385 pub auth_code_hash: &'a CodeHash,
387}
388
389#[derive(Debug, Encode)]
392#[doc(hidden)]
393pub struct OnTransferParamsRef<'a> {
394 pub slot: Slot,
396 pub id: ServiceId,
398 pub transfers: &'a [TransferRecord],
400}
401
402#[derive(Debug, Clone, Encode, Decode, MaxEncodedLen)]
406pub struct ServiceInfo {
407 pub code_hash: CodeHash,
409 pub balance: Balance,
411 pub threshold: Balance,
413 pub min_item_gas: UnsignedGas,
416 pub min_memo_gas: UnsignedGas,
419 pub bytes: u64,
421 pub items: u32,
423}
424
425impl scale::ConstEncodedLen for ServiceInfo {}
426struct CompactRefineResult(Result<WorkOutput, WorkError>);
428struct CompactRefineResultRef<'a>(&'a Result<WorkOutput, WorkError>);
429
430impl From<CompactRefineResult> for Result<WorkOutput, WorkError> {
431 fn from(value: CompactRefineResult) -> Self {
432 value.0
433 }
434}
435
436impl<'a> From<&'a Result<WorkOutput, WorkError>> for CompactRefineResultRef<'a> {
437 fn from(value: &'a Result<WorkOutput, WorkError>) -> Self {
438 CompactRefineResultRef(value)
439 }
440}
441
442impl<'a> scale::EncodeAsRef<'a, Result<WorkOutput, WorkError>> for CompactRefineResult {
443 type RefType = CompactRefineResultRef<'a>;
444}
445
446impl Encode for CompactRefineResult {
447 fn encode_to<T: scale::Output + ?Sized>(&self, dest: &mut T) {
448 CompactRefineResultRef(&self.0).encode_to(dest)
449 }
450}
451
452impl Encode for CompactRefineResultRef<'_> {
453 fn encode_to<T: scale::Output + ?Sized>(&self, dest: &mut T) {
454 match &self.0 {
455 Ok(o) => {
456 dest.push_byte(0);
457 o.encode_to(dest)
458 },
459 Err(e) => e.encode_to(dest),
460 }
461 }
462}
463
464impl Decode for CompactRefineResult {
465 fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
466 match input.read_byte()? {
467 0 => Ok(Self(Ok(WorkOutput::decode(input)?))),
468 e => Ok(Self(Err(WorkError::decode(&mut &[e][..])?))),
469 }
470 }
471}
472
473#[cfg(test)]
474mod tests {
475 use super::*;
476
477 #[test]
478 fn compact_refine_result_codec() {
479 let enc_dec = |exp_res, exp_buf: &[u8]| {
480 let buf = CompactRefineResultRef(&exp_res).encode();
481 assert_eq!(buf, exp_buf);
482 let res = CompactRefineResult::decode(&mut &buf[..]).unwrap();
483 assert_eq!(res.0, exp_res);
484 };
485
486 enc_dec(Ok(vec![1, 2, 3].into()), &[0, 3, 1, 2, 3]);
487 enc_dec(Err(WorkError::OutOfGas), &[1]);
488 enc_dec(Err(WorkError::Panic), &[2]);
489 enc_dec(Err(WorkError::BadExports), &[3]);
490 enc_dec(Err(WorkError::BadCode), &[4]);
491 enc_dec(Err(WorkError::CodeOversize), &[5]);
492 }
493}