1
1
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
2
2
3
+ use fp_consensus:: { ensure_log, FindLogError } ;
4
+ use fp_rpc:: EthereumRuntimeRPCApi ;
3
5
use futures:: { channel:: mpsc, future, FutureExt } ;
4
6
use node_subtensor_runtime:: { opaque:: Block , RuntimeApi , TransactionConverter } ;
5
7
use sc_client_api:: { Backend as BackendT , BlockBackend } ;
6
- use sc_consensus:: { BasicQueue , BoxBlockImport } ;
8
+ use sc_consensus:: {
9
+ BasicQueue , BlockCheckParams , BlockImport , BlockImportParams , BoxBlockImport , ImportResult ,
10
+ } ;
7
11
use sc_consensus_grandpa:: BlockNumberOps ;
8
12
use sc_consensus_slots:: BackoffAuthoringOnFinalizedHeadLagging ;
9
13
use sc_network_sync:: strategy:: warp:: { WarpSyncConfig , WarpSyncProvider } ;
10
14
use sc_service:: { error:: Error as ServiceError , Configuration , PartialComponents , TaskManager } ;
11
15
use sc_telemetry:: { log, Telemetry , TelemetryHandle , TelemetryWorker } ;
12
16
use sc_transaction_pool:: FullPool ;
13
17
use sc_transaction_pool_api:: OffchainTransactionPoolFactory ;
18
+ use sp_api:: ProvideRuntimeApi ;
19
+ use sp_block_builder:: BlockBuilder as BlockBuilderApi ;
20
+ use sp_consensus:: Error as ConsensusError ;
14
21
use sp_consensus_aura:: sr25519:: AuthorityPair as AuraPair ;
15
22
use sp_core:: U256 ;
16
- use sp_runtime:: traits:: { Block as BlockT , NumberFor } ;
23
+ use sp_runtime:: traits:: { Block as BlockT , Header , NumberFor } ;
17
24
use std:: { cell:: RefCell , path:: Path } ;
18
- use std:: { sync:: Arc , time:: Duration } ;
25
+ use std:: { marker :: PhantomData , sync:: Arc , time:: Duration } ;
19
26
use substrate_prometheus_endpoint:: Registry ;
20
27
21
28
use crate :: cli:: Sealing ;
@@ -167,6 +174,106 @@ where
167
174
} )
168
175
}
169
176
177
+ #[ derive( Debug , thiserror:: Error ) ]
178
+ pub enum Error {
179
+ #[ error( "Multiple runtime Ethereum blocks, rejecting!" ) ]
180
+ MultipleRuntimeLogs ,
181
+ #[ error( "Runtime Ethereum block not found, rejecting!" ) ]
182
+ NoRuntimeLog ,
183
+ #[ error( "Cannot access the runtime at genesis, rejecting!" ) ]
184
+ RuntimeApiCallFailed ,
185
+ }
186
+
187
+ impl From < Error > for String {
188
+ fn from ( error : Error ) -> String {
189
+ error. to_string ( )
190
+ }
191
+ }
192
+
193
+ impl From < FindLogError > for Error {
194
+ fn from ( error : FindLogError ) -> Error {
195
+ match error {
196
+ FindLogError :: NotFound => Error :: NoRuntimeLog ,
197
+ FindLogError :: MultipleLogs => Error :: MultipleRuntimeLogs ,
198
+ }
199
+ }
200
+ }
201
+
202
+ impl From < Error > for ConsensusError {
203
+ fn from ( error : Error ) -> ConsensusError {
204
+ ConsensusError :: ClientImport ( error. to_string ( ) )
205
+ }
206
+ }
207
+
208
+ pub struct ConditionalEVMBlockImport < B : BlockT , I , F , C > {
209
+ inner : I ,
210
+ frontier_block_import : F ,
211
+ client : Arc < C > ,
212
+ _marker : PhantomData < B > ,
213
+ }
214
+
215
+ impl < B , I , F , C > Clone for ConditionalEVMBlockImport < B , I , F , C >
216
+ where
217
+ B : BlockT ,
218
+ I : Clone + BlockImport < B > ,
219
+ F : Clone + BlockImport < B > ,
220
+ {
221
+ fn clone ( & self ) -> Self {
222
+ ConditionalEVMBlockImport {
223
+ inner : self . inner . clone ( ) ,
224
+ frontier_block_import : self . frontier_block_import . clone ( ) ,
225
+ client : self . client . clone ( ) ,
226
+ _marker : PhantomData ,
227
+ }
228
+ }
229
+ }
230
+
231
+ impl < B , I , F , C > ConditionalEVMBlockImport < B , I , F , C >
232
+ where
233
+ B : BlockT ,
234
+ I : BlockImport < B > ,
235
+ I :: Error : Into < ConsensusError > ,
236
+ F : BlockImport < B > ,
237
+ F :: Error : Into < ConsensusError > ,
238
+ C : ProvideRuntimeApi < B > ,
239
+ C :: Api : BlockBuilderApi < B > + EthereumRuntimeRPCApi < B > ,
240
+ {
241
+ pub fn new ( inner : I , frontier_block_import : F , client : Arc < C > ) -> Self {
242
+ Self {
243
+ inner,
244
+ frontier_block_import,
245
+ client,
246
+ _marker : PhantomData ,
247
+ }
248
+ }
249
+ }
250
+
251
+ #[ async_trait:: async_trait]
252
+ impl < B , I , F , C > BlockImport < B > for ConditionalEVMBlockImport < B , I , F , C >
253
+ where
254
+ B : BlockT ,
255
+ I : BlockImport < B > + Send + Sync ,
256
+ I :: Error : Into < ConsensusError > ,
257
+ F : BlockImport < B > + Send + Sync ,
258
+ F :: Error : Into < ConsensusError > ,
259
+ C : ProvideRuntimeApi < B > + Send + Sync ,
260
+ C :: Api : BlockBuilderApi < B > + EthereumRuntimeRPCApi < B > ,
261
+ {
262
+ type Error = ConsensusError ;
263
+
264
+ async fn check_block ( & self , block : BlockCheckParams < B > ) -> Result < ImportResult , Self :: Error > {
265
+ self . inner . check_block ( block) . await . map_err ( Into :: into)
266
+ }
267
+
268
+ async fn import_block ( & self , block : BlockImportParams < B > ) -> Result < ImportResult , Self :: Error > {
269
+ // Import like Frontier, but fallback to grandpa import for errors
270
+ match ensure_log ( block. header . digest ( ) ) . map_err ( Error :: from) {
271
+ Ok ( ( ) ) => self . inner . import_block ( block) . await . map_err ( Into :: into) ,
272
+ _ => self . inner . import_block ( block) . await . map_err ( Into :: into) ,
273
+ }
274
+ }
275
+ }
276
+
170
277
/// Build the import queue for the template runtime (aura + grandpa).
171
278
pub fn build_aura_grandpa_import_queue (
172
279
client : Arc < FullClient > ,
@@ -179,8 +286,11 @@ pub fn build_aura_grandpa_import_queue(
179
286
where
180
287
NumberFor < Block > : BlockNumberOps ,
181
288
{
182
- let frontier_block_import =
183
- FrontierBlockImport :: new ( grandpa_block_import. clone ( ) , client. clone ( ) ) ;
289
+ let conditional_block_import = ConditionalEVMBlockImport :: new (
290
+ grandpa_block_import. clone ( ) ,
291
+ FrontierBlockImport :: new ( grandpa_block_import. clone ( ) , client. clone ( ) ) ,
292
+ client. clone ( ) ,
293
+ ) ;
184
294
185
295
let slot_duration = sc_consensus_aura:: slot_duration ( & * client) ?;
186
296
let target_gas_price = eth_config. target_gas_price ;
@@ -197,8 +307,8 @@ where
197
307
198
308
let import_queue = sc_consensus_aura:: import_queue :: < AuraPair , _ , _ , _ , _ , _ > (
199
309
sc_consensus_aura:: ImportQueueParams {
200
- block_import : frontier_block_import . clone ( ) ,
201
- justification_import : Some ( Box :: new ( grandpa_block_import) ) ,
310
+ block_import : conditional_block_import . clone ( ) ,
311
+ justification_import : Some ( Box :: new ( grandpa_block_import. clone ( ) ) ) ,
202
312
client,
203
313
create_inherent_data_providers,
204
314
spawner : & task_manager. spawn_essential_handle ( ) ,
@@ -210,7 +320,7 @@ where
210
320
)
211
321
. map_err :: < ServiceError , _ > ( Into :: into) ?;
212
322
213
- Ok ( ( import_queue, Box :: new ( frontier_block_import ) ) )
323
+ Ok ( ( import_queue, Box :: new ( conditional_block_import ) ) )
214
324
}
215
325
216
326
/// Build the import queue for the template runtime (manual seal).
@@ -220,16 +330,20 @@ pub fn build_manual_seal_import_queue(
220
330
_eth_config : & EthConfiguration ,
221
331
task_manager : & TaskManager ,
222
332
_telemetry : Option < TelemetryHandle > ,
223
- _grandpa_block_import : GrandpaBlockImport ,
333
+ grandpa_block_import : GrandpaBlockImport ,
224
334
) -> Result < ( BasicQueue < Block > , BoxBlockImport < Block > ) , ServiceError > {
225
- let frontier_block_import = FrontierBlockImport :: new ( client. clone ( ) , client) ;
335
+ let conditional_block_import = ConditionalEVMBlockImport :: new (
336
+ grandpa_block_import. clone ( ) ,
337
+ FrontierBlockImport :: new ( grandpa_block_import. clone ( ) , client. clone ( ) ) ,
338
+ client,
339
+ ) ;
226
340
Ok ( (
227
341
sc_consensus_manual_seal:: import_queue (
228
- Box :: new ( frontier_block_import . clone ( ) ) ,
342
+ Box :: new ( conditional_block_import . clone ( ) ) ,
229
343
& task_manager. spawn_essential_handle ( ) ,
230
344
config. prometheus_registry ( ) ,
231
345
) ,
232
- Box :: new ( frontier_block_import ) ,
346
+ Box :: new ( conditional_block_import ) ,
233
347
) )
234
348
}
235
349
0 commit comments