subspace_runtime/
object_mapping.rs

1//! Object mapping extraction code.
2//! This code must be kept in sync with `test/subspace-test-runtime/src/lib.rs`.
3
4use crate::{Block, Runtime, RuntimeCall};
5use parity_scale_codec::{Compact, CompactLen, Encode};
6use sp_std::prelude::*;
7use subspace_core_primitives::hashes;
8use subspace_core_primitives::objects::{BlockObject, BlockObjectMapping};
9use subspace_runtime_primitives::MAX_CALL_RECURSION_DEPTH;
10
11/// Extract the nested `pallet-utility` object mappings from `call`.
12///
13/// Object mappings are currently ignored if nested within unprivileged multisig `RuntimeCalls`,
14/// privileged sudo, collective, and scheduler `RuntimeCall`s, and democracy nested `BoundedCall`s.
15// TODO:
16// - add start and end nesting closures to nested_call_iter(), so we can modify and restore
17//   the base offset
18// - convert this code to use nested_call_iter(), and remove the recursion depth limit
19// - extract other nested calls: sudo, collective, multisig, scheduler, democracy (BoundedCall)
20pub(crate) fn extract_utility_block_object_mapping(
21    mut base_offset: u32,
22    objects: &mut Vec<BlockObject>,
23    call: &pallet_utility::Call<Runtime>,
24    mut recursion_depth_left: u16,
25) {
26    if recursion_depth_left == 0 {
27        return;
28    }
29
30    recursion_depth_left -= 1;
31
32    // Add enum variant to the base offset.
33    base_offset += 1;
34
35    match call {
36        pallet_utility::Call::batch { calls }
37        | pallet_utility::Call::batch_all { calls }
38        | pallet_utility::Call::force_batch { calls } => {
39            base_offset += Compact::compact_len(&(calls.len() as u32)) as u32;
40
41            for call in calls {
42                extract_call_block_object_mapping(base_offset, objects, call, recursion_depth_left);
43
44                base_offset += call.encoded_size() as u32;
45            }
46        }
47        pallet_utility::Call::as_derivative { index, call } => {
48            base_offset += index.encoded_size() as u32;
49
50            extract_call_block_object_mapping(
51                base_offset,
52                objects,
53                call.as_ref(),
54                recursion_depth_left,
55            );
56        }
57        pallet_utility::Call::dispatch_as { as_origin, call } => {
58            base_offset += as_origin.encoded_size() as u32;
59
60            extract_call_block_object_mapping(
61                base_offset,
62                objects,
63                call.as_ref(),
64                recursion_depth_left,
65            );
66        }
67        pallet_utility::Call::with_weight { call, .. } => {
68            extract_call_block_object_mapping(
69                base_offset,
70                objects,
71                call.as_ref(),
72                recursion_depth_left,
73            );
74        }
75        pallet_utility::Call::__Ignore(_, _) => {
76            // Ignore.
77        }
78    }
79}
80
81/// Extract the object mappings from `call`.
82pub(crate) fn extract_call_block_object_mapping(
83    mut base_offset: u32,
84    objects: &mut Vec<BlockObject>,
85    call: &RuntimeCall,
86    recursion_depth_left: u16,
87) {
88    // Add RuntimeCall enum variant to the base offset.
89    base_offset += 1;
90
91    match call {
92        // Extract the actual object mappings.
93        RuntimeCall::System(frame_system::Call::remark { remark }) => {
94            objects.push(BlockObject {
95                hash: hashes::blake3_hash(remark),
96                // Add frame_system::Call enum variant to the base offset.
97                offset: base_offset + 1,
98            });
99        }
100        RuntimeCall::System(frame_system::Call::remark_with_event { remark }) => {
101            objects.push(BlockObject {
102                hash: hashes::blake3_hash(remark),
103                // Add frame_system::Call enum variant to the base offset.
104                offset: base_offset + 1,
105            });
106        }
107
108        // Recursively extract object mappings for the call.
109        RuntimeCall::Utility(call) => {
110            extract_utility_block_object_mapping(base_offset, objects, call, recursion_depth_left)
111        }
112        // Other calls don't contain object mappings.
113        _ => {}
114    }
115}
116
117/// Extract the object mappings from `block`.
118pub(crate) fn extract_block_object_mapping(block: Block) -> BlockObjectMapping {
119    let mut block_object_mapping = BlockObjectMapping::default();
120    let mut base_offset =
121        block.header.encoded_size() + Compact::compact_len(&(block.extrinsics.len() as u32));
122    for extrinsic in block.extrinsics {
123        let preamble_size = extrinsic.preamble.encoded_size();
124        // Extrinsic starts with vector length followed by preamble and
125        // `function` encoding.
126        let base_extrinsic_offset = base_offset
127            + Compact::compact_len(&((preamble_size + extrinsic.function.encoded_size()) as u32))
128            + preamble_size;
129
130        extract_call_block_object_mapping(
131            base_extrinsic_offset as u32,
132            block_object_mapping.objects_mut(),
133            &extrinsic.function,
134            MAX_CALL_RECURSION_DEPTH as u16,
135        );
136
137        base_offset += extrinsic.encoded_size();
138    }
139
140    block_object_mapping
141}