// Copyright 2017-2020 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Substrate is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . use std::{sync::Arc, panic::UnwindSafe, result, cell::RefCell}; use codec::{Encode, Decode}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, HasherFor, NumberFor}, }; use sp_state_machine::{ self, OverlayedChanges, Ext, ExecutionManager, StateMachine, ExecutionStrategy, backend::Backend as _, StorageProof, }; use sc_executor::{RuntimeVersion, RuntimeInfo, NativeVersion}; use sp_externalities::Extensions; use sp_core::{NativeOrEncoded, NeverNativeValue, traits::CodeExecutor}; use sp_api::{ProofRecorder, InitializeBlock, StorageTransactionCache}; use sc_client_api::{backend, call_executor::CallExecutor}; /// Call executor that executes methods locally, querying all required /// data from local backend. pub struct LocalCallExecutor { backend: Arc, executor: E, } impl LocalCallExecutor { /// Creates new instance of local call executor. pub fn new( backend: Arc, executor: E, ) -> Self { LocalCallExecutor { backend, executor, } } } impl Clone for LocalCallExecutor where E: Clone { fn clone(&self) -> Self { LocalCallExecutor { backend: self.backend.clone(), executor: self.executor.clone(), } } } impl CallExecutor for LocalCallExecutor where B: backend::Backend, E: CodeExecutor + RuntimeInfo + Clone + 'static, Block: BlockT, { type Error = E::Error; type Backend = B; fn call( &self, id: &BlockId, method: &str, call_data: &[u8], strategy: ExecutionStrategy, extensions: Option, ) -> sp_blockchain::Result> { let mut changes = OverlayedChanges::default(); let changes_trie = backend::changes_tries_state_at_block( id, self.backend.changes_trie_storage() )?; // make sure to destroy state before exiting this function let state = self.backend.state_at(*id)?; let return_data = StateMachine::new( &state, changes_trie, &mut changes, &self.executor, method, call_data, extensions.unwrap_or_default(), ).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( strategy.get_manager(), None, ); { let _lock = self.backend.get_import_lock().read(); self.backend.destroy_state(state)?; } Ok(return_data?.into_encoded()) } fn contextual_call< 'a, IB: Fn() -> sp_blockchain::Result<()>, EM: Fn( Result, Self::Error>, Result, Self::Error> ) -> Result, Self::Error>, R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, >( &self, initialize_block_fn: IB, at: &BlockId, method: &str, call_data: &[u8], changes: &RefCell, storage_transaction_cache: Option<&RefCell< StorageTransactionCache >>, initialize_block: InitializeBlock<'a, Block>, execution_manager: ExecutionManager, native_call: Option, recorder: &Option>, extensions: Option, ) -> Result, sp_blockchain::Error> where ExecutionManager: Clone { match initialize_block { InitializeBlock::Do(ref init_block) if init_block.borrow().as_ref().map(|id| id != at).unwrap_or(true) => { initialize_block_fn()?; }, // We don't need to initialize the runtime at a block. _ => {}, } let changes_trie_state = backend::changes_tries_state_at_block(at, self.backend.changes_trie_storage())?; let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut()); // make sure to destroy state before exiting this function let mut state = self.backend.state_at(*at)?; let result = match recorder { Some(recorder) => state.as_trie_backend() .ok_or_else(|| Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof) as Box ) .and_then(|trie_state| { let backend = sp_state_machine::ProvingBackend::new_with_recorder( trie_state, recorder.clone(), ); StateMachine::new( &backend, changes_trie_state, &mut *changes.borrow_mut(), &self.executor, method, call_data, extensions.unwrap_or_default(), ) // TODO: https://github.com/paritytech/substrate/issues/4455 // .with_storage_transaction_cache(storage_transaction_cache.as_mut().map(|c| &mut **c)) .execute_using_consensus_failure_handler(execution_manager, native_call) }), None => StateMachine::new( &state, changes_trie_state, &mut *changes.borrow_mut(), &self.executor, method, call_data, extensions.unwrap_or_default(), ) .with_storage_transaction_cache(storage_transaction_cache.as_mut().map(|c| &mut **c)) .execute_using_consensus_failure_handler(execution_manager, native_call) }; { let _lock = self.backend.get_import_lock().read(); self.backend.destroy_state(state)?; } result.map_err(Into::into) } fn runtime_version(&self, id: &BlockId) -> sp_blockchain::Result { let mut overlay = OverlayedChanges::default(); let changes_trie_state = backend::changes_tries_state_at_block(id, self.backend.changes_trie_storage())?; // make sure to destroy state before exiting this function let state = self.backend.state_at(*id)?; let mut cache = StorageTransactionCache::::default(); let mut ext = Ext::new( &mut overlay, &mut cache, &state, changes_trie_state, None, ); let version = self.executor.runtime_version(&mut ext); { let _lock = self.backend.get_import_lock().read(); self.backend.destroy_state(state)?; } version.map_err(|e| sp_blockchain::Error::VersionInvalid(format!("{:?}", e)).into()) } fn prove_at_trie_state>>( &self, trie_state: &sp_state_machine::TrieBackend>, overlay: &mut OverlayedChanges, method: &str, call_data: &[u8] ) -> Result<(Vec, StorageProof), sp_blockchain::Error> { sp_state_machine::prove_execution_on_trie_backend::<_, _, NumberFor, _>( trie_state, overlay, &self.executor, method, call_data, ) .map_err(Into::into) } fn native_runtime_version(&self) -> Option<&NativeVersion> { Some(self.executor.native_version()) } } impl sp_version::GetRuntimeVersion for LocalCallExecutor where B: backend::Backend, E: CodeExecutor + RuntimeInfo + Clone + 'static, Block: BlockT, { fn native_version(&self) -> &sp_version::NativeVersion { self.executor.native_version() } fn runtime_version( &self, at: &BlockId, ) -> Result { CallExecutor::runtime_version(self, at).map_err(|e| format!("{:?}", e)) } }