anvil_polkadot/substrate_node/service/
mod.rs1use crate::{
2 AnvilNodeConfig,
3 substrate_node::{
4 mining_engine::{MiningEngine, MiningMode, run_mining_engine},
5 rpc::spawn_rpc_server,
6 service::consensus::SameSlotConsensusDataProvider,
7 },
8};
9use anvil::eth::backend::time::TimeManager;
10use parking_lot::Mutex;
11use polkadot_sdk::{
12 parachains_common::opaque::Block,
13 sc_basic_authorship, sc_consensus,
14 sc_consensus_manual_seal::{self},
15 sc_service::{
16 self, Configuration, RpcHandlers, SpawnTaskHandle, TaskManager,
17 error::Error as ServiceError,
18 },
19 sc_transaction_pool, sp_timestamp,
20};
21use std::sync::Arc;
22use tokio_stream::wrappers::ReceiverStream;
23
24pub use backend::{BackendError, BackendWithOverlay, StorageOverrides};
25pub use client::Client;
26
27mod backend;
28mod client;
29mod consensus;
30mod executor;
31pub mod storage;
32
33pub type Backend = sc_service::TFullBackend<Block>;
34
35pub type TransactionPoolHandle = sc_transaction_pool::TransactionPoolHandle<Block, Client>;
36
37type SelectChain = sc_consensus::LongestChain<Backend, Block>;
38
39#[derive(Clone)]
40pub struct Service {
41 pub spawn_handle: SpawnTaskHandle,
42 pub client: Arc<Client>,
43 pub backend: Arc<Backend>,
44 pub tx_pool: Arc<TransactionPoolHandle>,
45 pub rpc_handlers: RpcHandlers,
46 pub mining_engine: Arc<MiningEngine>,
47 pub storage_overrides: Arc<Mutex<StorageOverrides>>,
48 pub genesis_block_number: u64,
49}
50
51pub fn new(
53 anvil_config: &AnvilNodeConfig,
54 config: Configuration,
55) -> Result<(Service, TaskManager), ServiceError> {
56 let storage_overrides =
57 Arc::new(Mutex::new(StorageOverrides::new(anvil_config.revive_rpc_block_limit)));
58
59 let (client, backend, keystore, mut task_manager) = client::new_client(
60 anvil_config.get_genesis_number(),
61 &config,
62 sc_service::new_wasm_executor(&config.executor),
63 storage_overrides.clone(),
64 )?;
65
66 let transaction_pool = Arc::from(
67 sc_transaction_pool::Builder::new(
68 task_manager.spawn_essential_handle(),
69 client.clone(),
70 config.role.is_authority().into(),
71 )
72 .with_options(config.transaction_pool.clone())
73 .build(),
74 );
75
76 task_manager.spawn_handle().spawn(
78 "txpool-notifications",
79 Some("transaction-pool"),
80 sc_transaction_pool::notification_future(client.clone(), transaction_pool.clone()),
81 );
82
83 let (seal_engine_command_sender, commands_stream) = tokio::sync::mpsc::channel(1024);
84 let commands_stream = ReceiverStream::new(commands_stream);
85
86 let mining_mode =
87 MiningMode::new(anvil_config.block_time, anvil_config.mixed_mining, anvil_config.no_mining);
88 let time_manager = Arc::new(TimeManager::new_with_milliseconds(
89 sp_timestamp::Timestamp::from(
90 anvil_config
91 .get_genesis_timestamp()
92 .checked_mul(1000)
93 .ok_or(ServiceError::Application("Genesis timestamp overflow".into()))?,
94 )
95 .into(),
96 ));
97
98 let mining_engine = Arc::new(MiningEngine::new(
99 mining_mode,
100 transaction_pool.clone(),
101 time_manager.clone(),
102 seal_engine_command_sender,
103 ));
104
105 let rpc_handlers = spawn_rpc_server(
106 anvil_config.get_genesis_number(),
107 &mut task_manager,
108 client.clone(),
109 config,
110 transaction_pool.clone(),
111 keystore,
112 backend.clone(),
113 )?;
114
115 task_manager.spawn_handle().spawn(
116 "mining_engine_task",
117 Some("consensus"),
118 run_mining_engine(mining_engine.clone()),
119 );
120
121 let proposer = sc_basic_authorship::ProposerFactory::new(
122 task_manager.spawn_handle(),
123 client.clone(),
124 transaction_pool.clone(),
125 None,
126 None,
127 );
128
129 let create_inherent_data_providers = {
130 move |_, ()| {
131 let next_timestamp = time_manager.next_timestamp();
132 async move { Ok(sp_timestamp::InherentDataProvider::new(next_timestamp.into())) }
133 }
134 };
135
136 let params = sc_consensus_manual_seal::ManualSealParams {
137 block_import: client.clone(),
138 env: proposer,
139 client: client.clone(),
140 pool: transaction_pool.clone(),
141 select_chain: SelectChain::new(backend.clone()),
142 commands_stream: Box::pin(commands_stream),
143 consensus_data_provider: Some(Box::new(SameSlotConsensusDataProvider::new())),
144 create_inherent_data_providers,
145 };
146 let authorship_future = sc_consensus_manual_seal::run_manual_seal(params);
147
148 task_manager.spawn_essential_handle().spawn_blocking(
149 "manual-seal",
150 "substrate",
151 authorship_future,
152 );
153
154 Ok((
155 Service {
156 spawn_handle: task_manager.spawn_handle(),
157 client,
158 backend,
159 tx_pool: transaction_pool,
160 rpc_handlers,
161 mining_engine,
162 storage_overrides,
163 genesis_block_number: anvil_config.get_genesis_number(),
164 },
165 task_manager,
166 ))
167}