Skip to content

Commit c9109ac

Browse files
authored
Merge pull request #1023 from opentensor/fix/pre-evm-block-import
Fix pre-evm sync issue with evm-enabled node
2 parents 9da2947 + c74f8f2 commit c9109ac

File tree

4 files changed

+132
-12
lines changed

4 files changed

+132
-12
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ syn = { version = "2", features = [
7979
] }
8080
quote = "1"
8181
proc-macro2 = { version = "1", features = ["span-locations"] }
82+
thiserror = "1.0"
8283
walkdir = "2"
8384

8485
subtensor-macros = { path = "support/macros" }
@@ -173,6 +174,7 @@ fp-account = { git = "https://github.com/gztensor/frontier", rev = "b8e3025", de
173174
fc-storage = { git = "https://github.com/gztensor/frontier", rev = "b8e3025", default-features = false }
174175
fc-db = { git = "https://github.com/gztensor/frontier", rev = "b8e3025", default-features = false }
175176
fc-consensus = { git = "https://github.com/gztensor/frontier", rev = "b8e3025", default-features = false }
177+
fp-consensus = { git = "https://github.com/gztensor/frontier", rev = "b8e3025", default-features = false }
176178
fp-dynamic-fee = { git = "https://github.com/gztensor/frontier", rev = "b8e3025", default-features = false }
177179
fc-api = { git = "https://github.com/gztensor/frontier", rev = "b8e3025", default-features = false }
178180
fc-rpc = { git = "https://github.com/gztensor/frontier", rev = "b8e3025", default-features = false }

node/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ fc-rpc = { workspace = true }
9696
fc-rpc-core = { workspace = true }
9797
fp-rpc = { workspace = true }
9898
fc-mapping-sync = { workspace = true }
99+
fp-consensus = { workspace = true }
100+
thiserror = { workspace = true }
99101

100102
# Local Dependencies
101103
node-subtensor-runtime = { path = "../runtime" }

node/src/service.rs

Lines changed: 126 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
22
3+
use fp_consensus::{ensure_log, FindLogError};
4+
use fp_rpc::EthereumRuntimeRPCApi;
35
use futures::{channel::mpsc, future, FutureExt};
46
use node_subtensor_runtime::{opaque::Block, RuntimeApi, TransactionConverter};
57
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+
};
711
use sc_consensus_grandpa::BlockNumberOps;
812
use sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging;
913
use sc_network_sync::strategy::warp::{WarpSyncConfig, WarpSyncProvider};
1014
use sc_service::{error::Error as ServiceError, Configuration, PartialComponents, TaskManager};
1115
use sc_telemetry::{log, Telemetry, TelemetryHandle, TelemetryWorker};
1216
use sc_transaction_pool::FullPool;
1317
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;
1421
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
1522
use sp_core::U256;
16-
use sp_runtime::traits::{Block as BlockT, NumberFor};
23+
use sp_runtime::traits::{Block as BlockT, Header, NumberFor};
1724
use std::{cell::RefCell, path::Path};
18-
use std::{sync::Arc, time::Duration};
25+
use std::{marker::PhantomData, sync::Arc, time::Duration};
1926
use substrate_prometheus_endpoint::Registry;
2027

2128
use crate::cli::Sealing;
@@ -167,6 +174,106 @@ where
167174
})
168175
}
169176

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+
170277
/// Build the import queue for the template runtime (aura + grandpa).
171278
pub fn build_aura_grandpa_import_queue(
172279
client: Arc<FullClient>,
@@ -179,8 +286,11 @@ pub fn build_aura_grandpa_import_queue(
179286
where
180287
NumberFor<Block>: BlockNumberOps,
181288
{
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+
);
184294

185295
let slot_duration = sc_consensus_aura::slot_duration(&*client)?;
186296
let target_gas_price = eth_config.target_gas_price;
@@ -197,8 +307,8 @@ where
197307

198308
let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _>(
199309
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())),
202312
client,
203313
create_inherent_data_providers,
204314
spawner: &task_manager.spawn_essential_handle(),
@@ -210,7 +320,7 @@ where
210320
)
211321
.map_err::<ServiceError, _>(Into::into)?;
212322

213-
Ok((import_queue, Box::new(frontier_block_import)))
323+
Ok((import_queue, Box::new(conditional_block_import)))
214324
}
215325

216326
/// Build the import queue for the template runtime (manual seal).
@@ -220,16 +330,20 @@ pub fn build_manual_seal_import_queue(
220330
_eth_config: &EthConfiguration,
221331
task_manager: &TaskManager,
222332
_telemetry: Option<TelemetryHandle>,
223-
_grandpa_block_import: GrandpaBlockImport,
333+
grandpa_block_import: GrandpaBlockImport,
224334
) -> 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+
);
226340
Ok((
227341
sc_consensus_manual_seal::import_queue(
228-
Box::new(frontier_block_import.clone()),
342+
Box::new(conditional_block_import.clone()),
229343
&task_manager.spawn_essential_handle(),
230344
config.prometheus_registry(),
231345
),
232-
Box::new(frontier_block_import),
346+
Box::new(conditional_block_import),
233347
))
234348
}
235349

0 commit comments

Comments
 (0)