#188 Added EVM RPC to the node (#198)

* #188 added RPC node to enable interaction
This commit is contained in:
Nikita Khateev
2024-05-28 18:29:06 +04:00
committed by GitHub
parent 3132574062
commit 135e186816
14 changed files with 1284 additions and 87 deletions
+3
View File
@@ -194,6 +194,9 @@ fn testnet_genesis(
.collect::<Vec<_>>(),
},
"treasury": {},
"evmChainId": {
"chainId": 9999
},
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
},
+5
View File
@@ -1,5 +1,7 @@
use std::path::PathBuf;
use crate::eth::EthConfiguration;
/// Sub-commands supported by the collator.
#[derive(Debug, clap::Subcommand)]
pub enum Subcommand {
@@ -84,6 +86,9 @@ pub struct Cli {
/// Relay chain arguments
#[arg(raw = true)]
pub relay_chain_args: Vec<String>,
#[command(flatten)]
pub eth: EthConfiguration,
}
#[derive(Debug)]
+6 -4
View File
@@ -99,8 +99,9 @@ impl SubstrateCli for RelayChainCli {
macro_rules! construct_async_run {
(|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{
let runner = $cli.create_runner($cmd)?;
let eth = $cli.eth.clone();
runner.async_run(|$config| {
let $components = new_partial(&$config)?;
let $components = new_partial(&$config, &eth)?;
let task_manager = $components.task_manager;
{ $( $code )* }.map(|v| (v, task_manager))
})
@@ -163,7 +164,7 @@ pub fn run() -> Result<()> {
Some(Subcommand::ExportGenesisHead(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| {
let partials = new_partial(&config)?;
let partials = new_partial(&config, &cli.eth)?;
cmd.run(partials.client)
})
@@ -188,7 +189,7 @@ pub fn run() -> Result<()> {
.into())
},
BenchmarkCmd::Block(cmd) => runner.sync_run(|config| {
let partials = new_partial(&config)?;
let partials = new_partial(&config, &cli.eth)?;
cmd.run(partials.client)
}),
#[cfg(not(feature = "runtime-benchmarks"))]
@@ -200,7 +201,7 @@ pub fn run() -> Result<()> {
)),
#[cfg(feature = "runtime-benchmarks")]
BenchmarkCmd::Storage(cmd) => runner.sync_run(|config| {
let partials = new_partial(&config)?;
let partials = new_partial(&config, &cli.eth)?;
let db = partials.backend.expose_db();
let storage = partials.backend.expose_storage();
cmd.run(config, partials.client.clone(), db, storage)
@@ -254,6 +255,7 @@ pub fn run() -> Result<()> {
config,
polkadot_config,
collator_options,
&cli.eth,
id,
hwbench,
)
+208
View File
@@ -0,0 +1,208 @@
use std::{
collections::BTreeMap,
path::PathBuf,
sync::{Arc, Mutex},
time::Duration,
};
use fc_rpc::{EthTask, OverrideHandle};
pub use fc_rpc_core::types::{FeeHistoryCache, FeeHistoryCacheLimit, FilterPool};
use futures::{future, prelude::*};
// Local
use parachain_template_runtime::opaque::Block;
// Substrate
use sc_client_api::BlockchainEvents;
use sc_executor::{NativeElseWasmExecutor, NativeExecutionDispatch};
use sc_network_sync::SyncingService;
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
use sp_api::ConstructRuntimeApi;
/// Full backend.
pub type FullBackend = sc_service::TFullBackend<Block>;
/// Full client.
pub type FullClient<RuntimeApi, Executor> =
sc_service::TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>;
/// Frontier DB backend type.
pub type FrontierBackend = fc_db::Backend<Block>;
pub fn db_config_dir(config: &Configuration) -> PathBuf {
config.base_path.config_dir(config.chain_spec.id())
}
/// Avalailable frontier backend types.
#[derive(Debug, Copy, Clone, Default, clap::ValueEnum)]
pub enum BackendType {
/// Either RocksDb or ParityDb as per inherited from the global backend settings.
#[default]
KeyValue,
/// Sql database with custom log indexing.
Sql,
}
/// The ethereum-compatibility configuration used to run a node.
#[derive(Clone, Debug, clap::Parser)]
pub struct EthConfiguration {
/// Maximum number of logs in a query.
#[arg(long, default_value = "10000")]
pub max_past_logs: u32,
/// Maximum fee history cache size.
#[arg(long, default_value = "2048")]
pub fee_history_limit: u64,
#[arg(long)]
pub enable_dev_signer: bool,
/// The dynamic-fee pallet target gas price set by block author
#[arg(long, default_value = "1")]
pub target_gas_price: u64,
/// Maximum allowed gas limit will be `block.gas_limit * execute_gas_limit_multiplier`
/// when using eth_call/eth_estimateGas.
#[arg(long, default_value = "10")]
pub execute_gas_limit_multiplier: u64,
/// Size in bytes of the LRU cache for block data.
#[arg(long, default_value = "50")]
pub eth_log_block_cache: usize,
/// Size in bytes of the LRU cache for transactions statuses data.
#[arg(long, default_value = "50")]
pub eth_statuses_cache: usize,
/// Sets the frontier backend type (KeyValue or Sql)
#[arg(long, value_enum, ignore_case = true, default_value_t = BackendType::default())]
pub frontier_backend_type: BackendType,
// Sets the SQL backend's pool size.
#[arg(long, default_value = "100")]
pub frontier_sql_backend_pool_size: u32,
/// Sets the SQL backend's query timeout in number of VM ops.
#[arg(long, default_value = "10000000")]
pub frontier_sql_backend_num_ops_timeout: u32,
/// Sets the SQL backend's auxiliary thread limit.
#[arg(long, default_value = "4")]
pub frontier_sql_backend_thread_count: u32,
/// Sets the SQL backend's query timeout in number of VM ops.
/// Default value is 200MB.
#[arg(long, default_value = "209715200")]
pub frontier_sql_backend_cache_size: u64,
}
pub struct FrontierPartialComponents {
pub filter_pool: Option<FilterPool>,
pub fee_history_cache: FeeHistoryCache,
pub fee_history_cache_limit: FeeHistoryCacheLimit,
}
pub fn new_frontier_partial(
config: &EthConfiguration,
) -> Result<FrontierPartialComponents, ServiceError> {
Ok(FrontierPartialComponents {
filter_pool: Some(Arc::new(Mutex::new(BTreeMap::new()))),
fee_history_cache: Arc::new(Mutex::new(BTreeMap::new())),
fee_history_cache_limit: config.fee_history_limit,
})
}
/// A set of APIs that ethereum-compatible runtimes must implement.
pub trait EthCompatRuntimeApiCollection:
sp_api::ApiExt<Block>
+ fp_rpc::ConvertTransactionRuntimeApi<Block>
+ fp_rpc::EthereumRuntimeRPCApi<Block>
{
}
impl<Api> EthCompatRuntimeApiCollection for Api where
Api: sp_api::ApiExt<Block>
+ fp_rpc::ConvertTransactionRuntimeApi<Block>
+ fp_rpc::EthereumRuntimeRPCApi<Block>
{
}
pub async fn spawn_frontier_tasks<RuntimeApi, Executor>(
task_manager: &TaskManager,
client: Arc<FullClient<RuntimeApi, Executor>>,
backend: Arc<FullBackend>,
frontier_backend: FrontierBackend,
filter_pool: Option<FilterPool>,
overrides: Arc<OverrideHandle<Block>>,
fee_history_cache: FeeHistoryCache,
fee_history_cache_limit: FeeHistoryCacheLimit,
sync: Arc<SyncingService<Block>>,
pubsub_notification_sinks: Arc<
fc_mapping_sync::EthereumBlockNotificationSinks<
fc_mapping_sync::EthereumBlockNotification<Block>,
>,
>,
) where
RuntimeApi: ConstructRuntimeApi<Block, FullClient<RuntimeApi, Executor>>,
RuntimeApi: Send + Sync + 'static,
RuntimeApi::RuntimeApi: EthCompatRuntimeApiCollection,
Executor: NativeExecutionDispatch + 'static,
{
// Spawn main mapping sync worker background task.
match frontier_backend {
fc_db::Backend::KeyValue(b) => {
task_manager.spawn_essential_handle().spawn(
"frontier-mapping-sync-worker",
Some("frontier"),
fc_mapping_sync::kv::MappingSyncWorker::new(
client.import_notification_stream(),
Duration::new(6, 0),
client.clone(),
backend,
overrides.clone(),
Arc::new(b),
3,
0,
fc_mapping_sync::SyncStrategy::Normal,
sync,
pubsub_notification_sinks,
)
.for_each(|()| future::ready(())),
);
}
fc_db::Backend::Sql(b) => {
task_manager.spawn_essential_handle().spawn_blocking(
"frontier-mapping-sync-worker",
Some("frontier"),
fc_mapping_sync::sql::SyncWorker::run(
client.clone(),
backend,
Arc::new(b),
client.import_notification_stream(),
fc_mapping_sync::sql::SyncWorkerConfig {
read_notification_timeout: Duration::from_secs(10),
check_indexed_blocks_interval: Duration::from_secs(60),
},
fc_mapping_sync::SyncStrategy::Parachain,
sync,
pubsub_notification_sinks,
),
);
}
}
// Spawn Frontier EthFilterApi maintenance task.
if let Some(filter_pool) = filter_pool {
// Each filter is allowed to stay in the pool for 100 blocks.
const FILTER_RETAIN_THRESHOLD: u64 = 100;
task_manager.spawn_essential_handle().spawn(
"frontier-filter-pool",
Some("frontier"),
EthTask::filter_pool_task(client.clone(), filter_pool, FILTER_RETAIN_THRESHOLD),
);
}
// Spawn Frontier FeeHistory cache maintenance task.
task_manager.spawn_essential_handle().spawn(
"frontier-fee-history",
Some("frontier"),
EthTask::fee_history_task(client, overrides, fee_history_cache, fee_history_cache_limit),
);
}
+1
View File
@@ -7,6 +7,7 @@ mod chain_spec;
mod service;
mod cli;
mod command;
mod eth;
mod rpc;
fn main() -> sc_cli::Result<()> {
-57
View File
@@ -1,57 +0,0 @@
//! A collection of node-specific RPC methods.
//! Substrate provides the `sc-rpc` crate, which defines the core RPC layer
//! used by Substrate nodes. This file extends those RPC definitions with
//! capabilities that are specific to this project's runtime configuration.
#![warn(missing_docs)]
use std::sync::Arc;
use parachain_template_runtime::{opaque::Block, AccountId, Balance, Nonce};
use sc_client_api::AuxStore;
pub use sc_rpc::DenyUnsafe;
use sc_transaction_pool_api::TransactionPool;
use sp_api::ProvideRuntimeApi;
use sp_block_builder::BlockBuilder;
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
/// A type representing all RPC extensions.
pub type RpcExtension = jsonrpsee::RpcModule<()>;
/// Full client dependencies
pub struct FullDeps<C, P> {
/// The client instance to use.
pub client: Arc<C>,
/// Transaction pool instance.
pub pool: Arc<P>,
/// Whether to deny unsafe calls
pub deny_unsafe: DenyUnsafe,
}
/// Instantiate all RPC extensions.
pub fn create_full<C, P>(
deps: FullDeps<C, P>,
) -> Result<RpcExtension, Box<dyn std::error::Error + Send + Sync>>
where
C: ProvideRuntimeApi<Block>
+ HeaderBackend<Block>
+ AuxStore
+ HeaderMetadata<Block, Error = BlockChainError>
+ Send
+ Sync
+ 'static,
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>,
C::Api: BlockBuilder<Block>,
P: TransactionPool + Sync + Send + 'static,
{
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
use substrate_frame_rpc_system::{System, SystemApiServer};
let mut module = RpcExtension::new(());
let FullDeps { client, pool, deny_unsafe } = deps;
module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?;
module.merge(TransactionPayment::new(client).into_rpc())?;
Ok(module)
}
+198
View File
@@ -0,0 +1,198 @@
use std::{collections::BTreeMap, sync::Arc};
// Frontier
pub use fc_rpc::{EthBlockDataCacheTask, EthConfig, OverrideHandle};
pub use fc_rpc_core::types::{FeeHistoryCache, FeeHistoryCacheLimit, FilterPool};
pub use fc_storage::overrides_handle;
use fp_rpc::{ConvertTransaction, ConvertTransactionRuntimeApi, EthereumRuntimeRPCApi};
use jsonrpsee::RpcModule;
// Substrate
use sc_client_api::{
backend::{Backend, StorageProvider},
client::BlockchainEvents,
AuxStore, UsageProvider,
};
use sc_network::NetworkService;
use sc_network_sync::SyncingService;
use sc_rpc::SubscriptionTaskExecutor;
use sc_transaction_pool::{ChainApi, Pool};
use sc_transaction_pool_api::TransactionPool;
use sp_api::{CallApiAt, ProvideRuntimeApi};
use sp_block_builder::BlockBuilder as BlockBuilderApi;
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
use sp_consensus_aura::{sr25519::AuthorityId as AuraId, AuraApi};
use sp_core::H256;
use sp_inherents::CreateInherentDataProviders;
use sp_runtime::traits::Block as BlockT;
/// Extra dependencies for Ethereum compatibility.
pub struct EthDeps<B: BlockT, C, P, A: ChainApi, CT, CIDP> {
/// The client instance to use.
pub client: Arc<C>,
/// Transaction pool instance.
pub pool: Arc<P>,
/// Graph pool instance.
pub graph: Arc<Pool<A>>,
/// Ethereum transaction converter.
pub converter: Option<CT>,
/// The Node authority flag
pub is_authority: bool,
/// Whether to enable dev signer
pub enable_dev_signer: bool,
/// Network service
pub network: Arc<NetworkService<B, B::Hash>>,
/// Chain syncing service
pub sync: Arc<SyncingService<B>>,
/// Frontier Backend.
pub frontier_backend: Arc<dyn fc_api::Backend<B>>,
/// Ethereum data access overrides.
pub overrides: Arc<OverrideHandle<B>>,
/// Cache for Ethereum block data.
pub block_data_cache: Arc<EthBlockDataCacheTask<B>>,
/// EthFilterApi pool.
pub filter_pool: Option<FilterPool>,
/// Maximum number of logs in a query.
pub max_past_logs: u32,
/// Fee history cache.
pub fee_history_cache: FeeHistoryCache,
/// Maximum fee history cache size.
pub fee_history_cache_limit: FeeHistoryCacheLimit,
/// Maximum allowed gas limit will be ` block.gas_limit * execute_gas_limit_multiplier` when
/// using eth_call/eth_estimateGas.
pub execute_gas_limit_multiplier: u64,
/// Mandated parent hashes for a given block hash.
pub forced_parent_hashes: Option<BTreeMap<H256, H256>>,
/// Something that can create the inherent data providers for pending state
pub pending_create_inherent_data_providers: CIDP,
}
/// Instantiate Ethereum-compatible RPC extensions.
pub fn create_eth<B, C, BE, P, A, CT, CIDP, EC>(
mut io: RpcModule<()>,
deps: EthDeps<B, C, P, A, CT, CIDP>,
subscription_task_executor: SubscriptionTaskExecutor,
pubsub_notification_sinks: Arc<
fc_mapping_sync::EthereumBlockNotificationSinks<
fc_mapping_sync::EthereumBlockNotification<B>,
>,
>,
) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
where
B: BlockT<Hash = H256>,
C: CallApiAt<B> + ProvideRuntimeApi<B>,
C::Api: AuraApi<B, AuraId>
+ BlockBuilderApi<B>
+ ConvertTransactionRuntimeApi<B>
+ EthereumRuntimeRPCApi<B>,
C: HeaderBackend<B> + HeaderMetadata<B, Error = BlockChainError>,
C: BlockchainEvents<B> + AuxStore + UsageProvider<B> + StorageProvider<B, BE> + 'static,
BE: Backend<B> + 'static,
P: TransactionPool<Block = B> + 'static,
A: ChainApi<Block = B> + 'static,
CT: ConvertTransaction<<B as BlockT>::Extrinsic> + Send + Sync + 'static,
CIDP: CreateInherentDataProviders<B, ()> + Send + 'static,
EC: EthConfig<B, C>,
{
use fc_rpc::{
pending::AuraConsensusDataProvider, Debug, DebugApiServer, Eth, EthApiServer, EthDevSigner,
EthFilter, EthFilterApiServer, EthPubSub, EthPubSubApiServer, EthSigner, Net, NetApiServer,
Web3, Web3ApiServer,
};
#[cfg(feature = "txpool")]
use fc_rpc::{TxPool, TxPoolApiServer};
let EthDeps {
client,
pool,
graph,
converter,
is_authority,
enable_dev_signer,
network,
sync,
frontier_backend,
overrides,
block_data_cache,
filter_pool,
max_past_logs,
fee_history_cache,
fee_history_cache_limit,
execute_gas_limit_multiplier,
forced_parent_hashes,
pending_create_inherent_data_providers,
} = deps;
let mut signers = Vec::new();
if enable_dev_signer {
signers.push(Box::new(EthDevSigner::new()) as Box<dyn EthSigner>);
}
io.merge(
Eth::<B, C, P, CT, BE, A, CIDP, EC>::new(
client.clone(),
pool.clone(),
graph.clone(),
converter,
sync.clone(),
signers,
overrides.clone(),
frontier_backend.clone(),
is_authority,
block_data_cache.clone(),
fee_history_cache,
fee_history_cache_limit,
execute_gas_limit_multiplier,
forced_parent_hashes,
pending_create_inherent_data_providers,
Some(Box::new(AuraConsensusDataProvider::new(client.clone()))),
)
.replace_config::<EC>()
.into_rpc(),
)?;
if let Some(filter_pool) = filter_pool {
io.merge(
EthFilter::new(
client.clone(),
frontier_backend.clone(),
graph.clone(),
filter_pool,
500_usize, // max stored filters
max_past_logs,
block_data_cache.clone(),
)
.into_rpc(),
)?;
}
io.merge(
EthPubSub::new(
pool,
client.clone(),
sync,
subscription_task_executor,
overrides.clone(),
pubsub_notification_sinks,
)
.into_rpc(),
)?;
io.merge(
Net::new(
client.clone(),
network,
// Whether to format the `peer_count` response as Hex (default) or not.
true,
)
.into_rpc(),
)?;
io.merge(Web3::new(client.clone()).into_rpc())?;
io.merge(Debug::new(client.clone(), frontier_backend, overrides, block_data_cache).into_rpc())?;
#[cfg(feature = "txpool")]
io.merge(TxPool::new(client, graph).into_rpc())?;
Ok(io)
}
+102
View File
@@ -0,0 +1,102 @@
//! A collection of node-specific RPC methods.
//! Substrate provides the `sc-rpc` crate, which defines the core RPC layer
//! used by Substrate nodes. This file extends those RPC definitions with
//! capabilities that are specific to this project's runtime configuration.
#![warn(missing_docs)]
mod eth;
use std::sync::Arc;
use parachain_template_runtime::{opaque::Block, AccountId, Balance, Nonce};
use sc_client_api::{backend::Backend, AuxStore, BlockchainEvents, StorageProvider, UsageProvider};
pub use sc_rpc::DenyUnsafe;
use sc_rpc::SubscriptionTaskExecutor;
use sc_transaction_pool::ChainApi;
use sc_transaction_pool_api::TransactionPool;
use sp_api::{CallApiAt, ProvideRuntimeApi};
use sp_block_builder::BlockBuilder;
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_inherents::CreateInherentDataProviders;
use sp_runtime::traits::Block as BlockT;
pub use self::eth::{overrides_handle, EthDeps};
use crate::rpc::eth::create_eth;
/// A type representing all RPC extensions.
pub type RpcExtension = jsonrpsee::RpcModule<()>;
/// Full client dependencies
pub struct FullDeps<C, P, A: ChainApi, CT, CIDP> {
/// The client instance to use.
pub client: Arc<C>,
/// Transaction pool instance.
pub pool: Arc<P>,
/// Whether to deny unsafe calls
pub deny_unsafe: DenyUnsafe,
/// Ethereum-compatibility specific dependencies.
pub eth: EthDeps<Block, C, P, A, CT, CIDP>,
}
pub struct DefaultEthConfig<C, BE>(std::marker::PhantomData<(C, BE)>);
impl<C, BE> fc_rpc::EthConfig<Block, C> for DefaultEthConfig<C, BE>
where
C: StorageProvider<Block, BE> + Sync + Send + 'static,
BE: Backend<Block> + 'static,
{
type EstimateGasAdapter = ();
type RuntimeStorageOverride =
fc_rpc::frontier_backend_client::SystemAccountId20StorageOverride<Block, C, BE>;
}
/// Instantiate all RPC extensions.
pub fn create_full<C, P, A, CT, CIDP, BE>(
deps: FullDeps<C, P, A, CT, CIDP>,
subscription_task_executor: SubscriptionTaskExecutor,
pubsub_notification_sinks: Arc<
fc_mapping_sync::EthereumBlockNotificationSinks<
fc_mapping_sync::EthereumBlockNotification<Block>,
>,
>,
) -> Result<RpcExtension, Box<dyn std::error::Error + Send + Sync>>
where
C: ProvideRuntimeApi<Block>
+ HeaderBackend<Block>
+ AuxStore
+ HeaderMetadata<Block, Error = BlockChainError>
+ Send
+ Sync
+ CallApiAt<Block>
+ UsageProvider<Block>
+ StorageProvider<Block, BE>
+ BlockchainEvents<Block>
+ 'static,
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>,
C::Api: sp_consensus_aura::AuraApi<Block, AuraId>,
C::Api: BlockBuilder<Block>,
C::Api: fp_rpc::ConvertTransactionRuntimeApi<Block>,
C::Api: fp_rpc::EthereumRuntimeRPCApi<Block>,
P: TransactionPool<Block = Block> + Sync + Send + 'static,
A: ChainApi<Block = Block> + 'static,
CIDP: CreateInherentDataProviders<Block, ()> + Send + 'static,
CT: fp_rpc::ConvertTransaction<<Block as BlockT>::Extrinsic> + Send + Sync + 'static,
BE: Backend<Block> + 'static,
{
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
use substrate_frame_rpc_system::{System, SystemApiServer};
let mut module = RpcExtension::new(());
let FullDeps { client, pool, deny_unsafe, eth } = deps;
module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?;
module.merge(TransactionPayment::new(client).into_rpc())?;
let module = create_eth::<_, _, _, _, _, _, _, DefaultEthConfig<C, BE>>(
module,
eth,
subscription_task_executor,
pubsub_notification_sinks,
)?;
Ok(module)
}
+146 -12
View File
@@ -2,7 +2,7 @@
//! substrate service.
// std
use std::{sync::Arc, time::Duration};
use std::{path::Path, sync::Arc, time::Duration};
use cumulus_client_cli::CollatorOptions;
// Cumulus Imports
@@ -22,7 +22,7 @@ use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE;
// Local Runtime Types
use parachain_template_runtime::{
opaque::{Block, Hash},
RuntimeApi,
RuntimeApi, TransactionConverter,
};
use sc_client_api::Backend;
use sc_consensus::ImportQueue;
@@ -34,9 +34,15 @@ use sc_network_sync::SyncingService;
use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager};
use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle};
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
use sp_core::U256;
use sp_keystore::KeystorePtr;
use substrate_prometheus_endpoint::Registry;
use crate::eth::{
db_config_dir, new_frontier_partial, spawn_frontier_tasks, BackendType, EthConfiguration,
FrontierBackend, FrontierPartialComponents,
};
/// Native executor type.
pub struct ParachainNativeExecutor;
@@ -66,6 +72,7 @@ type ParachainBlockImport = TParachainBlockImport<Block, Arc<ParachainClient>, P
/// builder in order to be able to perform chain operations.
pub fn new_partial(
config: &Configuration,
eth_config: &EthConfiguration,
) -> Result<
PartialComponents<
ParachainClient,
@@ -73,7 +80,13 @@ pub fn new_partial(
(),
sc_consensus::DefaultImportQueue<Block>,
sc_transaction_pool::FullPool<Block, ParachainClient>,
(ParachainBlockImport, Option<Telemetry>, Option<TelemetryWorkerHandle>),
(
ParachainBlockImport,
Option<Telemetry>,
Option<TelemetryWorkerHandle>,
FrontierBackend,
Arc<fc_rpc::OverrideHandle<Block>>,
),
>,
sc_service::Error,
> {
@@ -135,6 +148,37 @@ pub fn new_partial(
&task_manager,
)?;
let overrides = crate::rpc::overrides_handle(client.clone());
let frontier_backend = match eth_config.frontier_backend_type {
BackendType::KeyValue => FrontierBackend::KeyValue(fc_db::kv::Backend::open(
Arc::clone(&client),
&config.database,
&db_config_dir(config),
)?),
BackendType::Sql => {
let db_path = db_config_dir(config).join("sql");
std::fs::create_dir_all(&db_path).expect("failed creating sql db directory");
let backend = futures::executor::block_on(fc_db::sql::Backend::new(
fc_db::sql::BackendConfig::Sqlite(fc_db::sql::SqliteBackendConfig {
path: Path::new("sqlite:///")
.join(db_path)
.join("frontier.db3")
.to_str()
.unwrap(),
create_if_missing: true,
thread_count: eth_config.frontier_sql_backend_thread_count,
cache_size: eth_config.frontier_sql_backend_cache_size,
}),
eth_config.frontier_sql_backend_pool_size,
std::num::NonZeroU32::new(eth_config.frontier_sql_backend_num_ops_timeout),
overrides.clone(),
))
.unwrap_or_else(|err| panic!("failed creating sql backend: {:?}", err));
FrontierBackend::Sql(backend)
}
};
Ok(PartialComponents {
backend,
client,
@@ -143,7 +187,7 @@ pub fn new_partial(
task_manager,
transaction_pool,
select_chain: (),
other: (block_import, telemetry, telemetry_worker_handle),
other: (block_import, telemetry, telemetry_worker_handle, frontier_backend, overrides),
})
}
@@ -157,13 +201,19 @@ async fn start_node_impl(
parachain_config: Configuration,
polkadot_config: Configuration,
collator_options: CollatorOptions,
eth_config: &EthConfiguration,
para_id: ParaId,
hwbench: Option<sc_sysinfo::HwBench>,
) -> sc_service::error::Result<(TaskManager, Arc<ParachainClient>)> {
let parachain_config = prepare_node_config(parachain_config);
let params = new_partial(&parachain_config)?;
let (block_import, mut telemetry, telemetry_worker_handle) = params.other;
let params = new_partial(&parachain_config, eth_config)?;
let FrontierPartialComponents { filter_pool, fee_history_cache, fee_history_cache_limit } =
new_frontier_partial(eth_config)?;
let (block_import, mut telemetry, telemetry_worker_handle, frontier_backend, overrides) =
params.other;
let net_config = sc_network::config::FullNetworkConfiguration::new(&parachain_config.network);
let client = params.client.clone();
@@ -185,6 +235,7 @@ async fn start_node_impl(
let prometheus_registry = parachain_config.prometheus_registry().cloned();
let transaction_pool = params.transaction_pool.clone();
let import_queue_service = params.import_queue.service();
let slot_duration = sc_consensus_aura::slot_duration(&*client)?;
let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) =
build_network(BuildNetworkParams {
@@ -223,18 +274,81 @@ async fn start_node_impl(
);
}
let pubsub_notification_sinks: fc_mapping_sync::EthereumBlockNotificationSinks<
fc_mapping_sync::EthereumBlockNotification<Block>,
> = Default::default();
let pubsub_notification_sinks = Arc::new(pubsub_notification_sinks);
let rpc_builder = {
let client = client.clone();
let transaction_pool = transaction_pool.clone();
let target_gas_price = eth_config.target_gas_price;
let enable_dev_signer = eth_config.enable_dev_signer;
let pending_create_inherent_data_providers = move |_, ()| async move {
let current = sp_timestamp::InherentDataProvider::from_system_time();
let next_slot = current.timestamp().as_millis() + slot_duration.as_millis();
let timestamp = sp_timestamp::InherentDataProvider::new(next_slot.into());
let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
*timestamp,
slot_duration,
);
let dynamic_fee = fp_dynamic_fee::InherentDataProvider(U256::from(target_gas_price));
Ok((slot, timestamp, dynamic_fee))
};
let block_data_cache = Arc::new(fc_rpc::EthBlockDataCacheTask::new(
task_manager.spawn_handle(),
overrides.clone(),
eth_config.eth_log_block_cache,
eth_config.eth_statuses_cache,
prometheus_registry.clone(),
));
let execute_gas_limit_multiplier = eth_config.execute_gas_limit_multiplier;
let max_past_logs = eth_config.max_past_logs;
let network = network.clone();
let sync_service = sync_service.clone();
let frontier_backend = frontier_backend.clone();
let filter_pool = filter_pool.clone();
let overrides = overrides.clone();
let fee_history_cache = fee_history_cache.clone();
let pubsub_notification_sinks = pubsub_notification_sinks.clone();
Box::new(move |deny_unsafe, _| {
Box::new(move |deny_unsafe, subscription_task_executor| {
let eth = crate::rpc::EthDeps {
client: client.clone(),
pool: transaction_pool.clone(),
graph: transaction_pool.pool().clone(),
converter: Some(TransactionConverter),
is_authority: validator,
enable_dev_signer,
network: network.clone(),
sync: sync_service.clone(),
frontier_backend: match frontier_backend.clone() {
fc_db::Backend::KeyValue(b) => Arc::new(b),
fc_db::Backend::Sql(b) => Arc::new(b),
},
overrides: overrides.clone(),
block_data_cache: block_data_cache.clone(),
filter_pool: filter_pool.clone(),
max_past_logs,
fee_history_cache: fee_history_cache.clone(),
fee_history_cache_limit,
execute_gas_limit_multiplier,
forced_parent_hashes: None,
pending_create_inherent_data_providers,
};
let deps = crate::rpc::FullDeps {
client: client.clone(),
pool: transaction_pool.clone(),
deny_unsafe,
eth,
};
crate::rpc::create_full(deps).map_err(Into::into)
crate::rpc::create_full(
deps,
subscription_task_executor,
pubsub_notification_sinks.clone(),
)
.map_err(Into::into)
})
};
@@ -245,9 +359,6 @@ async fn start_node_impl(
task_manager: &mut task_manager,
config: parachain_config,
keystore: params.keystore_container.keystore(),
#[cfg(not(feature = "async-backing"))]
backend,
#[cfg(feature = "async-backing")]
backend: backend.clone(),
network: network.clone(),
sync_service: sync_service.clone(),
@@ -311,6 +422,20 @@ async fn start_node_impl(
sync_service: sync_service.clone(),
})?;
spawn_frontier_tasks(
&task_manager,
client.clone(),
backend.clone(),
frontier_backend,
filter_pool,
overrides,
fee_history_cache,
fee_history_cache_limit,
sync_service.clone(),
pubsub_notification_sinks,
)
.await;
if validator {
start_consensus(
client.clone(),
@@ -464,8 +589,17 @@ pub async fn start_parachain_node(
parachain_config: Configuration,
polkadot_config: Configuration,
collator_options: CollatorOptions,
eth_config: &EthConfiguration,
para_id: ParaId,
hwbench: Option<sc_sysinfo::HwBench>,
) -> sc_service::error::Result<(TaskManager, Arc<ParachainClient>)> {
start_node_impl(parachain_config, polkadot_config, collator_options, para_id, hwbench).await
start_node_impl(
parachain_config,
polkadot_config,
collator_options,
eth_config,
para_id,
hwbench,
)
.await
}