use crate::BuilderError;
use alloc::string::String;
use alloy_primitives::B256;
use kona_genesis::SystemConfigUpdateError;
use kona_protocol::{DepositError, SpanBatchError};
use thiserror::Error;
#[macro_export]
macro_rules! ensure {
($cond:expr, $err:expr) => {
if !($cond) {
return Err($err);
}
};
}
#[derive(Error, Debug, PartialEq, Eq)]
pub enum PipelineErrorKind {
#[error("Temporary error: {0}")]
Temporary(#[source] PipelineError),
#[error("Critical error: {0}")]
Critical(#[source] PipelineError),
#[error("Pipeline reset: {0}")]
Reset(#[from] ResetError),
}
#[derive(Error, Debug, PartialEq, Eq)]
pub enum PipelineError {
#[error("EOF")]
Eof,
#[error("Not enough data")]
NotEnoughData,
#[error("The channel provider is empty")]
ChannelProviderEmpty,
#[error("Channel already built")]
ChannelAlreadyBuilt,
#[error("Channel not found in channel provider")]
ChannelNotFound,
#[error("The channel reader has no channel available")]
ChannelReaderEmpty,
#[error("The batch queue has no batches available")]
BatchQueueEmpty,
#[error("Missing L1 origin from previous stage")]
MissingOrigin,
#[error("L1 Retrieval missing data")]
MissingL1Data,
#[error("Invalid batch type passed to stage")]
InvalidBatchType,
#[error("Invalid batch validity")]
InvalidBatchValidity,
#[error("Error updating system config: {0}")]
SystemConfigUpdate(SystemConfigUpdateError),
#[error("Attributes builder error: {0}")]
AttributesBuilder(#[from] BuilderError),
#[error("Decode error: {0}")]
BadEncoding(#[from] PipelineEncodingError),
#[error("Data source exhausted")]
EndOfSource,
#[error("Provider error: {0}")]
Provider(String),
#[error("Unsupported signal")]
UnsupportedSignal,
}
impl PipelineError {
pub const fn crit(self) -> PipelineErrorKind {
PipelineErrorKind::Critical(self)
}
pub const fn temp(self) -> PipelineErrorKind {
PipelineErrorKind::Temporary(self)
}
}
#[derive(Error, Clone, Debug, Eq, PartialEq)]
pub enum ResetError {
#[error("Bad parent hash: expected {0}, got {1}")]
BadParentHash(B256, B256),
#[error("Bad timestamp: expected {0}, got {1}")]
BadTimestamp(u64, u64),
#[error("L1 origin mismatch. Expected {0:?}, got {1:?}")]
L1OriginMismatch(u64, u64),
#[error("L1 reorg detected: expected {0}, got {1}")]
ReorgDetected(B256, B256),
#[error("Attributes builder error: {0}")]
AttributesBuilder(#[from] BuilderError),
#[error("Holocene activation reset")]
HoloceneActivation,
#[error("Next L1 block hash mismatch: expected {0}, got {1}")]
NextL1BlockHashMismatch(B256, B256),
}
impl ResetError {
pub const fn reset(self) -> PipelineErrorKind {
PipelineErrorKind::Reset(self)
}
}
#[derive(Error, Debug, PartialEq, Eq)]
pub enum PipelineEncodingError {
#[error("Empty buffer")]
EmptyBuffer,
#[error("Error decoding deposit: {0}")]
DepositError(#[from] DepositError),
#[error("RLP error: {0}")]
AlloyRlpError(alloy_rlp::Error),
#[error("{0}")]
SpanBatchError(#[from] SpanBatchError),
}
#[cfg(test)]
mod tests {
use super::*;
use core::error::Error;
#[test]
fn test_pipeline_error_kind_source() {
let err = PipelineErrorKind::Temporary(PipelineError::Eof);
assert!(err.source().is_some());
let err = PipelineErrorKind::Critical(PipelineError::Eof);
assert!(err.source().is_some());
let err = PipelineErrorKind::Reset(ResetError::BadParentHash(
Default::default(),
Default::default(),
));
assert!(err.source().is_some());
}
#[test]
fn test_pipeline_error_source() {
let err = PipelineError::AttributesBuilder(BuilderError::BlockMismatch(
Default::default(),
Default::default(),
));
assert!(err.source().is_some());
let encoding_err = PipelineEncodingError::EmptyBuffer;
let err: PipelineError = encoding_err.into();
assert!(err.source().is_some());
let err = PipelineError::Eof;
assert!(err.source().is_none());
}
#[test]
fn test_pipeline_encoding_error_source() {
let err = PipelineEncodingError::DepositError(DepositError::UnexpectedTopicsLen(0));
assert!(err.source().is_some());
let err = SpanBatchError::TooBigSpanBatchSize;
let err: PipelineEncodingError = err.into();
assert!(err.source().is_some());
let err = PipelineEncodingError::EmptyBuffer;
assert!(err.source().is_none());
}
#[test]
fn test_reset_error_kinds() {
let reset_errors = [
ResetError::BadParentHash(Default::default(), Default::default()),
ResetError::BadTimestamp(0, 0),
ResetError::L1OriginMismatch(0, 0),
ResetError::ReorgDetected(Default::default(), Default::default()),
ResetError::AttributesBuilder(BuilderError::BlockMismatch(
Default::default(),
Default::default(),
)),
ResetError::HoloceneActivation,
];
for error in reset_errors.into_iter() {
let expected = PipelineErrorKind::Reset(error.clone());
assert_eq!(error.reset(), expected);
}
}
}