1use hash_db::{HashDB, Hasher, Prefix};
4use parity_scale_codec::{Codec, Decode, Encode};
5use sc_client_api::{backend, ExecutorProvider, StateBackend};
6use sp_core::offchain::OffchainOverlayedChange;
7use sp_core::traits::{CallContext, CodeExecutor, FetchRuntimeCode};
8use sp_inherents::InherentData;
9use sp_runtime::traits::{Block as BlockT, HashingFor, NumberFor};
10use sp_runtime::{ApplyExtrinsicResult, ExtrinsicInclusionMode, TransactionOutcome};
11use sp_state_machine::backend::AsTrieBackend;
12use sp_state_machine::{
13 BackendTransaction, DBValue, IndexOperation, OverlayedChanges, StateMachine, StorageChanges,
14 StorageKey, StorageValue, TrieBackend, TrieBackendBuilder, TrieBackendStorage,
15};
16use std::borrow::Cow;
17use std::collections::HashMap;
18use std::marker::PhantomData;
19use std::sync::Arc;
20use subspace_runtime_primitives::ExtrinsicFor;
21
22type TrieBackendStorageFor<State, Block> =
23 <State as StateBackend<HashingFor<Block>>>::TrieBackendStorage;
24
25pub(crate) type TrieDeltaBackendFor<'a, State, Block> = TrieBackend<
26 DeltaBackend<'a, TrieBackendStorageFor<State, Block>, HashingFor<Block>>,
27 HashingFor<Block>,
28>;
29
30struct MappedStorageChanges<H: Hasher> {
31 pub main_storage_changes: HashMap<StorageKey, Option<StorageValue>>,
35 pub child_storage_changes: HashMap<StorageKey, HashMap<StorageKey, Option<StorageValue>>>,
37 pub offchain_storage_changes: HashMap<(Vec<u8>, Vec<u8>), OffchainOverlayedChange>,
39 pub transaction: BackendTransaction<H>,
44 pub transaction_storage_root: H::Out,
46 pub transaction_index_changes: Vec<IndexOperation>,
48}
49
50#[derive(Clone)]
51struct RuntimeCode {
52 code: Vec<u8>,
53 heap_pages: Option<u64>,
54 hash: Vec<u8>,
55}
56
57impl<H: Hasher> From<MappedStorageChanges<H>> for StorageChanges<H> {
58 fn from(value: MappedStorageChanges<H>) -> Self {
59 let MappedStorageChanges {
60 main_storage_changes,
61 child_storage_changes,
62 offchain_storage_changes,
63 transaction,
64 transaction_storage_root,
65 transaction_index_changes,
66 } = value;
67 StorageChanges {
68 main_storage_changes: main_storage_changes.into_iter().collect(),
69 child_storage_changes: child_storage_changes
70 .into_iter()
71 .map(|(k, v)| (k, v.into_iter().collect()))
72 .collect(),
73 offchain_storage_changes: offchain_storage_changes.into_iter().collect(),
74 transaction,
75 transaction_storage_root,
76 transaction_index_changes,
77 }
78 }
79}
80
81impl<H: Hasher> From<StorageChanges<H>> for MappedStorageChanges<H> {
82 fn from(value: StorageChanges<H>) -> Self {
83 let StorageChanges {
84 main_storage_changes,
85 child_storage_changes,
86 offchain_storage_changes,
87 transaction,
88 transaction_storage_root,
89 transaction_index_changes,
90 } = value;
91 MappedStorageChanges {
92 main_storage_changes: main_storage_changes.into_iter().collect(),
93 child_storage_changes: child_storage_changes
94 .into_iter()
95 .map(|(k, v)| (k, v.into_iter().collect()))
96 .collect(),
97 offchain_storage_changes: offchain_storage_changes.into_iter().collect(),
98 transaction,
99 transaction_storage_root,
100 transaction_index_changes,
101 }
102 }
103}
104
105impl<H: Hasher> MappedStorageChanges<H> {
106 fn consolidate_storage_changes(&mut self, changes: StorageChanges<H>) -> H::Out {
107 let StorageChanges {
108 main_storage_changes,
109 child_storage_changes,
110 offchain_storage_changes,
111 transaction,
112 transaction_storage_root,
113 mut transaction_index_changes,
114 } = changes;
115 self.main_storage_changes.extend(main_storage_changes);
116 child_storage_changes
117 .into_iter()
118 .for_each(|(k, v)| self.child_storage_changes.entry(k).or_default().extend(v));
119 self.offchain_storage_changes
120 .extend(offchain_storage_changes);
121 self.transaction.consolidate(transaction);
122 self.transaction.purge();
123 self.transaction_index_changes
124 .append(&mut transaction_index_changes);
125 let previous_storage_root = self.transaction_storage_root;
126 self.transaction_storage_root = transaction_storage_root;
127 previous_storage_root
128 }
129}
130
131pub struct CollectedStorageChanges<H: Hasher> {
133 pub storage_changes: StorageChanges<H>,
136 pub intermediate_roots: Vec<H::Out>,
138}
139
140pub fn create_delta_backend<'a, S, H>(
145 backend: &'a TrieBackend<S, H>,
146 delta: &'a BackendTransaction<H>,
147 post_delta_root: H::Out,
148) -> TrieBackend<DeltaBackend<'a, S, H>, H>
149where
150 S: 'a + TrieBackendStorage<H>,
151 H: 'a + Hasher,
152 H::Out: Codec,
153{
154 create_delta_backend_with_maybe_delta(backend, Some(delta), post_delta_root)
155}
156
157fn create_delta_backend_with_maybe_delta<'a, S, H>(
158 backend: &'a TrieBackend<S, H>,
159 maybe_delta: Option<&'a BackendTransaction<H>>,
160 post_delta_root: H::Out,
161) -> TrieBackend<DeltaBackend<'a, S, H>, H>
162where
163 S: 'a + TrieBackendStorage<H>,
164 H: 'a + Hasher,
165 H::Out: Codec,
166{
167 let essence = backend.essence();
168 let delta_backend = DeltaBackend {
169 backend: essence.backend_storage(),
170 delta: maybe_delta,
171 _phantom: PhantomData::<H>,
172 };
173 TrieBackendBuilder::new(delta_backend, post_delta_root).build()
174}
175
176pub struct DeltaBackend<'a, S, H>
179where
180 S: 'a + TrieBackendStorage<H>,
181 H: 'a + Hasher,
182{
183 backend: &'a S,
184 delta: Option<&'a BackendTransaction<H>>,
185 _phantom: PhantomData<H>,
186}
187
188impl<'a, S, H> TrieBackendStorage<H> for DeltaBackend<'a, S, H>
189where
190 S: 'a + TrieBackendStorage<H>,
191 H: 'a + Hasher,
192{
193 fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>, String> {
194 if let Some(db) = &self.delta
195 && let Some(v) = HashDB::get(*db, key, prefix)
196 {
197 Ok(Some(v))
198 } else {
199 Ok(self.backend.get(key, prefix)?)
200 }
201 }
202}
203
204pub(crate) struct TrieBackendApi<Client, Block: BlockT, Backend: backend::Backend<Block>, Exec> {
205 parent_hash: Block::Hash,
206 parent_number: NumberFor<Block>,
207 client: Arc<Client>,
208 state: Backend::State,
209 executor: Arc<Exec>,
210 maybe_storage_changes: Option<MappedStorageChanges<HashingFor<Block>>>,
211 intermediate_roots: Vec<Block::Hash>,
212 runtime_code: RuntimeCode,
213}
214
215impl<Client, Block, Backend, Exec> FetchRuntimeCode for TrieBackendApi<Client, Block, Backend, Exec>
216where
217 Block: BlockT,
218 Backend: backend::Backend<Block>,
219{
220 fn fetch_runtime_code(&self) -> Option<Cow<[u8]>> {
221 Some(Cow::from(&self.runtime_code.code))
222 }
223}
224
225impl<Client, Block, Backend, Exec> TrieBackendApi<Client, Block, Backend, Exec>
226where
227 Block: BlockT,
228 Backend: backend::Backend<Block>,
229 Client: ExecutorProvider<Block>,
230 Exec: CodeExecutor,
231{
232 pub(crate) fn new(
233 parent_hash: Block::Hash,
234 parent_number: NumberFor<Block>,
235 client: Arc<Client>,
236 backend: Arc<Backend>,
237 executor: Arc<Exec>,
238 ) -> Result<Self, sp_blockchain::Error> {
239 let state = backend.state_at(parent_hash)?;
240 let trie_backend = state.as_trie_backend();
241 let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_backend);
242 let sp_core::traits::RuntimeCode {
243 code_fetcher,
244 heap_pages,
245 hash,
246 } = state_runtime_code
247 .runtime_code()
248 .map_err(sp_blockchain::Error::RuntimeCode)?;
249 let runtime_code = RuntimeCode {
250 code: code_fetcher
251 .fetch_runtime_code()
252 .map(|c| c.to_vec())
253 .ok_or(sp_blockchain::Error::RuntimeCode("missing runtime code"))?,
254 heap_pages,
255 hash,
256 };
257 Ok(Self {
258 parent_hash,
259 parent_number,
260 client,
261 state,
262 executor,
263 maybe_storage_changes: None,
264 intermediate_roots: vec![],
265 runtime_code,
266 })
267 }
268
269 fn runtime_code(&self) -> sp_core::traits::RuntimeCode {
270 sp_core::traits::RuntimeCode {
271 code_fetcher: self,
272 heap_pages: self.runtime_code.heap_pages,
273 hash: self.runtime_code.hash.clone(),
274 }
275 }
276
277 fn call_function<R: Decode>(
278 &self,
279 method: &str,
280 call_data: Vec<u8>,
281 trie_backend: &TrieDeltaBackendFor<Backend::State, Block>,
282 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>,
283 ) -> Result<R, sp_blockchain::Error> {
284 let mut extensions = self
285 .client
286 .execution_extensions()
287 .extensions(self.parent_hash, self.parent_number);
288
289 let runtime_code = self.runtime_code();
290
291 let result = StateMachine::<_, _, _>::new(
292 trie_backend,
293 overlayed_changes,
294 &*self.executor,
295 method,
296 call_data.as_slice(),
297 &mut extensions,
298 &runtime_code,
299 CallContext::Onchain,
300 )
301 .set_parent_hash(self.parent_hash)
302 .execute()?;
303
304 R::decode(&mut result.as_slice())
305 .map_err(|err| sp_blockchain::Error::CallResultDecode("failed to decode Result", err))
306 }
307
308 fn consolidate_storage_changes(&mut self, changes: StorageChanges<HashingFor<Block>>) {
309 let changes = if let Some(mut mapped_changes) = self.maybe_storage_changes.take() {
310 let previous_root = mapped_changes.consolidate_storage_changes(changes);
311 self.intermediate_roots.push(previous_root);
312 mapped_changes
313 } else {
314 changes.into()
315 };
316 self.maybe_storage_changes = Some(changes)
317 }
318
319 pub(crate) fn initialize_block(
320 &self,
321 header: Block::Header,
322 backend: &TrieDeltaBackendFor<Backend::State, Block>,
323 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>,
324 ) -> Result<ExtrinsicInclusionMode, sp_blockchain::Error> {
325 let call_data = header.encode();
326 self.call_function(
327 "Core_initialize_block",
328 call_data,
329 backend,
330 overlayed_changes,
331 )
332 }
333
334 pub(crate) fn apply_extrinsic(
335 &self,
336 extrinsic: ExtrinsicFor<Block>,
337 backend: &TrieDeltaBackendFor<Backend::State, Block>,
338 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>,
339 ) -> Result<ApplyExtrinsicResult, sp_blockchain::Error> {
340 let call_data = extrinsic.encode();
341 self.call_function(
342 "BlockBuilder_apply_extrinsic",
343 call_data,
344 backend,
345 overlayed_changes,
346 )
347 }
348
349 pub(crate) fn finalize_block(
350 &self,
351 backend: &TrieDeltaBackendFor<Backend::State, Block>,
352 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>,
353 ) -> Result<Block::Header, sp_blockchain::Error> {
354 self.call_function(
355 "BlockBuilder_finalize_block",
356 vec![],
357 backend,
358 overlayed_changes,
359 )
360 }
361
362 pub(crate) fn inherent_extrinsics(
363 &self,
364 inherent: InherentData,
365 backend: &TrieDeltaBackendFor<Backend::State, Block>,
366 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>,
367 ) -> Result<Vec<ExtrinsicFor<Block>>, sp_blockchain::Error> {
368 let call_data = inherent.encode();
369 self.call_function(
370 "BlockBuilder_inherent_extrinsics",
371 call_data,
372 backend,
373 overlayed_changes,
374 )
375 }
376
377 pub(crate) fn collect_storage_changes(
381 &mut self,
382 ) -> Option<CollectedStorageChanges<HashingFor<Block>>> {
383 let mut intermediate_roots = self.intermediate_roots.drain(..).collect::<Vec<_>>();
384 let maybe_storage_changes = self.maybe_storage_changes.take();
387 if let Some(storage_changes) = maybe_storage_changes {
388 intermediate_roots.push(storage_changes.transaction_storage_root);
389 Some(CollectedStorageChanges {
390 storage_changes: storage_changes.into(),
391 intermediate_roots,
392 })
393 } else {
394 None
395 }
396 }
397
398 pub(crate) fn execute_in_transaction<F, R>(
399 &mut self,
400 call: F,
401 ) -> Result<R, sp_blockchain::Error>
402 where
403 F: FnOnce(
404 &Self,
405 &TrieDeltaBackendFor<Backend::State, Block>,
406 &mut OverlayedChanges<HashingFor<Block>>,
407 ) -> TransactionOutcome<Result<R, sp_blockchain::Error>>,
408 R: Decode,
409 {
410 let trie_backend = self.state.as_trie_backend();
411 let mut overlayed_changes = OverlayedChanges::default();
412 let (state_root, delta) = if let Some(changes) = &self.maybe_storage_changes {
413 (changes.transaction_storage_root, Some(&changes.transaction))
414 } else {
415 (*trie_backend.root(), None)
416 };
417 let trie_delta_backend =
418 create_delta_backend_with_maybe_delta(trie_backend, delta, state_root);
419
420 let outcome = call(self, &trie_delta_backend, &mut overlayed_changes);
421 match outcome {
422 TransactionOutcome::Commit(result) => {
423 let state_version = sp_core::storage::StateVersion::V1;
424 let storage_changes = overlayed_changes
425 .drain_storage_changes(&trie_delta_backend, state_version)
426 .map_err(sp_blockchain::Error::StorageChanges)?;
427 self.consolidate_storage_changes(storage_changes);
428 result
429 }
430 TransactionOutcome::Rollback(result) => result,
431 }
432 }
433}