ibc-relayer 0.32.2

Implementation of an IBC Relayer in Rust, as a library
use core::time::Duration;

use flex_error::{define_error, ErrorMessageTracer};

use ibc_relayer_types::core::ics03_connection::connection::{Counterparty, State};
use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ClientId, ConnectionId};
use ibc_relayer_types::events::IbcEvent;

use crate::error::Error as RelayerError;
use crate::foreign_client::{ForeignClientError, HasExpiredOrFrozenError};
use crate::supervisor::Error as SupervisorError;

define_error! {
    ConnectionError {
        Relayer
            [ RelayerError ]
            |e| { format_args!("relayer error: {}", e.source) },

        MissingLocalConnectionId
            |_| { "failed due to missing local connection id" },

        MissingCounterpartyConnectionIdField
            { counterparty: Counterparty }
            |e| {
                format!("the connection end has no connection id field in the counterparty: {:?}",
                    e.counterparty)
            },

        MissingCounterpartyConnectionId
            |_| { "failed due to missing counterparty connection id" },

        ChainQuery
            { chain_id: ChainId }
            [ RelayerError ]
            |e| {
                format!("failed during a query to chain id {0}", e.chain_id)
            },

        ConnectionQuery
            { connection_id: ConnectionId }
            [ RelayerError ]
            |e| {
                format!("failed to query the connection for {}", e.connection_id)
            },

        ClientOperation
            {
                client_id: ClientId,
                chain_id: ChainId,
            }
            [ ForeignClientError ]
            |e| {
                format!("failed during an operation on client '{0}' hosted by chain '{1}'",
                    e.client_id, e.chain_id)
            },

        Submit
            { chain_id: ChainId }
            [ RelayerError ]
            |e| {
                format!("failed during a transaction submission step to chain '{0}'",
                    e.chain_id)
            },

        HandshakeFinalize
            |_| { "continue handshake" },

        MaxDelayPeriod
            {
                delay_period: Duration,
                max_delay_period: Duration
            }
            |e| {
                format!("invalid delay period '{:?}': should be at max '{:?}'",
                    e.delay_period, e.max_delay_period)
            },

        InvalidEvent
            { event: IbcEvent }
            |e| {
                format!("a connection object cannot be built from {}",
                    e.event)
            },

        RetryInternal
            { reason: String }
            | e | {
                format_args!("encountered internal error during retry: {}",
                    e.reason)
            },

        TxResponse
            { event: String }
            |e| {
                format!("tx response event consists of an error: {}",
                    e.event)
            },

        ConnectionClientIdMismatch
            {
                client_id: ClientId,
                foreign_client_id: ClientId
            }
            |e| {
                format!("the client id ({}) in the connection end does not match the foreign client id ({})",
                    e.client_id, e.foreign_client_id)
            },

        ChainIdMismatch
            {
                source_chain_id: ChainId,
                destination_chain_id: ChainId
            }
            |e| {
                format!("the source chain of client a ({}) does not match the destination chain of client b ({})",
                    e.source_chain_id, e.destination_chain_id)
            },

        ConnectionNotOpen
            {
                state: State,
            }
            |e| {
                format!("the connection end is expected to be in state 'Open'; found state: {:?}",
                    e.state)
            },

        Supervisor
            [ SupervisorError ]
            |_| { "supervisor error" },

        MissingConnectionId
            {
                chain_id: ChainId,
            }
            |e| {
                format!("missing connection on source chain {}",
                    e.chain_id)
            },

        Signer
            { chain_id: ChainId }
            [ RelayerError ]
            |e| {
                format!("failed while fetching the signer for chain ({})",
                    e.chain_id)
            },

        MissingConnectionIdFromEvent
            |_| { "cannot extract connection_id from result" },

        MissingConnectionInitEvent
            |_| { "no conn init event was in the response" },

        MissingConnectionTryEvent
            |_| { "no conn try event was in the response" },

        MissingConnectionAckEvent
            |_| { "no conn ack event was in the response" },

        MissingConnectionConfirmEvent
            |_| { "no conn confirm event was in the response" },

        ConnectionProof
            [ RelayerError ]
            |_| { "failed to build connection proofs" },

        ConnectionAlreadyExists
            { connection_id: ConnectionId }
            |e| {
                format!("connection {} already exists in an incompatible state", e.connection_id)
            },

        MaxRetry
            {
                description: String,
                tries: u64,
                total_delay: Duration,
            }
            [ Self ]
            | e | {
                format_args!("error after maximum retry of {} and total delay of {}s: {}",
                    e.tries, e.total_delay.as_secs(), e.description)
            },

    }
}

impl HasExpiredOrFrozenError for ConnectionErrorDetail {
    fn is_frozen_error(&self) -> bool {
        match self {
            Self::ClientOperation(e) => e.source.is_frozen_error(),
            _ => false,
        }
    }

    fn is_expired_error(&self) -> bool {
        match self {
            Self::ClientOperation(e) => e.source.is_expired_error(),
            _ => false,
        }
    }
}

impl HasExpiredOrFrozenError for ConnectionError {
    fn is_frozen_error(&self) -> bool {
        self.detail().is_frozen_error()
    }

    fn is_expired_error(&self) -> bool {
        self.detail().is_expired_error()
    }
}