1
// Copyright 2024 Moonbeam foundation
2
// This file is part of Moonbeam.
3

            
4
// Moonbeam is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Moonbeam is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
use crate::lazy_loading::wasm_override::WasmOverride;
18
use crate::lazy_loading::wasm_substitutes::WasmSubstitutes;
19
use moonbeam_cli_opt::LazyLoadingConfig;
20
use sc_client_api::{
21
	backend, call_executor::CallExecutor, execution_extensions::ExecutionExtensions, HeaderBackend,
22
};
23
use sc_executor::{NativeVersion, RuntimeVersion, RuntimeVersionOf};
24
use sc_service::ClientConfig;
25
use sp_api::ProofRecorder;
26
use sp_core::traits::{CallContext, CodeExecutor, Externalities, RuntimeCode};
27
use sp_runtime::{
28
	generic::BlockId,
29
	traits::{Block as BlockT, HashingFor},
30
};
31
use sp_state_machine::{backend::AsTrieBackend, Ext, OverlayedChanges, StateMachine, StorageProof};
32
use sp_version::{GetNativeVersion, GetRuntimeVersionAt};
33
use std::{cell::RefCell, path::PathBuf, sync::Arc};
34

            
35
/// Call executor that executes methods locally, querying all required
36
/// data from local backend.
37
pub struct LazyLoadingCallExecutor<Block: BlockT, B, E> {
38
	backend: Arc<B>,
39
	lazy_loading_config: LazyLoadingConfig,
40
	executor: E,
41
	wasm_override: Arc<Option<WasmOverride>>,
42
	wasm_substitutes: WasmSubstitutes<Block, E, B>,
43
	wasmtime_precompiled_path: Option<PathBuf>,
44
	execution_extensions: Arc<ExecutionExtensions<Block>>,
45
}
46

            
47
impl<Block: BlockT + sp_runtime::DeserializeOwned, B, E> LazyLoadingCallExecutor<Block, B, E>
48
where
49
	E: CodeExecutor + RuntimeVersionOf + Clone + 'static,
50
	B: backend::Backend<Block>,
51
	Block::Hash: From<sp_core::H256>,
52
{
53
	/// Creates new instance of local call executor.
54
	pub fn new(
55
		backend: Arc<B>,
56
		lazy_loading_config: &LazyLoadingConfig,
57
		executor: E,
58
		client_config: ClientConfig<Block>,
59
		execution_extensions: ExecutionExtensions<Block>,
60
	) -> sp_blockchain::Result<Self> {
61
		let wasm_override = client_config
62
			.wasm_runtime_overrides
63
			.as_ref()
64
			.map(|p| WasmOverride::new(p.clone(), &executor))
65
			.transpose()?;
66

            
67
		let wasm_substitutes = WasmSubstitutes::new(
68
			client_config.wasm_runtime_substitutes,
69
			executor.clone(),
70
			backend.clone(),
71
		)?;
72

            
73
		Ok(LazyLoadingCallExecutor {
74
			backend,
75
			lazy_loading_config: (*lazy_loading_config).clone(),
76
			executor,
77
			wasm_override: Arc::new(wasm_override),
78
			wasm_substitutes,
79
			wasmtime_precompiled_path: client_config.wasmtime_precompiled,
80
			execution_extensions: Arc::new(execution_extensions),
81
		})
82
	}
83

            
84
	/// Check if local runtime code overrides are enabled and one is available
85
	/// for the given `BlockId`. If yes, return it; otherwise return the same
86
	/// `RuntimeCode` instance that was passed.
87
	fn check_override<'a>(
88
		&'a self,
89
		onchain_code: RuntimeCode<'a>,
90
		state: &B::State,
91
		hash: Block::Hash,
92
	) -> sp_blockchain::Result<(RuntimeCode<'a>, RuntimeVersion)>
93
	where
94
		Block: BlockT,
95
		B: backend::Backend<Block>,
96
	{
97
		let on_chain_version = self.on_chain_runtime_version(&onchain_code, state)?;
98
		let code_and_version = if let Some(d) = self.wasm_override.as_ref().as_ref().and_then(|o| {
99
			o.get(
100
				&on_chain_version.spec_version,
101
				onchain_code.heap_pages,
102
				&on_chain_version.spec_name,
103
			)
104
		}) {
105
			log::debug!(target: "wasm_overrides", "using WASM override for block {}", hash);
106
			d
107
		} else if let Some(s) =
108
			self.wasm_substitutes
109
				.get(on_chain_version.spec_version, onchain_code.heap_pages, hash)
110
		{
111
			log::debug!(target: "wasm_substitutes", "Using WASM substitute for block {:?}", hash);
112
			s
113
		} else {
114
			log::debug!(
115
				target: "wasm_overrides",
116
				"Neither WASM override nor substitute available for block {hash}, using onchain code",
117
			);
118
			(onchain_code, on_chain_version)
119
		};
120

            
121
		Ok(code_and_version)
122
	}
123

            
124
	/// Returns the on chain runtime version.
125
	fn on_chain_runtime_version(
126
		&self,
127
		code: &RuntimeCode,
128
		state: &B::State,
129
	) -> sp_blockchain::Result<RuntimeVersion> {
130
		let mut overlay = OverlayedChanges::default();
131

            
132
		let mut ext = Ext::new(&mut overlay, state, None);
133

            
134
		self.executor
135
			.runtime_version(&mut ext, code)
136
			.map_err(|e| sp_blockchain::Error::VersionInvalid(e.to_string()))
137
	}
138
}
139

            
140
impl<Block: BlockT + sp_runtime::DeserializeOwned, B, E> Clone
141
	for LazyLoadingCallExecutor<Block, B, E>
