1#[cfg(not(feature = "std"))]
2extern crate alloc;
3
4use crate::bundle::bundle_v0::{BundleHeaderV0, SealedBundleHeaderV0};
5use crate::execution_receipt::{ExecutionReceipt, ExecutionReceiptMutRef, ExecutionReceiptRef};
6use crate::{
7 DomainId, HeaderHashFor, HeaderNumberFor, OperatorId, OperatorSignature, ProofOfElection,
8};
9#[cfg(not(feature = "std"))]
10use alloc::collections::BTreeSet;
11#[cfg(not(feature = "std"))]
12use alloc::string::String;
13#[cfg(not(feature = "std"))]
14use alloc::vec::Vec;
15use bundle_v0::BundleV0;
16use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode};
17use scale_info::TypeInfo;
18use sp_core::H256;
19use sp_runtime::OpaqueExtrinsic;
20use sp_runtime::traits::{BlakeTwo256, Hash, Header as HeaderT, NumberFor, Zero};
21use sp_weights::Weight;
22use subspace_runtime_primitives::BlockHashFor;
23
24pub mod bundle_v0;
25
26#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
28pub enum SealedBundleHeaderRef<'a, Number, Hash, DomainHeader: HeaderT, Balance> {
29 V0(&'a SealedBundleHeaderV0<Number, Hash, DomainHeader, Balance>),
30}
31
32impl<'a, Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
33 SealedBundleHeaderRef<'a, Number, Hash, DomainHeader, Balance>
34{
35 pub fn pre_hash(&self) -> HeaderHashFor<DomainHeader> {
37 match self {
38 SealedBundleHeaderRef::V0(bundle) => bundle.header.hash(),
39 }
40 }
41
42 pub fn signature(&self) -> &'a OperatorSignature {
44 match self {
45 SealedBundleHeaderRef::V0(bundle) => &bundle.signature,
46 }
47 }
48
49 pub fn proof_of_election(&self) -> &'a ProofOfElection {
51 match self {
52 SealedBundleHeaderRef::V0(bundle) => &bundle.header.proof_of_election,
53 }
54 }
55
56 pub fn receipt(
58 &self,
59 ) -> ExecutionReceiptRef<
60 'a,
61 Number,
62 Hash,
63 HeaderNumberFor<DomainHeader>,
64 HeaderHashFor<DomainHeader>,
65 Balance,
66 > {
67 match self {
68 SealedBundleHeaderRef::V0(bundle) => match &bundle.header.receipt {
69 ExecutionReceipt::V0(receipt) => ExecutionReceiptRef::V0(receipt),
70 },
71 }
72 }
73
74 pub fn slot_number(&self) -> u64 {
75 match self {
76 SealedBundleHeaderRef::V0(bundle) => bundle.header.proof_of_election.slot_number,
77 }
78 }
79
80 pub fn bundle_extrinsics_root(&self) -> HeaderHashFor<DomainHeader> {
81 match self {
82 SealedBundleHeaderRef::V0(bundle) => bundle.header.bundle_extrinsics_root,
83 }
84 }
85}
86
87#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, Copy)]
89pub enum BundleVersion {
90 V0,
92}
93
94#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
96pub enum Bundle<Extrinsic, Number, Hash, DomainHeader: HeaderT, Balance> {
97 V0(BundleV0<Extrinsic, Number, Hash, DomainHeader, Balance>),
99}
100
101impl<Extrinsic, Number, Hash, DomainHeader, Balance>
102 Bundle<Extrinsic, Number, Hash, DomainHeader, Balance>
103where
104 Extrinsic: Encode + Clone,
105 Number: Encode + Zero,
106 Hash: Encode + Default,
107 DomainHeader: HeaderT,
108 Balance: Encode + Zero + Default,
109{
110 pub fn hash(&self) -> H256 {
112 BlakeTwo256::hash_of(self)
113 }
114
115 pub fn domain_id(&self) -> DomainId {
117 match self {
118 Bundle::V0(bundle) => bundle.sealed_header.header.proof_of_election.domain_id,
119 }
120 }
121
122 pub fn extrinsics_root(&self) -> HeaderHashFor<DomainHeader> {
124 match self {
125 Bundle::V0(bundle) => bundle.sealed_header.header.bundle_extrinsics_root,
126 }
127 }
128
129 pub fn operator_id(&self) -> OperatorId {
131 match self {
132 Bundle::V0(bundle) => bundle.sealed_header.header.proof_of_election.operator_id,
133 }
134 }
135
136 pub fn receipt_domain_block_number(&self) -> &HeaderNumberFor<DomainHeader> {
138 match self {
139 Bundle::V0(bundle) => bundle.sealed_header.header.receipt.domain_block_number(),
140 }
141 }
142
143 pub fn into_receipt(
145 self,
146 ) -> ExecutionReceipt<
147 Number,
148 Hash,
149 HeaderNumberFor<DomainHeader>,
150 HeaderHashFor<DomainHeader>,
151 Balance,
152 > {
153 match self {
154 Bundle::V0(bundle) => bundle.sealed_header.header.receipt,
155 }
156 }
157
158 pub fn receipt(
159 &self,
160 ) -> ExecutionReceiptRef<
161 '_,
162 Number,
163 Hash,
164 HeaderNumberFor<DomainHeader>,
165 HeaderHashFor<DomainHeader>,
166 Balance,
167 > {
168 match self {
169 Bundle::V0(bundle) => match &bundle.sealed_header.header.receipt {
170 ExecutionReceipt::V0(er) => ExecutionReceiptRef::V0(er),
171 },
172 }
173 }
174
175 pub fn size(&self) -> u32 {
177 self.encoded_size() as u32
178 }
179
180 pub fn body_size(&self) -> u32 {
182 let extrinsics = match self {
183 Bundle::V0(bundle) => &bundle.extrinsics,
184 };
185
186 extrinsics
187 .iter()
188 .map(|tx| tx.encoded_size() as u32)
189 .sum::<u32>()
190 }
191
192 pub fn body_length(&self) -> usize {
194 let extrinsics = match self {
195 Bundle::V0(bundle) => &bundle.extrinsics,
196 };
197 extrinsics.len()
198 }
199
200 pub fn estimated_weight(&self) -> Weight {
202 match self {
203 Bundle::V0(bundle) => bundle.sealed_header.header.estimated_bundle_weight,
204 }
205 }
206
207 pub fn slot_number(&self) -> u64 {
209 match self {
210 Bundle::V0(bundle) => bundle.sealed_header.header.proof_of_election.slot_number,
211 }
212 }
213
214 pub fn proof_of_election(&self) -> &ProofOfElection {
216 match self {
217 Bundle::V0(bundle) => &bundle.sealed_header.header.proof_of_election,
218 }
219 }
220
221 pub fn sealed_header(&self) -> SealedBundleHeaderRef<'_, Number, Hash, DomainHeader, Balance> {
223 match self {
224 Bundle::V0(bundle) => SealedBundleHeaderRef::V0(&bundle.sealed_header),
225 }
226 }
227
228 pub fn into_extrinsics(self) -> Vec<Extrinsic> {
230 match self {
231 Bundle::V0(bundle) => bundle.extrinsics,
232 }
233 }
234
235 pub fn extrinsics(&self) -> &[Extrinsic] {
237 match self {
238 Bundle::V0(bundle) => &bundle.extrinsics,
239 }
240 }
241
242 pub fn set_extrinsics(&mut self, exts: Vec<Extrinsic>) {
244 match self {
245 Bundle::V0(bundle) => bundle.extrinsics = exts,
246 }
247 }
248
249 pub fn set_bundle_extrinsics_root(&mut self, root: HeaderHashFor<DomainHeader>) {
251 match self {
252 Bundle::V0(bundle) => bundle.sealed_header.header.bundle_extrinsics_root = root,
253 }
254 }
255
256 pub fn execution_receipt_as_mut(
258 &mut self,
259 ) -> ExecutionReceiptMutRef<
260 '_,
261 Number,
262 Hash,
263 HeaderNumberFor<DomainHeader>,
264 HeaderHashFor<DomainHeader>,
265 Balance,
266 > {
267 match self {
268 Bundle::V0(bundle) => match &mut bundle.sealed_header.header.receipt {
269 ExecutionReceipt::V0(er) => ExecutionReceiptMutRef::V0(er),
270 },
271 }
272 }
273
274 pub fn set_estimated_bundle_weight(&mut self, weight: Weight) {
276 match self {
277 Bundle::V0(bundle) => bundle.sealed_header.header.estimated_bundle_weight = weight,
278 }
279 }
280
281 pub fn set_signature(&mut self, signature: OperatorSignature) {
283 match self {
284 Bundle::V0(bundle) => bundle.sealed_header.signature = signature,
285 }
286 }
287
288 pub fn set_proof_of_election(&mut self, poe: ProofOfElection) {
290 match self {
291 Bundle::V0(bundle) => bundle.sealed_header.header.proof_of_election = poe,
292 }
293 }
294}
295
296pub type OpaqueBundle<Number, Hash, DomainHeader, Balance> =
298 Bundle<OpaqueExtrinsic, Number, Hash, DomainHeader, Balance>;
299
300pub type OpaqueBundles<Block, DomainHeader, Balance> =
302 Vec<OpaqueBundle<NumberFor<Block>, BlockHashFor<Block>, DomainHeader, Balance>>;
303
304#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
305pub fn dummy_opaque_bundle<
306 Number: Encode,
307 Hash: Default + Encode,
308 DomainHeader: HeaderT,
309 Balance: Encode,
310>(
311 domain_id: DomainId,
312 operator_id: OperatorId,
313 receipt: ExecutionReceipt<
314 Number,
315 Hash,
316 HeaderNumberFor<DomainHeader>,
317 HeaderHashFor<DomainHeader>,
318 Balance,
319 >,
320) -> OpaqueBundle<Number, Hash, DomainHeader, Balance> {
321 use sp_core::crypto::UncheckedFrom;
322
323 let header = BundleHeaderV0 {
324 proof_of_election: ProofOfElection::dummy(domain_id, operator_id),
325 receipt,
326 estimated_bundle_weight: Default::default(),
327 bundle_extrinsics_root: Default::default(),
328 };
329 let signature = OperatorSignature::unchecked_from([0u8; 64]);
330
331 OpaqueBundle::V0(BundleV0 {
332 sealed_header: SealedBundleHeaderV0::new(header, signature),
333 extrinsics: Vec::new(),
334 })
335}
336
337#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
339pub struct BundleDigest<Hash> {
340 pub header_hash: Hash,
342 pub extrinsics_root: Hash,
344 pub size: u32,
346}
347
348#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq, DecodeWithMemTracking)]
352pub enum InvalidBundleType {
353 #[codec(index = 0)]
355 UndecodableTx(u32),
356 #[codec(index = 1)]
358 OutOfRangeTx(u32),
359 #[codec(index = 2)]
361 IllegalTx(u32),
362 #[codec(index = 3)]
364 InvalidXDM(u32),
365 #[codec(index = 4)]
367 InherentExtrinsic(u32),
368 #[codec(index = 5)]
370 InvalidBundleWeight,
371}
372
373impl InvalidBundleType {
374 pub fn checking_order(&self) -> u64 {
376 let extrinsic_order = match self {
379 Self::UndecodableTx(i) => *i,
380 Self::OutOfRangeTx(i) => *i,
381 Self::IllegalTx(i) => *i,
382 Self::InvalidXDM(i) => *i,
383 Self::InherentExtrinsic(i) => *i,
384 Self::InvalidBundleWeight => u32::MAX,
389 };
390
391 let rule_order = match self {
398 Self::UndecodableTx(_) => 1,
399 Self::OutOfRangeTx(_) => 2,
400 Self::InherentExtrinsic(_) => 3,
401 Self::InvalidXDM(_) => 4,
402 Self::IllegalTx(_) => 5,
403 Self::InvalidBundleWeight => 6,
404 };
405
406 ((extrinsic_order as u64) << 32) | (rule_order as u64)
411 }
412
413 pub fn extrinsic_index(&self) -> Option<u32> {
418 match self {
419 Self::UndecodableTx(i) => Some(*i),
420 Self::OutOfRangeTx(i) => Some(*i),
421 Self::IllegalTx(i) => Some(*i),
422 Self::InvalidXDM(i) => Some(*i),
423 Self::InherentExtrinsic(i) => Some(*i),
424 Self::InvalidBundleWeight => None,
425 }
426 }
427}
428
429#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
430pub enum BundleValidity<Hash> {
431 Invalid(InvalidBundleType),
434 Valid(Hash),
438}
439
440#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
442pub struct InboxedBundle<Hash> {
443 pub bundle: BundleValidity<Hash>,
444 pub extrinsics_root: Hash,
446}
447
448impl<Hash> InboxedBundle<Hash> {
449 pub fn valid(bundle_digest_hash: Hash, extrinsics_root: Hash) -> Self {
450 InboxedBundle {
451 bundle: BundleValidity::Valid(bundle_digest_hash),
452 extrinsics_root,
453 }
454 }
455
456 pub fn invalid(invalid_bundle_type: InvalidBundleType, extrinsics_root: Hash) -> Self {
457 InboxedBundle {
458 bundle: BundleValidity::Invalid(invalid_bundle_type),
459 extrinsics_root,
460 }
461 }
462
463 pub fn is_invalid(&self) -> bool {
464 matches!(self.bundle, BundleValidity::Invalid(_))
465 }
466
467 pub fn invalid_extrinsic_index(&self) -> Option<u32> {
468 match &self.bundle {
469 BundleValidity::Invalid(invalid_bundle_type) => invalid_bundle_type.extrinsic_index(),
470 BundleValidity::Valid(_) => None,
471 }
472 }
473
474 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
475 pub fn dummy(extrinsics_root: Hash) -> Self
476 where
477 Hash: Default,
478 {
479 InboxedBundle {
480 bundle: BundleValidity::Valid(Hash::default()),
481 extrinsics_root,
482 }
483 }
484}