kaspa_rpc_core/api/
notifications.rs

1//!
2//! RPC notifications that can be sent to clients.
3//!
4
5use crate::model::message::*;
6use derive_more::Display;
7use kaspa_notify::{
8    events::EventType,
9    notification::{full_featured, Notification as NotificationTrait},
10    subscription::{
11        context::SubscriptionContext,
12        single::{OverallSubscription, UtxosChangedSubscription, VirtualChainChangedSubscription},
13        Subscription,
14    },
15};
16use serde::{Deserialize, Serialize};
17use std::sync::Arc;
18use wasm_bindgen::JsValue;
19use workflow_serializer::prelude::*;
20use workflow_wasm::serde::to_value;
21
22full_featured! {
23#[derive(Clone, Debug, Display, Serialize, Deserialize)]
24pub enum Notification {
25    #[display(fmt = "BlockAdded notification: block hash {}", "_0.block.header.hash")]
26    BlockAdded(BlockAddedNotification),
27
28    #[display(fmt = "VirtualChainChanged notification: {} removed blocks, {} added blocks, {} accepted transactions", "_0.removed_chain_block_hashes.len()", "_0.added_chain_block_hashes.len()", "_0.accepted_transaction_ids.len()")]
29    VirtualChainChanged(VirtualChainChangedNotification),
30
31    #[display(fmt = "FinalityConflict notification: violating block hash {}", "_0.violating_block_hash")]
32    FinalityConflict(FinalityConflictNotification),
33
34    #[display(fmt = "FinalityConflict notification: violating block hash {}", "_0.finality_block_hash")]
35    FinalityConflictResolved(FinalityConflictResolvedNotification),
36
37    #[display(fmt = "UtxosChanged notification: {} removed, {} added", "_0.removed.len()", "_0.added.len()")]
38    UtxosChanged(UtxosChangedNotification),
39
40    #[display(fmt = "SinkBlueScoreChanged notification: virtual selected parent blue score {}", "_0.sink_blue_score")]
41    SinkBlueScoreChanged(SinkBlueScoreChangedNotification),
42
43    #[display(fmt = "VirtualDaaScoreChanged notification: virtual DAA score {}", "_0.virtual_daa_score")]
44    VirtualDaaScoreChanged(VirtualDaaScoreChangedNotification),
45
46    #[display(fmt = "PruningPointUtxoSetOverride notification")]
47    PruningPointUtxoSetOverride(PruningPointUtxoSetOverrideNotification),
48
49    #[display(fmt = "NewBlockTemplate notification")]
50    NewBlockTemplate(NewBlockTemplateNotification),
51}
52}
53
54impl Notification {
55    ///
56    pub fn to_value(&self) -> std::result::Result<JsValue, serde_wasm_bindgen::Error> {
57        match self {
58            Notification::BlockAdded(v) => to_value(&v),
59            Notification::FinalityConflict(v) => to_value(&v),
60            Notification::FinalityConflictResolved(v) => to_value(&v),
61            Notification::NewBlockTemplate(v) => to_value(&v),
62            Notification::PruningPointUtxoSetOverride(v) => to_value(&v),
63            Notification::UtxosChanged(v) => to_value(&v),
64            Notification::VirtualDaaScoreChanged(v) => to_value(&v),
65            Notification::SinkBlueScoreChanged(v) => to_value(&v),
66            Notification::VirtualChainChanged(v) => to_value(&v),
67        }
68    }
69}
70
71impl NotificationTrait for Notification {
72    fn apply_overall_subscription(&self, subscription: &OverallSubscription, _context: &SubscriptionContext) -> Option<Self> {
73        match subscription.active() {
74            true => Some(self.clone()),
75            false => None,
76        }
77    }
78
79    fn apply_virtual_chain_changed_subscription(
80        &self,
81        subscription: &VirtualChainChangedSubscription,
82        _context: &SubscriptionContext,
83    ) -> Option<Self> {
84        match subscription.active() {
85            true => {
86                if let Notification::VirtualChainChanged(ref payload) = self {
87                    if !subscription.include_accepted_transaction_ids() && !payload.accepted_transaction_ids.is_empty() {
88                        return Some(Notification::VirtualChainChanged(VirtualChainChangedNotification {
89                            removed_chain_block_hashes: payload.removed_chain_block_hashes.clone(),
90                            added_chain_block_hashes: payload.added_chain_block_hashes.clone(),
91                            accepted_transaction_ids: Arc::new(vec![]),
92                        }));
93                    }
94                }
95                Some(self.clone())
96            }
97            false => None,
98        }
99    }
100
101    fn apply_utxos_changed_subscription(
102        &self,
103        subscription: &UtxosChangedSubscription,
104        context: &SubscriptionContext,
105    ) -> Option<Self> {
106        match subscription.active() {
107            true => {
108                let Self::UtxosChanged(notification) = self else { return None };
109                notification.apply_utxos_changed_subscription(subscription, context).map(Self::UtxosChanged)
110            }
111            false => None,
112        }
113    }
114
115    fn event_type(&self) -> EventType {
116        self.into()
117    }
118}
119
120impl Serializer for Notification {
121    fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
122        store!(u16, &1, writer)?;
123        match self {
124            Notification::BlockAdded(notification) => {
125                store!(u16, &0, writer)?;
126                serialize!(BlockAddedNotification, notification, writer)?;
127            }
128            Notification::VirtualChainChanged(notification) => {
129                store!(u16, &1, writer)?;
130                serialize!(VirtualChainChangedNotification, notification, writer)?;
131            }
132            Notification::FinalityConflict(notification) => {
133                store!(u16, &2, writer)?;
134                serialize!(FinalityConflictNotification, notification, writer)?;
135            }
136            Notification::FinalityConflictResolved(notification) => {
137                store!(u16, &3, writer)?;
138                serialize!(FinalityConflictResolvedNotification, notification, writer)?;
139            }
140            Notification::UtxosChanged(notification) => {
141                store!(u16, &4, writer)?;
142                serialize!(UtxosChangedNotification, notification, writer)?;
143            }
144            Notification::SinkBlueScoreChanged(notification) => {
145                store!(u16, &5, writer)?;
146                serialize!(SinkBlueScoreChangedNotification, notification, writer)?;
147            }
148            Notification::VirtualDaaScoreChanged(notification) => {
149                store!(u16, &6, writer)?;
150                serialize!(VirtualDaaScoreChangedNotification, notification, writer)?;
151            }
152            Notification::PruningPointUtxoSetOverride(notification) => {
153                store!(u16, &7, writer)?;
154                serialize!(PruningPointUtxoSetOverrideNotification, notification, writer)?;
155            }
156            Notification::NewBlockTemplate(notification) => {
157                store!(u16, &8, writer)?;
158                serialize!(NewBlockTemplateNotification, notification, writer)?;
159            }
160        }
161        Ok(())
162    }
163}
164
165impl Deserializer for Notification {
166    fn deserialize<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
167        let _version = load!(u16, reader)?;
168        match load!(u16, reader)? {
169            0 => {
170                let notification = deserialize!(BlockAddedNotification, reader)?;
171                Ok(Notification::BlockAdded(notification))
172            }
173            1 => {
174                let notification = deserialize!(VirtualChainChangedNotification, reader)?;
175                Ok(Notification::VirtualChainChanged(notification))
176            }
177            2 => {
178                let notification = deserialize!(FinalityConflictNotification, reader)?;
179                Ok(Notification::FinalityConflict(notification))
180            }
181            3 => {
182                let notification = deserialize!(FinalityConflictResolvedNotification, reader)?;
183                Ok(Notification::FinalityConflictResolved(notification))
184            }
185            4 => {
186                let notification = deserialize!(UtxosChangedNotification, reader)?;
187                Ok(Notification::UtxosChanged(notification))
188            }
189            5 => {
190                let notification = deserialize!(SinkBlueScoreChangedNotification, reader)?;
191                Ok(Notification::SinkBlueScoreChanged(notification))
192            }
193            6 => {
194                let notification = deserialize!(VirtualDaaScoreChangedNotification, reader)?;
195                Ok(Notification::VirtualDaaScoreChanged(notification))
196            }
197            7 => {
198                let notification = deserialize!(PruningPointUtxoSetOverrideNotification, reader)?;
199                Ok(Notification::PruningPointUtxoSetOverride(notification))
200            }
201            8 => {
202                let notification = deserialize!(NewBlockTemplateNotification, reader)?;
203                Ok(Notification::NewBlockTemplate(notification))
204            }
205            _ => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid variant")),
206        }
207    }
208}