1use crate::{
2 message::{DATA_MAX_LEN, SEQUENCE_LEN, TOPIC_MAX_LEN},
3 monitor::MonitorMessageError,
4};
5use bitcoin::consensus;
6use core::{cmp::min, fmt};
7
8pub type Result<T> = core::result::Result<T, Error>;
9
10#[derive(Debug)]
11pub enum Error {
12 InvalidMutlipartLength(usize),
13 InvalidTopic(usize, [u8; TOPIC_MAX_LEN]),
14 InvalidDataLength(usize),
15 InvalidSequenceLength(usize),
16 InvalidSequenceMessageLength(usize),
17 InvalidSequenceMessageLabel(u8),
18 Invalid256BitHashLength(usize),
19 BitcoinDeserialization(consensus::encode::Error),
20 Zmq(zmq::Error),
21 MonitorMessage(MonitorMessageError),
22}
23
24impl Error {
25 pub fn invalid_topic_data(&self) -> Option<(&[u8], usize)> {
30 if let Self::InvalidTopic(len, buf) = self {
31 Some((&buf[..min(*len, buf.len())], *len))
32 } else {
33 None
34 }
35 }
36}
37
38impl From<zmq::Error> for Error {
39 #[inline]
40 fn from(value: zmq::Error) -> Self {
41 Self::Zmq(value)
42 }
43}
44
45#[cfg(feature = "async")]
46impl From<async_zmq::SocketError> for Error {
47 #[inline]
48 fn from(value: async_zmq::SocketError) -> Self {
49 Self::Zmq(value.into())
50 }
51}
52
53#[cfg(feature = "async")]
54impl From<async_zmq::SubscribeError> for Error {
55 #[inline]
56 fn from(value: async_zmq::SubscribeError) -> Self {
57 Self::Zmq(value.into())
58 }
59}
60
61#[cfg(feature = "async")]
62impl From<async_zmq::RecvError> for Error {
63 #[inline]
64 fn from(value: async_zmq::RecvError) -> Self {
65 Self::Zmq(value.into())
66 }
67}
68
69impl From<consensus::encode::Error> for Error {
70 #[inline]
71 fn from(value: consensus::encode::Error) -> Self {
72 Self::BitcoinDeserialization(value)
73 }
74}
75
76impl From<MonitorMessageError> for Error {
77 #[inline]
78 fn from(value: MonitorMessageError) -> Self {
79 Self::MonitorMessage(value)
80 }
81}
82
83impl fmt::Display for Error {
84 #[inline]
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 match self {
87 Self::InvalidMutlipartLength(len) => {
88 write!(f, "invalid multipart message length: {len} (expected 3)")
89 }
90 Self::InvalidTopic(len, topic) => {
91 write!(
92 f,
93 "invalid message topic '{}'{}",
94 String::from_utf8_lossy(&topic[..min(*len, topic.len())]),
95 if *len > TOPIC_MAX_LEN {
96 " (truncated)"
97 } else {
98 ""
99 }
100 )
101 }
102 Self::InvalidDataLength(len) => {
103 write!(f, "data too long ({len} > {DATA_MAX_LEN})")
104 }
105 Self::InvalidSequenceLength(len) => {
106 write!(
107 f,
108 "invalid sequence length: {len} (expected {SEQUENCE_LEN})"
109 )
110 }
111 Self::InvalidSequenceMessageLength(len) => {
112 write!(f, "invalid message length {len} of message type 'sequence'")
113 }
114 Self::InvalidSequenceMessageLabel(label) => {
115 write!(
116 f,
117 "invalid label '{}' (0x{:02x}) of message type 'sequence'",
118 *label as char, label
119 )
120 }
121 Self::Invalid256BitHashLength(len) => {
122 write!(f, "invalid hash length: {len} (expected 32)")
123 }
124
125 Self::BitcoinDeserialization(e) => {
126 write!(f, "bitcoin consensus deserialization error: {e}")
127 }
128 Self::Zmq(e) => write!(f, "ZMQ Error: {e}"),
129 Self::MonitorMessage(err) => write!(f, "unable to parse monitor message: {err}"),
130 }
131 }
132}
133
134impl std::error::Error for Error {
135 #[inline]
136 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
137 Some(match self {
138 Self::BitcoinDeserialization(e) => e,
139 Self::Zmq(e) => e,
140 Self::MonitorMessage(e) => e,
141 Self::InvalidMutlipartLength(_)
142 | Self::InvalidTopic(_, _)
143 | Self::InvalidDataLength(_)
144 | Self::InvalidSequenceLength(_)
145 | Self::InvalidSequenceMessageLength(_)
146 | Self::InvalidSequenceMessageLabel(_)
147 | Self::Invalid256BitHashLength(_) => return None,
148 })
149 }
150}