referrerpolicy=no-referrer-when-downgrade

sc_service/client/
call_executor.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19use super::{code_provider::CodeProvider, ClientConfig};
20use sc_client_api::{
21	backend, call_executor::CallExecutor, execution_extensions::ExecutionExtensions, HeaderBackend,
22	TrieCacheContext,
23};
24use sc_executor::{RuntimeVersion, RuntimeVersionOf};
25use sp_api::ProofRecorder;
26use sp_core::traits::{CallContext, CodeExecutor};
27use sp_externalities::Extensions;
28use sp_runtime::{
29	generic::BlockId,
30	traits::{Block as BlockT, HashingFor},
31};
32use sp_state_machine::{backend::AsTrieBackend, OverlayedChanges, StateMachine, StorageProof};
33use std::{cell::RefCell, sync::Arc};
34
35/// Call executor that executes methods locally, querying all required
36/// data from local backend.
37pub struct LocalCallExecutor<Block: BlockT, B, E> {
38	backend: Arc<B>,
39	executor: E,
40	code_provider: CodeProvider<Block, B, E>,
41	execution_extensions: Arc<ExecutionExtensions<Block>>,
42}
43
44impl<Block: BlockT, B, E> LocalCallExecutor<Block, B, E>
45where
46	E: CodeExecutor + RuntimeVersionOf + Clone + 'static,
47	B: backend::Backend<Block>,
48{
49	/// Creates new instance of local call executor.
50	pub fn new(
51		backend: Arc<B>,
52		executor: E,
53		client_config: ClientConfig<Block>,
54		execution_extensions: ExecutionExtensions<Block>,
55	) -> sp_blockchain::Result<Self> {
56		let code_provider = CodeProvider::new(&client_config, executor.clone(), backend.clone())?;
57
58		Ok(LocalCallExecutor {
59			backend,
60			executor,
61			code_provider,
62			execution_extensions: Arc::new(execution_extensions),
63		})
64	}
65}
66
67impl<Block: BlockT, B, E> Clone for LocalCallExecutor<Block, B, E>
68where
69	E: Clone,
70{
71	fn clone(&self) -> Self {
72		LocalCallExecutor {
73			backend: self.backend.clone(),
74			executor: self.executor.clone(),
75			code_provider: self.code_provider.clone(),
76			execution_extensions: self.execution_extensions.clone(),
77		}
78	}
79}
80
81impl<B, E, Block> CallExecutor<Block> for LocalCallExecutor<Block, B, E>
82where
83	B: backend::Backend<Block>,
84	E: CodeExecutor + RuntimeVersionOf + Clone + 'static,
85	Block: BlockT,
86{
87	type Error = E::Error;
88
89	type Backend = B;
90
91	fn execution_extensions(&self) -> &ExecutionExtensions<Block> {
92		&self.execution_extensions
93	}
94
95	fn call(
96		&self,
97		at_hash: Block::Hash,
98		method: &str,
99		call_data: &[u8],
100		context: CallContext,
101	) -> sp_blockchain::Result<Vec<u8>> {
102		let mut changes = OverlayedChanges::default();
103		let at_number =
104			self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(at_hash))?;
105		let state = self.backend.state_at(at_hash, context.into())?;
106
107		let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
108		let runtime_code =
109			state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
110
111		let runtime_code = self.code_provider.maybe_override_code(runtime_code, &state, at_hash)?.0;
112
113		let mut extensions = self.execution_extensions.extensions(at_hash, at_number);
114
115		let mut sm = StateMachine::new(
116			&state,
117			&mut changes,
118			&self.executor,
119			method,
120			call_data,
121			&mut extensions,
122			&runtime_code,
123			context,
124		)
125		.set_parent_hash(at_hash);
126
127		sm.execute().map_err(Into::into)
128	}
129
130	fn contextual_call(
131		&self,
132		at_hash: Block::Hash,
133		method: &str,
134		call_data: &[u8],
135		changes: &RefCell<OverlayedChanges<HashingFor<Block>>>,
136		recorder: &Option<ProofRecorder<Block>>,
137		call_context: CallContext,
138		extensions: &RefCell<Extensions>,
139	) -> Result<Vec<u8>, sp_blockchain::Error> {
140		let state = self.backend.state_at(at_hash, call_context.into())?;
141
142		let changes = &mut *changes.borrow_mut();
143
144		// It is important to extract the runtime code here before we create the proof
145		// recorder to not record it. We also need to fetch the runtime code from `state` to
146		// make sure we use the caching layers.
147		let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
148
149		let runtime_code =
150			state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
151		let runtime_code = self.code_provider.maybe_override_code(runtime_code, &state, at_hash)?.0;
152		let mut extensions = extensions.borrow_mut();
153
154		match recorder {
155			Some(recorder) => {
156				let trie_state = state.as_trie_backend();
157
158				let backend = sp_state_machine::TrieBackendBuilder::wrap(&trie_state)
159					.with_recorder(recorder.clone())
160					.build();
161
162				let mut state_machine = StateMachine::new(
163					&backend,
164					changes,
165					&self.executor,
166					method,
167					call_data,
168					&mut extensions,
169					&runtime_code,
170					call_context,
171				)
172				.set_parent_hash(at_hash);
173				state_machine.execute()
174			},
175			None => {
176				let mut state_machine = StateMachine::new(
177					&state,
178					changes,
179					&self.executor,
180					method,
181					call_data,
182					&mut extensions,
183					&runtime_code,
184					call_context,
185				)
186				.set_parent_hash(at_hash);
187				state_machine.execute()
188			},
189		}
190		.map_err(Into::into)
191	}
192
193	fn runtime_version(&self, at_hash: Block::Hash) -> sp_blockchain::Result<RuntimeVersion> {
194		let state = self.backend.state_at(at_hash, backend::TrieCacheContext::Untrusted)?;
195		let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
196
197		let runtime_code =
198			state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
199		self.code_provider
200			.maybe_override_code(runtime_code, &state, at_hash)
201			.map(|(_, v)| v)
202	}
203
204	fn prove_execution(
205		&self,
206		at_hash: Block::Hash,
207		method: &str,
208		call_data: &[u8],
209	) -> sp_blockchain::Result<(Vec<u8>, StorageProof)> {
210		let at_number =
211			self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(at_hash))?;
212		let state = self.backend.state_at(at_hash, TrieCacheContext::Untrusted)?;
213
214		let trie_backend = state.as_trie_backend();
215
216		let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_backend);
217		let runtime_code =
218			state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
219		let runtime_code = self.code_provider.maybe_override_code(runtime_code, &state, at_hash)?.0;
220
221		sp_state_machine::prove_execution_on_trie_backend(
222			trie_backend,
223			&mut Default::default(),
224			&self.executor,
225			method,
226			call_data,
227			&runtime_code,
228			&mut self.execution_extensions.extensions(at_hash, at_number),
229		)
230		.map_err(Into::into)
231	}
232}
233
234impl<B, E, Block> RuntimeVersionOf for LocalCallExecutor<Block, B, E>
235where
236	E: RuntimeVersionOf,
237	Block: BlockT,
238{
239	fn runtime_version(
240		&self,
241		ext: &mut dyn sp_externalities::Externalities,
242		runtime_code: &sp_core::traits::RuntimeCode,
243	) -> Result<sp_version::RuntimeVersion, sc_executor::error::Error> {
244		RuntimeVersionOf::runtime_version(&self.executor, ext, runtime_code)
245	}
246}
247
248impl<Block, B, E> sp_version::GetRuntimeVersionAt<Block> for LocalCallExecutor<Block, B, E>
249where
250	B: backend::Backend<Block>,
251	E: CodeExecutor + RuntimeVersionOf + Clone + 'static,
252	Block: BlockT,
253{
254	fn runtime_version(&self, at: Block::Hash) -> Result<sp_version::RuntimeVersion, String> {
255		CallExecutor::runtime_version(self, at).map_err(|e| e.to_string())
256	}
257}
258
259impl<Block, B, E> sp_version::GetNativeVersion for LocalCallExecutor<Block, B, E>
260where
261	B: backend::Backend<Block>,
262	E: CodeExecutor + sp_version::GetNativeVersion + Clone + 'static,
263	Block: BlockT,
264{
265	fn native_version(&self) -> &sp_version::NativeVersion {
266		self.executor.native_version()
267	}
268}