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