1pub mod execution_receipt_v0;
2
3#[cfg(not(feature = "std"))]
4extern crate alloc;
5
6use crate::bundle::InboxedBundle;
7use crate::execution_receipt::execution_receipt_v0::ExecutionReceiptV0;
8use crate::runtime_decl_for_bundle_producer_election_api::HashT;
9use crate::{
10 ChainId, DomainId, HeaderHashFor, HeaderHashingFor, HeaderNumberFor, OperatorId,
11 OperatorSignature, ProofOfElection,
12};
13#[cfg(not(feature = "std"))]
14use alloc::collections::BTreeSet;
15#[cfg(not(feature = "std"))]
16use alloc::string::String;
17#[cfg(not(feature = "std"))]
18use alloc::vec::Vec;
19use parity_scale_codec::{Decode, Encode};
20use scale_info::TypeInfo;
21use sp_core::H256;
22use sp_runtime::traits::{CheckedAdd, Header as HeaderT, NumberFor, Zero};
23use sp_std::collections::btree_map::BTreeMap;
24use subspace_runtime_primitives::BlockHashFor;
25
26#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, Copy)]
28pub enum ExecutionReceiptVersion {
29 V0,
31}
32
33#[derive(Clone, Debug, Decode, Default, Encode, Eq, PartialEq, TypeInfo)]
34pub struct BlockFees<Balance> {
35 pub consensus_storage_fee: Balance,
37 pub domain_execution_fee: Balance,
40 pub burned_balance: Balance,
42 pub chain_rewards: BTreeMap<ChainId, Balance>,
44}
45
46impl<Balance> BlockFees<Balance>
47where
48 Balance: CheckedAdd + Zero,
49{
50 pub fn new(
51 domain_execution_fee: Balance,
52 consensus_storage_fee: Balance,
53 burned_balance: Balance,
54 chain_rewards: BTreeMap<ChainId, Balance>,
55 ) -> Self {
56 BlockFees {
57 consensus_storage_fee,
58 domain_execution_fee,
59 burned_balance,
60 chain_rewards,
61 }
62 }
63
64 pub fn total_fees(&self) -> Option<Balance> {
66 let total_chain_reward = self
67 .chain_rewards
68 .values()
69 .try_fold(Zero::zero(), |acc: Balance, cr| acc.checked_add(cr))?;
70 self.consensus_storage_fee
71 .checked_add(&self.domain_execution_fee)
72 .and_then(|balance| balance.checked_add(&self.burned_balance))
73 .and_then(|balance| balance.checked_add(&total_chain_reward))
74 }
75}
76
77#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, Default)]
79pub struct Transfers<Balance> {
80 pub transfers_in: BTreeMap<ChainId, Balance>,
82 pub transfers_out: BTreeMap<ChainId, Balance>,
84 pub rejected_transfers_claimed: BTreeMap<ChainId, Balance>,
86 pub transfers_rejected: BTreeMap<ChainId, Balance>,
88}
89
90impl<Balance> Transfers<Balance> {
91 pub fn is_valid(&self, chain_id: ChainId) -> bool {
92 !self.transfers_rejected.contains_key(&chain_id)
93 && !self.transfers_in.contains_key(&chain_id)
94 && !self.transfers_out.contains_key(&chain_id)
95 && !self.rejected_transfers_claimed.contains_key(&chain_id)
96 }
97}
98
99#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Copy, Clone)]
101pub enum ExecutionReceiptRef<'a, Number, Hash, DomainNumber, DomainHash, Balance> {
102 V0(&'a ExecutionReceiptV0<Number, Hash, DomainNumber, DomainHash, Balance>),
103}
104
105impl<'a, Number, Hash, DomainNumber, DomainHash, Balance>
106 ExecutionReceiptRef<'a, Number, Hash, DomainNumber, DomainHash, Balance>
107where
108 Number: Encode + Clone,
109 Hash: Encode + Clone,
110 DomainNumber: Encode + Clone,
111 DomainHash: Encode + Clone,
112 Balance: Encode + Clone,
113{
114 pub fn hash<DomainHashing: HashT<Output = DomainHash>>(&self) -> DomainHash {
115 match self {
116 ExecutionReceiptRef::V0(receipt) => receipt.hash::<DomainHashing>(),
118 }
119 }
120
121 pub fn to_owned_er(self) -> ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance> {
123 match self {
124 ExecutionReceiptRef::V0(er) => ExecutionReceipt::V0(er.clone()),
125 }
126 }
127
128 pub fn consensus_block_number(&self) -> &Number {
130 match self {
131 ExecutionReceiptRef::V0(er) => &er.consensus_block_number,
132 }
133 }
134
135 pub fn version(&self) -> ExecutionReceiptVersion {
137 match self {
138 ExecutionReceiptRef::V0(_) => ExecutionReceiptVersion::V0,
139 }
140 }
141}
142
143#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq)]
145pub enum ExecutionReceiptMutRef<'a, Number, Hash, DomainNumber, DomainHash, Balance> {
146 V0(&'a mut ExecutionReceiptV0<Number, Hash, DomainNumber, DomainHash, Balance>),
147}
148
149#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
151pub enum ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance> {
152 V0(ExecutionReceiptV0<Number, Hash, DomainNumber, DomainHash, Balance>),
153}
154
155impl<Number, Hash, DomainNumber, DomainHash, Balance>
156 ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance>
157where
158 Number: Encode + Zero,
159 Hash: Encode + Default,
160 DomainNumber: Encode + Zero,
161 DomainHash: Clone + Encode + Default + Copy,
162 Balance: Encode + Zero + Default,
163{
164 pub fn domain_block_number(&self) -> &DomainNumber {
166 let ExecutionReceipt::V0(receipt) = self;
167 &receipt.domain_block_number
168 }
169
170 pub fn domain_block_hash(&self) -> &DomainHash {
172 let ExecutionReceipt::V0(receipt) = self;
173 &receipt.domain_block_hash
174 }
175
176 pub fn final_state_root(&self) -> &DomainHash {
178 let ExecutionReceipt::V0(receipt) = self;
179 &receipt.final_state_root
180 }
181
182 pub fn parent_domain_block_receipt_hash(&self) -> &DomainHash {
184 let ExecutionReceipt::V0(receipt) = self;
185 &receipt.parent_domain_block_receipt_hash
186 }
187
188 pub fn consensus_block_number(&self) -> &Number {
190 let ExecutionReceipt::V0(receipt) = self;
191 &receipt.consensus_block_number
192 }
193
194 pub fn consensus_block_hash(&self) -> &Hash {
196 let ExecutionReceipt::V0(receipt) = self;
197 &receipt.consensus_block_hash
198 }
199
200 pub fn inboxed_bundles(&self) -> &[InboxedBundle<DomainHash>] {
202 let ExecutionReceipt::V0(receipt) = self;
203 &receipt.inboxed_bundles
204 }
205
206 pub fn execution_traces(&self) -> &[DomainHash] {
208 let ExecutionReceipt::V0(receipt) = self;
209 &receipt.execution_trace
210 }
211
212 pub fn domain_block_extrinsics_root(&self) -> &DomainHash {
214 let ExecutionReceipt::V0(receipt) = self;
215 &receipt.domain_block_extrinsic_root
216 }
217
218 pub fn block_fees(&self) -> &BlockFees<Balance> {
220 let ExecutionReceipt::V0(receipt) = self;
221 &receipt.block_fees
222 }
223
224 pub fn transfers(&self) -> &Transfers<Balance> {
226 let ExecutionReceipt::V0(receipt) = self;
227 &receipt.transfers
228 }
229
230 pub fn valid_bundle_digests(&self) -> Vec<DomainHash> {
232 let ExecutionReceipt::V0(receipt) = self;
233 receipt.valid_bundle_digests()
234 }
235
236 pub fn bundles_extrinsics_roots(&self) -> Vec<&DomainHash> {
238 let ExecutionReceipt::V0(receipt) = self;
239 receipt.bundles_extrinsics_roots()
240 }
241
242 pub fn valid_bundle_indexes(&self) -> Vec<u32> {
244 let ExecutionReceipt::V0(receipt) = self;
245 receipt.valid_bundle_indexes()
246 }
247
248 pub fn valid_bundle_digest_at(&self, idx: usize) -> Option<DomainHash> {
250 let ExecutionReceipt::V0(receipt) = self;
251 receipt.valid_bundle_digest_at(idx)
252 }
253
254 pub fn set_final_state_root(&mut self, final_state_root: DomainHash) {
256 let ExecutionReceipt::V0(receipt) = self;
257 receipt.final_state_root = final_state_root;
258 }
259
260 pub fn set_inboxed_bundles(&mut self, inboxed_bundles: Vec<InboxedBundle<DomainHash>>) {
262 let ExecutionReceipt::V0(receipt) = self;
263 receipt.inboxed_bundles = inboxed_bundles;
264 }
265
266 pub fn set_domain_block_number(&mut self, domain_block_number: DomainNumber) {
268 let ExecutionReceipt::V0(receipt) = self;
269 receipt.domain_block_number = domain_block_number;
270 }
271
272 pub fn set_consensus_block_number(&mut self, consensus_block_number: Number) {
274 let ExecutionReceipt::V0(receipt) = self;
275 receipt.consensus_block_number = consensus_block_number;
276 }
277
278 pub fn set_consensus_block_hash(&mut self, consensus_block_hash: Hash) {
280 let ExecutionReceipt::V0(receipt) = self;
281 receipt.consensus_block_hash = consensus_block_hash;
282 }
283
284 pub fn set_parent_receipt_hash(&mut self, receipt_hash: DomainHash) {
286 let ExecutionReceipt::V0(receipt) = self;
287 receipt.parent_domain_block_receipt_hash = receipt_hash;
288 }
289
290 pub fn set_execution_traces(&mut self, execution_traces: Vec<DomainHash>) {
291 let ExecutionReceipt::V0(receipt) = self;
292 receipt.execution_trace = execution_traces;
293 }
294
295 pub fn set_execution_trace_root(&mut self, execution_trace_root: H256) {
296 let ExecutionReceipt::V0(receipt) = self;
297 receipt.execution_trace_root = execution_trace_root;
298 }
299
300 pub fn as_execution_receipt_ref(
302 &self,
303 ) -> ExecutionReceiptRef<Number, Hash, DomainNumber, DomainHash, Balance> {
304 let ExecutionReceipt::V0(receipt) = self;
305 ExecutionReceiptRef::V0(receipt)
306 }
307
308 pub fn hash<DomainHashing: HashT<Output = DomainHash>>(&self) -> DomainHash {
310 match self {
311 ExecutionReceipt::V0(receipt) => receipt.hash::<DomainHashing>(),
313 }
314 }
315
316 pub fn version(&self) -> ExecutionReceiptVersion {
318 match self {
319 ExecutionReceipt::V0(_) => ExecutionReceiptVersion::V0,
320 }
321 }
322
323 pub fn genesis(
325 genesis_state_root: DomainHash,
326 genesis_extrinsic_root: DomainHash,
327 genesis_domain_block_hash: DomainHash,
328 execution_receipt_version: ExecutionReceiptVersion,
329 ) -> Self {
330 match execution_receipt_version {
331 ExecutionReceiptVersion::V0 => ExecutionReceipt::V0(ExecutionReceiptV0 {
332 domain_block_number: Zero::zero(),
333 domain_block_hash: genesis_domain_block_hash,
334 domain_block_extrinsic_root: genesis_extrinsic_root,
335 parent_domain_block_receipt_hash: Default::default(),
336 consensus_block_hash: Default::default(),
337 consensus_block_number: Zero::zero(),
338 inboxed_bundles: Vec::new(),
339 final_state_root: genesis_state_root,
340 execution_trace: sp_std::vec![genesis_state_root],
341 execution_trace_root: Default::default(),
342 block_fees: Default::default(),
343 transfers: Default::default(),
344 }),
345 }
346 }
347
348 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
349 pub fn dummy<DomainHashing>(
350 consensus_block_number: Number,
351 consensus_block_hash: Hash,
352 domain_block_number: DomainNumber,
353 parent_domain_block_receipt_hash: DomainHash,
354 ) -> ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance>
355 where
356 DomainHashing: HashT<Output = DomainHash>,
357 {
358 let execution_trace = sp_std::vec![Default::default(), Default::default()];
359 let execution_trace_root = {
360 let trace: Vec<[u8; 32]> = execution_trace
361 .iter()
362 .map(|r: &DomainHash| r.encode().try_into().expect("H256 must fit into [u8; 32]"))
363 .collect();
364 crate::merkle_tree::MerkleTree::from_leaves(trace.as_slice())
365 .root()
366 .expect("Compute merkle root of trace should success")
367 .into()
368 };
369 ExecutionReceipt::V0(ExecutionReceiptV0 {
370 domain_block_number,
371 domain_block_hash: Default::default(),
372 domain_block_extrinsic_root: Default::default(),
373 parent_domain_block_receipt_hash,
374 consensus_block_number,
375 consensus_block_hash,
376 inboxed_bundles: sp_std::vec![InboxedBundle::dummy(Default::default())],
377 final_state_root: Default::default(),
378 execution_trace,
379 execution_trace_root,
380 block_fees: Default::default(),
381 transfers: Default::default(),
382 })
383 }
384}
385
386#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
389pub struct SingletonReceipt<Number, Hash, DomainHeader: HeaderT, Balance> {
390 pub proof_of_election: ProofOfElection,
392 pub receipt: ExecutionReceipt<
394 Number,
395 Hash,
396 HeaderNumberFor<DomainHeader>,
397 HeaderHashFor<DomainHeader>,
398 Balance,
399 >,
400}
401
402impl<Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
403 SingletonReceipt<Number, Hash, DomainHeader, Balance>
404{
405 pub fn hash(&self) -> HeaderHashFor<DomainHeader> {
406 HeaderHashingFor::<DomainHeader>::hash_of(&self)
407 }
408}
409
410#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
412pub struct SealedSingletonReceipt<Number, Hash, DomainHeader: HeaderT, Balance> {
413 pub singleton_receipt: SingletonReceipt<Number, Hash, DomainHeader, Balance>,
415 pub signature: OperatorSignature,
417}
418
419impl<Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
420 SealedSingletonReceipt<Number, Hash, DomainHeader, Balance>
421{
422 pub fn domain_id(&self) -> DomainId {
424 self.singleton_receipt.proof_of_election.domain_id
425 }
426
427 pub fn operator_id(&self) -> OperatorId {
429 self.singleton_receipt.proof_of_election.operator_id
430 }
431
432 pub fn slot_number(&self) -> u64 {
434 self.singleton_receipt.proof_of_election.slot_number
435 }
436
437 pub fn receipt(
439 &self,
440 ) -> &ExecutionReceipt<
441 Number,
442 Hash,
443 HeaderNumberFor<DomainHeader>,
444 HeaderHashFor<DomainHeader>,
445 Balance,
446 > {
447 &self.singleton_receipt.receipt
448 }
449
450 pub fn into_receipt(
452 self,
453 ) -> ExecutionReceipt<
454 Number,
455 Hash,
456 HeaderNumberFor<DomainHeader>,
457 HeaderHashFor<DomainHeader>,
458 Balance,
459 > {
460 self.singleton_receipt.receipt
461 }
462
463 pub fn pre_hash(&self) -> HeaderHashFor<DomainHeader> {
465 HeaderHashingFor::<DomainHeader>::hash_of(&self.singleton_receipt)
466 }
467
468 pub fn size(&self) -> u32 {
470 self.encoded_size() as u32
471 }
472}
473
474pub type ExecutionReceiptFor<DomainHeader, CBlock, Balance> = ExecutionReceipt<
475 NumberFor<CBlock>,
476 BlockHashFor<CBlock>,
477 <DomainHeader as HeaderT>::Number,
478 <DomainHeader as HeaderT>::Hash,
479 Balance,
480>;