Skip to main content

ckb_rpc/module/
alert.rs

1use crate::error::RPCError;
2use async_trait::async_trait;
3use ckb_async_runtime::Handle;
4use ckb_jsonrpc_types::Alert;
5use ckb_network::{NetworkController, SupportProtocols};
6use ckb_network_alert::{notifier::Notifier as AlertNotifier, verifier::Verifier as AlertVerifier};
7use ckb_types::{packed, prelude::*};
8use ckb_util::Mutex;
9
10use jsonrpc_core::Result;
11use jsonrpc_utils::rpc;
12use std::sync::Arc;
13
14/// RPC Module Alert for network alerts.
15///
16/// An alert is a message about critical problems to be broadcast to all nodes via the p2p network.
17///
18/// The alerts must be signed by 2-of-4 signatures, where the public keys are hard-coded in the source code
19/// and belong to early CKB developers.
20#[rpc(openrpc)]
21#[async_trait]
22pub trait AlertRpc {
23    /// Sends an alert.
24    ///
25    /// This RPC returns `null` on success.
26    ///
27    /// ## Errors
28    ///
29    /// * [`AlertFailedToVerifySignatures (-1000)`](../enum.RPCError.html#variant.AlertFailedToVerifySignatures) - Some signatures in the request are invalid.
30    /// * [`P2PFailedToBroadcast (-101)`](../enum.RPCError.html#variant.P2PFailedToBroadcast) - Alert is saved locally but has failed to broadcast to the P2P network.
31    /// * `InvalidParams (-32602)` - The time specified in `alert.notice_until` must be in the future.
32    ///
33    /// ## Examples
34    ///
35    /// Request
36    ///
37    /// ```json
38    /// {
39    ///   "jsonrpc": "2.0",
40    ///   "method": "send_alert",
41    ///   "params": [
42    ///     {
43    ///       "id": "0x1",
44    ///       "cancel": "0x0",
45    ///       "priority": "0x1",
46    ///       "message": "An example alert message!",
47    ///       "notice_until": "0x24bcca57c00",
48    ///       "signatures": [
49    ///         "0xbd07059aa9a3d057da294c2c4d96fa1e67eeb089837c87b523f124239e18e9fc7d11bb95b720478f7f937d073517d0e4eb9a91d12da5c88a05f750362f4c214dd0",
50    ///         "0x0242ef40bb64fe3189284de91f981b17f4d740c5e24a3fc9b70059db6aa1d198a2e76da4f84ab37549880d116860976e0cf81cd039563c452412076ebffa2e4453"
51    ///       ]
52    ///     }
53    ///   ],
54    ///   "id": 42
55    /// }
56    /// ```
57    ///
58    /// Response
59    ///
60    /// ```json
61    /// {
62    ///   "error": {
63    ///     "code": -1000,
64    ///     "data": "SigNotEnough",
65    ///     "message":"AlertFailedToVerifySignatures: The count of sigs is less than threshold."
66    ///   },
67    ///   "jsonrpc": "2.0",
68    ///   "result": null,
69    ///   "id": 42
70    /// }
71    /// ```
72    #[rpc(name = "send_alert")]
73    fn send_alert(&self, alert: Alert) -> Result<()>;
74}
75
76#[derive(Clone)]
77pub(crate) struct AlertRpcImpl {
78    network_controller: NetworkController,
79    verifier: Arc<AlertVerifier>,
80    notifier: Arc<Mutex<AlertNotifier>>,
81    handle: Handle,
82}
83
84impl AlertRpcImpl {
85    pub fn new(
86        verifier: Arc<AlertVerifier>,
87        notifier: Arc<Mutex<AlertNotifier>>,
88        network_controller: NetworkController,
89        handle: Handle,
90    ) -> Self {
91        AlertRpcImpl {
92            network_controller,
93            verifier,
94            notifier,
95            handle,
96        }
97    }
98}
99
100#[async_trait]
101impl AlertRpc for AlertRpcImpl {
102    fn send_alert(&self, alert: Alert) -> Result<()> {
103        let alert: packed::Alert = alert.into();
104        let now_ms = ckb_systemtime::unix_time_as_millis();
105        let notice_until: u64 = alert.raw().notice_until().into();
106        if notice_until < now_ms {
107            return Err(RPCError::invalid_params(format!(
108                "Expected `params[0].notice_until` in the future (> {now_ms}), got {notice_until}",
109            )));
110        }
111
112        let result = self.verifier.verify_signatures(&alert);
113
114        match result {
115            Ok(()) => {
116                // set self node notifier
117                self.notifier.lock().add(&alert);
118
119                self.network_controller.broadcast_with_handle(
120                    SupportProtocols::Alert.protocol_id(),
121                    alert.as_bytes(),
122                    &self.handle,
123                );
124                Ok(())
125            }
126            Err(e) => Err(RPCError::custom_with_error(
127                RPCError::AlertFailedToVerifySignatures,
128                e,
129            )),
130        }
131    }
132}