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