142
where
143
	E: Clone,
144
{
145
	fn clone(&self) -> Self {
146
		LazyLoadingCallExecutor {
147
			backend: self.backend.clone(),
148
			lazy_loading_config: self.lazy_loading_config.clone(),
149
			executor: self.executor.clone(),
150
			wasm_override: self.wasm_override.clone(),
151
			wasm_substitutes: self.wasm_substitutes.clone(),
152
			wasmtime_precompiled_path: self.wasmtime_precompiled_path.clone(),
153
			execution_extensions: self.execution_extensions.clone(),
154
		}
155
	}
156
}
157

            
158
impl<B, E, Block> CallExecutor<Block> for LazyLoadingCallExecutor<Block, B, E>
159
where
160
	B: backend::Backend<Block>,
161
	E: CodeExecutor + RuntimeVersionOf + Clone + 'static,
162
	Block: BlockT + sp_runtime::DeserializeOwned,
163
	Block::Hash: From<sp_core::H256>,
164
{
165
	type Error = E::Error;
166

            
167
	type Backend = B;
168

            
169
	fn execution_extensions(&self) -> &ExecutionExtensions<Block> {
170
		&self.execution_extensions
171
	}
172

            
173
	fn call(
174
		&self,
175
		at_hash: Block::Hash,
176
		method: &str,
177
		call_data: &[u8],
178
		context: CallContext,
179
	) -> sp_blockchain::Result<Vec<u8>> {
180
		let mut changes = OverlayedChanges::default();
181
		let at_number = self
182
			.backend
183
			.blockchain()
184
			.expect_block_number_from_id(&BlockId::Hash(at_hash))?;
185
		let state = self.backend.state_at(at_hash)?;
186

            
187
		let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
188
		let runtime_code = state_runtime_code
189
			.runtime_code()
190
			.map_err(sp_blockchain::Error::RuntimeCode)?;
191

            
192
		let runtime_code = self.check_override(runtime_code, &state, at_hash)?.0;
193

            
194
		let mut extensions = self.execution_extensions.extensions(at_hash, at_number);
195

            
196
		let mut sm = StateMachine::new(
197
			&state,
198
			&mut changes,
199
			&self.executor,
200
			method,
201
			call_data,
202
			&mut extensions,
203
			&runtime_code,
204
			context,
205
		)
206
		.set_parent_hash(at_hash);
207

            
208
		sm.execute().map_err(Into::into)
209
	}
210

            
211
	fn contextual_call(
212
		&self,
213
		at_hash: Block::Hash,
214
		method: &str,
215
		call_data: &[u8],
216
		changes: &RefCell<OverlayedChanges<HashingFor<Block>>>,
217
		// TODO: Confirm that `recorder` is not needed.
218
		_recorder: &Option<ProofRecorder<Block>>,
219
		call_context: CallContext,
220
		extensions: &RefCell<sp_externalities::Extensions>,
221
	) -> Result<Vec<u8>, sp_blockchain::Error> {
222
		let state = self.backend.state_at(at_hash)?;
223

            
224
		let changes = &mut *changes.borrow_mut();
225

            
226
		// It is important to extract the runtime code here before we create the proof
227
		// recorder to not record it. We also need to fetch the runtime code from `state` to
228
		// make sure we use the caching layers.
229
		let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
230

            
231
		let runtime_code = state_runtime_code
232
			.runtime_code()
233
			.map_err(sp_blockchain::Error::RuntimeCode)?;
234
		let runtime_code = self.check_override(runtime_code, &state, at_hash)?.0;
235
		let mut extensions = extensions.borrow_mut();
236

            
237
		let mut state_machine = StateMachine::new(
238
			&state,
239
			changes,
240
			&self.executor,
241
			method,
242
			call_data,
243
			&mut extensions,
244
			&runtime_code,
245
			call_context,
246
		)
247
		.set_parent_hash(at_hash);
248
		state_machine.execute().map_err(Into::into)
249
	}
250

            
251
	fn runtime_version(&self, at_hash: Block::Hash) -> sp_blockchain::Result<RuntimeVersion> {
252
		let state = self.backend.state_at(at_hash)?;
253
		let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
254

            
255
		let runtime_code = state_runtime_code
256
			.runtime_code()
257
			.map_err(sp_blockchain::Error::RuntimeCode)?;
258
		self.check_override(runtime_code, &state, at_hash)
259
			.map(|(_, v)| v)
260
	}
261

            
262
	fn prove_execution(
263
		&self,
264
		at_hash: Block::Hash,
265
		method: &str,
266
		call_data: &[u8],
267
	) -> sp_blockchain::Result<(Vec<u8>, StorageProof)> {
268
		let at_number = self
269
			.backend
270
			.blockchain()
271
			.expect_block_number_from_id(&BlockId::Hash(at_hash))?;
272
		let state = self.backend.state_at(at_hash)?;
273

            
274
		let trie_backend = state.as_trie_backend();
275

            
276
		let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_backend);
277
		let runtime_code = state_runtime_code
278
			.runtime_code()
279
			.map_err(sp_blockchain::Error::RuntimeCode)?;
280
		let runtime_code = self.check_override(runtime_code, &state, at_hash)?.0;
281

            
282
		sp_state_machine::prove_execution_on_trie_backend(
283
			trie_backend,
284
			&mut Default::default(),
285
			&self.executor,
286
			method,
287
			call_data,
288
			&runtime_code,
289
			&mut self.execution_extensions.extensions(at_hash, at_number),
290
		)
291
		.map_err(Into::into)
292
	}
