1#![warn(missing_docs)]
5#![warn(unused_crate_dependencies)]
6
7use api_trait::MassaApiServer;
8use http::Method;
9use jsonrpsee::core::{client::Error as JsonRpseeError, RpcResult};
10use jsonrpsee::proc_macros::rpc;
11use jsonrpsee::server::middleware::http::HostFilterLayer;
12use jsonrpsee::server::{BatchRequestConfig, PingConfig, ServerBuilder, ServerHandle};
13use jsonrpsee::RpcModule;
14use massa_api_exports::address::GetAddressDatastoreKeysResponse;
15use massa_api_exports::execution::{
16 DeferredCallResponse, DeferredCallsQuoteRequest, DeferredCallsQuoteResponse,
17 DeferredCallsSlotResponse, Transfer,
18};
19use massa_api_exports::{
20 address::{AddressFilter, AddressInfo, GetAddressDatastoreKeysRequest},
21 block::{BlockInfo, BlockSummary},
22 config::APIConfig,
23 datastore::{DatastoreEntryInput, DatastoreEntryOutput},
24 endorsement::EndorsementInfo,
25 error::ApiError::WrongAPI,
26 execution::{ExecuteReadOnlyResponse, ReadOnlyBytecodeExecution, ReadOnlyCall},
27 node::NodeStatus,
28 operation::{OperationInfo, OperationInput},
29 page::{PageRequest, PagedVec},
30 TimeInterval,
31};
32use massa_consensus_exports::{ConsensusBroadcasts, ConsensusController};
33use massa_execution_exports::ExecutionController;
34use massa_models::clique::Clique;
35use massa_models::composite::PubkeySig;
36use massa_models::node::NodeId;
37use massa_models::operation::OperationId;
38use massa_models::output_event::SCOutputEvent;
39use massa_models::prehash::PreHashSet;
40use massa_models::{
41 address::Address, block::Block, block_id::BlockId, endorsement::EndorsementId,
42 execution::EventFilter, slot::Slot, version::Version,
43};
44use massa_pool_exports::{PoolBroadcasts, PoolController};
45use massa_pos_exports::SelectorController;
46use massa_protocol_exports::{ProtocolConfig, ProtocolController};
47use massa_storage::Storage;
48use massa_versioning::keypair_factory::KeyPairFactory;
49use massa_wallet::Wallet;
50use parking_lot::RwLock;
51use serde_json::Value;
52use std::net::{IpAddr, SocketAddr};
53use std::sync::{Arc, Condvar, Mutex};
54use tower_http::cors::{Any, CorsLayer};
55use tracing::{info, warn};
56
57#[cfg(feature = "test-exports")]
58use massa_channel as _;
59#[cfg(feature = "test-exports")]
60use massa_grpc as _;
61
62mod api;
63mod api_trait;
64mod private;
65mod public;
66
67#[cfg(test)]
68mod tests;
69
70pub struct Public {
72 pub consensus_controller: Box<dyn ConsensusController>,
74 pub execution_controller: Box<dyn ExecutionController>,
76 pub selector_controller: Box<dyn SelectorController>,
78 pub pool_command_sender: Box<dyn PoolController>,
80 pub protocol_controller: Box<dyn ProtocolController>,
82 pub storage: Storage,
84 pub api_settings: APIConfig,
86 pub protocol_config: ProtocolConfig,
88 pub version: Version,
90 pub node_id: NodeId,
92 pub keypair_factory: KeyPairFactory,
94}
95
96pub struct Private {
98 pub protocol_controller: Box<dyn ProtocolController>,
100 pub execution_controller: Box<dyn ExecutionController>,
102 pub api_settings: APIConfig,
104 pub stop_cv: Arc<(Mutex<bool>, Condvar)>,
107 pub node_wallet: Arc<RwLock<Wallet>>,
109}
110
111pub struct ApiV2 {
113 pub consensus_controller: Box<dyn ConsensusController>,
115 pub consensus_broadcasts: ConsensusBroadcasts,
117 pub execution_controller: Box<dyn ExecutionController>,
119 pub pool_broadcasts: PoolBroadcasts,
121 pub api_settings: APIConfig,
123 pub version: Version,
125}
126
127pub struct API<T>(T);
129
130#[async_trait::async_trait]
132pub trait RpcServer: MassaRpcServer {
133 async fn serve(
135 self,
136 url: &SocketAddr,
137 api_config: &APIConfig,
138 ) -> Result<StopHandle, JsonRpseeError>;
139}
140
141#[async_trait::async_trait]
143pub trait ApiServer: MassaApiServer {
144 async fn serve(
146 self,
147 url: &SocketAddr,
148 api_config: &APIConfig,
149 ) -> Result<StopHandle, JsonRpseeError>;
150}
151
152async fn serve<T>(
153 api: RpcModule<T>,
154 url: &SocketAddr,
155 api_config: &APIConfig,
156) -> Result<StopHandle, JsonRpseeError> {
157 let ping_config = PingConfig::new().ping_interval(api_config.ping_interval.to_duration());
158 let mut server_builder = ServerBuilder::new()
159 .max_request_body_size(api_config.max_request_body_size)
160 .max_response_body_size(api_config.max_response_body_size)
161 .max_connections(api_config.max_connections)
162 .set_batch_request_config(if api_config.batch_request_limit > 0 {
163 BatchRequestConfig::Limit(api_config.batch_request_limit)
164 } else {
165 BatchRequestConfig::Disabled
166 })
167 .enable_ws_ping(ping_config);
168
169 if api_config.enable_http && !api_config.enable_ws {
170 server_builder = server_builder.http_only();
171 } else if api_config.enable_ws && !api_config.enable_http {
172 server_builder = server_builder.ws_only()
173 } else if !api_config.enable_http && !api_config.enable_ws {
174 panic!("wrong server configuration, you can't disable both http and ws");
175 }
176
177 let cors = CorsLayer::new()
178 .allow_methods([Method::POST, Method::OPTIONS])
180 .allow_origin(Any)
182 .allow_headers([http::header::CONTENT_TYPE]);
183
184 let hosts = if api_config.allow_hosts.is_empty() {
185 vec!["*:*"]
186 } else {
187 api_config
188 .allow_hosts
189 .iter()
190 .map(|hostname| hostname.as_str())
191 .collect()
192 };
193
194 let allowed_hosts = HostFilterLayer::new(hosts).expect("failed to build allowed hosts filter");
195
196 let middleware = tower::ServiceBuilder::new()
197 .layer(cors)
198 .layer(allowed_hosts);
199
200 let server = server_builder
201 .set_http_middleware(middleware)
202 .build(url)
203 .await
204 .expect("failed to build server");
205
206 let server_handler = server.start(api);
207 let stop_handler = StopHandle { server_handler };
208
209 Ok(stop_handler)
210}
211
212pub struct StopHandle {
214 server_handler: ServerHandle,
215}
216
217impl StopHandle {
218 pub async fn stop(self) {
220 match self.server_handler.stop() {
221 Ok(_) => {
222 info!("API stop signal sent successfully");
223 }
224 Err(err) => warn!("API thread panicked: {:?}", err),
225 }
226 self.server_handler.stopped().await;
227 }
228}
229
230#[rpc(server)]
232pub trait MassaRpc {
233 #[method(name = "stop_node")]
235 fn stop_node(&self) -> RpcResult<()>;
236
237 #[method(name = "node_sign_message")]
240 async fn node_sign_message(&self, arg: Vec<u8>) -> RpcResult<PubkeySig>;
241
242 #[method(name = "add_staking_secret_keys")]
245 async fn add_staking_secret_keys(&self, arg: Vec<String>) -> RpcResult<()>;
246
247 #[method(name = "execute_read_only_bytecode")]
249 async fn execute_read_only_bytecode(
250 &self,
251 arg: Vec<ReadOnlyBytecodeExecution>,
252 ) -> RpcResult<Vec<ExecuteReadOnlyResponse>>;
253
254 #[method(name = "execute_read_only_call")]
256 async fn execute_read_only_call(
257 &self,
258 arg: Vec<ReadOnlyCall>,
259 ) -> RpcResult<Vec<ExecuteReadOnlyResponse>>;
260
261 #[method(name = "remove_staking_addresses")]
264 async fn remove_staking_addresses(&self, arg: Vec<Address>) -> RpcResult<()>;
265
266 #[method(name = "get_staking_addresses")]
268 async fn get_staking_addresses(&self) -> RpcResult<PreHashSet<Address>>;
269
270 #[method(name = "node_ban_by_ip")]
273 async fn node_ban_by_ip(&self, arg: Vec<IpAddr>) -> RpcResult<()>;
274
275 #[method(name = "node_ban_by_id")]
278 async fn node_ban_by_id(&self, arg: Vec<NodeId>) -> RpcResult<()>;
279
280 #[method(name = "node_peers_whitelist")]
282 async fn node_peers_whitelist(&self) -> RpcResult<Vec<IpAddr>>;
283
284 #[method(name = "node_add_to_peers_whitelist")]
288 async fn node_add_to_peers_whitelist(&self, arg: Vec<IpAddr>) -> RpcResult<()>;
289
290 #[method(name = "node_remove_from_peers_whitelist")]
294 async fn node_remove_from_peers_whitelist(&self, arg: Vec<IpAddr>) -> RpcResult<()>;
295
296 #[method(name = "node_bootstrap_whitelist")]
298 async fn node_bootstrap_whitelist(&self) -> RpcResult<Vec<IpAddr>>;
299
300 #[method(name = "node_bootstrap_whitelist_allow_all")]
303 async fn node_bootstrap_whitelist_allow_all(&self) -> RpcResult<()>;
304
305 #[method(name = "node_add_to_bootstrap_whitelist")]
307 async fn node_add_to_bootstrap_whitelist(&self, arg: Vec<IpAddr>) -> RpcResult<()>;
308
309 #[method(name = "node_remove_from_bootstrap_whitelist")]
311 async fn node_remove_from_bootstrap_whitelist(&self, arg: Vec<IpAddr>) -> RpcResult<()>;
312
313 #[method(name = "node_bootstrap_blacklist")]
315 async fn node_bootstrap_blacklist(&self) -> RpcResult<Vec<IpAddr>>;
316
317 #[method(name = "node_add_to_bootstrap_blacklist")]
319 async fn node_add_to_bootstrap_blacklist(&self, arg: Vec<IpAddr>) -> RpcResult<()>;
320
321 #[method(name = "node_remove_from_bootstrap_blacklist")]
323 async fn node_remove_from_bootstrap_blacklist(&self, arg: Vec<IpAddr>) -> RpcResult<()>;
324
325 #[method(name = "node_unban_by_ip")]
328 async fn node_unban_by_ip(&self, arg: Vec<IpAddr>) -> RpcResult<()>;
329
330 #[method(name = "node_unban_by_id")]
333 async fn node_unban_by_id(&self, arg: Vec<NodeId>) -> RpcResult<()>;
334
335 #[method(name = "get_status")]
337 async fn get_status(&self) -> RpcResult<NodeStatus>;
338
339 #[method(name = "get_cliques")]
341 async fn get_cliques(&self) -> RpcResult<Vec<Clique>>;
342
343 #[method(name = "get_stakers")]
345 async fn get_stakers(
346 &self,
347 page_request: Option<PageRequest>,
348 ) -> RpcResult<PagedVec<(Address, u64)>>;
349
350 #[method(name = "get_operations")]
352 async fn get_operations(&self, arg: Vec<OperationId>) -> RpcResult<Vec<OperationInfo>>;
353
354 #[method(name = "get_endorsements")]
356 async fn get_endorsements(&self, arg: Vec<EndorsementId>) -> RpcResult<Vec<EndorsementInfo>>;
357
358 #[method(name = "get_blocks")]
360 async fn get_blocks(&self, arg: Vec<BlockId>) -> RpcResult<Vec<BlockInfo>>;
361
362 #[method(name = "get_blockclique_block_by_slot")]
365 async fn get_blockclique_block_by_slot(&self, arg: Slot) -> RpcResult<Option<Block>>;
366
367 #[method(name = "get_graph_interval")]
370 async fn get_graph_interval(&self, arg: TimeInterval) -> RpcResult<Vec<BlockSummary>>;
371
372 #[method(name = "get_datastore_entries")]
374 async fn get_datastore_entries(
375 &self,
376 arg: Vec<DatastoreEntryInput>,
377 ) -> RpcResult<Vec<DatastoreEntryOutput>>;
378
379 #[method(name = "get_addresses")]
381 async fn get_addresses(&self, arg: Vec<Address>) -> RpcResult<Vec<AddressInfo>>;
382
383 #[method(name = "get_addresses_bytecode")]
385 async fn get_addresses_bytecode(&self, args: Vec<AddressFilter>) -> RpcResult<Vec<Vec<u8>>>;
386
387 #[method(name = "get_slots_transfers")]
389 async fn get_slots_transfers(&self, arg: Vec<Slot>) -> RpcResult<Vec<Vec<Transfer>>>;
390
391 #[method(name = "send_operations")]
393 async fn send_operations(&self, arg: Vec<OperationInput>) -> RpcResult<Vec<OperationId>>;
394
395 #[method(name = "get_filtered_sc_output_event")]
402 async fn get_filtered_sc_output_event(&self, arg: EventFilter)
403 -> RpcResult<Vec<SCOutputEvent>>;
404
405 #[method(name = "rpc.discover")]
407 async fn get_openrpc_spec(&self) -> RpcResult<Value>;
408
409 #[method(name = "get_deferred_call_quote")]
411 async fn get_deferred_call_quote(
412 &self,
413 arg: Vec<DeferredCallsQuoteRequest>,
414 ) -> RpcResult<Vec<DeferredCallsQuoteResponse>>;
415
416 #[method(name = "get_deferred_call_info")]
418 async fn get_deferred_call_info(
419 &self,
420 arg: Vec<String>,
421 ) -> RpcResult<Vec<DeferredCallResponse>>;
422
423 #[method(name = "get_deferred_call_ids_by_slot")]
425 async fn get_deferred_call_ids_by_slot(
426 &self,
427 arg: Vec<Slot>,
428 ) -> RpcResult<Vec<DeferredCallsSlotResponse>>;
429
430 #[method(name = "get_addresses_datastore_keys")]
432 async fn get_addresses_datastore_keys(
433 &self,
434 arg: Vec<GetAddressDatastoreKeysRequest>,
435 ) -> RpcResult<Vec<GetAddressDatastoreKeysResponse>>;
436}
437
438fn wrong_api<T>() -> RpcResult<T> {
439 Err((WrongAPI).into())
440}