use dig_chainsource_interface::ChainSourceError;
use thiserror::Error;
#[derive(Debug, Error, Clone, PartialEq, Eq)]
pub enum ChiaPeerError {
#[error("chia peer transport error: {0}")]
Transport(String),
#[error("chia peer rejected the request: {0}")]
Rejected(String),
#[error("malformed chia peer response: {0}")]
Malformed(String),
#[error("chia peer request timed out")]
Timeout,
#[error("chia peer discovery failed")]
PeerDiscoveryFailed,
#[error("chia light client is not connected")]
NotConnected,
#[error("chia peer TLS setup error: {0}")]
Tls(String),
}
impl ChiaPeerError {
fn looks_like_timeout(message: &str) -> bool {
let lower = message.to_ascii_lowercase();
lower.contains("timed out") || lower.contains("timeout")
}
}
impl From<ChiaPeerError> for ChainSourceError {
fn from(error: ChiaPeerError) -> Self {
match error {
ChiaPeerError::Timeout => ChainSourceError::Timeout,
ChiaPeerError::Transport(msg) if ChiaPeerError::looks_like_timeout(&msg) => {
ChainSourceError::Timeout
}
ChiaPeerError::Transport(msg) => ChainSourceError::Transport(msg),
ChiaPeerError::Rejected(msg) => ChainSourceError::Transport(msg),
ChiaPeerError::Malformed(msg) => ChainSourceError::Malformed(msg),
ChiaPeerError::PeerDiscoveryFailed => {
ChainSourceError::Transport("peer discovery failed".to_string())
}
ChiaPeerError::NotConnected => {
ChainSourceError::Transport("light client is not connected".to_string())
}
ChiaPeerError::Tls(msg) => ChainSourceError::Transport(format!("TLS: {msg}")),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn timeout_variant_maps_to_timeout() {
assert_eq!(
ChainSourceError::from(ChiaPeerError::Timeout),
ChainSourceError::Timeout
);
}
#[test]
fn timed_out_transport_message_maps_to_timeout() {
let mapped = ChainSourceError::from(ChiaPeerError::Transport("request timed out".into()));
assert_eq!(mapped, ChainSourceError::Timeout);
}
#[test]
fn plain_transport_maps_to_transport_never_absence() {
let mapped = ChainSourceError::from(ChiaPeerError::Transport("socket reset".into()));
assert_eq!(mapped, ChainSourceError::Transport("socket reset".into()));
}
#[test]
fn rejected_maps_to_transport() {
let mapped = ChainSourceError::from(ChiaPeerError::Rejected("reorg".into()));
assert!(matches!(mapped, ChainSourceError::Transport(_)));
}
#[test]
fn malformed_maps_to_malformed() {
let mapped = ChainSourceError::from(ChiaPeerError::Malformed("bad bytes".into()));
assert!(matches!(mapped, ChainSourceError::Malformed(_)));
}
#[test]
fn not_connected_and_discovery_and_tls_map_to_transport() {
assert!(matches!(
ChainSourceError::from(ChiaPeerError::NotConnected),
ChainSourceError::Transport(_)
));
assert!(matches!(
ChainSourceError::from(ChiaPeerError::PeerDiscoveryFailed),
ChainSourceError::Transport(_)
));
assert!(matches!(
ChainSourceError::from(ChiaPeerError::Tls("x".into())),
ChainSourceError::Transport(_)
));
}
}