1use hash_db::{HashDB, Hasher, Prefix};
4use parity_scale_codec::{Codec, Decode, Encode};
5use sc_client_api::{ExecutorProvider, StateBackend, backend};
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, sc_client_api::TrieCacheContext::Trusted)?;
241 let trie_backend = state.as_trie_backend();
242 let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_backend);
243 let sp_core::traits::RuntimeCode {
244 code_fetcher,
245 heap_pages,
246 hash,
247 } = state_runtime_code
248 .runtime_code()
249 .map_err(sp_blockchain::Error::RuntimeCode)?;
250 let runtime_code = RuntimeCode {
251 code: code_fetcher
252 .fetch_runtime_code()
253 .map(|c| c.to_vec())
254 .ok_or(sp_blockchain::Error::RuntimeCode("missing runtime code"))?,
255 heap_pages,
256 hash,
257 };
258 Ok(Self {
259 parent_hash,
260 parent_number,
261 client,
262 state,
263 executor,
264 maybe_storage_changes: None,
265 intermediate_roots: vec![],
266 runtime_code,
267 })
268 }
269
270 fn runtime_code(&self) -> sp_core::traits::RuntimeCode<'_> {
271 sp_core::traits::RuntimeCode {
272 code_fetcher: self,
273 heap_pages: self.runtime_code.heap_pages,
274 hash: self.runtime_code.hash.clone(),
275 }
276 }
277
278 fn call_function<R: Decode>(
279 &self,
280 method: &str,
281 call_data: Vec<u8>,
282 trie_backend: &TrieDeltaBackendFor<Backend::State, Block>,
283 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>,
284 ) -> Result<R, sp_blockchain::Error> {
285 let mut extensions = self
286 .client
287 .execution_extensions()
288 .extensions(self.parent_hash, self.parent_number);
289
290 let runtime_code = self.runtime_code();
291
292 let result = StateMachine::<_, _, _>::new(
293 trie_backend,
294 overlayed_changes,
295 &*self.executor,
296 method,
297 call_data.as_slice(),
298 &mut extensions,
299 &runtime_code,
300 CallContext::Onchain,
301 )
302 .set_parent_hash(self.parent_hash)
303 .execute()?;
304
305 R::decode(&mut result.as_slice())
306 .map_err(|err| sp_blockchain::Error::CallResultDecode("failed to decode Result", err))
307 }
308
309 fn consolidate_storage_changes(&mut self, changes: StorageChanges<HashingFor<Block>>) {
310 let changes = if let Some(mut mapped_changes) = self.maybe_storage_changes.take() {
311 let previous_root = mapped_changes.consolidate_storage_changes(changes);
312 self.intermediate_roots.push(previous_root);
313 mapped_changes
314 } else {
315 changes.into()
316 };
317 self.maybe_storage_changes = Some(changes)
318 }
319
320 pub(crate) fn initialize_block(
321 &self,
322 header: Block::Header,
323 backend: &TrieDeltaBackendFor<Backend::State, Block>,
324 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>,
325 ) -> Result<ExtrinsicInclusionMode, sp_blockchain::Error> {
326 let call_data = header.encode();
327 self.call_function(
328 "Core_initialize_block",
329 call_data,
330 backend,
331 overlayed_changes,
332 )
333 }
334
335 pub(crate) fn apply_extrinsic(
336 &self,
337 extrinsic: ExtrinsicFor<Block>,
338 backend: &TrieDeltaBackendFor<Backend::State, Block>,
339 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>,
340 ) -> Result<ApplyExtrinsicResult, sp_blockchain::Error> {
341 let call_data = extrinsic.encode();
342 self.call_function(
343 "BlockBuilder_apply_extrinsic",
344 call_data,
345 backend,
346 overlayed_changes,
347 )
348 }
349
350 pub(crate) fn finalize_block(
351 &self,
352 backend: &TrieDeltaBackendFor<Backend::State, Block>,
353 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>,
354 ) -> Result<Block::Header, sp_blockchain::Error> {
355 self.call_function(
356 "BlockBuilder_finalize_block",
357 vec![],
358 backend,
359 overlayed_changes,
360 )
361 }
362
363 pub(crate) fn inherent_extrinsics(
364 &self,
365 inherent: InherentData,
366 backend: &TrieDeltaBackendFor<Backend::State, Block>,
367 overlayed_changes: &mut OverlayedChanges<HashingFor<Block>>,
368 ) -> Result<Vec<ExtrinsicFor<Block>>, sp_blockchain::Error> {
369 let call_data = inherent.encode();
370 self.call_function(
371 "BlockBuilder_inherent_extrinsics",
372 call_data,
373 backend,
374 overlayed_changes,
375 )
376 }
377
378 pub(crate) fn collect_storage_changes(
382 &mut self,
383 ) -> Option<CollectedStorageChanges<HashingFor<Block>>> {
384 let mut intermediate_roots = self.intermediate_roots.drain(..).collect::<Vec<_>>();
385 let maybe_storage_changes = self.maybe_storage_changes.take();
388 if let Some(storage_changes) = maybe_storage_changes {
389 intermediate_roots.push(storage_changes.transaction_storage_root);
390 Some(CollectedStorageChanges {
391 storage_changes: storage_changes.into(),
392 intermediate_roots,
393 })
394 } else {
395 None
396 }
397 }
398
399 pub(crate) fn execute_in_transaction<F, R>(
400 &mut self,
401 call: F,
402 ) -> Result<R, sp_blockchain::Error>
403 where
404 F: FnOnce(
405 &Self,
406 &TrieDeltaBackendFor<Backend::State, Block>,
407 &mut OverlayedChanges<HashingFor<Block>>,
408 ) -> TransactionOutcome<Result<R, sp_blockchain::Error>>,
409 R: Decode,
410 {
411 let trie_backend = self.state.as_trie_backend();
412 let mut overlayed_changes = OverlayedChanges::default();
413 let (state_root, delta) = if let Some(changes) = &self.maybe_storage_changes {
414 (changes.transaction_storage_root, Some(&changes.transaction))
415 } else {
416 (*trie_backend.root(), None)
417 };
418 let trie_delta_backend =
419 create_delta_backend_with_maybe_delta(trie_backend, delta, state_root);
420
421 let outcome = call(self, &trie_delta_backend, &mut overlayed_changes);
422 match outcome {
423 TransactionOutcome::Commit(result) => {
424 let state_version = sp_core::storage::StateVersion::V1;
425 let storage_changes = overlayed_changes
426 .drain_storage_changes(&trie_delta_backend, state_version)
427 .map_err(sp_blockchain::Error::StorageChanges)?;
428 self.consolidate_storage_changes(storage_changes);
429 result
430 }
431 TransactionOutcome::Rollback(result) => result,
432 }
433 }
434}