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, 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)]
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 Number,
162 Hash,
163 HeaderNumberFor<DomainHeader>,
164 HeaderHashFor<DomainHeader>,
165 Balance,
166 > {
167 match self {
168 Bundle::V0(bundle) => match &bundle.sealed_header.header.receipt {
169 ExecutionReceipt::V0(er) => ExecutionReceiptRef::V0(er),
170 },
171 }
172 }
173
174 pub fn size(&self) -> u32 {
176 self.encoded_size() as u32
177 }
178
179 pub fn body_size(&self) -> u32 {
181 let extrinsics = match self {
182 Bundle::V0(bundle) => &bundle.extrinsics,
183 };
184
185 extrinsics
186 .iter()
187 .map(|tx| tx.encoded_size() as u32)
188 .sum::<u32>()
189 }
190
191 pub fn body_length(&self) -> usize {
193 let extrinsics = match self {
194 Bundle::V0(bundle) => &bundle.extrinsics,
195 };
196 extrinsics.len()
197 }
198
199 pub fn estimated_weight(&self) -> Weight {
201 match self {
202 Bundle::V0(bundle) => bundle.sealed_header.header.estimated_bundle_weight,
203 }
204 }
205
206 pub fn slot_number(&self) -> u64 {
208 match self {
209 Bundle::V0(bundle) => bundle.sealed_header.header.proof_of_election.slot_number,
210 }
211 }
212
213 pub fn proof_of_election(&self) -> &ProofOfElection {
215 match self {
216 Bundle::V0(bundle) => &bundle.sealed_header.header.proof_of_election,
217 }
218 }
219
220 pub fn sealed_header(&self) -> SealedBundleHeaderRef<Number, Hash, DomainHeader, Balance> {
222 match self {
223 Bundle::V0(bundle) => SealedBundleHeaderRef::V0(&bundle.sealed_header),
224 }
225 }
226
227 pub fn into_extrinsics(self) -> Vec<Extrinsic> {
229 match self {
230 Bundle::V0(bundle) => bundle.extrinsics,
231 }
232 }
233
234 pub fn extrinsics(&self) -> &[Extrinsic] {
236 match self {
237 Bundle::V0(bundle) => &bundle.extrinsics,
238 }
239 }
240
241 pub fn set_extrinsics(&mut self, exts: Vec<Extrinsic>) {
243 match self {
244 Bundle::V0(bundle) => bundle.extrinsics = exts,
245 }
246 }
247
248 pub fn set_bundle_extrinsics_root(&mut self, root: HeaderHashFor<DomainHeader>) {
250 match self {
251 Bundle::V0(bundle) => bundle.sealed_header.header.bundle_extrinsics_root = root,
252 }
253 }
254
255 pub fn execution_receipt_as_mut(
257 &mut self,
258 ) -> ExecutionReceiptMutRef<
259 Number,
260 Hash,
261 HeaderNumberFor<DomainHeader>,
262 HeaderHashFor<DomainHeader>,
263 Balance,
264 > {
265 match self {
266 Bundle::V0(bundle) => match &mut bundle.sealed_header.header.receipt {
267 ExecutionReceipt::V0(er) => ExecutionReceiptMutRef::V0(er),
268 },
269 }
270 }
271
272 pub fn set_estimated_bundle_weight(&mut self, weight: Weight) {
274 match self {
275 Bundle::V0(bundle) => bundle.sealed_header.header.estimated_bundle_weight = weight,
276 }
277 }
278
279 pub fn set_signature(&mut self, signature: OperatorSignature) {
281 match self {
282 Bundle::V0(bundle) => bundle.sealed_header.signature = signature,
283 }
284 }
285
286 pub fn set_proof_of_election(&mut self, poe: ProofOfElection) {
288 match self {
289 Bundle::V0(bundle) => bundle.sealed_header.header.proof_of_election = poe,
290 }
291 }
292}
293
294pub type OpaqueBundle<Number, Hash, DomainHeader, Balance> =
296 Bundle<OpaqueExtrinsic, Number, Hash, DomainHeader, Balance>;
297
298pub type OpaqueBundles<Block, DomainHeader, Balance> =
300 Vec<OpaqueBundle<NumberFor<Block>, BlockHashFor<Block>, DomainHeader, Balance>>;
301
302#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
303pub fn dummy_opaque_bundle<
304 Number: Encode,
305 Hash: Default + Encode,
306 DomainHeader: HeaderT,
307 Balance: Encode,
308>(
309 domain_id: DomainId,
310 operator_id: OperatorId,
311 receipt: ExecutionReceipt<
312 Number,
313 Hash,
314 HeaderNumberFor<DomainHeader>,
315 HeaderHashFor<DomainHeader>,
316 Balance,
317 >,
318) -> OpaqueBundle<Number, Hash, DomainHeader, Balance> {
319 use sp_core::crypto::UncheckedFrom;
320
321 let header = BundleHeaderV0 {
322 proof_of_election: ProofOfElection::dummy(domain_id, operator_id),
323 receipt,
324 estimated_bundle_weight: Default::default(),
325 bundle_extrinsics_root: Default::default(),
326 };
327 let signature = OperatorSignature::unchecked_from([0u8; 64]);
328
329 OpaqueBundle::V0(BundleV0 {
330 sealed_header: SealedBundleHeaderV0::new(header, signature),
331 extrinsics: Vec::new(),
332 })
333}
334
335#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
337pub struct BundleDigest<Hash> {
338 pub header_hash: Hash,
340 pub extrinsics_root: Hash,
342 pub size: u32,
344}
345
346#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
350pub enum InvalidBundleType {
351 #[codec(index = 0)]
353 UndecodableTx(u32),
354 #[codec(index = 1)]
356 OutOfRangeTx(u32),
357 #[codec(index = 2)]
359 IllegalTx(u32),
360 #[codec(index = 3)]
362 InvalidXDM(u32),
363 #[codec(index = 4)]
365 InherentExtrinsic(u32),
366 #[codec(index = 5)]
368 InvalidBundleWeight,
369}
370
371impl InvalidBundleType {
372 pub fn checking_order(&self) -> u64 {
374 let extrinsic_order = match self {
377 Self::UndecodableTx(i) => *i,
378 Self::OutOfRangeTx(i) => *i,
379 Self::IllegalTx(i) => *i,
380 Self::InvalidXDM(i) => *i,
381 Self::InherentExtrinsic(i) => *i,
382 Self::InvalidBundleWeight => u32::MAX,
387 };
388
389 let rule_order = match self {
396 Self::UndecodableTx(_) => 1,
397 Self::OutOfRangeTx(_) => 2,
398 Self::InherentExtrinsic(_) => 3,
399 Self::InvalidXDM(_) => 4,
400 Self::IllegalTx(_) => 5,
401 Self::InvalidBundleWeight => 6,
402 };
403
404 ((extrinsic_order as u64) << 32) | (rule_order as u64)
409 }
410
411 pub fn extrinsic_index(&self) -> Option<u32> {
416 match self {
417 Self::UndecodableTx(i) => Some(*i),
418 Self::OutOfRangeTx(i) => Some(*i),
419 Self::IllegalTx(i) => Some(*i),
420 Self::InvalidXDM(i) => Some(*i),
421 Self::InherentExtrinsic(i) => Some(*i),
422 Self::InvalidBundleWeight => None,
423 }
424 }
425}
426
427#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
428pub enum BundleValidity<Hash> {
429 Invalid(InvalidBundleType),
432 Valid(Hash),
436}
437
438#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
440pub struct InboxedBundle<Hash> {
441 pub bundle: BundleValidity<Hash>,
442 pub extrinsics_root: Hash,
444}
445
446impl<Hash> InboxedBundle<Hash> {
447 pub fn valid(bundle_digest_hash: Hash, extrinsics_root: Hash) -> Self {
448 InboxedBundle {
449 bundle: BundleValidity::Valid(bundle_digest_hash),
450 extrinsics_root,
451 }
452 }
453
454 pub fn invalid(invalid_bundle_type: InvalidBundleType, extrinsics_root: Hash) -> Self {
455 InboxedBundle {
456 bundle: BundleValidity::Invalid(invalid_bundle_type),
457 extrinsics_root,
458 }
459 }
460
461 pub fn is_invalid(&self) -> bool {
462 matches!(self.bundle, BundleValidity::Invalid(_))
463 }
464
465 pub fn invalid_extrinsic_index(&self) -> Option<u32> {
466 match &self.bundle {
467 BundleValidity::Invalid(invalid_bundle_type) => invalid_bundle_type.extrinsic_index(),
468 BundleValidity::Valid(_) => None,
469 }
470 }
471
472 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
473 pub fn dummy(extrinsics_root: Hash) -> Self
474 where
475 Hash: Default,
476 {
477 InboxedBundle {
478 bundle: BundleValidity::Valid(Hash::default()),
479 extrinsics_root,
480 }
481 }
482}