293
}
294

            
295
impl<B, E, Block> RuntimeVersionOf for LazyLoadingCallExecutor<Block, B, E>
296
where
297
	E: RuntimeVersionOf,
298
	Block: BlockT,
299
{
300
	fn runtime_version(
301
		&self,
302
		ext: &mut dyn Externalities,
303
		runtime_code: &sp_core::traits::RuntimeCode,
304
	) -> Result<RuntimeVersion, sc_executor::error::Error> {
305
		RuntimeVersionOf::runtime_version(&self.executor, ext, runtime_code)
306
	}
307
}
308

            
309
impl<Block, B, E> GetRuntimeVersionAt<Block> for LazyLoadingCallExecutor<Block, B, E>
310
where
311
	B: backend::Backend<Block>,
312
	E: CodeExecutor + RuntimeVersionOf + Clone + 'static,
313
	Block: BlockT + sp_runtime::DeserializeOwned,
314
	Block::Hash: From<sp_core::H256>,
315
{
316
	fn runtime_version(&self, at: Block::Hash) -> Result<sp_version::RuntimeVersion, String> {
317
		CallExecutor::runtime_version(self, at).map_err(|e| e.to_string())
318
	}
319
}
320

            
321
impl<Block, B, E> GetNativeVersion for LazyLoadingCallExecutor<Block, B, E>
322
where
323
	B: backend::Backend<Block>,
324
	E: CodeExecutor + sp_version::GetNativeVersion + Clone + 'static,
325
	Block: BlockT + sp_runtime::DeserializeOwned,
326
{
327
	fn native_version(&self) -> &NativeVersion {
328
		self.executor.native_version()
329
	}
330
}