fc_consensus/
lib.rs

1// This file is part of Frontier.
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
19#![warn(unused_crate_dependencies)]
20
21use std::{marker::PhantomData, sync::Arc};
22
23// Substrate
24use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResult};
25use sp_api::ProvideRuntimeApi;
26use sp_block_builder::BlockBuilder as BlockBuilderApi;
27use sp_consensus::Error as ConsensusError;
28use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
29// Frontier
30use fp_consensus::{ensure_log, FindLogError};
31use fp_rpc::EthereumRuntimeRPCApi;
32
33#[derive(Debug, thiserror::Error)]
34pub enum Error {
35	#[error("Multiple runtime Ethereum blocks, rejecting!")]
36	MultipleRuntimeLogs,
37	#[error("Runtime Ethereum block not found, rejecting!")]
38	NoRuntimeLog,
39	#[error("Cannot access the runtime at genesis, rejecting!")]
40	RuntimeApiCallFailed,
41}
42
43impl From<Error> for String {
44	fn from(error: Error) -> String {
45		error.to_string()
46	}
47}
48
49impl From<FindLogError> for Error {
50	fn from(error: FindLogError) -> Error {
51		match error {
52			FindLogError::NotFound => Error::NoRuntimeLog,
53			FindLogError::MultipleLogs => Error::MultipleRuntimeLogs,
54		}
55	}
56}
57
58impl From<Error> for ConsensusError {
59	fn from(error: Error) -> ConsensusError {
60		ConsensusError::ClientImport(error.to_string())
61	}
62}
63
64pub struct FrontierBlockImport<B: BlockT, I, C> {
65	inner: I,
66	client: Arc<C>,
67	_marker: PhantomData<B>,
68}
69
70impl<Block: BlockT, I: Clone + BlockImport<Block>, C> Clone for FrontierBlockImport<Block, I, C> {
71	fn clone(&self) -> Self {
72		FrontierBlockImport {
73			inner: self.inner.clone(),
74			client: self.client.clone(),
75			_marker: PhantomData,
76		}
77	}
78}
79
80impl<B, I, C> FrontierBlockImport<B, I, C>
81where
82	B: BlockT,
83	I: BlockImport<B>,
84	I::Error: Into<ConsensusError>,
85	C: ProvideRuntimeApi<B>,
86	C::Api: BlockBuilderApi<B> + EthereumRuntimeRPCApi<B>,
87{
88	pub fn new(inner: I, client: Arc<C>) -> Self {
89		Self {
90			inner,
91			client,
92			_marker: PhantomData,
93		}
94	}
95}
96
97#[async_trait::async_trait]
98impl<B, I, C> BlockImport<B> for FrontierBlockImport<B, I, C>
99where
100	B: BlockT,
101	I: BlockImport<B> + Send + Sync,
102	I::Error: Into<ConsensusError>,
103	C: ProvideRuntimeApi<B> + Send + Sync,
104	C::Api: BlockBuilderApi<B> + EthereumRuntimeRPCApi<B>,
105{
106	type Error = ConsensusError;
107
108	async fn check_block(&self, block: BlockCheckParams<B>) -> Result<ImportResult, Self::Error> {
109		self.inner.check_block(block).await.map_err(Into::into)
110	}
111
112	async fn import_block(&self, block: BlockImportParams<B>) -> Result<ImportResult, Self::Error> {
113		// We validate that there are only one frontier log. No other
114		// actions are needed and mapping syncing is delegated to a separate
115		// worker.
116		ensure_log(block.header.digest()).map_err(Error::from)?;
117
118		self.inner.import_block(block).await.map_err(Into::into)
119	}
120}