1use crate::{MassaRpcServer, Private, RpcServer, StopHandle, Value, API};
4
5use async_trait::async_trait;
6use jsonrpsee::core::{client::Error as JsonRpseeError, RpcResult};
7use massa_api_exports::{
8 address::{
9 AddressFilter, AddressInfo, GetAddressDatastoreKeysRequest, GetAddressDatastoreKeysResponse,
10 },
11 block::{BlockInfo, BlockSummary},
12 config::APIConfig,
13 datastore::{DatastoreEntryInput, DatastoreEntryOutput},
14 endorsement::EndorsementInfo,
15 error::ApiError,
16 execution::{
17 DeferredCallResponse, DeferredCallsQuoteRequest, DeferredCallsQuoteResponse,
18 DeferredCallsSlotResponse, ExecuteReadOnlyResponse, ReadOnlyBytecodeExecution,
19 ReadOnlyCall, Transfer,
20 },
21 node::NodeStatus,
22 operation::{OperationInfo, OperationInput},
23 page::{PageRequest, PagedVec},
24 ListType, ScrudOperation, TimeInterval,
25};
26use massa_execution_exports::ExecutionController;
27use massa_hash::Hash;
28use massa_models::{
29 address::Address, block::Block, block_id::BlockId, clique::Clique, composite::PubkeySig,
30 endorsement::EndorsementId, execution::EventFilter, node::NodeId, operation::OperationId,
31 output_event::SCOutputEvent, prehash::PreHashSet, slot::Slot,
32};
33use massa_protocol_exports::{PeerId, ProtocolController};
34use massa_signature::KeyPair;
35use massa_wallet::Wallet;
36use parking_lot::RwLock;
37use std::net::{IpAddr, SocketAddr};
38use std::path::PathBuf;
39use std::str::FromStr;
40use std::sync::Arc;
41use std::{collections::BTreeSet, sync::Mutex};
42use std::{
43 fs::{remove_file, OpenOptions},
44 sync::Condvar,
45};
46
47impl API<Private> {
48 pub fn new(
50 protocol_controller: Box<dyn ProtocolController>,
51 execution_controller: Box<dyn ExecutionController>,
52 api_settings: APIConfig,
53 stop_cv: Arc<(Mutex<bool>, Condvar)>,
54 node_wallet: Arc<RwLock<Wallet>>,
55 ) -> Self {
56 API(Private {
57 protocol_controller,
58 execution_controller,
59 api_settings,
60 stop_cv,
61 node_wallet,
62 })
63 }
64}
65
66#[async_trait]
67impl RpcServer for API<Private> {
68 async fn serve(
69 self,
70 url: &SocketAddr,
71 settings: &APIConfig,
72 ) -> Result<StopHandle, JsonRpseeError> {
73 crate::serve(self.into_rpc(), url, settings).await
74 }
75}
76
77#[doc(hidden)]
78#[async_trait]
79impl MassaRpcServer for API<Private> {
80 fn stop_node(&self) -> RpcResult<()> {
81 *self.0.stop_cv.0.lock().expect("twice-locked in-thread") = true;
82 self.0.stop_cv.1.notify_all();
83 Ok(())
84 }
85
86 async fn node_sign_message(&self, message: Vec<u8>) -> RpcResult<PubkeySig> {
87 let signature = match self
88 .0
89 .api_settings
90 .keypair
91 .sign(&Hash::compute_from(&message))
92 {
93 Ok(signature) => signature,
94 Err(e) => {
95 return Err(
96 ApiError::InconsistencyError(format!("error signing message: {}", e)).into(),
97 );
98 }
99 };
100 Ok(PubkeySig {
101 public_key: self.0.api_settings.keypair.get_public_key(),
102 signature,
103 })
104 }
105
106 async fn add_staking_secret_keys(&self, secret_keys: Vec<String>) -> RpcResult<()> {
107 let keypairs = match secret_keys.iter().map(|x| KeyPair::from_str(x)).collect() {
108 Ok(keypairs) => keypairs,
109 Err(e) => return Err(ApiError::BadRequest(e.to_string()).into()),
110 };
111
112 let node_wallet = self.0.node_wallet.clone();
113 let mut w_wallet = node_wallet.write();
114 w_wallet
115 .add_keypairs(keypairs)
116 .map(|_| ())
117 .map_err(|e| ApiError::WalletError(e).into())
118 }
119
120 async fn execute_read_only_bytecode(
121 &self,
122 _reqs: Vec<ReadOnlyBytecodeExecution>,
123 ) -> RpcResult<Vec<ExecuteReadOnlyResponse>> {
124 crate::wrong_api::<_>()
125 }
126
127 async fn execute_read_only_call(
128 &self,
129 _reqs: Vec<ReadOnlyCall>,
130 ) -> RpcResult<Vec<ExecuteReadOnlyResponse>> {
131 crate::wrong_api::<_>()
132 }
133
134 async fn remove_staking_addresses(&self, addresses: Vec<Address>) -> RpcResult<()> {
135 let node_wallet = self.0.node_wallet.clone();
136
137 let changed = {
138 node_wallet
139 .write()
140 .remove_addresses(&addresses)
141 .map_err(ApiError::WalletError)?
142 };
143
144 if changed {
145 node_wallet.read().save().map_err(ApiError::WalletError)?;
146 }
147 Ok(())
148 }
149
150 async fn get_staking_addresses(&self) -> RpcResult<PreHashSet<Address>> {
151 let node_wallet = self.0.node_wallet.clone();
152 let w_wallet = node_wallet.read();
153 Ok(w_wallet.get_wallet_address_list())
154 }
155
156 async fn node_ban_by_ip(&self, _ips: Vec<IpAddr>) -> RpcResult<()> {
157 return Err(
164 ApiError::BadRequest("This request is currently not available".to_string()).into(),
165 );
166 }
167
168 async fn node_ban_by_id(&self, ids: Vec<NodeId>) -> RpcResult<()> {
169 let protocol_controller = self.0.protocol_controller.clone();
170 let peer_ids = ids
172 .into_iter()
173 .map(|id| PeerId::from_public_key(id.get_public_key()))
174 .collect();
175 protocol_controller
176 .ban_peers(peer_ids)
177 .map_err(|e| ApiError::ProtocolError(e.to_string()).into())
178 }
179
180 async fn node_unban_by_id(&self, ids: Vec<NodeId>) -> RpcResult<()> {
181 let protocol_controller = self.0.protocol_controller.clone();
182 let peer_ids = ids
184 .into_iter()
185 .map(|id| PeerId::from_public_key(id.get_public_key()))
186 .collect();
187 protocol_controller
188 .unban_peers(peer_ids)
189 .map_err(|e| ApiError::ProtocolError(e.to_string()).into())
190 }
191
192 async fn node_unban_by_ip(&self, _ips: Vec<IpAddr>) -> RpcResult<()> {
193 return Err(
200 ApiError::BadRequest("This request is currently not available".to_string()).into(),
201 );
202 }
203
204 async fn get_slots_transfers(&self, _: Vec<Slot>) -> RpcResult<Vec<Vec<Transfer>>> {
205 crate::wrong_api::<Vec<Vec<Transfer>>>()
206 }
207
208 async fn get_status(&self) -> RpcResult<NodeStatus> {
209 crate::wrong_api::<NodeStatus>()
210 }
211
212 async fn get_cliques(&self) -> RpcResult<Vec<Clique>> {
213 crate::wrong_api::<Vec<Clique>>()
214 }
215
216 async fn get_stakers(&self, _: Option<PageRequest>) -> RpcResult<PagedVec<(Address, u64)>> {
217 crate::wrong_api::<PagedVec<(Address, u64)>>()
218 }
219
220 async fn get_operations(&self, _: Vec<OperationId>) -> RpcResult<Vec<OperationInfo>> {
221 crate::wrong_api::<Vec<OperationInfo>>()
222 }
223
224 async fn get_endorsements(&self, _: Vec<EndorsementId>) -> RpcResult<Vec<EndorsementInfo>> {
225 crate::wrong_api::<Vec<EndorsementInfo>>()
226 }
227
228 async fn get_blocks(&self, _: Vec<BlockId>) -> RpcResult<Vec<BlockInfo>> {
229 crate::wrong_api::<Vec<BlockInfo>>()
230 }
231
232 async fn get_blockclique_block_by_slot(&self, _: Slot) -> RpcResult<Option<Block>> {
233 crate::wrong_api::<Option<Block>>()
234 }
235
236 async fn get_graph_interval(&self, _: TimeInterval) -> RpcResult<Vec<BlockSummary>> {
237 crate::wrong_api::<Vec<BlockSummary>>()
238 }
239
240 async fn get_datastore_entries(
241 &self,
242 _: Vec<DatastoreEntryInput>,
243 ) -> RpcResult<Vec<DatastoreEntryOutput>> {
244 crate::wrong_api()
245 }
246
247 async fn get_addresses(&self, _: Vec<Address>) -> RpcResult<Vec<AddressInfo>> {
248 crate::wrong_api::<Vec<AddressInfo>>()
249 }
250
251 async fn get_addresses_bytecode(&self, _: Vec<AddressFilter>) -> RpcResult<Vec<Vec<u8>>> {
252 crate::wrong_api::<Vec<Vec<u8>>>()
253 }
254
255 async fn send_operations(&self, _: Vec<OperationInput>) -> RpcResult<Vec<OperationId>> {
256 crate::wrong_api::<Vec<OperationId>>()
257 }
258
259 async fn get_filtered_sc_output_event(&self, _: EventFilter) -> RpcResult<Vec<SCOutputEvent>> {
260 crate::wrong_api::<Vec<SCOutputEvent>>()
261 }
262
263 async fn node_peers_whitelist(&self) -> RpcResult<Vec<IpAddr>> {
264 return Err(
271 ApiError::BadRequest("This request is currently not available".to_string()).into(),
272 );
273 }
274
275 async fn node_add_to_peers_whitelist(&self, _ips: Vec<IpAddr>) -> RpcResult<()> {
276 return Err(
283 ApiError::BadRequest("This request is currently not available".to_string()).into(),
284 );
285 }
286
287 async fn node_remove_from_peers_whitelist(&self, _ips: Vec<IpAddr>) -> RpcResult<()> {
288 return Err(
296 ApiError::BadRequest("This request is currently not available".to_string()).into(),
297 );
298 }
299
300 async fn node_bootstrap_whitelist(&self) -> RpcResult<Vec<IpAddr>> {
301 read_ips_from_jsonfile(
302 self.0.api_settings.bootstrap_whitelist_path.clone(),
303 &ListType::Whitelist,
304 )
305 }
306
307 async fn node_bootstrap_whitelist_allow_all(&self) -> RpcResult<()> {
308 remove_file(self.0.api_settings.bootstrap_whitelist_path.clone()).map_err(|e| {
309 ApiError::InternalServerError(format!(
310 "failed to delete bootstrap whitelist configuration file: {}",
311 e
312 ))
313 .into()
314 })
315 }
316
317 async fn node_add_to_bootstrap_whitelist(&self, ips: Vec<IpAddr>) -> RpcResult<()> {
318 run_scrud_operation(
319 self.0.api_settings.bootstrap_whitelist_path.clone(),
320 ips,
321 ListType::Whitelist,
322 ScrudOperation::Create,
323 )
324 }
325
326 async fn node_remove_from_bootstrap_whitelist(&self, ips: Vec<IpAddr>) -> RpcResult<()> {
327 run_scrud_operation(
328 self.0.api_settings.bootstrap_whitelist_path.clone(),
329 ips,
330 ListType::Whitelist,
331 ScrudOperation::Delete,
332 )
333 }
334
335 async fn node_bootstrap_blacklist(&self) -> RpcResult<Vec<IpAddr>> {
336 read_ips_from_jsonfile(
337 self.0.api_settings.bootstrap_blacklist_path.clone(),
338 &ListType::Blacklist,
339 )
340 }
341
342 async fn node_add_to_bootstrap_blacklist(&self, ips: Vec<IpAddr>) -> RpcResult<()> {
343 run_scrud_operation(
344 self.0.api_settings.bootstrap_blacklist_path.clone(),
345 ips,
346 ListType::Blacklist,
347 ScrudOperation::Create,
348 )
349 }
350
351 async fn node_remove_from_bootstrap_blacklist(&self, ips: Vec<IpAddr>) -> RpcResult<()> {
352 run_scrud_operation(
353 self.0.api_settings.bootstrap_blacklist_path.clone(),
354 ips,
355 ListType::Blacklist,
356 ScrudOperation::Delete,
357 )
358 }
359
360 async fn get_deferred_call_quote(
361 &self,
362 _req: Vec<DeferredCallsQuoteRequest>,
363 ) -> RpcResult<Vec<DeferredCallsQuoteResponse>> {
364 crate::wrong_api::<Vec<DeferredCallsQuoteResponse>>()
365 }
366 async fn get_deferred_call_info(
367 &self,
368 _arg: Vec<String>,
369 ) -> RpcResult<Vec<DeferredCallResponse>> {
370 crate::wrong_api::<Vec<DeferredCallResponse>>()
371 }
372
373 async fn get_deferred_call_ids_by_slot(
374 &self,
375 _slot: Vec<Slot>,
376 ) -> RpcResult<Vec<DeferredCallsSlotResponse>> {
377 crate::wrong_api::<Vec<DeferredCallsSlotResponse>>()
378 }
379
380 async fn get_openrpc_spec(&self) -> RpcResult<Value> {
381 crate::wrong_api::<Value>()
382 }
383
384 async fn get_addresses_datastore_keys(
385 &self,
386 _arg: Vec<GetAddressDatastoreKeysRequest>,
387 ) -> RpcResult<Vec<GetAddressDatastoreKeysResponse>> {
388 crate::wrong_api::<Vec<_>>()
389 }
390}
391
392fn run_scrud_operation(
394 bootstrap_list_file: PathBuf,
395 ips: Vec<IpAddr>,
396 list_type: ListType,
397 scrud_operation: ScrudOperation,
398) -> RpcResult<()> {
399 match scrud_operation {
400 ScrudOperation::Create => get_file_len(bootstrap_list_file.clone(), &list_type, true)
401 .and_then(|length| {
402 if length == 0 {
403 write_ips_to_jsonfile(bootstrap_list_file, BTreeSet::from_iter(ips), &list_type)
404 } else {
405 read_ips_from_jsonfile(bootstrap_list_file.clone(), &list_type)
406 .map(BTreeSet::from_iter)
407 .and_then(|mut list_ips: BTreeSet<IpAddr>| {
408 list_ips.extend(ips);
409 write_ips_to_jsonfile(bootstrap_list_file, list_ips, &list_type)
410 })
411 }
412 }),
413 ScrudOperation::Delete => get_file_len(bootstrap_list_file.clone(), &list_type, false)
414 .and_then(|length| {
415 if length == 0 {
416 Err(ApiError::InternalServerError(format!(
417 "failed, bootstrap {} configuration file is empty",
418 list_type
419 ))
420 .into())
421 } else {
422 read_ips_from_jsonfile(bootstrap_list_file.clone(), &list_type)
423 .map(BTreeSet::from_iter)
424 .and_then(|mut list_ips: BTreeSet<IpAddr>| {
425 if list_ips.is_empty() {
426 return Err(ApiError::InternalServerError(format!(
427 "failed to execute delete operation, bootstrap {} is empty",
428 list_type
429 ))
430 .into());
431 }
432 ips.into_iter().for_each(|ip| {
433 list_ips.remove(&ip);
434 });
435 write_ips_to_jsonfile(bootstrap_list_file, list_ips, &list_type)
436 })
437 }
438 }),
439 _ => Err(ApiError::BadRequest(format!(
440 "failed operation {} is not supported on {}",
441 list_type, scrud_operation
442 ))
443 .into()),
444 }
445}
446
447fn get_file_len(
449 bootstrap_list_file: PathBuf,
450 list_type: &ListType,
451 create: bool,
452) -> RpcResult<u64> {
453 OpenOptions::new()
454 .read(true)
455 .write(true)
456 .create(create)
457 .open(bootstrap_list_file)
458 .map_err(|e| {
459 ApiError::InternalServerError(format!(
460 "failed to read bootstrap {} configuration file: {}",
461 list_type, e
462 ))
463 .into()
464 })
465 .and_then(|file| match file.metadata() {
466 Ok(metadata) => Ok(metadata.len()),
467 Err(e) => Err(ApiError::InternalServerError(format!(
468 "failed to read bootstrap {} configuration file metadata: {}",
469 list_type, e
470 ))
471 .into()),
472 })
473}
474
475fn read_ips_from_jsonfile(
477 bootstrap_list_file: PathBuf,
478 list_type: &ListType,
479) -> RpcResult<Vec<IpAddr>> {
480 std::fs::read_to_string(bootstrap_list_file)
481 .map_err(|e| {
482 ApiError::InternalServerError(format!(
483 "failed to read bootstrap {} configuration file: {}",
484 list_type, e
485 ))
486 .into()
487 })
488 .and_then(|bootstrap_list_str| {
489 serde_json::from_str(&bootstrap_list_str).map_err(|e| {
490 ApiError::InternalServerError(format!(
491 "failed to parse bootstrap {} configuration file: {}",
492 list_type, e
493 ))
494 .into()
495 })
496 })
497}
498
499fn write_ips_to_jsonfile(
501 bootstrap_list_file: PathBuf,
502 ips: BTreeSet<IpAddr>,
503 list_type: &ListType,
504) -> RpcResult<()> {
505 OpenOptions::new()
506 .write(true)
507 .create(true)
508 .truncate(true)
509 .open(bootstrap_list_file)
510 .map_err(|e| {
511 ApiError::InternalServerError(format!(
512 "failed to create bootstrap {} configuration file: {}",
513 list_type, e
514 ))
515 .into()
516 })
517 .and_then(|file| {
518 serde_json::to_writer_pretty(file, &ips).map_err(|e| {
519 ApiError::InternalServerError(format!(
520 "failed to write bootstrap {} configuration file: {}",
521 list_type, e
522 ))
523 .into()
524 })
525 })
526}