anvil_polkadot/substrate_node/
rpc.rs1use crate::substrate_node::service::{Backend, Client, TransactionPoolHandle};
2use jsonrpsee::RpcModule;
3use polkadot_sdk::{
4 parachains_common::opaque::Block,
5 sc_chain_spec::ChainSpec,
6 sc_client_api::{Backend as ClientBackend, HeaderBackend},
7 sc_client_db::{BlocksPruning, PruningMode},
8 sc_network_types::{self, multiaddr::Multiaddr},
9 sc_rpc::{
10 author::AuthorApiServer,
11 chain::ChainApiServer,
12 offchain::OffchainApiServer,
13 state::{ChildStateApiServer, StateApiServer},
14 system::{Request, SystemApiServer, SystemInfo},
15 },
16 sc_rpc_api::DenyUnsafe,
17 sc_rpc_spec_v2::{
18 archive::ArchiveApiServer,
19 chain_head::ChainHeadApiServer,
20 chain_spec::ChainSpecApiServer,
21 transaction::{TransactionApiServer, TransactionBroadcastApiServer},
22 },
23 sc_service::{
24 self, Configuration, RpcHandlers, SpawnTaskHandle, TaskManager,
25 error::Error as ServiceError,
26 },
27 sc_utils::mpsc::{TracingUnboundedSender, tracing_unbounded},
28 sp_keystore::KeystorePtr,
29 substrate_frame_rpc_system::SystemApiServer as _,
30};
31use std::sync::Arc;
32
33pub fn spawn_rpc_server(
34 genesis_number: u64,
35 task_manager: &mut TaskManager,
36 client: Arc<Client>,
37 mut config: Configuration,
38 transaction_pool: Arc<TransactionPoolHandle>,
39 keystore: KeystorePtr,
40 backend: Arc<Backend>,
41) -> Result<RpcHandlers, ServiceError> {
42 let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc", 10_000);
43
44 let rpc_id_provider = config.rpc.id_provider.take();
45
46 let gen_rpc_module = || {
47 gen_rpc_module(
48 genesis_number,
49 task_manager.spawn_handle(),
50 client.clone(),
51 transaction_pool.clone(),
52 keystore.clone(),
53 system_rpc_tx.clone(),
54 config.impl_name.clone(),
55 config.impl_version.clone(),
56 config.chain_spec.as_ref(),
57 &config.state_pruning,
58 config.blocks_pruning,
59 backend.clone(),
60 )
61 };
62
63 let rpc_server_handle = sc_service::start_rpc_servers(
64 &config.rpc,
65 config.prometheus_registry(),
66 &config.tokio_handle,
67 gen_rpc_module,
68 rpc_id_provider,
69 )?;
70
71 let listen_addrs = rpc_server_handle
72 .listen_addrs()
73 .iter()
74 .map(|socket_addr| {
75 let mut multiaddr: Multiaddr = socket_addr.ip().into();
76 multiaddr.push(sc_network_types::multiaddr::Protocol::Tcp(socket_addr.port()));
77 multiaddr
78 })
79 .collect();
80
81 let in_memory_rpc = {
82 let mut module = gen_rpc_module()?;
83 module.extensions_mut().insert(DenyUnsafe::No);
84 module
85 };
86
87 let in_memory_rpc_handle = RpcHandlers::new(Arc::new(in_memory_rpc), listen_addrs);
88
89 task_manager.keep_alive((config.base_path, rpc_server_handle, system_rpc_rx));
90
91 Ok(in_memory_rpc_handle)
92}
93
94#[allow(clippy::too_many_arguments)]
99fn gen_rpc_module(
100 genesis_number: u64,
101 spawn_handle: SpawnTaskHandle,
102 client: Arc<Client>,
103 transaction_pool: Arc<TransactionPoolHandle>,
104 keystore: KeystorePtr,
105 system_rpc_tx: TracingUnboundedSender<Request<Block>>,
106 impl_name: String,
107 impl_version: String,
108 chain_spec: &dyn ChainSpec,
109 state_pruning: &Option<PruningMode>,
110 blocks_pruning: BlocksPruning,
111 backend: Arc<Backend>,
112) -> Result<RpcModule<()>, ServiceError> {
113 let rpc_builder = {
115 let client = client.clone();
116 let pool = transaction_pool.clone();
117
118 Box::new(move |_| {
119 let rpc_builder_ext: Result<_, ServiceError> = Ok(
120 polkadot_sdk::substrate_frame_rpc_system::System::new(client.clone(), pool.clone())
121 .into_rpc(),
122 );
123 rpc_builder_ext
124 })
125 };
126
127 let system_info = SystemInfo {
128 chain_name: chain_spec.name().into(),
129 impl_name,
130 impl_version,
131 properties: chain_spec.properties(),
132 chain_type: chain_spec.chain_type(),
133 };
134
135 let mut rpc_api = RpcModule::new(());
136 let task_executor = Arc::new(spawn_handle);
137
138 let (chain, state, child_state) = {
139 let chain =
140 polkadot_sdk::sc_rpc::chain::new_full(client.clone(), task_executor.clone()).into_rpc();
141 let (state, child_state) =
142 polkadot_sdk::sc_rpc::state::new_full(client.clone(), task_executor.clone(), None);
143 let state = state.into_rpc();
144 let child_state = child_state.into_rpc();
145
146 (chain, state, child_state)
147 };
148
149 const MAX_TRANSACTION_PER_CONNECTION: usize = 16;
150
151 let transaction_broadcast_rpc_v2 =
152 polkadot_sdk::sc_rpc_spec_v2::transaction::TransactionBroadcast::new(
153 client.clone(),
154 transaction_pool.clone(),
155 task_executor.clone(),
156 MAX_TRANSACTION_PER_CONNECTION,
157 )
158 .into_rpc();
159
160 let transaction_v2 = polkadot_sdk::sc_rpc_spec_v2::transaction::Transaction::new(
161 client.clone(),
162 transaction_pool.clone(),
163 task_executor.clone(),
164 None,
165 )
166 .into_rpc();
167
168 let chain_head_v2 = polkadot_sdk::sc_rpc_spec_v2::chain_head::ChainHead::new(
169 client.clone(),
170 backend.clone(),
171 task_executor.clone(),
172 polkadot_sdk::sc_rpc_spec_v2::chain_head::ChainHeadConfig::default(),
174 )
175 .into_rpc();
176
177 let is_archive_node = state_pruning.as_ref().map(|sp| sp.is_archive()).unwrap_or(false)
178 && blocks_pruning.is_archive();
179 let Some(genesis_hash) = client.hash(genesis_number as u32).ok().flatten() else {
181 return Err(ServiceError::Application(
182 format!("Genesis hash not found for genesis block number {genesis_number}").into(),
183 ));
184 };
185 if is_archive_node {
186 let archive_v2 = polkadot_sdk::sc_rpc_spec_v2::archive::Archive::new(
187 client.clone(),
188 backend.clone(),
189 genesis_hash,
190 task_executor.clone(),
191 )
192 .into_rpc();
193 rpc_api.merge(archive_v2).map_err(|e| ServiceError::Application(e.into()))?;
194 }
195
196 let chain_spec_v2 = polkadot_sdk::sc_rpc_spec_v2::chain_spec::ChainSpec::new(
197 chain_spec.name().into(),
198 genesis_hash,
199 chain_spec.properties(),
200 )
201 .into_rpc();
202
203 let author = polkadot_sdk::sc_rpc::author::Author::new(
204 client,
205 transaction_pool,
206 keystore,
207 task_executor.clone(),
208 )
209 .into_rpc();
210
211 let system = polkadot_sdk::sc_rpc::system::System::new(system_info, system_rpc_tx).into_rpc();
212
213 if let Some(storage) = backend.offchain_storage() {
214 let offchain = polkadot_sdk::sc_rpc::offchain::Offchain::new(storage).into_rpc();
215
216 rpc_api.merge(offchain).map_err(|e| ServiceError::Application(e.into()))?;
217 }
218
219 rpc_api.merge(transaction_v2).map_err(|e| ServiceError::Application(e.into()))?;
221 rpc_api.merge(transaction_broadcast_rpc_v2).map_err(|e| ServiceError::Application(e.into()))?;
222 rpc_api.merge(chain_head_v2).map_err(|e| ServiceError::Application(e.into()))?;
223 rpc_api.merge(chain_spec_v2).map_err(|e| ServiceError::Application(e.into()))?;
224
225 rpc_api.merge(chain).map_err(|e| ServiceError::Application(e.into()))?;
227 rpc_api.merge(author).map_err(|e| ServiceError::Application(e.into()))?;
228 rpc_api.merge(system).map_err(|e| ServiceError::Application(e.into()))?;
229 rpc_api.merge(state).map_err(|e| ServiceError::Application(e.into()))?;
230 rpc_api.merge(child_state).map_err(|e| ServiceError::Application(e.into()))?;
231 let extra_rpcs = rpc_builder(task_executor)?;
233 rpc_api.merge(extra_rpcs).map_err(|e| ServiceError::Application(e.into()))?;
234
235 Ok(rpc_api)
236}