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}