massa_api/
private.rs

1//! Copyright (c) 2022 MASSA LABS <info@massa.net>
2
3use 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    /// generate a new private API
49    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        //TODO: Reinvoke
158        // let network_command_sender = self.0.network_command_sender.clone();
159        // network_command_sender
160        //    .node_ban_by_ips(ips)
161        //    .await
162        //    .map_err(|e| ApiError::NetworkError(e).into())
163        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        //TODO: Change when unify node id and peer id
171        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        //TODO: Change when unify node id and peer id
183        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        //TODO: Reinvoke
194        // let network_command_sender = self.0.network_command_sender.clone();
195        // network_command_sender
196        //     .node_unban_ips(ips)
197        //     .await
198        //     .map_err(|e| ApiError::NetworkError(e).into())
199        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        //TODO: Reinvoke
265        // let network_command_sender = self.0.network_command_sender.clone();
266        // match network_command_sender.get_peers().await {
267        //     Ok(peers) => Ok(peers.peers.into_keys().sorted().collect::<Vec<IpAddr>>()),
268        //     Err(e) => Err(ApiError::NetworkError(e).into()),
269        // }
270        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        //TODO: Readd in network refactoring
277        // let network_command_sender = self.0.network_command_sender.clone();
278        // network_command_sender
279        //     .add_to_whitelist(ips)
280        //     .await
281        //     .map_err(|e| ApiError::NetworkError(e).into())
282        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        //TODO: Reinvoke
289        //TODO: Readd in network refactoring
290        // let network_command_sender = self.0.network_command_sender.clone();
291        // network_command_sender
292        //     .remove_from_whitelist(ips)
293        //     .await
294        //     .map_err(|e| ApiError::NetworkError(e).into())
295        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
392/// Run Search, Create, Read, Update, Delete operation on bootstrap list of IP(s)
393fn 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
447/// Get length of the given file if it exists(or create it if requested)
448fn 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
475/// Read bootstrap list IP(s) from json file
476fn 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
499/// Write bootstrap list IP(s) from json file
500fn 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}