Implements full Inter-Blockchain Communication (IBC) protocol: synor-ibc crate (new): - Light client management (create, update, verify headers) - Connection handshake (4-way: Init, Try, Ack, Confirm) - Channel handshake (4-way: Init, Try, Ack, Confirm) - Packet handling (send, receive, acknowledge, timeout) - Merkle commitment proofs for state verification - ICS-20 fungible token transfer support - Atomic swap engine with HTLC (hashlock + timelock) IBC Bridge Contract (contracts/ibc-bridge): - Token locking/unlocking for cross-chain transfers - Relayer whitelist management - Channel registration and sequence tracking - HTLC atomic swap (create, claim, refund) - Event emission for indexing - 52KB optimized WASM binary Test coverage: 40 tests passing
163 lines
4.2 KiB
Rust
163 lines
4.2 KiB
Rust
//! IBC error types
|
|
|
|
use thiserror::Error;
|
|
|
|
/// Result type for IBC operations
|
|
pub type IbcResult<T> = Result<T, IbcError>;
|
|
|
|
/// IBC error types
|
|
#[derive(Debug, Error)]
|
|
pub enum IbcError {
|
|
// Client errors
|
|
#[error("Client not found: {0}")]
|
|
ClientNotFound(String),
|
|
|
|
#[error("Client already exists: {0}")]
|
|
ClientAlreadyExists(String),
|
|
|
|
#[error("Invalid client state: {0}")]
|
|
InvalidClientState(String),
|
|
|
|
#[error("Client frozen: {0}")]
|
|
ClientFrozen(String),
|
|
|
|
#[error("Client expired: {0}")]
|
|
ClientExpired(String),
|
|
|
|
// Connection errors
|
|
#[error("Connection not found: {0}")]
|
|
ConnectionNotFound(String),
|
|
|
|
#[error("Connection already exists: {0}")]
|
|
ConnectionAlreadyExists(String),
|
|
|
|
#[error("Invalid connection state: expected {expected}, got {actual}")]
|
|
InvalidConnectionState { expected: String, actual: String },
|
|
|
|
#[error("Connection version mismatch: {0}")]
|
|
ConnectionVersionMismatch(String),
|
|
|
|
// Channel errors
|
|
#[error("Channel not found: port={port}, channel={channel}")]
|
|
ChannelNotFound { port: String, channel: String },
|
|
|
|
#[error("Channel already exists: port={port}, channel={channel}")]
|
|
ChannelAlreadyExists { port: String, channel: String },
|
|
|
|
#[error("Invalid channel state: expected {expected}, got {actual}")]
|
|
InvalidChannelState { expected: String, actual: String },
|
|
|
|
#[error("Port not bound: {0}")]
|
|
PortNotBound(String),
|
|
|
|
#[error("Port already bound: {0}")]
|
|
PortAlreadyBound(String),
|
|
|
|
// Packet errors
|
|
#[error("Packet timeout: height={height}, timestamp={timestamp}")]
|
|
PacketTimeout { height: u64, timestamp: u64 },
|
|
|
|
#[error("Packet already received: sequence={0}")]
|
|
PacketAlreadyReceived(u64),
|
|
|
|
#[error("Packet not found: sequence={0}")]
|
|
PacketNotFound(u64),
|
|
|
|
#[error("Invalid packet sequence: expected {expected}, got {actual}")]
|
|
InvalidPacketSequence { expected: u64, actual: u64 },
|
|
|
|
#[error("Packet data too large: {size} bytes (max {max})")]
|
|
PacketDataTooLarge { size: usize, max: usize },
|
|
|
|
#[error("Invalid packet data: {0}")]
|
|
InvalidPacketData(String),
|
|
|
|
#[error("Invalid acknowledgement: {0}")]
|
|
InvalidAcknowledgement(String),
|
|
|
|
// Swap errors
|
|
#[error("Swap not found: {0}")]
|
|
SwapNotFound(String),
|
|
|
|
#[error("Invalid swap state: expected {expected}, got {actual}")]
|
|
InvalidSwapState { expected: String, actual: String },
|
|
|
|
#[error("Swap timeout expired: {0}")]
|
|
SwapTimeoutExpired(String),
|
|
|
|
#[error("Invalid secret: {0}")]
|
|
InvalidSecret(String),
|
|
|
|
// Proof errors
|
|
#[error("Proof verification failed: {0}")]
|
|
ProofVerificationFailed(String),
|
|
|
|
#[error("Invalid proof: {0}")]
|
|
InvalidProof(String),
|
|
|
|
#[error("Invalid proof height: expected {expected}, got {actual}")]
|
|
InvalidProofHeight { expected: u64, actual: u64 },
|
|
|
|
#[error("Missing proof: {0}")]
|
|
MissingProof(String),
|
|
|
|
// Commitment errors
|
|
#[error("Commitment not found: {0}")]
|
|
CommitmentNotFound(String),
|
|
|
|
#[error("Invalid commitment: {0}")]
|
|
InvalidCommitment(String),
|
|
|
|
// Handshake errors
|
|
#[error("Handshake error: {0}")]
|
|
HandshakeError(String),
|
|
|
|
#[error("Invalid counterparty: {0}")]
|
|
InvalidCounterparty(String),
|
|
|
|
// Serialization errors
|
|
#[error("Serialization error: {0}")]
|
|
SerializationError(String),
|
|
|
|
#[error("Deserialization error: {0}")]
|
|
DeserializationError(String),
|
|
|
|
// General errors
|
|
#[error("Invalid identifier: {0}")]
|
|
InvalidIdentifier(String),
|
|
|
|
#[error("Unauthorized: {0}")]
|
|
Unauthorized(String),
|
|
|
|
#[error("Internal error: {0}")]
|
|
Internal(String),
|
|
}
|
|
|
|
impl From<serde_json::Error> for IbcError {
|
|
fn from(err: serde_json::Error) -> Self {
|
|
IbcError::SerializationError(err.to_string())
|
|
}
|
|
}
|
|
|
|
impl From<std::io::Error> for IbcError {
|
|
fn from(err: std::io::Error) -> Self {
|
|
IbcError::Internal(err.to_string())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_error_display() {
|
|
let err = IbcError::ClientNotFound("client-1".to_string());
|
|
assert!(err.to_string().contains("client-1"));
|
|
|
|
let err = IbcError::PacketTimeout {
|
|
height: 100,
|
|
timestamp: 1000,
|
|
};
|
|
assert!(err.to_string().contains("100"));
|
|
}
|
|
}
|