From 0d98ebf673a93bffd22ed636053959331ea2b28e Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Thu, 22 Aug 2024 11:34:52 -0500 Subject: [PATCH 01/18] Clean up `ibc-apps` errors (#1318) * Clean up ics20-transfer error * Clean up NftTransfer error * Incorporate PR feedback * Remove redundant TODO comment * Simplify NftTransferError variant * Add TODO reminder --- ibc-apps/ics20-transfer/src/handler/mod.rs | 4 +- .../src/handler/on_recv_packet.rs | 2 +- .../src/handler/send_transfer.rs | 8 +- ibc-apps/ics20-transfer/src/module.rs | 42 +++---- ibc-apps/ics20-transfer/types/src/coin.rs | 4 +- ibc-apps/ics20-transfer/types/src/denom.rs | 2 +- ibc-apps/ics20-transfer/types/src/error.rs | 97 +++++---------- .../ics20-transfer/types/src/msgs/transfer.rs | 16 ++- .../ics721-nft-transfer/src/handler/mod.rs | 4 +- .../src/handler/on_recv_packet.rs | 11 +- .../src/handler/send_transfer.rs | 8 +- ibc-apps/ics721-nft-transfer/src/module.rs | 44 +++---- .../ics721-nft-transfer/types/src/class.rs | 9 +- .../ics721-nft-transfer/types/src/data.rs | 4 +- .../ics721-nft-transfer/types/src/error.rs | 111 +++++------------- .../types/src/msgs/transfer.rs | 12 +- .../ics721-nft-transfer/types/src/packet.rs | 27 +++-- .../ics721-nft-transfer/types/src/token.rs | 18 +-- 18 files changed, 171 insertions(+), 252 deletions(-) diff --git a/ibc-apps/ics20-transfer/src/handler/mod.rs b/ibc-apps/ics20-transfer/src/handler/mod.rs index 39dcd373d..6d3cde510 100644 --- a/ibc-apps/ics20-transfer/src/handler/mod.rs +++ b/ibc-apps/ics20-transfer/src/handler/mod.rs @@ -20,7 +20,7 @@ pub fn refund_packet_token_execute( .sender .clone() .try_into() - .map_err(|_| TokenTransferError::ParseAccountFailure)?; + .map_err(|_| TokenTransferError::FailedToParseAccount)?; if is_sender_chain_source( packet.port_id_on_a.clone(), @@ -49,7 +49,7 @@ pub fn refund_packet_token_validate( .sender .clone() .try_into() - .map_err(|_| TokenTransferError::ParseAccountFailure)?; + .map_err(|_| TokenTransferError::FailedToParseAccount)?; if is_sender_chain_source( packet.port_id_on_a.clone(), diff --git a/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs b/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs index 193b33196..b0fcbd877 100644 --- a/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs +++ b/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs @@ -26,7 +26,7 @@ pub fn process_recv_packet_execute( let receiver_account = data.receiver.clone().try_into().map_err(|_| { ( ModuleExtras::empty(), - TokenTransferError::ParseAccountFailure, + TokenTransferError::FailedToParseAccount, ) })?; diff --git a/ibc-apps/ics20-transfer/src/handler/send_transfer.rs b/ibc-apps/ics20-transfer/src/handler/send_transfer.rs index 439e5604c..39d40ea46 100644 --- a/ibc-apps/ics20-transfer/src/handler/send_transfer.rs +++ b/ibc-apps/ics20-transfer/src/handler/send_transfer.rs @@ -45,7 +45,7 @@ where let chan_id_on_b = chan_end_on_a .counterparty() .channel_id() - .ok_or_else(|| TokenTransferError::DestinationChannelNotFound { + .ok_or_else(|| TokenTransferError::MissingDestinationChannel { port_id: msg.port_id_on_a.clone(), channel_id: msg.chan_id_on_a.clone(), })? @@ -61,7 +61,7 @@ where .sender .clone() .try_into() - .map_err(|_| TokenTransferError::ParseAccountFailure)?; + .map_err(|_| TokenTransferError::FailedToParseAccount)?; if is_sender_chain_source( msg.port_id_on_a.clone(), @@ -117,7 +117,7 @@ where let chan_on_b = chan_end_on_a .counterparty() .channel_id() - .ok_or_else(|| TokenTransferError::DestinationChannelNotFound { + .ok_or_else(|| TokenTransferError::MissingDestinationChannel { port_id: msg.port_id_on_a.clone(), channel_id: msg.chan_id_on_a.clone(), })? @@ -134,7 +134,7 @@ where .sender .clone() .try_into() - .map_err(|_| TokenTransferError::ParseAccountFailure)?; + .map_err(|_| TokenTransferError::FailedToParseAccount)?; if is_sender_chain_source( msg.port_id_on_a.clone(), diff --git a/ibc-apps/ics20-transfer/src/module.rs b/ibc-apps/ics20-transfer/src/module.rs index 392ca5939..66370f10c 100644 --- a/ibc-apps/ics20-transfer/src/module.rs +++ b/ibc-apps/ics20-transfer/src/module.rs @@ -27,16 +27,16 @@ pub fn on_chan_open_init_validate( version: &Version, ) -> Result<(), TokenTransferError> { if order != Order::Unordered { - return Err(TokenTransferError::ChannelNotUnordered { - expect_order: Order::Unordered, - got_order: order, + return Err(TokenTransferError::MismatchedChannelOrders { + expected: Order::Unordered, + actual: order, }); } let bound_port = ctx.get_port()?; if port_id != &bound_port { - return Err(TokenTransferError::InvalidPort { - port_id: port_id.clone(), - exp_port_id: bound_port, + return Err(TokenTransferError::MismatchedPortIds { + actual: port_id.clone(), + expected: bound_port, }); } @@ -71,9 +71,9 @@ pub fn on_chan_open_try_validate( counterparty_version: &Version, ) -> Result<(), TokenTransferError> { if order != Order::Unordered { - return Err(TokenTransferError::ChannelNotUnordered { - expect_order: Order::Unordered, - got_order: order, + return Err(TokenTransferError::MismatchedChannelOrders { + expected: Order::Unordered, + actual: order, }); } @@ -139,7 +139,7 @@ pub fn on_chan_close_init_validate( _port_id: &PortId, _channel_id: &ChannelId, ) -> Result<(), TokenTransferError> { - Err(TokenTransferError::CantCloseChannel) + Err(TokenTransferError::UnsupportedClosedChannel) } pub fn on_chan_close_init_execute( @@ -147,7 +147,7 @@ pub fn on_chan_close_init_execute( _port_id: &PortId, _channel_id: &ChannelId, ) -> Result { - Err(TokenTransferError::CantCloseChannel) + Err(TokenTransferError::UnsupportedClosedChannel) } pub fn on_chan_close_confirm_validate( @@ -172,7 +172,7 @@ pub fn on_recv_packet_execute( ) -> (ModuleExtras, Acknowledgement) { let Ok(data) = serde_json::from_slice::(&packet.data) else { let ack = - AcknowledgementStatus::error(TokenTransferError::PacketDataDeserialization.into()); + AcknowledgementStatus::error(TokenTransferError::FailedToDeserializePacketData.into()); return (ModuleExtras::empty(), ack.into()); }; @@ -204,10 +204,10 @@ where Ctx: TokenTransferValidationContext, { let data = serde_json::from_slice::(&packet.data) - .map_err(|_| TokenTransferError::PacketDataDeserialization)?; + .map_err(|_| TokenTransferError::FailedToDeserializePacketData)?; let acknowledgement = serde_json::from_slice::(acknowledgement.as_ref()) - .map_err(|_| TokenTransferError::AckDeserialization)?; + .map_err(|_| TokenTransferError::FailedToDeserializeAck)?; if !acknowledgement.is_successful() { refund_packet_token_validate(ctx, packet, &data)?; @@ -225,7 +225,7 @@ pub fn on_acknowledgement_packet_execute( let Ok(data) = serde_json::from_slice::(&packet.data) else { return ( ModuleExtras::empty(), - Err(TokenTransferError::PacketDataDeserialization), + Err(TokenTransferError::FailedToDeserializePacketData), ); }; @@ -234,7 +234,7 @@ pub fn on_acknowledgement_packet_execute( else { return ( ModuleExtras::empty(), - Err(TokenTransferError::AckDeserialization), + Err(TokenTransferError::FailedToDeserializeAck), ); }; @@ -270,7 +270,7 @@ where Ctx: TokenTransferValidationContext, { let data = serde_json::from_slice::(&packet.data) - .map_err(|_| TokenTransferError::PacketDataDeserialization)?; + .map_err(|_| TokenTransferError::FailedToDeserializePacketData)?; refund_packet_token_validate(ctx, packet, &data)?; @@ -285,7 +285,7 @@ pub fn on_timeout_packet_execute( let Ok(data) = serde_json::from_slice::(&packet.data) else { return ( ModuleExtras::empty(), - Err(TokenTransferError::PacketDataDeserialization), + Err(TokenTransferError::FailedToDeserializePacketData), ); }; @@ -324,7 +324,7 @@ mod test { r#"{"result":"AQ=="}"#, ); ser_json_assert_eq( - AcknowledgementStatus::error(TokenTransferError::PacketDataDeserialization.into()), + AcknowledgementStatus::error(TokenTransferError::FailedToDeserializePacketData.into()), r#"{"error":"failed to deserialize packet data"}"#, ); } @@ -342,7 +342,7 @@ mod test { #[test] fn test_ack_error_to_vec() { let ack_error: Vec = - AcknowledgementStatus::error(TokenTransferError::PacketDataDeserialization.into()) + AcknowledgementStatus::error(TokenTransferError::FailedToDeserializePacketData.into()) .into(); // Check that it's the same output as ibc-go @@ -367,7 +367,7 @@ mod test { ); de_json_assert_eq( r#"{"error":"failed to deserialize packet data"}"#, - AcknowledgementStatus::error(TokenTransferError::PacketDataDeserialization.into()), + AcknowledgementStatus::error(TokenTransferError::FailedToDeserializePacketData.into()), ); assert!(serde_json::from_str::(r#"{"success":"AQ=="}"#).is_err()); diff --git a/ibc-apps/ics20-transfer/types/src/coin.rs b/ibc-apps/ics20-transfer/types/src/coin.rs index 65a147218..9470bbdbc 100644 --- a/ibc-apps/ics20-transfer/types/src/coin.rs +++ b/ibc-apps/ics20-transfer/types/src/coin.rs @@ -76,9 +76,7 @@ where .chars() .all(|x| x.is_alphanumeric() || VALID_DENOM_CHARACTERS.contains(x)) }) - .ok_or_else(|| TokenTransferError::InvalidCoin { - coin: coin_str.to_string(), - })?; + .ok_or_else(|| TokenTransferError::InvalidCoin(coin_str.to_string()))?; Ok(Coin { amount: amount.parse()?, diff --git a/ibc-apps/ics20-transfer/types/src/denom.rs b/ibc-apps/ics20-transfer/types/src/denom.rs index 4bd30f60c..cc814280f 100644 --- a/ibc-apps/ics20-transfer/types/src/denom.rs +++ b/ibc-apps/ics20-transfer/types/src/denom.rs @@ -219,7 +219,7 @@ impl FromStr for TracePath { remaining_parts .is_none() .then_some(trace_path) - .ok_or_else(|| TokenTransferError::MalformedTrace(s.to_string())) + .ok_or_else(|| TokenTransferError::InvalidTrace(s.to_string())) } } diff --git a/ibc-apps/ics20-transfer/types/src/error.rs b/ibc-apps/ics20-transfer/types/src/error.rs index a394eb77d..7924e2609 100644 --- a/ibc-apps/ics20-transfer/types/src/error.rs +++ b/ibc-apps/ics20-transfer/types/src/error.rs @@ -1,6 +1,5 @@ //! Defines the token transfer error type use core::convert::Infallible; -use core::str::Utf8Error; use displaydoc::Display; use ibc_core::channel::types::acknowledgement::StatusValue; @@ -17,68 +16,39 @@ pub enum TokenTransferError { ContextError(ContextError), /// invalid identifier: `{0}` InvalidIdentifier(IdentifierError), - /// insufficient funds: tried to send `{send_attempt}`, sender only has `{available_funds}` - InsufficientFunds { - send_attempt: String, - available_funds: String, - }, - /// destination channel not found in the counterparty of port_id `{port_id}` and channel_id `{channel_id}` - DestinationChannelNotFound { - port_id: PortId, - channel_id: ChannelId, - }, - /// base denomination is empty - EmptyBaseDenom, - /// invalid prot id n trace at position: `{pos}`, validation error: `{validation_error}` - InvalidTracePortId { - pos: u64, - validation_error: IdentifierError, - }, - /// invalid channel id in trace at position: `{pos}`, validation error: `{validation_error}` - InvalidTraceChannelId { - pos: u64, - validation_error: IdentifierError, - }, - /// malformed trace: `{0}` - MalformedTrace(String), - /// trace length must be even but got: `{len}` - InvalidTraceLength { len: u64 }, + /// invalid trace: `{0}` + InvalidTrace(String), /// invalid amount: `{0}` InvalidAmount(FromDecStrErr), - /// invalid token - InvalidToken, - /// expected `{expect_order}` channel, got `{got_order}` - ChannelNotUnordered { - expect_order: Order, - got_order: Order, + /// invalid coin: `{0}` + InvalidCoin(String), + /// missing token + MissingToken, + /// missing destination channel `{channel_id}` on port `{port_id}` + MissingDestinationChannel { + port_id: PortId, + channel_id: ChannelId, }, - /// channel cannot be closed - CantCloseChannel, + /// mismatched channel orders: expected `{expected}`, actual `{actual}` + MismatchedChannelOrders { expected: Order, actual: Order }, + /// mismatched port IDs: expected `{expected}`, actual `{actual}` + MismatchedPortIds { expected: PortId, actual: PortId }, /// failed to deserialize packet data - PacketDataDeserialization, + FailedToDeserializePacketData, /// failed to deserialize acknowledgement - AckDeserialization, - /// receive is not enabled - ReceiveDisabled { reason: String }, - /// send is not enabled - SendDisabled { reason: String }, - /// failed to parse as AccountId - ParseAccountFailure, - /// invalid port: `{port_id}`, expected `{exp_port_id}` - InvalidPort { - port_id: PortId, - exp_port_id: PortId, - }, - /// decoding raw msg error: `{reason}` - DecodeRawMsg { reason: String }, - /// unknown msg type: `{msg_type}` - UnknownMsgType { msg_type: String }, - /// invalid coin string: `{coin}` - InvalidCoin { coin: String }, - /// decoding raw bytes as UTF-8 string error: `{0}` - Utf8Decode(Utf8Error), - /// other error: `{0}` - Other(String), + FailedToDeserializeAck, + // TODO(seanchen1991): Used in basecoin; this variant should be moved + // to a host-relevant error + /// failed to parse account ID + FailedToParseAccount, + /// failed to decode raw msg: `{description}` + FailedToDecodeRawMsg { description: String }, + /// channel cannot be closed + UnsupportedClosedChannel, + /// empty base denomination + EmptyBaseDenom, + /// unknown msg type: `{0}` + UnknownMsgType(String), } #[cfg(feature = "std")] @@ -86,17 +56,8 @@ impl std::error::Error for TokenTransferError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { Self::ContextError(e) => Some(e), - Self::InvalidIdentifier(e) - | Self::InvalidTracePortId { - validation_error: e, - .. - } - | Self::InvalidTraceChannelId { - validation_error: e, - .. - } => Some(e), + Self::InvalidIdentifier(e) => Some(e), Self::InvalidAmount(e) => Some(e), - Self::Utf8Decode(e) => Some(e), _ => None, } } diff --git a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs index cc311a2ca..048ea956c 100644 --- a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs @@ -69,9 +69,9 @@ impl TryFrom for MsgTransfer { packet_data: PacketData { token: raw_msg .token - .ok_or(TokenTransferError::InvalidToken)? + .ok_or(TokenTransferError::MissingToken)? .try_into() - .map_err(|_| TokenTransferError::InvalidToken)?, + .map_err(|_| TokenTransferError::MissingToken)?, sender: raw_msg.sender.into(), receiver: raw_msg.receiver.into(), memo: raw_msg.memo.into(), @@ -104,14 +104,12 @@ impl TryFrom for MsgTransfer { fn try_from(raw: Any) -> Result { match raw.type_url.as_str() { - TYPE_URL => { - MsgTransfer::decode_vec(&raw.value).map_err(|e| TokenTransferError::DecodeRawMsg { - reason: e.to_string(), - }) - } - _ => Err(TokenTransferError::UnknownMsgType { - msg_type: raw.type_url, + TYPE_URL => MsgTransfer::decode_vec(&raw.value).map_err(|e| { + TokenTransferError::FailedToDecodeRawMsg { + description: e.to_string(), + } }), + _ => Err(TokenTransferError::UnknownMsgType(raw.type_url)), } } } diff --git a/ibc-apps/ics721-nft-transfer/src/handler/mod.rs b/ibc-apps/ics721-nft-transfer/src/handler/mod.rs index 2adbb47f6..8f8d0775c 100644 --- a/ibc-apps/ics721-nft-transfer/src/handler/mod.rs +++ b/ibc-apps/ics721-nft-transfer/src/handler/mod.rs @@ -21,7 +21,7 @@ pub fn refund_packet_nft_execute( .sender .clone() .try_into() - .map_err(|_| NftTransferError::ParseAccountFailure)?; + .map_err(|_| NftTransferError::FailedToParseAccount)?; if is_sender_chain_source( packet.port_id_on_a.clone(), @@ -58,7 +58,7 @@ pub fn refund_packet_nft_validate( .sender .clone() .try_into() - .map_err(|_| NftTransferError::ParseAccountFailure)?; + .map_err(|_| NftTransferError::FailedToParseAccount)?; if is_sender_chain_source( packet.port_id_on_a.clone(), diff --git a/ibc-apps/ics721-nft-transfer/src/handler/on_recv_packet.rs b/ibc-apps/ics721-nft-transfer/src/handler/on_recv_packet.rs index 8782bf7a2..59e6f3cb8 100644 --- a/ibc-apps/ics721-nft-transfer/src/handler/on_recv_packet.rs +++ b/ibc-apps/ics721-nft-transfer/src/handler/on_recv_packet.rs @@ -25,11 +25,12 @@ where .can_receive_nft() .map_err(|err| (ModuleExtras::empty(), err))?; - let receiver_account = data - .receiver - .clone() - .try_into() - .map_err(|_| (ModuleExtras::empty(), NftTransferError::ParseAccountFailure))?; + let receiver_account = data.receiver.clone().try_into().map_err(|_| { + ( + ModuleExtras::empty(), + NftTransferError::FailedToParseAccount, + ) + })?; let extras = if is_receiver_chain_source( packet.port_id_on_a.clone(), diff --git a/ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs b/ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs index 4cf1a759c..8a33fef56 100644 --- a/ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs +++ b/ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs @@ -47,7 +47,7 @@ where let chan_id_on_b = chan_end_on_a .counterparty() .channel_id() - .ok_or_else(|| NftTransferError::DestinationChannelNotFound { + .ok_or_else(|| NftTransferError::MissingDestinationChannel { port_id: msg.port_id_on_a.clone(), channel_id: msg.chan_id_on_a.clone(), })? @@ -61,7 +61,7 @@ where .sender .clone() .try_into() - .map_err(|_| NftTransferError::ParseAccountFailure)?; + .map_err(|_| NftTransferError::FailedToParseAccount)?; let mut packet_data = msg.packet_data; let class_id = &packet_data.class_id; @@ -149,7 +149,7 @@ where let chan_on_b = chan_end_on_a .counterparty() .channel_id() - .ok_or_else(|| NftTransferError::DestinationChannelNotFound { + .ok_or_else(|| NftTransferError::MissingDestinationChannel { port_id: msg.port_id_on_a.clone(), channel_id: msg.chan_id_on_a.clone(), })? @@ -164,7 +164,7 @@ where .sender .clone() .try_into() - .map_err(|_| NftTransferError::ParseAccountFailure)?; + .map_err(|_| NftTransferError::FailedToParseAccount)?; let mut packet_data = msg.packet_data; let class_id = &packet_data.class_id; diff --git a/ibc-apps/ics721-nft-transfer/src/module.rs b/ibc-apps/ics721-nft-transfer/src/module.rs index 074e7c869..5560b686f 100644 --- a/ibc-apps/ics721-nft-transfer/src/module.rs +++ b/ibc-apps/ics721-nft-transfer/src/module.rs @@ -28,16 +28,16 @@ pub fn on_chan_open_init_validate( version: &Version, ) -> Result<(), NftTransferError> { if order != Order::Unordered { - return Err(NftTransferError::ChannelNotUnordered { - expect_order: Order::Unordered, - got_order: order, + return Err(NftTransferError::MismatchedChannelOrders { + expected: Order::Unordered, + actual: order, }); } let bound_port = ctx.get_port()?; if port_id != &bound_port { - return Err(NftTransferError::InvalidPort { - port_id: port_id.clone(), - exp_port_id: bound_port, + return Err(NftTransferError::MismatchedPortIds { + actual: port_id.clone(), + expected: bound_port, }); } @@ -72,9 +72,9 @@ pub fn on_chan_open_try_validate( counterparty_version: &Version, ) -> Result<(), NftTransferError> { if order != Order::Unordered { - return Err(NftTransferError::ChannelNotUnordered { - expect_order: Order::Unordered, - got_order: order, + return Err(NftTransferError::MismatchedChannelOrders { + expected: Order::Unordered, + actual: order, }); } @@ -140,7 +140,7 @@ pub fn on_chan_close_init_validate( _port_id: &PortId, _channel_id: &ChannelId, ) -> Result<(), NftTransferError> { - Err(NftTransferError::CantCloseChannel) + Err(NftTransferError::UnsupportedClosedChannel) } pub fn on_chan_close_init_execute( @@ -148,7 +148,7 @@ pub fn on_chan_close_init_execute( _port_id: &PortId, _channel_id: &ChannelId, ) -> Result { - Err(NftTransferError::CantCloseChannel) + Err(NftTransferError::UnsupportedClosedChannel) } pub fn on_chan_close_confirm_validate( @@ -172,7 +172,8 @@ pub fn on_recv_packet_execute( packet: &Packet, ) -> (ModuleExtras, Acknowledgement) { let Ok(data) = serde_json::from_slice::(&packet.data) else { - let ack = AcknowledgementStatus::error(NftTransferError::PacketDataDeserialization.into()); + let ack = + AcknowledgementStatus::error(NftTransferError::FailedToDeserializePacketData.into()); return (ModuleExtras::empty(), ack.into()); }; @@ -204,10 +205,10 @@ pub fn on_acknowledgement_packet_validate( _relayer: &Signer, ) -> Result<(), NftTransferError> { let data = serde_json::from_slice::(&packet.data) - .map_err(|_| NftTransferError::PacketDataDeserialization)?; + .map_err(|_| NftTransferError::FailedToDeserializePacketData)?; let acknowledgement = serde_json::from_slice::(acknowledgement.as_ref()) - .map_err(|_| NftTransferError::AckDeserialization)?; + .map_err(|_| NftTransferError::FailedToDeserializeAck)?; if !acknowledgement.is_successful() { refund_packet_nft_validate(ctx, packet, &data)?; @@ -225,7 +226,7 @@ pub fn on_acknowledgement_packet_execute( let Ok(data) = serde_json::from_slice::(&packet.data) else { return ( ModuleExtras::empty(), - Err(NftTransferError::PacketDataDeserialization), + Err(NftTransferError::FailedToDeserializePacketData), ); }; @@ -234,7 +235,7 @@ pub fn on_acknowledgement_packet_execute( else { return ( ModuleExtras::empty(), - Err(NftTransferError::AckDeserialization), + Err(NftTransferError::FailedToDeserializeAck), ); }; @@ -267,7 +268,7 @@ pub fn on_timeout_packet_validate( _relayer: &Signer, ) -> Result<(), NftTransferError> { let data = serde_json::from_slice::(&packet.data) - .map_err(|_| NftTransferError::PacketDataDeserialization)?; + .map_err(|_| NftTransferError::FailedToDeserializePacketData)?; refund_packet_nft_validate(ctx, packet, &data)?; @@ -282,7 +283,7 @@ pub fn on_timeout_packet_execute( let Ok(data) = serde_json::from_slice::(&packet.data) else { return ( ModuleExtras::empty(), - Err(NftTransferError::PacketDataDeserialization), + Err(NftTransferError::FailedToDeserializePacketData), ); }; @@ -321,7 +322,7 @@ mod test { r#"{"result":"AQ=="}"#, ); ser_json_assert_eq( - AcknowledgementStatus::error(NftTransferError::PacketDataDeserialization.into()), + AcknowledgementStatus::error(NftTransferError::FailedToDeserializePacketData.into()), r#"{"error":"failed to deserialize packet data"}"#, ); } @@ -339,7 +340,8 @@ mod test { #[test] fn test_ack_error_to_vec() { let ack_error: Vec = - AcknowledgementStatus::error(NftTransferError::PacketDataDeserialization.into()).into(); + AcknowledgementStatus::error(NftTransferError::FailedToDeserializePacketData.into()) + .into(); // Check that it's the same output as ibc-go // Note: this also implicitly checks that the ack bytes are non-empty, @@ -363,7 +365,7 @@ mod test { ); de_json_assert_eq( r#"{"error":"failed to deserialize packet data"}"#, - AcknowledgementStatus::error(NftTransferError::PacketDataDeserialization.into()), + AcknowledgementStatus::error(NftTransferError::FailedToDeserializePacketData.into()), ); assert!(serde_json::from_str::(r#"{"success":"AQ=="}"#).is_err()); diff --git a/ibc-apps/ics721-nft-transfer/types/src/class.rs b/ibc-apps/ics721-nft-transfer/types/src/class.rs index 831883331..8a7c941e6 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/class.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/class.rs @@ -142,9 +142,9 @@ impl TryFrom for PrefixedClassId { fn try_from(value: RawClassTrace) -> Result { let base_class_id = ClassId::from_str(&value.base_class_id)?; - // FIXME: separate `TracePath` error. let trace_path = TracePath::from_str(&value.path) - .map_err(|err| NftTransferError::Other(err.to_string()))?; + .map_err(|_| NftTransferError::InvalidTrace(value.path))?; + Ok(Self { trace_path, base_class_id, @@ -248,10 +248,7 @@ impl FromStr for ClassUri { fn from_str(class_uri: &str) -> Result { match Uri::from_str(class_uri) { Ok(uri) => Ok(Self(uri)), - Err(err) => Err(NftTransferError::InvalidUri { - uri: class_uri.to_string(), - validation_error: err, - }), + Err(err) => Err(NftTransferError::InvalidUri(err)), } } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/data.rs b/ibc-apps/ics721-nft-transfer/types/src/data.rs index a9aecc509..8150545bb 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/data.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/data.rs @@ -97,7 +97,9 @@ impl FromStr for Ics721Data { type Err = NftTransferError; fn from_str(s: &str) -> Result { - serde_json::from_str(s).map_err(|_| NftTransferError::InvalidIcs721Data) + serde_json::from_str(s).map_err(|e| NftTransferError::InvalidJsonData { + description: e.to_string(), + }) } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/error.rs b/ibc-apps/ics721-nft-transfer/types/src/error.rs index 94c230add..626eb9f6d 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/error.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/error.rs @@ -1,6 +1,5 @@ //! Defines the Non-Fungible Token Transfer (ICS-721) error types. use core::convert::Infallible; -use core::str::Utf8Error; use displaydoc::Display; use ibc_core::channel::types::acknowledgement::StatusValue; @@ -16,80 +15,39 @@ pub enum NftTransferError { ContextError(ContextError), /// invalid identifier: `{0}` InvalidIdentifier(IdentifierError), - /// invalid URI: `{uri}`, validation error: `{validation_error}`` - InvalidUri { - uri: String, - validation_error: http::uri::InvalidUri, - }, - /// destination channel not found in the counterparty of port_id `{port_id}` and channel_id `{channel_id}` - DestinationChannelNotFound { + /// invalid URI: `{0}` + InvalidUri(http::uri::InvalidUri), + /// invalid json data: `{description}` + InvalidJsonData { description: String }, + /// invalid trace `{0}` + InvalidTrace(String), + /// missing destination channel `{channel_id}` on port `{port_id}` + MissingDestinationChannel { port_id: PortId, channel_id: ChannelId, }, - /// base class ID is empty + /// empty base class ID EmptyBaseClassId, - /// invalid prot id n trace at position: `{pos}`, validation error: `{validation_error}` - InvalidTracePortId { - pos: u64, - validation_error: IdentifierError, - }, - /// invalid channel id in trace at position: `{pos}`, validation error: `{validation_error}` - InvalidTraceChannelId { - pos: u64, - validation_error: IdentifierError, - }, - /// trace length must be even but got: `{len}` - InvalidTraceLength { len: u64 }, - /// no token ID - NoTokenId, - /// invalid token ID - InvalidTokenId, - /// duplicated token IDs - DuplicatedTokenIds, - /// The length of token IDs mismatched that of token URIs or token data - TokenMismatched, - /// invalid json data - InvalidJsonData, - /// the data is not in the JSON format specified by ICS-721 - InvalidIcs721Data, - /// expected `{expect_order}` channel, got `{got_order}` - ChannelNotUnordered { - expect_order: Order, - got_order: Order, - }, - /// channel cannot be closed - CantCloseChannel, - /// `{sender}` doesn't own the NFT - InvalidOwner { sender: String }, - /// owner is not found - OwnerNotFound, - /// nft is not found - NftNotFound, - /// nft class is not found - NftClassNotFound, + /// empty token ID + EmptyTokenId, + /// mismatched number of token IDs: expected `{expected}`, actual `{actual}` + MismatchedNumberOfTokenIds { expected: usize, actual: usize }, + /// mismatched channel orders: expected `{expected}`, actual `{actual}` + MismatchedChannelOrders { expected: Order, actual: Order }, + /// mismatched port IDs: expected `{expected}`, actual `{actual}` + MismatchedPortIds { expected: PortId, actual: PortId }, /// failed to deserialize packet data - PacketDataDeserialization, + FailedToDeserializePacketData, /// failed to deserialize acknowledgement - AckDeserialization, - /// receive is not enabled - ReceiveDisabled { reason: String }, - /// send is not enabled - SendDisabled { reason: String }, - /// failed to parse as AccountId - ParseAccountFailure, - /// invalid port: `{port_id}`, expected `{exp_port_id}` - InvalidPort { - port_id: PortId, - exp_port_id: PortId, - }, - /// decoding raw msg error: `{reason}` - DecodeRawMsg { reason: String }, - /// unknown msg type: `{msg_type}` - UnknownMsgType { msg_type: String }, - /// decoding raw bytes as UTF-8 string error: `{0}` - Utf8Decode(Utf8Error), - /// other error: `{0}` - Other(String), + FailedToDeserializeAck, + /// failed to parse account ID + FailedToParseAccount, + /// failed to decode raw msg: `{description}` + FailedToDecodeRawMsg { description: String }, + /// channel cannot be closed + UnsupportedClosedChannel, + /// unknown msg type: `{0}` + UnknownMsgType(String), } #[cfg(feature = "std")] @@ -97,19 +55,8 @@ impl std::error::Error for NftTransferError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { Self::ContextError(e) => Some(e), - Self::InvalidUri { - validation_error: e, - .. - } => Some(e), - Self::InvalidIdentifier(e) - | Self::InvalidTracePortId { - validation_error: e, - .. - } - | Self::InvalidTraceChannelId { - validation_error: e, - .. - } => Some(e), + Self::InvalidUri(e) => Some(e), + Self::InvalidIdentifier(e) => Some(e), _ => None, } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs index b35a5c1cc..499d7d448 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs @@ -122,14 +122,12 @@ impl TryFrom for MsgTransfer { fn try_from(raw: Any) -> Result { match raw.type_url.as_str() { - TYPE_URL => { - MsgTransfer::decode_vec(&raw.value).map_err(|e| NftTransferError::DecodeRawMsg { - reason: e.to_string(), - }) - } - _ => Err(NftTransferError::UnknownMsgType { - msg_type: raw.type_url, + TYPE_URL => MsgTransfer::decode_vec(&raw.value).map_err(|e| { + NftTransferError::FailedToDecodeRawMsg { + description: e.to_string(), + } }), + _ => Err(NftTransferError::UnknownMsgType(raw.type_url)), } } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/packet.rs b/ibc-apps/ics721-nft-transfer/types/src/packet.rs index c2f9d2d2f..027e5fcb1 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/packet.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/packet.rs @@ -91,7 +91,7 @@ impl PacketData { /// Performs the basic validation of the packet data fields. pub fn validate_basic(&self) -> Result<(), NftTransferError> { if self.token_ids.0.is_empty() { - return Err(NftTransferError::NoTokenId); + return Err(NftTransferError::EmptyTokenId); } let num = self.token_ids.0.len(); let num_uri = self @@ -105,7 +105,10 @@ impl PacketData { .map(|t| t.len()) .unwrap_or_default(); if (num_uri != 0 && num_uri != num) || (num_data != 0 && num_data != num) { - return Err(NftTransferError::TokenMismatched); + return Err(NftTransferError::MismatchedNumberOfTokenIds { + actual: num, + expected: num_uri, + }); } Ok(()) } @@ -125,9 +128,13 @@ impl TryFrom for PacketData { } else { let decoded = BASE64_STANDARD .decode(raw_pkt_data.class_data) - .map_err(|_| NftTransferError::InvalidJsonData)?; + .map_err(|e| NftTransferError::InvalidJsonData { + description: e.to_string(), + })?; let data_str = - String::from_utf8(decoded).map_err(|_| NftTransferError::InvalidJsonData)?; + String::from_utf8(decoded).map_err(|e| NftTransferError::InvalidJsonData { + description: e.to_string(), + })?; Some(data_str.parse()?) }; @@ -138,11 +145,15 @@ impl TryFrom for PacketData { .token_data .iter() .map(|data| { - let decoded = BASE64_STANDARD - .decode(data) - .map_err(|_| NftTransferError::InvalidJsonData)?; + let decoded = BASE64_STANDARD.decode(data).map_err(|e| { + NftTransferError::InvalidJsonData { + description: e.to_string(), + } + })?; let data_str = - String::from_utf8(decoded).map_err(|_| NftTransferError::InvalidJsonData)?; + String::from_utf8(decoded).map_err(|e| NftTransferError::InvalidJsonData { + description: e.to_string(), + })?; data_str.parse() }) .collect(); diff --git a/ibc-apps/ics721-nft-transfer/types/src/token.rs b/ibc-apps/ics721-nft-transfer/types/src/token.rs index 1571eac48..fa11e93a1 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/token.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/token.rs @@ -45,7 +45,7 @@ impl FromStr for TokenId { fn from_str(token_id: &str) -> Result { if token_id.trim().is_empty() { - Err(NftTransferError::InvalidTokenId) + Err(NftTransferError::EmptyTokenId) } else { Ok(Self(token_id.to_string())) } @@ -94,15 +94,22 @@ impl TryFrom> for TokenIds { fn try_from(token_ids: Vec) -> Result { if token_ids.is_empty() { - return Err(NftTransferError::NoTokenId); + return Err(NftTransferError::EmptyTokenId); } + let ids: Result, _> = token_ids.iter().map(|t| t.parse()).collect(); let mut ids = ids?; + ids.sort(); ids.dedup(); + if ids.len() != token_ids.len() { - return Err(NftTransferError::DuplicatedTokenIds); + return Err(NftTransferError::MismatchedNumberOfTokenIds { + expected: token_ids.len(), + actual: ids.len(), + }); } + Ok(Self(ids)) } } @@ -175,10 +182,7 @@ impl FromStr for TokenUri { fn from_str(token_uri: &str) -> Result { match Uri::from_str(token_uri) { Ok(uri) => Ok(Self(uri)), - Err(err) => Err(NftTransferError::InvalidUri { - uri: token_uri.to_string(), - validation_error: err, - }), + Err(err) => Err(NftTransferError::InvalidUri(err)), } } } From e1b4db28c1ba83d422ff2a8921aa55995bc9bbf6 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 23 Aug 2024 11:26:33 -0500 Subject: [PATCH 02/18] Clean up `ibc-core` and `ibc-clients` error types (#1317) * Clean up pass of ClientError type * Clean up pass of ics24 errors * Clean up pass of ics23 errors * Clean up pass of ics07 errors * Clean up ChannelError type * Clean up PacketError type * Better organize error variants * cargo nightly fmt * Update error variant in integration tests * Fix ics23 tests * Fix typo in doc comment * Update cw-check Cargo.lock * Clean up ics08 error * Cargo nightly fmt * Change single-field error variants to tuple structs * Propogate error variant changes * Propogate error variant changes * Clean up PacketError type * Clean up IdentifierError type * Clean up ics26 RouterError * Clean up ics03 ConnectionError * Fix error variant naming * Fix error variant naming * Remove redundant Other error variant * Clarify tendermint client error naming * Rename tendermint client Error to TendermintClientError * Rename wasm light client Error to WasmClientError * Rename ics25-handler Error to HandlerError * Remove unused HandlerError * Remove TendermintClientError::InvalidHeader error for more specific variant * Rename LightClientVerifierError variant to FailedToVerifyHeader * Rename ConsensusStateTimestampGteTrustingPeriod to InsufficientTrustingPeriod * Remove redundant ChannelError::FailedToParseSequence variant * Rename ChannelError::FailedChannelVerification to FailedProofVerification * Replace incorrect usages of FailedPacketVerification * Define From for ClientError impl * Add IdentifierError::FailedToParse variant * Replace InvalidPrefix error usage * Fix doc comment typo * Improve ChannelError variant names * Add PacketError::InvalidPathPrefix variant * Remove unnecessary PacketError variant * Add error variants used by basecoin * nit: remove unnecessary map_err in verify_(non_)membership * imp: define EmptyCommitmentRoot * nit: remove MissingHostHeight * fix: remove unnecessary map_err(PacketError::Channel) * Remove a TODO --------- Co-authored-by: Farhad Shabani --- ci/cw-check/Cargo.lock | 1 + .../ics07-tendermint/src/client_state.rs | 4 +- .../src/client_state/common.rs | 40 ++-- .../src/client_state/misbehaviour.rs | 9 +- .../src/client_state/update_client.rs | 10 +- .../src/client_state/validation.rs | 2 +- .../ics07-tendermint/src/consensus_state.rs | 4 +- .../types/src/client_state.rs | 95 ++++---- .../types/src/consensus_state.rs | 33 ++- .../ics07-tendermint/types/src/error.rs | 119 ++++------ .../ics07-tendermint/types/src/header.rs | 72 +++--- .../types/src/misbehaviour.rs | 28 +-- .../types/src/trust_threshold.rs | 8 +- .../ics08-wasm/types/src/client_state.rs | 30 ++- ibc-clients/ics08-wasm/types/src/error.rs | 20 +- .../types/src/msgs/migrate_contract.rs | 4 +- .../ics02-client/src/handler/create_client.rs | 8 +- .../src/handler/recover_client.rs | 2 +- .../ics02-client/src/handler/update_client.rs | 4 +- .../src/handler/upgrade_client.rs | 2 +- ibc-core/ics02-client/types/src/error.rs | 183 ++++++++------- ibc-core/ics02-client/types/src/events.rs | 156 ++++--------- ibc-core/ics02-client/types/src/height.rs | 2 +- .../types/src/msgs/misbehaviour.rs | 2 +- .../types/src/msgs/recover_client.rs | 4 +- .../types/src/msgs/update_client.rs | 4 +- ibc-core/ics02-client/types/src/status.rs | 4 +- ibc-core/ics03-connection/src/delay.rs | 6 +- .../src/handler/conn_open_ack.rs | 19 +- .../src/handler/conn_open_confirm.rs | 2 +- .../src/handler/conn_open_try.rs | 19 +- ibc-core/ics03-connection/src/handler/mod.rs | 4 +- .../ics03-connection/types/src/connection.rs | 12 +- ibc-core/ics03-connection/types/src/error.rs | 119 +++++----- .../ics03-connection/types/src/version.rs | 12 +- ibc-core/ics04-channel/Cargo.toml | 1 + .../src/handler/acknowledgement.rs | 30 ++- .../src/handler/chan_close_confirm.rs | 24 +- .../src/handler/chan_close_init.rs | 12 +- .../src/handler/chan_open_ack.rs | 12 +- .../src/handler/chan_open_confirm.rs | 29 ++- .../src/handler/chan_open_try.rs | 12 +- .../ics04-channel/src/handler/recv_packet.rs | 23 +- .../ics04-channel/src/handler/send_packet.rs | 10 +- ibc-core/ics04-channel/src/handler/timeout.rs | 21 +- .../src/handler/timeout_on_close.rs | 33 ++- .../types/src/acknowledgement.rs | 4 +- ibc-core/ics04-channel/types/src/error.rs | 209 +++++++----------- .../types/src/msgs/acknowledgement.rs | 6 +- .../types/src/msgs/chan_close_confirm.rs | 4 +- .../types/src/msgs/chan_open_ack.rs | 4 +- .../types/src/msgs/chan_open_confirm.rs | 4 +- .../types/src/msgs/chan_open_init.rs | 2 +- .../types/src/msgs/chan_open_try.rs | 6 +- .../types/src/msgs/recv_packet.rs | 6 +- .../ics04-channel/types/src/msgs/timeout.rs | 6 +- .../types/src/msgs/timeout_on_close.rs | 8 +- ibc-core/ics04-channel/types/src/packet.rs | 4 +- ibc-core/ics04-channel/types/src/version.rs | 2 +- .../ics23-commitment/types/src/commitment.rs | 2 +- ibc-core/ics23-commitment/types/src/error.rs | 26 +-- ibc-core/ics23-commitment/types/src/merkle.rs | 26 ++- ibc-core/ics23-commitment/types/src/specs.rs | 44 ++-- .../cosmos/src/upgrade_proposal/handler.rs | 2 +- .../cosmos/src/upgrade_proposal/plan.rs | 20 +- .../cosmos/src/upgrade_proposal/proposal.rs | 8 +- .../cosmos/src/validate_self_client.rs | 23 +- ibc-core/ics24-host/types/src/error.rs | 23 +- .../types/src/identifiers/chain_id.rs | 7 +- .../types/src/identifiers/sequence.rs | 4 +- ibc-core/ics24-host/types/src/validate.rs | 17 +- ibc-core/ics25-handler/src/entrypoint.rs | 24 +- ibc-core/ics25-handler/types/src/events.rs | 56 +---- ibc-core/ics25-handler/types/src/msgs.rs | 40 ++-- ibc-core/ics26-routing/types/src/error.rs | 16 +- .../src/fixtures/clients/tendermint.rs | 8 +- .../testapp/ibc/clients/mock/client_state.rs | 18 +- .../ibc/clients/mock/consensus_state.rs | 4 +- .../src/testapp/ibc/clients/mock/header.rs | 6 +- .../testapp/ibc/clients/mock/misbehaviour.rs | 4 +- .../src/testapp/ibc/core/client_ctx.rs | 14 +- ibc-testkit/src/testapp/ibc/core/core_ctx.rs | 93 +++----- .../tests/core/ics02_client/create_client.rs | 24 +- .../tests/core/ics02_client/upgrade_client.rs | 13 +- .../core/ics03_connection/conn_open_ack.rs | 23 +- 85 files changed, 886 insertions(+), 1174 deletions(-) diff --git a/ci/cw-check/Cargo.lock b/ci/cw-check/Cargo.lock index b7b3e2a48..2ba932c42 100644 --- a/ci/cw-check/Cargo.lock +++ b/ci/cw-check/Cargo.lock @@ -852,6 +852,7 @@ dependencies = [ "ibc-core-client", "ibc-core-commitment-types", "ibc-core-connection", + "ibc-core-connection-types", "ibc-core-handler-types", "ibc-core-host", "ibc-core-router", diff --git a/ibc-clients/ics07-tendermint/src/client_state.rs b/ibc-clients/ics07-tendermint/src/client_state.rs index 0adb68f22..ecfbba885 100644 --- a/ibc-clients/ics07-tendermint/src/client_state.rs +++ b/ibc-clients/ics07-tendermint/src/client_state.rs @@ -8,7 +8,7 @@ //! Rust). As such, this module also includes some trait implementations that //! serve to pass through traits implemented on the wrapped `ClientState` type. -use ibc_client_tendermint_types::error::Error; +use ibc_client_tendermint_types::error::TendermintClientError; use ibc_client_tendermint_types::proto::v1::ClientState as RawTmClientState; use ibc_client_tendermint_types::ClientState as ClientStateType; use ibc_core_client::types::error::ClientError; @@ -44,7 +44,7 @@ impl ClientState { impl Protobuf for ClientState {} impl TryFrom for ClientState { - type Error = Error; + type Error = TendermintClientError; fn try_from(raw: RawTmClientState) -> Result { Ok(Self(ClientStateType::try_from(raw)?)) diff --git a/ibc-clients/ics07-tendermint/src/client_state/common.rs b/ibc-clients/ics07-tendermint/src/client_state/common.rs index ef5b04469..66ac52aec 100644 --- a/ibc-clients/ics07-tendermint/src/client_state/common.rs +++ b/ibc-clients/ics07-tendermint/src/client_state/common.rs @@ -67,7 +67,7 @@ impl ClientStateCommon for ClientState { let (upgrade_path_prefix, upgrade_path) = match upgrade_path.len() { 0 => { return Err(UpgradeClientError::InvalidUpgradePath { - reason: "no upgrade path has been set".to_string(), + description: "no upgrade path has been set".to_string(), } .into()); } @@ -78,7 +78,7 @@ impl ClientStateCommon for ClientState { ), _ => { return Err(UpgradeClientError::InvalidUpgradePath { - reason: "upgrade path is too long".to_string(), + description: "upgrade path is too long".to_string(), } .into()); } @@ -162,15 +162,11 @@ pub fn verify_consensus_state( let tm_consensus_state = TmConsensusState::try_from(consensus_state)?; if tm_consensus_state.root().is_empty() { - return Err(ClientError::Other { - description: "empty commitment root".into(), - }); + Err(CommitmentError::EmptyCommitmentRoot)?; }; if consensus_state_status(&tm_consensus_state, host_timestamp, trusting_period)?.is_expired() { - return Err(ClientError::ClientNotActive { - status: Status::Expired, - }); + return Err(ClientError::InvalidStatus(Status::Expired)); } Ok(()) @@ -214,8 +210,8 @@ pub fn validate_proof_height( if latest_height < proof_height { return Err(ClientError::InvalidProofHeight { - latest_height, - proof_height, + actual: latest_height, + expected: proof_height, }); } @@ -258,7 +254,7 @@ pub fn verify_upgrade_client( // the upgrade height This condition checks both the revision number and // the height if latest_height >= upgraded_tm_client_state_height { - Err(UpgradeClientError::LowUpgradeHeight { + Err(UpgradeClientError::InsufficientUpgradeHeight { upgraded_height: upgraded_tm_client_state_height, client_height: latest_height, })? @@ -301,17 +297,16 @@ pub fn verify_membership( value: Vec, ) -> Result<(), ClientError> { if prefix.is_empty() { - return Err(ClientError::Ics23Verification( - CommitmentError::EmptyCommitmentPrefix, - )); + Err(CommitmentError::EmptyCommitmentPrefix)?; } let merkle_path = MerklePath::new(vec![prefix.as_bytes().to_vec().into(), path]); - let merkle_proof = MerkleProof::try_from(proof).map_err(ClientError::InvalidCommitmentProof)?; - merkle_proof - .verify_membership::(proof_specs, root.clone().into(), merkle_path, value, 0) - .map_err(ClientError::Ics23Verification) + let merkle_proof = MerkleProof::try_from(proof)?; + + merkle_proof.verify_membership::(proof_specs, root.clone().into(), merkle_path, value, 0)?; + + Ok(()) } /// Verify that the given value does not belong in the client's merkle proof. @@ -327,9 +322,10 @@ pub fn verify_non_membership( path: PathBytes, ) -> Result<(), ClientError> { let merkle_path = MerklePath::new(vec![prefix.as_bytes().to_vec().into(), path]); - let merkle_proof = MerkleProof::try_from(proof).map_err(ClientError::InvalidCommitmentProof)?; - merkle_proof - .verify_non_membership::(proof_specs, root.clone().into(), merkle_path) - .map_err(ClientError::Ics23Verification) + let merkle_proof = MerkleProof::try_from(proof)?; + + merkle_proof.verify_non_membership::(proof_specs, root.clone().into(), merkle_path)?; + + Ok(()) } diff --git a/ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs b/ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs index ea40fa717..29e672c6b 100644 --- a/ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs +++ b/ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs @@ -1,4 +1,4 @@ -use ibc_client_tendermint_types::error::{Error, IntoResult}; +use ibc_client_tendermint_types::error::{IntoResult, TendermintClientError}; use ibc_client_tendermint_types::{ ConsensusState as ConsensusStateType, Header as TmHeader, Misbehaviour as TmMisbehaviour, }; @@ -101,14 +101,11 @@ where let duration_since_consensus_state = current_timestamp.duration_since(&trusted_timestamp).ok_or( - ClientError::InvalidConsensusStateTimestamp { - time1: trusted_timestamp, - time2: current_timestamp, - }, + ClientError::InvalidConsensusStateTimestamp(trusted_timestamp), )?; if duration_since_consensus_state >= options.trusting_period { - return Err(Error::ConsensusStateTimestampGteTrustingPeriod { + return Err(TendermintClientError::InsufficientTrustingPeriod { duration_since_consensus_state, trusting_period: options.trusting_period, } diff --git a/ibc-clients/ics07-tendermint/src/client_state/update_client.rs b/ibc-clients/ics07-tendermint/src/client_state/update_client.rs index 03da355ff..40ec52751 100644 --- a/ibc-clients/ics07-tendermint/src/client_state/update_client.rs +++ b/ibc-clients/ics07-tendermint/src/client_state/update_client.rs @@ -1,4 +1,4 @@ -use ibc_client_tendermint_types::error::{Error, IntoResult}; +use ibc_client_tendermint_types::error::{IntoResult, TendermintClientError}; use ibc_client_tendermint_types::{ConsensusState as ConsensusStateType, Header as TmHeader}; use ibc_core_client::context::{Convertible, ExtClientValidationContext}; use ibc_core_client::types::error::ClientError; @@ -63,10 +63,10 @@ where .trusted_height .revision_height() .try_into() - .map_err(|_| ClientError::ClientSpecific { - description: Error::InvalidHeaderHeight { - height: header.trusted_height.revision_height(), - } + .map_err(|_| ClientError::FailedHeaderVerification { + description: TendermintClientError::InvalidHeaderHeight( + header.trusted_height.revision_height(), + ) .to_string(), })?, next_validators: &header.trusted_next_validator_set, diff --git a/ibc-clients/ics07-tendermint/src/client_state/validation.rs b/ibc-clients/ics07-tendermint/src/client_state/validation.rs index b1a028749..4cd1a9cc8 100644 --- a/ibc-clients/ics07-tendermint/src/client_state/validation.rs +++ b/ibc-clients/ics07-tendermint/src/client_state/validation.rs @@ -278,5 +278,5 @@ where && subject_proof_specs == &substitute_proof_specs && subject_upgrade_path == &substitute_upgrade_path) .then_some(()) - .ok_or(ClientError::ClientRecoveryStateMismatch) + .ok_or(ClientError::MismatchedClientRecoveryStates) } diff --git a/ibc-clients/ics07-tendermint/src/consensus_state.rs b/ibc-clients/ics07-tendermint/src/consensus_state.rs index 3f64ce085..6d0ed7f63 100644 --- a/ibc-clients/ics07-tendermint/src/consensus_state.rs +++ b/ibc-clients/ics07-tendermint/src/consensus_state.rs @@ -6,7 +6,7 @@ //! implementations that serve to pass through traits implemented on the wrapped //! `ConsensusState` type. -use ibc_client_tendermint_types::error::Error; +use ibc_client_tendermint_types::error::TendermintClientError; use ibc_client_tendermint_types::proto::v1::ConsensusState as RawTmConsensusState; use ibc_client_tendermint_types::ConsensusState as ConsensusStateType; use ibc_core_client::context::consensus_state::ConsensusState as ConsensusStateTrait; @@ -52,7 +52,7 @@ impl From for ConsensusStateType { impl Protobuf for ConsensusState {} impl TryFrom for ConsensusState { - type Error = Error; + type Error = TendermintClientError; fn try_from(raw: RawTmConsensusState) -> Result { Ok(Self(ConsensusStateType::try_from(raw)?)) diff --git a/ibc-clients/ics07-tendermint/types/src/client_state.rs b/ibc-clients/ics07-tendermint/types/src/client_state.rs index ee30dbdb0..98ce38460 100644 --- a/ibc-clients/ics07-tendermint/types/src/client_state.rs +++ b/ibc-clients/ics07-tendermint/types/src/client_state.rs @@ -18,7 +18,7 @@ use tendermint::chain::id::MAX_LENGTH as MaxChainIdLen; use tendermint::trust_threshold::TrustThresholdFraction as TendermintTrustThresholdFraction; use tendermint_light_client_verifier::options::Options; -use crate::error::Error; +use crate::error::TendermintClientError; use crate::header::Header as TmHeader; use crate::trust_threshold::TrustThreshold; @@ -88,7 +88,7 @@ impl ClientState { proof_specs: ProofSpecs, upgrade_path: Vec, allow_update: AllowUpdate, - ) -> Result { + ) -> Result { let client_state = Self::new_without_validation( chain_id, trust_level, @@ -105,7 +105,7 @@ impl ClientState { Ok(client_state) } - pub fn with_header(self, header: TmHeader) -> Result { + pub fn with_header(self, header: TmHeader) -> Result { Ok(Self { latest_height: max(header.height(), self.latest_height), ..self @@ -119,14 +119,14 @@ impl ClientState { } } - pub fn validate(&self) -> Result<(), Error> { + pub fn validate(&self) -> Result<(), TendermintClientError> { self.chain_id.validate_length(3, MaxChainIdLen as u64)?; // `TrustThreshold` is guaranteed to be in the range `[0, 1)`, but a `TrustThreshold::ZERO` // value is invalid in this context if self.trust_level == TrustThreshold::ZERO { - return Err(Error::InvalidTrustThreshold { - reason: "ClientState trust-level cannot be zero".to_string(), + return Err(TendermintClientError::InvalidTrustThreshold { + description: "ClientState trust-level cannot be zero".to_string(), }); } @@ -134,12 +134,18 @@ impl ClientState { self.trust_level.numerator(), self.trust_level.denominator(), ) - .map_err(Error::InvalidTendermintTrustThreshold)?; + .map_err(|_| TendermintClientError::InvalidTrustThreshold { + description: format!( + "invalid Tendermint trust threshold: {:?}/{:?}", + self.trust_level.numerator(), + self.trust_level.denominator() + ), + })?; // Basic validation of trusting period and unbonding period: each should be non-zero. if self.trusting_period <= Duration::new(0, 0) { - return Err(Error::InvalidTrustThreshold { - reason: format!( + return Err(TendermintClientError::InvalidTrustThreshold { + description: format!( "ClientState trusting period ({:?}) must be greater than zero", self.trusting_period ), @@ -147,8 +153,8 @@ impl ClientState { } if self.unbonding_period <= Duration::new(0, 0) { - return Err(Error::InvalidTrustThreshold { - reason: format!( + return Err(TendermintClientError::InvalidTrustThreshold { + description: format!( "ClientState unbonding period ({:?}) must be greater than zero", self.unbonding_period ), @@ -156,23 +162,21 @@ impl ClientState { } if self.trusting_period >= self.unbonding_period { - return Err(Error::InvalidTrustThreshold { - reason: format!( + return Err(TendermintClientError::InvalidTrustThreshold { + description: format!( "ClientState trusting period ({:?}) must be smaller than unbonding period ({:?})", self.trusting_period, self.unbonding_period ), }); } if self.max_clock_drift <= Duration::new(0, 0) { - return Err(Error::InvalidMaxClockDrift { - reason: "ClientState max-clock-drift must be greater than zero".to_string(), - }); + return Err(TendermintClientError::InvalidMaxClockDrift); } if self.latest_height.revision_number() != self.chain_id.revision_number() { - return Err(Error::InvalidLatestHeight { - reason: "ClientState latest-height revision number must match chain-id version" - .to_string(), + return Err(TendermintClientError::MismatchedRevisionHeights { + expected: self.chain_id.revision_number(), + actual: self.latest_height.revision_number(), }); } @@ -180,13 +184,9 @@ impl ClientState { self.proof_specs.validate()?; // `upgrade_path` itself may be empty, but if not then each key must be non-empty - for (idx, key) in self.upgrade_path.iter().enumerate() { + for key in self.upgrade_path.iter() { if key.trim().is_empty() { - return Err(Error::Validation { - reason: format!( - "ClientState upgrade-path key at index {idx:?} cannot be empty" - ), - }); + return Err(TendermintClientError::EmptyUpgradePathKey); } } @@ -200,11 +200,11 @@ impl ClientState { /// Helper method to produce a [`Options`] struct for use in /// Tendermint-specific light client verification. - pub fn as_light_client_options(&self) -> Result { + pub fn as_light_client_options(&self) -> Result { Ok(Options { trust_threshold: self.trust_level.try_into().map_err(|e: ClientError| { - Error::InvalidTrustThreshold { - reason: e.to_string(), + TendermintClientError::InvalidTrustThreshold { + description: e.to_string(), } })?, trusting_period: self.trusting_period, @@ -234,49 +234,54 @@ impl ClientState { impl Protobuf for ClientState {} impl TryFrom for ClientState { - type Error = Error; + type Error = TendermintClientError; fn try_from(raw: RawTmClientState) -> Result { let chain_id = ChainId::from_str(raw.chain_id.as_str())?; let trust_level = { - let trust_level = raw.trust_level.ok_or(Error::MissingTrustingPeriod)?; + let trust_level = raw + .trust_level + .ok_or(TendermintClientError::MissingTrustingPeriod)?; trust_level .try_into() - .map_err(|e| Error::InvalidTrustThreshold { - reason: format!("{e}"), + .map_err(|e| TendermintClientError::InvalidTrustThreshold { + description: format!("{e}"), })? }; let trusting_period = raw .trusting_period - .ok_or(Error::MissingTrustingPeriod)? + .ok_or(TendermintClientError::MissingTrustingPeriod)? .try_into() - .map_err(|_| Error::MissingTrustingPeriod)?; + .map_err(|_| TendermintClientError::MissingTrustingPeriod)?; let unbonding_period = raw .unbonding_period - .ok_or(Error::MissingUnbondingPeriod)? + .ok_or(TendermintClientError::MissingUnbondingPeriod)? .try_into() - .map_err(|_| Error::MissingUnbondingPeriod)?; + .map_err(|_| TendermintClientError::MissingUnbondingPeriod)?; let max_clock_drift = raw .max_clock_drift - .ok_or(Error::NegativeMaxClockDrift)? + .ok_or(TendermintClientError::InvalidMaxClockDrift)? .try_into() - .map_err(|_| Error::NegativeMaxClockDrift)?; + .map_err(|_| TendermintClientError::InvalidMaxClockDrift)?; let latest_height = raw .latest_height - .ok_or(Error::MissingLatestHeight)? + .ok_or(TendermintClientError::MissingLatestHeight)? .try_into() - .map_err(|_| Error::MissingLatestHeight)?; + .map_err(|_| TendermintClientError::MissingLatestHeight)?; // NOTE: In `RawClientState`, a `frozen_height` of `0` means "not // frozen". See: // https://github.com/cosmos/ibc-go/blob/8422d0c4c35ef970539466c5bdec1cd27369bab3/modules/light-clients/07-tendermint/types/client_state.go#L74 - let frozen_height = - Height::try_from(raw.frozen_height.ok_or(Error::MissingFrozenHeight)?).ok(); + let frozen_height = Height::try_from( + raw.frozen_height + .ok_or(TendermintClientError::MissingFrozenHeight)?, + ) + .ok(); // We use set this deprecated field just so that we can properly convert // it back in its raw form @@ -346,9 +351,7 @@ impl TryFrom for ClientState { match raw.type_url.as_str() { TENDERMINT_CLIENT_STATE_TYPE_URL => decode_client_state(&raw.value), - _ => Err(ClientError::UnknownClientStateType { - client_state_type: raw.type_url, - }), + _ => Err(ClientError::InvalidClientStateType(raw.type_url)), } } } @@ -514,7 +517,7 @@ mod tests { for test in tests { let p = test.params.clone(); - let cs_result: Result = ClientState::new( + let cs_result: Result = ClientState::new( p.id, p.trust_level, p.trusting_period, diff --git a/ibc-clients/ics07-tendermint/types/src/consensus_state.rs b/ibc-clients/ics07-tendermint/types/src/consensus_state.rs index bc4e675c8..ec66fb264 100644 --- a/ibc-clients/ics07-tendermint/types/src/consensus_state.rs +++ b/ibc-clients/ics07-tendermint/types/src/consensus_state.rs @@ -11,7 +11,7 @@ use tendermint::time::Time; use tendermint::Hash; use tendermint_proto::google::protobuf as tpb; -use crate::error::Error; +use crate::error::TendermintClientError; use crate::header::Header; pub const TENDERMINT_CONSENSUS_STATE_TYPE_URL: &str = @@ -47,32 +47,33 @@ impl ConsensusState { impl Protobuf for ConsensusState {} impl TryFrom for ConsensusState { - type Error = Error; + type Error = TendermintClientError; fn try_from(raw: RawConsensusState) -> Result { let proto_root = raw .root - .ok_or(Error::InvalidRawClientState { - reason: "missing commitment root".into(), + .ok_or(TendermintClientError::InvalidRawClientState { + description: "missing commitment root".into(), })? .hash; let ibc_proto::google::protobuf::Timestamp { seconds, nanos } = - raw.timestamp.ok_or(Error::InvalidRawClientState { - reason: "missing timestamp".into(), - })?; + raw.timestamp + .ok_or(TendermintClientError::InvalidRawClientState { + description: "missing timestamp".into(), + })?; // FIXME: shunts like this are necessary due to // https://github.com/informalsystems/tendermint-rs/issues/1053 let proto_timestamp = tpb::Timestamp { seconds, nanos }; - let timestamp = proto_timestamp - .try_into() - .map_err(|e| Error::InvalidRawClientState { - reason: format!("invalid timestamp: {e}"), - })?; + let timestamp = proto_timestamp.try_into().map_err(|e| { + TendermintClientError::InvalidRawClientState { + description: format!("invalid timestamp: {e}"), + } + })?; let next_validators_hash = Hash::from_bytes(Algorithm::Sha256, &raw.next_validators_hash) - .map_err(|e| Error::InvalidRawClientState { - reason: e.to_string(), + .map_err(|e| TendermintClientError::InvalidRawClientState { + description: e.to_string(), })?; Ok(Self { @@ -116,9 +117,7 @@ impl TryFrom for ConsensusState { match raw.type_url.as_str() { TENDERMINT_CONSENSUS_STATE_TYPE_URL => decode_consensus_state(&raw.value), - _ => Err(ClientError::UnknownConsensusStateType { - consensus_state_type: raw.type_url, - }), + _ => Err(ClientError::InvalidConsensusStateType(raw.type_url)), } } } diff --git a/ibc-clients/ics07-tendermint/types/src/error.rs b/ibc-clients/ics07-tendermint/types/src/error.rs index 264e398a0..45f00354e 100644 --- a/ibc-clients/ics07-tendermint/types/src/error.rs +++ b/ibc-clients/ics07-tendermint/types/src/error.rs @@ -4,10 +4,8 @@ use core::time::Duration; use displaydoc::Display; use ibc_core_client_types::error::ClientError; -use ibc_core_client_types::Height; use ibc_core_commitment_types::error::CommitmentError; use ibc_core_host_types::error::IdentifierError; -use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_primitives::TimestampError; use tendermint::{Error as TendermintError, Hash}; @@ -15,32 +13,29 @@ use tendermint_light_client_verifier::errors::VerificationErrorDetail as LightCl use tendermint_light_client_verifier::operations::VotingPowerTally; use tendermint_light_client_verifier::Verdict; -/// The main error type +/// The main error type for the Tendermint light client #[derive(Debug, Display)] -pub enum Error { +pub enum TendermintClientError { /// invalid identifier: `{0}` InvalidIdentifier(IdentifierError), - /// invalid header, failed basic validation: `{reason}`, error: `{error}` - InvalidHeader { - reason: String, - error: TendermintError, - }, - /// invalid client state trust threshold: `{reason}` - InvalidTrustThreshold { reason: String }, - /// invalid tendermint client state trust threshold error: `{0}` - InvalidTendermintTrustThreshold(TendermintError), - /// invalid client state max clock drift: `{reason}` - InvalidMaxClockDrift { reason: String }, - /// invalid client state latest height: `{reason}` - InvalidLatestHeight { reason: String }, - /// missing signed header - MissingSignedHeader, - /// invalid header, failed basic validation: `{reason}` - Validation { reason: String }, + /// invalid client state trust threshold: `{description}` + InvalidTrustThreshold { description: String }, + /// invalid clock drift; must be greater than 0 + InvalidMaxClockDrift, /// invalid client proof specs: `{0}` InvalidProofSpec(CommitmentError), - /// invalid raw client state: `{reason}` - InvalidRawClientState { reason: String }, + /// invalid raw client state: `{description}` + InvalidRawClientState { description: String }, + /// invalid raw header error: `{0}` + InvalidRawHeader(TendermintError), + /// invalid raw misbehaviour: `{description}` + InvalidRawMisbehaviour { description: String }, + /// invalid header timestamp: `{0}` + InvalidHeaderTimestamp(TimestampError), + /// invalid header height: `{0}` + InvalidHeaderHeight(u64), + /// missing signed header + MissingSignedHeader, /// missing validator set MissingValidatorSet, /// missing trusted next validator set @@ -51,77 +46,55 @@ pub enum Error { MissingTrustingPeriod, /// missing unbonding period MissingUnbondingPeriod, - /// negative max clock drift - NegativeMaxClockDrift, /// missing the latest height MissingLatestHeight, - /// invalid raw header error: `{0}` - InvalidRawHeader(TendermintError), - /// invalid raw misbehaviour: `{reason}` - InvalidRawMisbehaviour { reason: String }, - /// invalid header timestamp: `{0}` - InvalidHeaderTimestamp(TimestampError), - /// header revision height = `{height}` is invalid - InvalidHeaderHeight { height: u64 }, - /// frozen height is missing + /// missing frozen height MissingFrozenHeight, - /// the header's trusted revision number (`{trusted_revision}`) and the update's revision number (`{header_revision}`) should be the same - MismatchHeightRevisions { - trusted_revision: u64, - header_revision: u64, - }, - /// the given chain-id (`{given}`) does not match the chain-id of the client (`{expected}`) - MismatchHeaderChainId { given: String, expected: String }, - /// not enough trust because insufficient validators overlap: `{reason}` - NotEnoughTrustedValsSigned { reason: VotingPowerTally }, - /// verification failed: `{detail}` - VerificationError { detail: Box }, - /// Processed time or height for the client `{client_id}` at height `{height}` not found - UpdateMetaDataNotFound { client_id: ClientId, height: Height }, - /// The given hash of the validators does not match the given hash in the signed header. Expected: `{signed_header_validators_hash}`, got: `{validators_hash}` - MismatchValidatorsHashes { - validators_hash: Hash, - signed_header_validators_hash: Hash, - }, - /// current timestamp minus the latest consensus state timestamp is greater than or equal to the trusting period (`{duration_since_consensus_state:?}` >= `{trusting_period:?}`) - ConsensusStateTimestampGteTrustingPeriod { + /// mismatched revision heights: expected `{expected}`, actual `{actual}` + MismatchedRevisionHeights { expected: u64, actual: u64 }, + /// mismatched header chain ids: expected `{expected}`, actual `{actual}` + MismatchedHeaderChainIds { expected: String, actual: String }, + /// mismatched validator hashes: expected `{expected}`, actual `{actual}` + MismatchedValidatorHashes { expected: Hash, actual: Hash }, + /// empty client state upgrade-path key + EmptyUpgradePathKey, + /// failed to verify header: `{0}` + FailedToVerifyHeader(Box), + /// insufficient validator overlap: `{0}` + InsufficientValidatorOverlap(VotingPowerTally), + /// insufficient trusting period `{trusting_period:?}`; should be > consensus state timestamp `{duration_since_consensus_state:?}` + InsufficientTrustingPeriod { duration_since_consensus_state: Duration, trusting_period: Duration, }, - /// headers block hashes are equal - MisbehaviourHeadersBlockHashesEqual, - /// headers are not at the same height and are monotonically increasing - MisbehaviourHeadersNotAtSameHeight, } #[cfg(feature = "std")] -impl std::error::Error for Error { +impl std::error::Error for TendermintClientError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { Self::InvalidIdentifier(e) => Some(e), - Self::InvalidHeader { error: e, .. } - | Self::InvalidTendermintTrustThreshold(e) - | Self::InvalidRawHeader(e) => Some(e), + Self::InvalidRawHeader(e) => Some(e), _ => None, } } } -impl From for ClientError { - fn from(e: Error) -> Self { +impl From for ClientError { + fn from(e: TendermintClientError) -> Self { Self::ClientSpecific { description: e.to_string(), } } } -impl From for Error { +impl From for TendermintClientError { fn from(e: IdentifierError) -> Self { Self::InvalidIdentifier(e) } } -impl From for Error { +impl From for TendermintClientError { fn from(e: CommitmentError) -> Self { Self::InvalidProofSpec(e) } @@ -131,14 +104,16 @@ pub trait IntoResult { fn into_result(self) -> Result; } -impl IntoResult<(), Error> for Verdict { - fn into_result(self) -> Result<(), Error> { +impl IntoResult<(), TendermintClientError> for Verdict { + fn into_result(self) -> Result<(), TendermintClientError> { match self { Verdict::Success => Ok(()), - Verdict::NotEnoughTrust(reason) => Err(Error::NotEnoughTrustedValsSigned { reason }), - Verdict::Invalid(detail) => Err(Error::VerificationError { - detail: Box::new(detail), - }), + Verdict::NotEnoughTrust(tally) => { + Err(TendermintClientError::InsufficientValidatorOverlap(tally)) + } + Verdict::Invalid(detail) => Err(TendermintClientError::FailedToVerifyHeader(Box::new( + detail, + ))), } } } diff --git a/ibc-clients/ics07-tendermint/types/src/header.rs b/ibc-clients/ics07-tendermint/types/src/header.rs index 6ee8069f0..72fc83333 100644 --- a/ibc-clients/ics07-tendermint/types/src/header.rs +++ b/ibc-clients/ics07-tendermint/types/src/header.rs @@ -20,7 +20,7 @@ use tendermint::validator::Set as ValidatorSet; use tendermint::{Hash, Time}; use tendermint_light_client_verifier::types::{TrustedBlockState, UntrustedBlockState}; -use crate::error::Error; +use crate::error::TendermintClientError; pub const TENDERMINT_HEADER_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.Header"; @@ -47,12 +47,12 @@ impl Display for Header { } impl Header { - pub fn timestamp(&self) -> Result { + pub fn timestamp(&self) -> Result { self.signed_header .header .time .try_into() - .map_err(Error::InvalidHeaderTimestamp) + .map_err(TendermintClientError::InvalidHeaderTimestamp) } pub fn height(&self) -> Height { @@ -78,7 +78,7 @@ impl Header { chain_id: &'a TmChainId, header_time: Time, next_validators_hash: Hash, - ) -> Result, Error> { + ) -> Result, TendermintClientError> { Ok(TrustedBlockState { chain_id, header_time, @@ -86,18 +86,23 @@ impl Header { .trusted_height .revision_height() .try_into() - .map_err(|_| Error::InvalidHeaderHeight { - height: self.trusted_height.revision_height(), + .map_err(|_| { + TendermintClientError::InvalidHeaderHeight( + self.trusted_height.revision_height(), + ) })?, next_validators: &self.trusted_next_validator_set, next_validators_hash, }) } - pub fn verify_chain_id_version_matches_height(&self, chain_id: &ChainId) -> Result<(), Error> { + pub fn verify_chain_id_version_matches_height( + &self, + chain_id: &ChainId, + ) -> Result<(), TendermintClientError> { if self.height().revision_number() != chain_id.revision_number() { - return Err(Error::MismatchHeaderChainId { - given: self.signed_header.header.chain_id.to_string(), + return Err(TendermintClientError::MismatchedHeaderChainIds { + actual: self.signed_header.header.chain_id.to_string(), expected: chain_id.to_string(), }); } @@ -114,8 +119,8 @@ impl Header { if &self.trusted_next_validator_set.hash_with::() == trusted_next_validator_hash { Ok(()) } else { - Err(ClientError::HeaderVerificationFailure { - reason: + Err(ClientError::FailedHeaderVerification { + description: "header trusted next validator set hash does not match hash stored on chain" .to_string(), }) @@ -123,11 +128,13 @@ impl Header { } /// Checks if the fields of a given header are consistent with the trusted fields of this header. - pub fn validate_basic(&self) -> Result<(), Error> { + pub fn validate_basic( + &self, + ) -> Result<(), TendermintClientError> { if self.height().revision_number() != self.trusted_height.revision_number() { - return Err(Error::MismatchHeightRevisions { - trusted_revision: self.trusted_height.revision_number(), - header_revision: self.height().revision_number(), + return Err(TendermintClientError::MismatchedRevisionHeights { + expected: self.trusted_height.revision_number(), + actual: self.height().revision_number(), }); } @@ -136,17 +143,17 @@ impl Header { // based on) must be smaller than height of the new header that we're // installing. if self.trusted_height >= self.height() { - return Err(Error::InvalidHeaderHeight { - height: self.height().revision_height(), - }); + return Err(TendermintClientError::InvalidHeaderHeight( + self.height().revision_height(), + )); } let validators_hash = self.validator_set.hash_with::(); if validators_hash != self.signed_header.header.validators_hash { - return Err(Error::MismatchValidatorsHashes { - signed_header_validators_hash: self.signed_header.header.validators_hash, - validators_hash, + return Err(TendermintClientError::MismatchedValidatorHashes { + expected: self.signed_header.header.validators_hash, + actual: validators_hash, }); } @@ -157,32 +164,29 @@ impl Header { impl Protobuf for Header {} impl TryFrom for Header { - type Error = Error; + type Error = TendermintClientError; fn try_from(raw: RawHeader) -> Result { let header = Self { signed_header: raw .signed_header - .ok_or(Error::MissingSignedHeader)? + .ok_or(TendermintClientError::MissingSignedHeader)? .try_into() - .map_err(|e| Error::InvalidHeader { - reason: "signed header conversion".to_string(), - error: e, - })?, + .map_err(TendermintClientError::InvalidRawHeader)?, validator_set: raw .validator_set - .ok_or(Error::MissingValidatorSet)? + .ok_or(TendermintClientError::MissingValidatorSet)? .try_into() - .map_err(Error::InvalidRawHeader)?, + .map_err(TendermintClientError::InvalidRawHeader)?, trusted_height: raw .trusted_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(Error::MissingTrustedHeight)?, + .ok_or(TendermintClientError::MissingTrustedHeight)?, trusted_next_validator_set: raw .trusted_validators - .ok_or(Error::MissingTrustedNextValidatorSet)? + .ok_or(TendermintClientError::MissingTrustedNextValidatorSet)? .try_into() - .map_err(Error::InvalidRawHeader)?, + .map_err(TendermintClientError::InvalidRawHeader)?, }; Ok(header) @@ -203,9 +207,7 @@ impl TryFrom for Header { } match raw.type_url.as_str() { TENDERMINT_HEADER_TYPE_URL => decode_header(&raw.value), - _ => Err(ClientError::UnknownHeaderType { - header_type: raw.type_url, - }), + _ => Err(ClientError::InvalidHeaderType(raw.type_url)), } } } diff --git a/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs b/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs index c51f1892f..dc35a34ec 100644 --- a/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs +++ b/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs @@ -9,7 +9,7 @@ use ibc_proto::Protobuf; use tendermint::crypto::Sha256; use tendermint::merkle::MerkleHash; -use crate::error::Error; +use crate::error::TendermintClientError; use crate::header::Header; pub const TENDERMINT_MISBEHAVIOUR_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.Misbehaviour"; @@ -44,20 +44,22 @@ impl Misbehaviour { &self.header2 } - pub fn validate_basic(&self) -> Result<(), Error> { + pub fn validate_basic( + &self, + ) -> Result<(), TendermintClientError> { self.header1.validate_basic::()?; self.header2.validate_basic::()?; if self.header1.signed_header.header.chain_id != self.header2.signed_header.header.chain_id { - return Err(Error::InvalidRawMisbehaviour { - reason: "headers must have identical chain_ids".to_owned(), + return Err(TendermintClientError::InvalidRawMisbehaviour { + description: "headers must have identical chain_ids".to_owned(), }); } if self.header1.height() < self.header2.height() { - return Err(Error::InvalidRawMisbehaviour { - reason: format!( + return Err(TendermintClientError::InvalidRawMisbehaviour { + description: format!( "header1 height is less than header2 height ({} < {})", self.header1.height(), self.header2.height() @@ -72,22 +74,22 @@ impl Misbehaviour { impl Protobuf for Misbehaviour {} impl TryFrom for Misbehaviour { - type Error = Error; + type Error = TendermintClientError; #[allow(deprecated)] fn try_from(raw: RawMisbehaviour) -> Result { let client_id = raw.client_id.parse()?; let header1: Header = raw .header_1 - .ok_or_else(|| Error::InvalidRawMisbehaviour { - reason: "missing header1".into(), + .ok_or_else(|| TendermintClientError::InvalidRawMisbehaviour { + description: "missing header1".into(), })? .try_into()?; let header2: Header = raw .header_2 - .ok_or_else(|| Error::InvalidRawMisbehaviour { - reason: "missing header2".into(), + .ok_or_else(|| TendermintClientError::InvalidRawMisbehaviour { + description: "missing header2".into(), })? .try_into()?; @@ -121,9 +123,7 @@ impl TryFrom for Misbehaviour { } match raw.type_url.as_str() { TENDERMINT_MISBEHAVIOUR_TYPE_URL => decode_misbehaviour(&raw.value), - _ => Err(ClientError::UnknownMisbehaviourType { - misbehaviour_type: raw.type_url, - }), + _ => Err(ClientError::InvalidMisbehaviourType(raw.type_url)), } } } diff --git a/ibc-clients/ics07-tendermint/types/src/trust_threshold.rs b/ibc-clients/ics07-tendermint/types/src/trust_threshold.rs index 830bba74d..401390b5e 100644 --- a/ibc-clients/ics07-tendermint/types/src/trust_threshold.rs +++ b/ibc-clients/ics07-tendermint/types/src/trust_threshold.rs @@ -106,11 +106,9 @@ impl TryFrom for TrustThresholdFraction { type Error = ClientError; fn try_from(t: TrustThreshold) -> Result { - Self::new(t.numerator, t.denominator).map_err(|_| { - ClientError::FailedTrustThresholdConversion { - numerator: t.numerator, - denominator: t.denominator, - } + Self::new(t.numerator, t.denominator).map_err(|_| ClientError::InvalidTrustThreshold { + numerator: t.numerator, + denominator: t.denominator, }) } } diff --git a/ibc-clients/ics08-wasm/types/src/client_state.rs b/ibc-clients/ics08-wasm/types/src/client_state.rs index e9570b320..c8c4aca41 100644 --- a/ibc-clients/ics08-wasm/types/src/client_state.rs +++ b/ibc-clients/ics08-wasm/types/src/client_state.rs @@ -5,7 +5,7 @@ use ibc_primitives::prelude::*; use ibc_primitives::proto::{Any, Protobuf}; use ibc_proto::ibc::lightclients::wasm::v1::ClientState as RawClientState; -use crate::error::Error; +use crate::error::WasmClientError; #[cfg(feature = "serde")] use crate::serializer::Base64; use crate::Bytes; @@ -38,18 +38,14 @@ impl From for RawClientState { } impl TryFrom for ClientState { - type Error = Error; + type Error = WasmClientError; fn try_from(raw: RawClientState) -> Result { let latest_height = raw .latest_height - .ok_or(Error::InvalidLatestHeight { - reason: "missing latest height".to_string(), - })? + .ok_or(WasmClientError::MissingLatestHeight)? .try_into() - .map_err(|_| Error::InvalidLatestHeight { - reason: "invalid protobuf latest height".to_string(), - })?; + .map_err(|_| WasmClientError::InvalidLatestHeight)?; Ok(Self { data: raw.data, checksum: raw.checksum, @@ -70,22 +66,24 @@ impl From for Any { } impl TryFrom for ClientState { - type Error = Error; + type Error = WasmClientError; fn try_from(any: Any) -> Result { - fn decode_client_state(value: &[u8]) -> Result { - let client_state = - Protobuf::::decode(value).map_err(|e| Error::DecodeError { - reason: e.to_string(), - })?; + fn decode_client_state(value: &[u8]) -> Result { + let client_state = Protobuf::::decode(value).map_err(|e| { + WasmClientError::DecodingError { + description: e.to_string(), + } + })?; Ok(client_state) } match any.type_url.as_str() { WASM_CLIENT_STATE_TYPE_URL => decode_client_state(&any.value), - _ => Err(Error::DecodeError { - reason: "type_url does not match".into(), + other_type_url => Err(WasmClientError::MismatchedTypeUrls { + expected: WASM_CLIENT_STATE_TYPE_URL.to_string(), + actual: other_type_url.to_string(), }), } } diff --git a/ibc-clients/ics08-wasm/types/src/error.rs b/ibc-clients/ics08-wasm/types/src/error.rs index eb48a2855..ecb3e1984 100644 --- a/ibc-clients/ics08-wasm/types/src/error.rs +++ b/ibc-clients/ics08-wasm/types/src/error.rs @@ -6,26 +6,30 @@ use ibc_primitives::prelude::*; /// The main error type #[derive(Debug, Display)] -pub enum Error { +pub enum WasmClientError { /// invalid identifier: `{0}` InvalidIdentifier(IdentifierError), - /// decoding error: `{reason}` - DecodeError { reason: String }, - /// invalid client state latest height: `{reason}` - InvalidLatestHeight { reason: String }, + /// invalid client state latest height + InvalidLatestHeight, + /// missing latest height + MissingLatestHeight, + /// mismatched type URLs: expected `{expected}`, actual `{actual}` + MismatchedTypeUrls { expected: String, actual: String }, + /// decoding error: `{description}` + DecodingError { description: String }, } #[cfg(feature = "std")] -impl std::error::Error for Error { +impl std::error::Error for WasmClientError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { - Error::InvalidIdentifier(err) => Some(err), + Self::InvalidIdentifier(err) => Some(err), _ => None, } } } -impl From for Error { +impl From for WasmClientError { fn from(e: IdentifierError) -> Self { Self::InvalidIdentifier(e) } diff --git a/ibc-clients/ics08-wasm/types/src/msgs/migrate_contract.rs b/ibc-clients/ics08-wasm/types/src/msgs/migrate_contract.rs index 40c737457..cd0bd9d3d 100644 --- a/ibc-clients/ics08-wasm/types/src/msgs/migrate_contract.rs +++ b/ibc-clients/ics08-wasm/types/src/msgs/migrate_contract.rs @@ -6,7 +6,7 @@ use ibc_primitives::Signer; use ibc_proto::ibc::lightclients::wasm::v1::MsgMigrateContract as RawMsgMigrateContract; use ibc_proto::Protobuf; -use crate::error::Error; +use crate::error::WasmClientError; use crate::Bytes; pub const MIGRATE_CONTRACT_TYPE_URL: &str = "/ibc.lightclients.wasm.v1.MsgMigrateContract"; @@ -34,7 +34,7 @@ impl From for RawMsgMigrateContract { } impl TryFrom for MsgMigrateContract { - type Error = Error; + type Error = WasmClientError; fn try_from(value: RawMsgMigrateContract) -> Result { Ok(Self { diff --git a/ibc-core/ics02-client/src/handler/create_client.rs b/ibc-core/ics02-client/src/handler/create_client.rs index d6413596f..263f8ffa4 100644 --- a/ibc-core/ics02-client/src/handler/create_client.rs +++ b/ibc-core/ics02-client/src/handler/create_client.rs @@ -4,6 +4,7 @@ use ibc_core_client_context::prelude::*; use ibc_core_client_types::error::ClientError; use ibc_core_client_types::events::CreateClient; use ibc_core_client_types::msgs::MsgCreateClient; +use ibc_core_client_types::Status; use ibc_core_handler_types::error::ContextError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::{ClientStateMut, ClientStateRef, ExecutionContext, ValidationContext}; @@ -35,10 +36,7 @@ where let status = client_state.status(client_val_ctx, &client_id)?; if status.is_frozen() { - return Err(ClientError::ClientFrozen { - description: "the client is frozen".to_string(), - } - .into()); + return Err(ClientError::InvalidStatus(Status::Frozen).into()); }; let host_timestamp = ctx.host_timestamp()?; @@ -46,7 +44,7 @@ where client_state.verify_consensus_state(consensus_state, &host_timestamp)?; if client_val_ctx.client_state(&client_id).is_ok() { - return Err(ClientError::ClientStateAlreadyExists { client_id }.into()); + return Err(ClientError::AlreadyExistingClientState(client_id).into()); }; Ok(()) diff --git a/ibc-core/ics02-client/src/handler/recover_client.rs b/ibc-core/ics02-client/src/handler/recover_client.rs index 1676c6e80..7994edab3 100644 --- a/ibc-core/ics02-client/src/handler/recover_client.rs +++ b/ibc-core/ics02-client/src/handler/recover_client.rs @@ -30,7 +30,7 @@ where let substitute_height = substitute_client_state.latest_height(); if subject_height >= substitute_height { - return Err(ClientError::ClientRecoveryHeightMismatch { + return Err(ClientError::NotAllowedClientRecoveryHeights { subject_height, substitute_height, } diff --git a/ibc-core/ics02-client/src/handler/update_client.rs b/ibc-core/ics02-client/src/handler/update_client.rs index 81e140b8a..66ce95ce1 100644 --- a/ibc-core/ics02-client/src/handler/update_client.rs +++ b/ibc-core/ics02-client/src/handler/update_client.rs @@ -64,8 +64,8 @@ where ctx.emit_ibc_event(event)?; } else { if !matches!(update_kind, UpdateKind::UpdateClient) { - return Err(ClientError::MisbehaviourHandlingFailure { - reason: "misbehaviour submitted, but none found".to_string(), + return Err(ClientError::FailedMisbehaviourHandling { + description: "misbehaviour submitted, but none found".to_string(), } .into()); } diff --git a/ibc-core/ics02-client/src/handler/upgrade_client.rs b/ibc-core/ics02-client/src/handler/upgrade_client.rs index a072988a2..7dce4cdaa 100644 --- a/ibc-core/ics02-client/src/handler/upgrade_client.rs +++ b/ibc-core/ics02-client/src/handler/upgrade_client.rs @@ -38,7 +38,7 @@ where ); let old_consensus_state = client_val_ctx .consensus_state(&old_client_cons_state_path) - .map_err(|_| ClientError::ConsensusStateNotFound { + .map_err(|_| ClientError::MissingConsensusState { client_id, height: old_client_state.latest_height(), })?; diff --git a/ibc-core/ics02-client/types/src/error.rs b/ibc-core/ics02-client/types/src/error.rs index cda8b0f05..9b16557ad 100644 --- a/ibc-core/ics02-client/types/src/error.rs +++ b/ibc-core/ics02-client/types/src/error.rs @@ -5,7 +5,7 @@ use core::convert::Infallible; use displaydoc::Display; use ibc_core_commitment_types::error::CommitmentError; use ibc_core_host_types::error::IdentifierError; -use ibc_core_host_types::identifiers::{ClientId, ClientType}; +use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_primitives::Timestamp; @@ -17,96 +17,75 @@ use crate::height::Height; pub enum ClientError { /// upgrade client error: `{0}` Upgrade(UpgradeClientError), - /// client is frozen with description: `{description}` - ClientFrozen { description: String }, - /// client is not active. Status=`{status}` - ClientNotActive { status: Status }, - /// client is not frozen or expired. Status=`{status}` - ClientNotInactive { status: Status }, - /// client state not found: `{client_id}` - ClientStateNotFound { client_id: ClientId }, - /// client state already exists: `{client_id}` - ClientStateAlreadyExists { client_id: ClientId }, - /// Substitute client height `{substitute_height}` is not greater than subject client height `{subject_height}` during client recovery - ClientRecoveryHeightMismatch { - subject_height: Height, - substitute_height: Height, - }, - /// Subject and substitute client state mismatch during client recovery - ClientRecoveryStateMismatch, - /// consensus state not found at: `{client_id}` at height `{height}` - ConsensusStateNotFound { client_id: ClientId, height: Height }, - /// Processed time or height for the client `{client_id}` at height `{height}` not found - UpdateMetaDataNotFound { client_id: ClientId, height: Height }, - /// header verification failed with reason: `{reason}` - HeaderVerificationFailure { reason: String }, - /// failed to build trust threshold from fraction: `{numerator}`/`{denominator}` + /// invalid client status: `{0}` + InvalidStatus(Status), + /// invalid trust threshold: `{numerator}`/`{denominator}` InvalidTrustThreshold { numerator: u64, denominator: u64 }, - /// failed to build Tendermint domain type trust threshold from fraction: `{numerator}`/`{denominator}` - FailedTrustThresholdConversion { numerator: u64, denominator: u64 }, - /// unknown client state type: `{client_state_type}` - UnknownClientStateType { client_state_type: String }, - /// unknown client consensus state type: `{consensus_state_type}` - UnknownConsensusStateType { consensus_state_type: String }, - /// unknown header type: `{header_type}` - UnknownHeaderType { header_type: String }, - /// unknown misbehaviour type: `{misbehaviour_type}` - UnknownMisbehaviourType { misbehaviour_type: String }, + /// invalid client state type: `{0}` + InvalidClientStateType(String), + /// invalid client consensus state type: `{0}` + InvalidConsensusStateType(String), + /// invalid header type: `{0}` + InvalidHeaderType(String), + /// invalid update client message + InvalidUpdateClientMessage, + /// invalid client identifier: `{0}` + InvalidClientIdentifier(IdentifierError), + /// invalid raw header: `{description}` + InvalidRawHeader { description: String }, + /// invalid misbehaviour type: `{0}` + InvalidMisbehaviourType(String), + /// invalid height; cannot be zero or negative + InvalidHeight, + /// invalid proof height; expected `{actual}` >= `{expected}` + InvalidProofHeight { actual: Height, expected: Height }, + /// invalid consensus state timestamp: `{0}` + InvalidConsensusStateTimestamp(Timestamp), + /// invalid attribute key: `{0}` + InvalidAttributeKey(String), + /// invalid attribute value: `{0}` + InvalidAttributeValue(String), + /// missing client state for client: `{0}` + MissingClientState(ClientId), + /// missing consensus state for client `{client_id}` at height `{height}` + MissingConsensusState { client_id: ClientId, height: Height }, + /// missing update client metadata for client `{client_id}` at height `{height}` + MissingUpdateMetaData { client_id: ClientId, height: Height }, /// missing raw client state MissingRawClientState, /// missing raw client consensus state MissingRawConsensusState, - /// invalid client id in the update client message: `{0}` - InvalidMsgUpdateClientId(IdentifierError), - /// invalid client id in recover client message: `{0}` - InvalidMsgRecoverClientId(IdentifierError), - /// invalid client identifier error: `{0}` - InvalidClientIdentifier(IdentifierError), - /// invalid raw header error: `{reason}` - InvalidRawHeader { reason: String }, /// missing raw client message - MissingClientMessage, - /// invalid raw misbehaviour error: `{0}` - InvalidRawMisbehaviour(IdentifierError), + MissingRawClientMessage, /// missing raw misbehaviour MissingRawMisbehaviour, - /// revision height cannot be zero - InvalidHeight, - /// height cannot end up zero or negative - InvalidHeightResult, - /// the proof height is insufficient: latest_height=`{latest_height}` proof_height=`{proof_height}` - InvalidProofHeight { - latest_height: Height, - proof_height: Height, + /// missing local consensus state at `{0}` + MissingLocalConsensusState(Height), + /// missing attribute key + MissingAttributeKey, + /// missing attribute value + MissingAttributeValue, + /// client state already exists: `{0}` + AlreadyExistingClientState(ClientId), + /// mismatched client recovery states + MismatchedClientRecoveryStates, + /// client recovery heights not allowed: expected substitute client height `{substitute_height}` > subject client height `{subject_height}` + NotAllowedClientRecoveryHeights { + subject_height: Height, + substitute_height: Height, }, - /// invalid commitment proof bytes error: `{0}` - InvalidCommitmentProof(CommitmentError), - /// mismatch between client and arguments types - ClientArgsTypeMismatch { client_type: ClientType }, - /// timestamp is invalid or missing, timestamp=`{time1}`, now=`{time2}` - InvalidConsensusStateTimestamp { time1: Timestamp, time2: Timestamp }, - /// the local consensus state could not be retrieved for height `{height}` - MissingLocalConsensusState { height: Height }, - /// invalid signer error: `{reason}` - InvalidSigner { reason: String }, - /// ics23 verification failure error: `{0}` - Ics23Verification(CommitmentError), - /// misbehaviour handling failed with reason: `{reason}` - MisbehaviourHandlingFailure { reason: String }, + /// failed ICS23 verification: `{0}` + FailedICS23Verification(CommitmentError), + /// failed header verification: `{description}` + FailedHeaderVerification { description: String }, + /// failed misbehaviour handling: `{description}` + FailedMisbehaviourHandling { description: String }, /// client-specific error: `{description}` ClientSpecific { description: String }, - /// client counter overflow error - CounterOverflow, - /// update client message did not contain valid header or misbehaviour - InvalidUpdateClientMessage, + + // TODO(seanchen1991): Incorporate these errors into their own variants /// other error: `{description}` Other { description: String }, - /// invalid attribute key: `{attribute_key}` - InvalidAttributeKey { attribute_key: String }, - /// invalid attribute value: `{attribute_value}` - InvalidAttributeValue { attribute_value: String }, - /// Missing attribute key: `{attribute_key}` - MissingAttributeKey { attribute_key: String }, } impl From<&'static str> for ClientError { @@ -123,14 +102,18 @@ impl From for ClientError { } } +impl From for ClientError { + fn from(e: CommitmentError) -> Self { + Self::FailedICS23Verification(e) + } +} + #[cfg(feature = "std")] impl std::error::Error for ClientError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::InvalidMsgUpdateClientId(e) - | Self::InvalidClientIdentifier(e) - | Self::InvalidRawMisbehaviour(e) => Some(e), - Self::InvalidCommitmentProof(e) | Self::Ics23Verification(e) => Some(e), + Self::InvalidClientIdentifier(e) => Some(e), + Self::FailedICS23Verification(e) => Some(e), _ => None, } } @@ -139,23 +122,35 @@ impl std::error::Error for ClientError { /// Encodes all the possible upgrade client errors #[derive(Debug, Display)] pub enum UpgradeClientError { - /// invalid proof for the upgraded client state error: `{0}` + /// invalid proof for the upgraded client state: `{0}` InvalidUpgradeClientProof(CommitmentError), - /// invalid proof for the upgraded consensus state error: `{0}` + /// invalid proof for the upgraded consensus state: `{0}` InvalidUpgradeConsensusStateProof(CommitmentError), - /// upgraded client height `{upgraded_height}` must be at greater than current client height `{client_height}` - LowUpgradeHeight { + /// invalid upgrade path: `{description}` + InvalidUpgradePath { description: String }, + /// invalid upgrade proposal: `{description}` + InvalidUpgradeProposal { description: String }, + /// invalid upgrade plan: `{description}` + InvalidUpgradePlan { description: String }, + /// mismatched type URLs: expected `{expected}`, actual `{actual}` + MismatchedTypeUrls { expected: String, actual: String }, + /// missing upgraded client state + MissingUpgradedClientState, + /// missing upgraded consensus state + MissingUpgradedConsensusState, + /// failed to decode raw upgrade plan: `{description}` + FailedToDecodeRawUpgradePlan { description: String }, + /// failed to store upgrade plan: `{description}` + FailedToStoreUpgradePlan { description: String }, + /// failed to store upgraded client state: `{description}` + FailedToStoreUpgradedClientState { description: String }, + /// failed to store upgraded consensus state: `{description}` + FailedToStoreUpgradedConsensusState { description: String }, + /// insufficient upgrade client height `{upgraded_height}`; must be greater than current client height `{client_height}` + InsufficientUpgradeHeight { upgraded_height: Height, client_height: Height, }, - /// Invalid upgrade path: `{reason}` - InvalidUpgradePath { reason: String }, - /// invalid upgrade proposal: `{reason}` - InvalidUpgradeProposal { reason: String }, - /// invalid upgrade plan: `{reason}` - InvalidUpgradePlan { reason: String }, - /// other upgrade client error: `{reason}` - Other { reason: String }, } impl From for ClientError { diff --git a/ibc-core/ics02-client/types/src/events.rs b/ibc-core/ics02-client/types/src/events.rs index a91e1b413..56585036a 100644 --- a/ibc-core/ics02-client/types/src/events.rs +++ b/ibc-core/ics02-client/types/src/events.rs @@ -58,29 +58,21 @@ impl TryFrom for ClientIdAttribute { fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != CLIENT_ID_ATTRIBUTE_KEY { - return Err(ClientError::InvalidAttributeKey { - attribute_key: key_str.to_string(), - }); + return Err(ClientError::InvalidAttributeKey(key_str.to_string())); } } else { - return Err(ClientError::InvalidAttributeKey { - attribute_key: String::new(), - }); + return Err(ClientError::MissingAttributeKey); } value .value_str() .map(|value| { - let client_id = - ClientId::from_str(value).map_err(|_| ClientError::InvalidAttributeValue { - attribute_value: value.to_string(), - })?; + let client_id = ClientId::from_str(value) + .map_err(|_| ClientError::InvalidAttributeValue(value.to_string()))?; Ok(ClientIdAttribute { client_id }) }) - .map_err(|_| ClientError::InvalidAttributeValue { - attribute_value: String::new(), - })? + .map_err(|_| ClientError::MissingAttributeValue)? } } @@ -114,30 +106,21 @@ impl TryFrom for ClientTypeAttribute { fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != CLIENT_TYPE_ATTRIBUTE_KEY { - return Err(ClientError::InvalidAttributeKey { - attribute_key: key_str.to_string(), - }); + return Err(ClientError::InvalidAttributeKey(key_str.to_string())); } } else { - return Err(ClientError::InvalidAttributeKey { - attribute_key: String::new(), - }); + return Err(ClientError::MissingAttributeKey); } value .value_str() .map(|value| { - let client_type = ClientType::from_str(value).map_err(|_| { - ClientError::InvalidAttributeValue { - attribute_value: value.to_string(), - } - })?; + let client_type = ClientType::from_str(value) + .map_err(|_| ClientError::InvalidAttributeValue(value.to_string()))?; Ok(ClientTypeAttribute { client_type }) }) - .map_err(|_| ClientError::InvalidAttributeValue { - attribute_value: String::new(), - })? + .map_err(|_| ClientError::MissingAttributeValue)? } } @@ -171,30 +154,23 @@ impl TryFrom for ConsensusHeightAttribute { fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != CONSENSUS_HEIGHT_ATTRIBUTE_KEY { - return Err(ClientError::InvalidAttributeKey { - attribute_key: key_str.to_string(), - }); + return Err(ClientError::InvalidAttributeKey(key_str.to_string())); } } else { - return Err(ClientError::InvalidAttributeKey { - attribute_key: String::new(), - }); + return Err(ClientError::MissingAttributeKey); } value .value_str() .map(|value| { - let consensus_height = - Height::from_str(value).map_err(|_| ClientError::InvalidAttributeValue { - attribute_value: value.to_string(), - })?; + let consensus_height = Height::from_str(value) + .map_err(|_| ClientError::InvalidAttributeValue(value.to_string()))?; Ok(ConsensusHeightAttribute { consensus_height }) }) - .map_err(|_| ClientError::InvalidAttributeKey { - attribute_key: String::new(), - })? + .map_err(|_| ClientError::MissingAttributeValue)? } } + #[cfg_attr( feature = "parity-scale-codec", derive( @@ -230,14 +206,10 @@ impl TryFrom for ConsensusHeightsAttribute { fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != CONSENSUS_HEIGHTS_ATTRIBUTE_KEY { - return Err(ClientError::InvalidAttributeKey { - attribute_key: key_str.to_string(), - }); + return Err(ClientError::InvalidAttributeKey(key_str.to_string())); } } else { - return Err(ClientError::InvalidAttributeKey { - attribute_key: String::new(), - }); + return Err(ClientError::MissingAttributeKey); } value @@ -246,19 +218,14 @@ impl TryFrom for ConsensusHeightsAttribute { let consensus_heights: Vec = value .split(',') .map(|height_str| { - Height::from_str(height_str).map_err(|_| { - ClientError::InvalidAttributeValue { - attribute_value: height_str.to_string(), - } - }) + Height::from_str(height_str) + .map_err(|_| ClientError::InvalidAttributeValue(height_str.to_string())) }) .collect::, ClientError>>()?; Ok(ConsensusHeightsAttribute { consensus_heights }) }) - .map_err(|_| ClientError::InvalidAttributeValue { - attribute_value: String::new(), - })? + .map_err(|_| ClientError::MissingAttributeValue)? } } @@ -298,29 +265,21 @@ impl TryFrom for HeaderAttribute { fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != HEADER_ATTRIBUTE_KEY { - return Err(ClientError::InvalidAttributeKey { - attribute_key: key_str.to_string(), - }); + return Err(ClientError::InvalidAttributeKey(key_str.to_string())); } } else { - return Err(ClientError::InvalidAttributeKey { - attribute_key: String::new(), - }); + return Err(ClientError::MissingAttributeKey); } value .value_str() .map(|value| { - let header = - hex::decode(value).map_err(|_| ClientError::InvalidAttributeValue { - attribute_value: value.to_string(), - })?; + let header = hex::decode(value) + .map_err(|_| ClientError::InvalidAttributeValue(value.to_string()))?; Ok(HeaderAttribute { header }) }) - .map_err(|_| ClientError::InvalidAttributeValue { - attribute_value: String::new(), - })? + .map_err(|_| ClientError::MissingAttributeValue)? } } @@ -405,12 +364,9 @@ impl TryFrom for CreateClient { Option, ), attribute| { - let key = - attribute - .key_str() - .map_err(|_| ClientError::InvalidAttributeKey { - attribute_key: String::new(), - })?; + let key = attribute + .key_str() + .map_err(|_| ClientError::MissingAttributeKey)?; match key { CLIENT_ID_ATTRIBUTE_KEY => Ok(( @@ -436,17 +392,10 @@ impl TryFrom for CreateClient { Option, Option, )| { - let client_id = client_id.ok_or_else(|| ClientError::MissingAttributeKey { - attribute_key: CLIENT_ID_ATTRIBUTE_KEY.to_string(), - })?; - let client_type = - client_type.ok_or_else(|| ClientError::MissingAttributeKey { - attribute_key: CLIENT_TYPE_ATTRIBUTE_KEY.to_string(), - })?; + let client_id = client_id.ok_or(ClientError::MissingAttributeKey)?; + let client_type = client_type.ok_or(ClientError::MissingAttributeKey)?; let consensus_height = - consensus_height.ok_or_else(|| ClientError::MissingAttributeKey { - attribute_key: CONSENSUS_HEIGHT_ATTRIBUTE_KEY.to_string(), - })?; + consensus_height.ok_or(ClientError::MissingAttributeKey)?; Ok(CreateClient::new( client_id.client_id, @@ -566,12 +515,9 @@ impl TryFrom for UpdateClient { .try_fold( (None, None, None, None, None), |acc: UpdateClientAttributes, attribute| { - let key = - attribute - .key_str() - .map_err(|_| ClientError::InvalidAttributeKey { - attribute_key: String::new(), - })?; + let key = attribute + .key_str() + .map_err(|_| ClientError::MissingAttributeKey)?; match key { CLIENT_ID_ATTRIBUTE_KEY => Ok(( @@ -615,31 +561,17 @@ impl TryFrom for UpdateClient { ) .and_then( |(client_id, client_type, consensus_height, consensus_heights, header)| { - let client_id = client_id - .ok_or_else(|| ClientError::MissingAttributeKey { - attribute_key: CLIENT_ID_ATTRIBUTE_KEY.to_string(), - })? - .client_id; + let client_id = client_id.ok_or(ClientError::MissingAttributeKey)?.client_id; let client_type = client_type - .ok_or_else(|| ClientError::MissingAttributeKey { - attribute_key: CLIENT_TYPE_ATTRIBUTE_KEY.to_string(), - })? + .ok_or(ClientError::MissingAttributeKey)? .client_type; let consensus_height = consensus_height - .ok_or_else(|| ClientError::MissingAttributeKey { - attribute_key: CONSENSUS_HEIGHT_ATTRIBUTE_KEY.to_string(), - })? + .ok_or(ClientError::MissingAttributeKey)? .consensus_height; let consensus_heights = consensus_heights - .ok_or_else(|| ClientError::MissingAttributeKey { - attribute_key: CONSENSUS_HEIGHTS_ATTRIBUTE_KEY.to_string(), - })? + .ok_or(ClientError::MissingAttributeKey)? .consensus_heights; - let header = header - .ok_or_else(|| ClientError::MissingAttributeKey { - attribute_key: HEADER_ATTRIBUTE_KEY.to_string(), - })? - .header; + let header = header.ok_or(ClientError::MissingAttributeKey)?.header; Ok(UpdateClient::new( client_id, @@ -808,9 +740,7 @@ mod tests { abci::EventAttribute::from(("consensus_height", "1-10")), ], }, - Err(ClientError::MissingAttributeKey { - attribute_key: CLIENT_ID_ATTRIBUTE_KEY.to_string(), - }), + Err(ClientError::MissingAttributeKey), )] fn test_create_client_try_from( #[case] event: abci::Event, @@ -872,9 +802,7 @@ mod tests { abci::EventAttribute::from(("header", "1234")), ], }, - Err(ClientError::MissingAttributeKey { - attribute_key: CLIENT_ID_ATTRIBUTE_KEY.to_string(), - }), + Err(ClientError::MissingAttributeKey), )] fn test_update_client_try_from( #[case] event: abci::Event, diff --git a/ibc-core/ics02-client/types/src/height.rs b/ibc-core/ics02-client/types/src/height.rs index 96eda4c92..8785a89d8 100644 --- a/ibc-core/ics02-client/types/src/height.rs +++ b/ibc-core/ics02-client/types/src/height.rs @@ -77,7 +77,7 @@ impl Height { pub fn sub(&self, delta: u64) -> Result { if self.revision_height <= delta { - return Err(ClientError::InvalidHeightResult); + return Err(ClientError::InvalidHeight); } Ok(Height { diff --git a/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs b/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs index 0b4031fe5..7d14f133f 100644 --- a/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs +++ b/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs @@ -48,7 +48,7 @@ impl TryFrom for MsgSubmitMisbehaviour { client_id: raw .client_id .parse() - .map_err(ClientError::InvalidRawMisbehaviour)?, + .map_err(ClientError::InvalidClientIdentifier)?, misbehaviour: raw_misbehaviour, signer: raw.signer.into(), }) diff --git a/ibc-core/ics02-client/types/src/msgs/recover_client.rs b/ibc-core/ics02-client/types/src/msgs/recover_client.rs index 5bc6c0594..62fc738fe 100644 --- a/ibc-core/ics02-client/types/src/msgs/recover_client.rs +++ b/ibc-core/ics02-client/types/src/msgs/recover_client.rs @@ -45,11 +45,11 @@ impl TryFrom for MsgRecoverClient { subject_client_id: raw .subject_client_id .parse() - .map_err(ClientError::InvalidMsgRecoverClientId)?, + .map_err(ClientError::InvalidClientIdentifier)?, substitute_client_id: raw .substitute_client_id .parse() - .map_err(ClientError::InvalidMsgRecoverClientId)?, + .map_err(ClientError::InvalidClientIdentifier)?, signer: raw.signer.into(), }) } diff --git a/ibc-core/ics02-client/types/src/msgs/update_client.rs b/ibc-core/ics02-client/types/src/msgs/update_client.rs index df79446ef..9eb088017 100644 --- a/ibc-core/ics02-client/types/src/msgs/update_client.rs +++ b/ibc-core/ics02-client/types/src/msgs/update_client.rs @@ -37,10 +37,10 @@ impl TryFrom for MsgUpdateClient { client_id: raw .client_id .parse() - .map_err(ClientError::InvalidMsgUpdateClientId)?, + .map_err(ClientError::InvalidClientIdentifier)?, client_message: raw .client_message - .ok_or(ClientError::MissingClientMessage)?, + .ok_or(ClientError::MissingRawClientMessage)?, signer: raw.signer.into(), }) } diff --git a/ibc-core/ics02-client/types/src/status.rs b/ibc-core/ics02-client/types/src/status.rs index d77a7bbe6..5fe9b9e0a 100644 --- a/ibc-core/ics02-client/types/src/status.rs +++ b/ibc-core/ics02-client/types/src/status.rs @@ -50,7 +50,7 @@ impl Status { pub fn verify_is_active(&self) -> Result<(), ClientError> { match self { Self::Active => Ok(()), - &status => Err(ClientError::ClientNotActive { status }), + &status => Err(ClientError::InvalidStatus(status)), } } @@ -58,7 +58,7 @@ impl Status { pub fn verify_is_inactive(&self) -> Result<(), ClientError> { match self { Self::Frozen | Self::Expired => Ok(()), - &status => Err(ClientError::ClientNotInactive { status }), + &status => Err(ClientError::InvalidStatus(status)), } } } diff --git a/ibc-core/ics03-connection/src/delay.rs b/ibc-core/ics03-connection/src/delay.rs index 06fb03098..82c162e4f 100644 --- a/ibc-core/ics03-connection/src/delay.rs +++ b/ibc-core/ics03-connection/src/delay.rs @@ -29,10 +29,10 @@ where // Verify that the current host chain time is later than the last client update time let earliest_valid_time = (last_client_update.0 + conn_delay_time_period) - .map_err(ConnectionError::TimestampOverflow)?; + .map_err(ConnectionError::OverflowedTimestamp)?; if current_host_time < earliest_valid_time { return Err(ContextError::ConnectionError( - ConnectionError::NotEnoughTimeElapsed { + ConnectionError::InsufficientTimeElapsed { current_host_time, earliest_valid_time, }, @@ -43,7 +43,7 @@ where let earliest_valid_height = last_client_update.1.add(conn_delay_height_period); if current_host_height < earliest_valid_height { return Err(ContextError::ConnectionError( - ConnectionError::NotEnoughBlocksElapsed { + ConnectionError::InsufficientBlocksElapsed { current_host_height, earliest_valid_height, }, diff --git a/ibc-core/ics03-connection/src/handler/conn_open_ack.rs b/ibc-core/ics03-connection/src/handler/conn_open_ack.rs index 443d32877..a061b3f06 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_ack.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_ack.rs @@ -37,11 +37,10 @@ where { ctx_a.validate_message_signer(&msg.signer)?; - let host_height = ctx_a.host_height().map_err(|_| ConnectionError::Other { - description: "failed to get host height".to_string(), - })?; + let host_height = ctx_a.host_height()?; + if msg.consensus_height_of_a_on_b > host_height { - return Err(ConnectionError::InvalidConsensusHeight { + return Err(ConnectionError::InsufficientConsensusHeight { target_height: msg.consensus_height_of_a_on_b, current_height: host_height, } @@ -104,7 +103,7 @@ where Path::Connection(ConnectionPath::new(&msg.conn_id_on_b)), expected_conn_end_on_b.encode_vec(), ) - .map_err(ConnectionError::VerifyConnectionState)?; + .map_err(ConnectionError::FailedToVerifyConnectionState)?; } client_state_of_b_on_a @@ -115,10 +114,7 @@ where Path::ClientState(ClientStatePath::new(vars.client_id_on_b().clone())), msg.client_state_of_a_on_b.to_vec(), ) - .map_err(|e| ConnectionError::ClientStateVerificationFailure { - client_id: vars.client_id_on_b().clone(), - client_error: e, - })?; + .map_err(ConnectionError::FailedToVerifyClientState)?; let expected_consensus_state_of_a_on_b = ctx_a.host_consensus_state(&msg.consensus_height_of_a_on_b)?; @@ -140,10 +136,7 @@ where Path::ClientConsensusState(client_cons_state_path_on_b), stored_consensus_state_of_a_on_b.to_vec(), ) - .map_err(|e| ConnectionError::ConsensusStateVerificationFailure { - height: msg.proofs_height_on_b, - client_error: e, - })?; + .map_err(ConnectionError::FailedToVerifyConsensusState)?; } Ok(()) diff --git a/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs b/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs index f9ef4eb61..e1751cfc9 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs @@ -81,7 +81,7 @@ where Path::Connection(ConnectionPath::new(conn_id_on_a)), expected_conn_end_on_a.encode_vec(), ) - .map_err(ConnectionError::VerifyConnectionState)?; + .map_err(ConnectionError::FailedToVerifyConnectionState)?; } Ok(()) diff --git a/ibc-core/ics03-connection/src/handler/conn_open_try.rs b/ibc-core/ics03-connection/src/handler/conn_open_try.rs index 4b59913e7..34bb18ae0 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_try.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_try.rs @@ -47,12 +47,11 @@ where ctx_b.validate_self_client(client_state_of_b_on_a)?; - let host_height = ctx_b.host_height().map_err(|_| ConnectionError::Other { - description: "failed to get host height".to_string(), - })?; + let host_height = ctx_b.host_height()?; + if msg.consensus_height_of_b_on_a > host_height { // Fail if the consensus height is too advanced. - return Err(ConnectionError::InvalidConsensusHeight { + return Err(ConnectionError::InsufficientConsensusHeight { target_height: msg.consensus_height_of_b_on_a, current_height: host_height, } @@ -100,7 +99,7 @@ where Path::Connection(ConnectionPath::new(&vars.conn_id_on_a)), expected_conn_end_on_a.encode_vec(), ) - .map_err(ConnectionError::VerifyConnectionState)?; + .map_err(ConnectionError::FailedToVerifyConnectionState)?; } client_state_of_a_on_b @@ -111,10 +110,7 @@ where Path::ClientState(ClientStatePath::new(client_id_on_a.clone())), msg.client_state_of_b_on_a.to_vec(), ) - .map_err(|e| ConnectionError::ClientStateVerificationFailure { - client_id: msg.client_id_on_b.clone(), - client_error: e, - })?; + .map_err(ConnectionError::FailedToVerifyClientState)?; let expected_consensus_state_of_b_on_a = ctx_b.host_consensus_state(&msg.consensus_height_of_b_on_a)?; @@ -136,10 +132,7 @@ where Path::ClientConsensusState(client_cons_state_path_on_a), stored_consensus_state_of_b_on_a.to_vec(), ) - .map_err(|e| ConnectionError::ConsensusStateVerificationFailure { - height: msg.proofs_height_on_a, - client_error: e, - })?; + .map_err(ConnectionError::FailedToVerifyConsensusState)?; } Ok(()) diff --git a/ibc-core/ics03-connection/src/handler/mod.rs b/ibc-core/ics03-connection/src/handler/mod.rs index 241136411..effc57fda 100644 --- a/ibc-core/ics03-connection/src/handler/mod.rs +++ b/ibc-core/ics03-connection/src/handler/mod.rs @@ -30,14 +30,14 @@ where let wasm_client_state = WasmClientState::try_from(value).map_err(|e| { ContextError::ConnectionError(ConnectionError::InvalidClientState { - reason: e.to_string(), + description: e.to_string(), }) })?; let any_client_state = ::decode(wasm_client_state.data.as_slice()) .map_err(|e| { ContextError::ConnectionError(ConnectionError::InvalidClientState { - reason: e.to_string(), + description: e.to_string(), }) })?; diff --git a/ibc-core/ics03-connection/types/src/connection.rs b/ibc-core/ics03-connection/types/src/connection.rs index dbfa87b01..2602c456d 100644 --- a/ibc-core/ics03-connection/types/src/connection.rs +++ b/ibc-core/ics03-connection/types/src/connection.rs @@ -257,7 +257,7 @@ impl ConnectionEnd { // + Init: contains the set of compatible versions, // + TryOpen/Open: contains the single version chosen by the handshake protocol. if state != State::Init && versions.len() != 1 { - return Err(ConnectionError::InvalidVersionLength); + return Err(ConnectionError::InvalidStateForConnectionEndInit); } Ok(Self { @@ -312,7 +312,7 @@ impl ConnectionEnd { /// Checks if the state of this connection end matches with an expected state. pub fn verify_state_matches(&self, expected: &State) -> Result<(), ConnectionError> { if !self.state.eq(expected) { - return Err(ConnectionError::InvalidState { + return Err(ConnectionError::MismatchedConnectionStates { expected: expected.to_string(), actual: self.state.to_string(), }); @@ -488,8 +488,8 @@ impl State { 1 => Ok(Self::Init), 2 => Ok(Self::TryOpen), 3 => Ok(Self::Open), - _ => Err(ConnectionError::InvalidState { - expected: "Must be one of: 0, 1, 2, 3".to_string(), + _ => Err(ConnectionError::MismatchedConnectionStates { + expected: "0, 1, 2, or 3".to_string(), actual: s.to_string(), }), } @@ -528,8 +528,8 @@ impl TryFrom for State { 1 => Ok(Self::Init), 2 => Ok(Self::TryOpen), 3 => Ok(Self::Open), - _ => Err(ConnectionError::InvalidState { - expected: "Must be one of: 0, 1, 2, 3".to_string(), + _ => Err(ConnectionError::MismatchedConnectionStates { + expected: "0, 1, 2, or 3".to_string(), actual: value.to_string(), }), } diff --git a/ibc-core/ics03-connection/types/src/error.rs b/ibc-core/ics03-connection/types/src/error.rs index e71d5426c..6062dfae6 100644 --- a/ibc-core/ics03-connection/types/src/error.rs +++ b/ibc-core/ics03-connection/types/src/error.rs @@ -1,9 +1,10 @@ //! Defines the connection error type use displaydoc::Display; -use ibc_core_client_types::{error as client_error, Height}; +use ibc_core_client_types::error::ClientError; +use ibc_core_client_types::Height; use ibc_core_host_types::error::IdentifierError; -use ibc_core_host_types::identifiers::{ClientId, ConnectionId}; +use ibc_core_host_types::identifiers::ConnectionId; use ibc_primitives::prelude::*; use ibc_primitives::{Timestamp, TimestampError}; @@ -11,96 +12,84 @@ use crate::version::Version; #[derive(Debug, Display)] pub enum ConnectionError { - /// client error: `{0}` - Client(client_error::ClientError), - /// invalid connection state: expected `{expected}`, actual `{actual}` - InvalidState { expected: String, actual: String }, - /// consensus height claimed by the client on the other party is too advanced: `{target_height}` (host chain current height: `{current_height}`) - InvalidConsensusHeight { - target_height: Height, - current_height: Height, - }, - /// identifier error: `{0}` + /// invalid identifier: `{0}` InvalidIdentifier(IdentifierError), - /// ConnectionEnd domain object could not be constructed out of empty proto object + /// invalid state for initializing new ConnectionEnd; expected `Init` connection state and a single version + InvalidStateForConnectionEndInit, + /// invalid connection proof + InvalidProof, + /// invalid counterparty + InvalidCounterparty, + /// invalid client state: `{description}` + InvalidClientState { description: String }, + /// mismatched connection states: expected `{expected}`, actual `{actual}` + MismatchedConnectionStates { expected: String, actual: String }, + /// empty proto connection end; failed to construct ConnectionEnd domain object EmptyProtoConnectionEnd, /// empty supported versions EmptyVersions, - /// single version must be negotiated on connection before opening channel - InvalidVersionLength, - /// version \"`{version}`\" not supported - VersionNotSupported { version: Version }, - /// no common version - NoCommonVersion, /// empty supported features EmptyFeatures, - /// feature \"`{feature}`\" not supported - FeatureNotSupported { feature: String }, - /// no common features - NoCommonFeatures, + /// unsupported version \"`{0}`\" + UnsupportedVersion(Version), + /// unsupported feature \"`{0}`\" + UnsupportedFeature(String), + /// missing common version + MissingCommonVersion, + /// missing common features + MissingCommonFeatures, /// missing proof height MissingProofHeight, /// missing consensus height MissingConsensusHeight, - /// invalid connection proof error - InvalidProof, - /// verifying connection state error: `{0}` - VerifyConnectionState(client_error::ClientError), - /// invalid signer error: `{reason}` - InvalidSigner { reason: String }, - /// no connection was found for the previous connection id provided `{connection_id}` - ConnectionNotFound { connection_id: ConnectionId }, - /// invalid counterparty - InvalidCounterparty, + /// missing connection `{0}` + MissingConnection(ConnectionId), + /// missing connection counter + MissingConnectionCounter, /// missing counterparty MissingCounterparty, /// missing client state MissingClientState, - /// the consensus proof verification failed (height: `{height}`), client error: `{client_error}` - ConsensusStateVerificationFailure { - height: Height, - client_error: client_error::ClientError, - }, - /// the client state proof verification failed for client id `{client_id}`, client error: `{client_error}` - ClientStateVerificationFailure { - // TODO: use more specific error source - client_id: ClientId, - client_error: client_error::ClientError, + /// insufficient consensus height `{current_height}` for host chain; needs to meet counterparty's height `{target_height}` + InsufficientConsensusHeight { + target_height: Height, + current_height: Height, }, - /// invalid client state: `{reason}` - InvalidClientState { reason: String }, - /// not enough blocks elapsed, current height `{current_host_height}` is still less than the earliest acceptable height `{earliest_valid_height}` - NotEnoughBlocksElapsed { + /// insufficient blocks elapsed: current height `{current_host_height}` needs to meet `{earliest_valid_height}` + InsufficientBlocksElapsed { current_host_height: Height, earliest_valid_height: Height, }, - /// not enough time elapsed, current timestamp `{current_host_time}` is still less than the earliest acceptable timestamp `{earliest_valid_time}` - NotEnoughTimeElapsed { + /// insufficient time elapsed: current timestamp `{current_host_time}` needs to meet `{earliest_valid_time}` + InsufficientTimeElapsed { current_host_time: Timestamp, earliest_valid_time: Timestamp, }, - /// timestamp overflowed error: `{0}` - TimestampOverflow(TimestampError), - /// connection counter overflow error - CounterOverflow, - /// other error: `{description}` - Other { description: String }, + /// failed to verify connection state: `{0}` + FailedToVerifyConnectionState(ClientError), + /// failed to verify consensus state: `{0}` + FailedToVerifyConsensusState(ClientError), + /// failed to verify client state: `{0}` + FailedToVerifyClientState(ClientError), + /// failed to store connection IDs + FailedToStoreConnectionIds, + /// failed to store connection end + FailedToStoreConnectionEnd, + /// failed to update connection counter + FailedToUpdateConnectionCounter, + /// overflowed timestamp: `{0}` + OverflowedTimestamp(TimestampError), } #[cfg(feature = "std")] impl std::error::Error for ConnectionError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::Client(e) - | Self::VerifyConnectionState(e) - | Self::ConsensusStateVerificationFailure { - client_error: e, .. - } - | Self::ClientStateVerificationFailure { - client_error: e, .. - } => Some(e), - Self::InvalidIdentifier(e) => Some(e), - Self::TimestampOverflow(e) => Some(e), + Self::FailedToVerifyConnectionState(e) + | Self::FailedToVerifyConsensusState(e) + | Self::FailedToVerifyClientState(e) => Some(e), + // Self::InvalidIdentifier(e) => Some(e), + // Self::OverflowedTimestamp(e) => Some(e), _ => None, } } diff --git a/ibc-core/ics03-connection/types/src/version.rs b/ibc-core/ics03-connection/types/src/version.rs index a4446d113..aa6f5316a 100644 --- a/ibc-core/ics03-connection/types/src/version.rs +++ b/ibc-core/ics03-connection/types/src/version.rs @@ -54,7 +54,7 @@ impl Version { /// Checks whether the given feature is supported in this version pub fn verify_feature_supported(&self, feature: String) -> Result<(), ConnectionError> { if !self.features.contains(&feature) { - return Err(ConnectionError::FeatureNotSupported { feature }); + return Err(ConnectionError::UnsupportedFeature(feature)); } Ok(()) } @@ -134,7 +134,7 @@ pub fn pick_version( } if intersection.is_empty() { - return Err(ConnectionError::NoCommonVersion); + return Err(ConnectionError::MissingCommonVersion); } intersection.sort_by(|a, b| a.identifier.cmp(&b.identifier)); @@ -150,9 +150,7 @@ fn find_supported_version( supported_versions .iter() .find(|sv| sv.identifier == version.identifier) - .ok_or(ConnectionError::VersionNotSupported { - version: version.clone(), - }) + .ok_or(ConnectionError::UnsupportedVersion(version.clone())) .cloned() } @@ -171,7 +169,7 @@ fn get_feature_set_intersection( .collect(); if feature_set_intersection.is_empty() { - return Err(ConnectionError::NoCommonFeatures); + return Err(ConnectionError::MissingCommonFeatures); } Ok(feature_set_intersection) @@ -368,7 +366,7 @@ mod tests { name: "Disjoint versions".to_string(), supported: disjoint().0, counterparty: disjoint().1, - picked: Err(ConnectionError::NoCommonVersion), + picked: Err(ConnectionError::MissingCommonVersion), want_pass: false, }, ]; diff --git a/ibc-core/ics04-channel/Cargo.toml b/ibc-core/ics04-channel/Cargo.toml index 1ad973cc1..f9dd35235 100644 --- a/ibc-core/ics04-channel/Cargo.toml +++ b/ibc-core/ics04-channel/Cargo.toml @@ -20,6 +20,7 @@ all-features = true [dependencies] ibc-core-client = { workspace = true } ibc-core-connection = { workspace = true } +ibc-core-connection-types = { workspace = true } ibc-core-channel-types = { workspace = true } ibc-core-commitment-types = { workspace = true } ibc-core-host = { workspace = true } diff --git a/ibc-core/ics04-channel/src/handler/acknowledgement.rs b/ibc-core/ics04-channel/src/handler/acknowledgement.rs index c58edc74a..68bc43128 100644 --- a/ibc-core/ics04-channel/src/handler/acknowledgement.rs +++ b/ibc-core/ics04-channel/src/handler/acknowledgement.rs @@ -139,15 +139,17 @@ where return Ok(()); }; - if commitment_on_a - != compute_packet_commitment( - &packet.data, - &packet.timeout_height_on_b, - &packet.timeout_timestamp_on_b, - ) - { - return Err(PacketError::IncorrectPacketCommitment { + let expected_commitment_on_a = compute_packet_commitment( + &packet.data, + &packet.timeout_height_on_b, + &packet.timeout_timestamp_on_b, + ); + + if commitment_on_a != expected_commitment_on_a { + return Err(PacketError::MismatchedPacketCommitments { sequence: packet.seq_on_a, + actual: commitment_on_a, + expected: expected_commitment_on_a, } .into()); } @@ -156,9 +158,9 @@ where let seq_ack_path_on_a = SeqAckPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); let next_seq_ack = ctx_a.get_next_sequence_ack(&seq_ack_path_on_a)?; if packet.seq_on_a != next_seq_ack { - return Err(PacketError::InvalidPacketSequence { - given_sequence: packet.seq_on_a, - next_sequence: next_seq_ack, + return Err(PacketError::MismatchedPacketSequences { + actual: packet.seq_on_a, + expected: next_seq_ack, } .into()); } @@ -199,11 +201,7 @@ where Path::Ack(ack_path_on_b), ack_commitment.into_vec(), ) - .map_err(|e| ChannelError::PacketVerificationFailed { - sequence: packet.seq_on_a, - client_error: e, - }) - .map_err(PacketError::Channel)?; + .map_err(ChannelError::FailedProofVerification)?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs index 5385d18c3..4f2dc0293 100644 --- a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs @@ -6,6 +6,7 @@ use ibc_core_channel_types::events::CloseConfirm; use ibc_core_channel_types::msgs::MsgChannelCloseConfirm; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; +use ibc_core_connection_types::error::ConnectionError; use ibc_core_handler_types::error::ContextError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; @@ -57,15 +58,9 @@ where let core_event = { let port_id_on_a = chan_end_on_b.counterparty().port_id.clone(); - let chan_id_on_a = chan_end_on_b - .counterparty() - .channel_id - .clone() - .ok_or(ContextError::ChannelError(ChannelError::Other { - description: - "internal error: ChannelEnd doesn't have a counterparty channel id in CloseInit" - .to_string(), - }))?; + let chan_id_on_a = chan_end_on_b.counterparty().channel_id.clone().ok_or( + ContextError::ChannelError(ChannelError::MissingCounterparty), + )?; let conn_id_on_b = chan_end_on_b.connection_hops[0].clone(); IbcEvent::CloseConfirmChannel(CloseConfirm::new( @@ -134,11 +129,10 @@ where .counterparty() .channel_id() .ok_or(ChannelError::MissingCounterparty)?; - let conn_id_on_a = conn_end_on_b.counterparty().connection_id().ok_or( - ChannelError::UndefinedConnectionCounterparty { - connection_id: chan_end_on_b.connection_hops()[0].clone(), - }, - )?; + let conn_id_on_a = conn_end_on_b + .counterparty() + .connection_id() + .ok_or(ConnectionError::MissingCounterparty)?; let expected_chan_end_on_a = ChannelEnd::new( ChannelState::Closed, @@ -159,7 +153,7 @@ where Path::ChannelEnd(chan_end_path_on_a), expected_chan_end_on_a.encode_vec(), ) - .map_err(ChannelError::VerifyChannelFailed)?; + .map_err(ChannelError::FailedProofVerification)?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_close_init.rs b/ibc-core/ics04-channel/src/handler/chan_close_init.rs index 15c38c9f5..6bdab73f6 100644 --- a/ibc-core/ics04-channel/src/handler/chan_close_init.rs +++ b/ibc-core/ics04-channel/src/handler/chan_close_init.rs @@ -56,15 +56,9 @@ where let core_event = { let port_id_on_b = chan_end_on_a.counterparty().port_id.clone(); - let chan_id_on_b = chan_end_on_a - .counterparty() - .channel_id - .clone() - .ok_or(ContextError::ChannelError(ChannelError::Other { - description: - "internal error: ChannelEnd doesn't have a counterparty channel id in CloseInit" - .to_string(), - }))?; + let chan_id_on_b = chan_end_on_a.counterparty().channel_id.clone().ok_or( + ContextError::ChannelError(ChannelError::MissingCounterparty), + )?; let conn_id_on_a = chan_end_on_a.connection_hops[0].clone(); IbcEvent::CloseInitChannel(CloseInit::new( diff --git a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs index 7e5b6b240..9369733a0 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs @@ -5,6 +5,7 @@ use ibc_core_channel_types::events::OpenAck; use ibc_core_channel_types::msgs::MsgChannelOpenAck; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; +use ibc_core_connection_types::error::ConnectionError; use ibc_core_handler_types::error::ContextError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; @@ -125,11 +126,10 @@ where client_val_ctx_a.consensus_state(&client_cons_state_path_on_a)?; let prefix_on_b = conn_end_on_a.counterparty().prefix(); let port_id_on_b = &chan_end_on_a.counterparty().port_id; - let conn_id_on_b = conn_end_on_a.counterparty().connection_id().ok_or( - ChannelError::UndefinedConnectionCounterparty { - connection_id: chan_end_on_a.connection_hops()[0].clone(), - }, - )?; + let conn_id_on_b = conn_end_on_a + .counterparty() + .connection_id() + .ok_or(ConnectionError::MissingCounterparty)?; let expected_chan_end_on_b = ChannelEnd::new( ChannelState::TryOpen, @@ -152,7 +152,7 @@ where Path::ChannelEnd(chan_end_path_on_b), expected_chan_end_on_b.encode_vec(), ) - .map_err(ChannelError::VerifyChannelFailed)?; + .map_err(ChannelError::FailedProofVerification)?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs index dfbc777c1..9d375a295 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs @@ -6,6 +6,7 @@ use ibc_core_channel_types::events::OpenConfirm; use ibc_core_channel_types::msgs::MsgChannelOpenConfirm; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; +use ibc_core_connection_types::error::ConnectionError; use ibc_core_handler_types::error::ContextError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; @@ -58,15 +59,14 @@ where let conn_id_on_b = chan_end_on_b.connection_hops[0].clone(); let port_id_on_a = chan_end_on_b.counterparty().port_id.clone(); - let chan_id_on_a = chan_end_on_b - .counterparty() - .channel_id - .clone() - .ok_or(ContextError::ChannelError(ChannelError::Other { - description: - "internal error: ChannelEnd doesn't have a counterparty channel id in OpenConfirm" - .to_string(), - }))?; + let chan_id_on_a = + chan_end_on_b + .counterparty() + .channel_id + .clone() + .ok_or(ContextError::ChannelError( + ChannelError::MissingCounterparty, + ))?; let core_event = IbcEvent::OpenConfirmChannel(OpenConfirm::new( msg.port_id_on_b.clone(), @@ -134,11 +134,10 @@ where .counterparty() .channel_id() .ok_or(ChannelError::MissingCounterparty)?; - let conn_id_on_a = conn_end_on_b.counterparty().connection_id().ok_or( - ChannelError::UndefinedConnectionCounterparty { - connection_id: chan_end_on_b.connection_hops()[0].clone(), - }, - )?; + let conn_id_on_a = conn_end_on_b + .counterparty() + .connection_id() + .ok_or(ConnectionError::MissingCounterparty)?; let expected_chan_end_on_a = ChannelEnd::new( ChannelState::Open, @@ -159,7 +158,7 @@ where Path::ChannelEnd(chan_end_path_on_a), expected_chan_end_on_a.encode_vec(), ) - .map_err(ChannelError::VerifyChannelFailed)?; + .map_err(ChannelError::FailedProofVerification)?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_open_try.rs b/ibc-core/ics04-channel/src/handler/chan_open_try.rs index 08c82deac..48138ce69 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_try.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_try.rs @@ -6,6 +6,7 @@ use ibc_core_channel_types::events::OpenTry; use ibc_core_channel_types::msgs::MsgChannelOpenTry; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; +use ibc_core_connection_types::error::ConnectionError; use ibc_core_handler_types::error::ContextError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::ChannelId; @@ -153,11 +154,10 @@ where let prefix_on_a = conn_end_on_b.counterparty().prefix(); let port_id_on_a = msg.port_id_on_a.clone(); let chan_id_on_a = msg.chan_id_on_a.clone(); - let conn_id_on_a = conn_end_on_b.counterparty().connection_id().ok_or( - ChannelError::UndefinedConnectionCounterparty { - connection_id: msg.connection_hops_on_b[0].clone(), - }, - )?; + let conn_id_on_a = conn_end_on_b + .counterparty() + .connection_id() + .ok_or(ConnectionError::MissingCounterparty)?; let expected_chan_end_on_a = ChannelEnd::new( ChannelState::Init, @@ -178,7 +178,7 @@ where Path::ChannelEnd(chan_end_path_on_a), expected_chan_end_on_a.encode_vec(), ) - .map_err(ChannelError::VerifyChannelFailed)?; + .map_err(ChannelError::FailedProofVerification)?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/recv_packet.rs b/ibc-core/ics04-channel/src/handler/recv_packet.rs index aa22d3ec9..f3229f493 100644 --- a/ibc-core/ics04-channel/src/handler/recv_packet.rs +++ b/ibc-core/ics04-channel/src/handler/recv_packet.rs @@ -162,7 +162,7 @@ where let latest_height = ctx_b.host_height()?; if msg.packet.timeout_height_on_b.has_expired(latest_height) { - return Err(PacketError::LowPacketHeight { + return Err(PacketError::InsufficientPacketHeight { chain_height: latest_height, timeout_height: msg.packet.timeout_height_on_b, } @@ -175,7 +175,7 @@ where .timeout_timestamp_on_b .has_expired(&latest_timestamp) { - return Err(PacketError::LowPacketTimestamp.into()); + return Err(PacketError::InsufficientPacketTimestamp.into()); } // Verify proofs @@ -221,11 +221,7 @@ where Path::Commitment(commitment_path_on_a), expected_commitment_on_a.into_vec(), ) - .map_err(|e| ChannelError::PacketVerificationFailed { - sequence: msg.packet.seq_on_a, - client_error: e, - }) - .map_err(PacketError::Channel)?; + .map_err(ChannelError::FailedProofVerification)?; } match chan_end_on_b.ordering { @@ -234,9 +230,9 @@ where SeqRecvPath::new(&msg.packet.port_id_on_b, &msg.packet.chan_id_on_b); let next_seq_recv = ctx_b.get_next_sequence_recv(&seq_recv_path_on_b)?; if msg.packet.seq_on_a > next_seq_recv { - return Err(PacketError::InvalidPacketSequence { - given_sequence: msg.packet.seq_on_a, - next_sequence: next_seq_recv, + return Err(PacketError::MismatchedPacketSequences { + actual: msg.packet.seq_on_a, + expected: next_seq_recv, } .into()); } @@ -256,7 +252,7 @@ where let packet_rec = ctx_b.get_packet_receipt(&receipt_path_on_b); match packet_rec { Ok(_receipt) => {} - Err(ContextError::PacketError(PacketError::PacketReceiptNotFound { sequence })) + Err(ContextError::PacketError(PacketError::MissingPacketReceipt(sequence))) if sequence == msg.packet.seq_on_a => {} Err(e) => return Err(e), } @@ -282,10 +278,7 @@ where let packet = msg.packet.clone(); let ack_path_on_b = AckPath::new(&packet.port_id_on_b, &packet.chan_id_on_b, packet.seq_on_a); if ctx_b.get_packet_acknowledgement(&ack_path_on_b).is_ok() { - return Err(PacketError::AcknowledgementExists { - sequence: msg.packet.seq_on_a, - } - .into()); + return Err(PacketError::DuplicateAcknowledgment(msg.packet.seq_on_a).into()); } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/send_packet.rs b/ibc-core/ics04-channel/src/handler/send_packet.rs index 514ffb89d..6680bf6fb 100644 --- a/ibc-core/ics04-channel/src/handler/send_packet.rs +++ b/ibc-core/ics04-channel/src/handler/send_packet.rs @@ -64,7 +64,7 @@ pub fn send_packet_validate( let latest_height_on_a = client_state_of_b_on_a.latest_height(); if packet.timeout_height_on_b.has_expired(latest_height_on_a) { - return Err(PacketError::LowPacketHeight { + return Err(PacketError::InsufficientPacketHeight { chain_height: latest_height_on_a, timeout_height: packet.timeout_height_on_b, } @@ -81,16 +81,16 @@ pub fn send_packet_validate( let latest_timestamp = consensus_state_of_b_on_a.timestamp(); let packet_timestamp = packet.timeout_timestamp_on_b; if packet_timestamp.has_expired(&latest_timestamp) { - return Err(PacketError::LowPacketTimestamp.into()); + return Err(PacketError::InsufficientPacketTimestamp.into()); } let seq_send_path_on_a = SeqSendPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); let next_seq_send_on_a = ctx_a.get_next_sequence_send(&seq_send_path_on_a)?; if packet.seq_on_a != next_seq_send_on_a { - return Err(PacketError::InvalidPacketSequence { - given_sequence: packet.seq_on_a, - next_sequence: next_seq_send_on_a, + return Err(PacketError::MismatchedPacketSequences { + actual: packet.seq_on_a, + expected: next_seq_send_on_a, } .into()); } diff --git a/ibc-core/ics04-channel/src/handler/timeout.rs b/ibc-core/ics04-channel/src/handler/timeout.rs index ef478ed4e..9ce98bc0a 100644 --- a/ibc-core/ics04-channel/src/handler/timeout.rs +++ b/ibc-core/ics04-channel/src/handler/timeout.rs @@ -168,9 +168,12 @@ where &msg.packet.timeout_height_on_b, &msg.packet.timeout_timestamp_on_b, ); + if commitment_on_a != expected_commitment_on_a { - return Err(PacketError::IncorrectPacketCommitment { + return Err(PacketError::MismatchedPacketCommitments { sequence: msg.packet.seq_on_a, + expected: expected_commitment_on_a, + actual: commitment_on_a, } .into()); } @@ -212,9 +215,9 @@ where let next_seq_recv_verification_result = match chan_end_on_a.ordering { Order::Ordered => { if msg.packet.seq_on_a < msg.next_seq_recv_on_b { - return Err(PacketError::InvalidPacketSequence { - given_sequence: msg.packet.seq_on_a, - next_sequence: msg.next_seq_recv_on_b, + return Err(PacketError::MismatchedPacketSequences { + actual: msg.packet.seq_on_a, + expected: msg.next_seq_recv_on_b, } .into()); } @@ -251,12 +254,10 @@ where } }; - next_seq_recv_verification_result - .map_err(|e| ChannelError::PacketVerificationFailed { - sequence: msg.next_seq_recv_on_b, - client_error: e, - }) - .map_err(PacketError::Channel)?; + next_seq_recv_verification_result.map_err(|e| ChannelError::FailedPacketVerification { + sequence: msg.next_seq_recv_on_b, + client_error: e, + })?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/timeout_on_close.rs b/ibc-core/ics04-channel/src/handler/timeout_on_close.rs index 8366a5d26..c52225f81 100644 --- a/ibc-core/ics04-channel/src/handler/timeout_on_close.rs +++ b/ibc-core/ics04-channel/src/handler/timeout_on_close.rs @@ -4,6 +4,7 @@ use ibc_core_channel_types::error::{ChannelError, PacketError}; use ibc_core_channel_types::msgs::MsgTimeoutOnClose; use ibc_core_client::context::prelude::*; use ibc_core_connection::delay::verify_conn_delay_passed; +use ibc_core_connection::types::error::ConnectionError; use ibc_core_handler_types::error::ContextError; use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, ReceiptPath, SeqRecvPath, @@ -50,8 +51,10 @@ where &packet.timeout_timestamp_on_b, ); if commitment_on_a != expected_commitment_on_a { - return Err(PacketError::IncorrectPacketCommitment { + return Err(PacketError::MismatchedPacketCommitments { sequence: packet.seq_on_a, + expected: expected_commitment_on_a, + actual: commitment_on_a, } .into()); } @@ -84,11 +87,10 @@ where .counterparty() .channel_id() .ok_or(PacketError::Channel(ChannelError::MissingCounterparty))?; - let conn_id_on_b = conn_end_on_a.counterparty().connection_id().ok_or( - PacketError::UndefinedConnectionCounterparty { - connection_id: chan_end_on_a.connection_hops()[0].clone(), - }, - )?; + let conn_id_on_b = conn_end_on_a + .counterparty() + .connection_id() + .ok_or(ConnectionError::MissingCounterparty)?; let expected_conn_hops_on_b = vec![conn_id_on_b.clone()]; let expected_counterparty = Counterparty::new( packet.port_id_on_a.clone(), @@ -114,17 +116,16 @@ where Path::ChannelEnd(chan_end_path_on_b), expected_chan_end_on_b.encode_vec(), ) - .map_err(ChannelError::VerifyChannelFailed) - .map_err(PacketError::Channel)?; + .map_err(ChannelError::FailedProofVerification)?; verify_conn_delay_passed(ctx_a, msg.proof_height_on_b, &conn_end_on_a)?; let next_seq_recv_verification_result = match chan_end_on_a.ordering { Order::Ordered => { if packet.seq_on_a < msg.next_seq_recv_on_b { - return Err(PacketError::InvalidPacketSequence { - given_sequence: packet.seq_on_a, - next_sequence: msg.next_seq_recv_on_b, + return Err(PacketError::MismatchedPacketSequences { + actual: packet.seq_on_a, + expected: msg.next_seq_recv_on_b, } .into()); } @@ -161,12 +162,10 @@ where } }; - next_seq_recv_verification_result - .map_err(|e| ChannelError::PacketVerificationFailed { - sequence: msg.next_seq_recv_on_b, - client_error: e, - }) - .map_err(PacketError::Channel)?; + next_seq_recv_verification_result.map_err(|e| ChannelError::FailedPacketVerification { + sequence: msg.next_seq_recv_on_b, + client_error: e, + })?; }; Ok(()) diff --git a/ibc-core/ics04-channel/types/src/acknowledgement.rs b/ibc-core/ics04-channel/types/src/acknowledgement.rs index 7364857d1..0e983b0ce 100644 --- a/ibc-core/ics04-channel/types/src/acknowledgement.rs +++ b/ibc-core/ics04-channel/types/src/acknowledgement.rs @@ -45,7 +45,7 @@ impl TryFrom> for Acknowledgement { fn try_from(bytes: Vec) -> Result { if bytes.is_empty() { - Err(PacketError::InvalidAcknowledgement) + Err(PacketError::EmptyAcknowledgment) } else { Ok(Self(bytes)) } @@ -81,7 +81,7 @@ impl StatusValue { let value = value.to_string(); if value.is_empty() { - return Err(PacketError::EmptyAcknowledgementStatus); + return Err(PacketError::EmptyAcknowledgmentStatus); } Ok(Self(value)) diff --git a/ibc-core/ics04-channel/types/src/error.rs b/ibc-core/ics04-channel/types/src/error.rs index 7042411d3..56cdadcd5 100644 --- a/ibc-core/ics04-channel/types/src/error.rs +++ b/ibc-core/ics04-channel/types/src/error.rs @@ -3,173 +3,132 @@ use displaydoc::Display; use ibc_core_client_types::error::ClientError; use ibc_core_client_types::Height; -use ibc_core_connection_types::error as connection_error; use ibc_core_host_types::error::IdentifierError; -use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId, Sequence}; +use ibc_core_host_types::identifiers::{ChannelId, PortId, Sequence}; use ibc_primitives::prelude::*; use ibc_primitives::{Timestamp, TimestampError}; use super::channel::Counterparty; use super::timeout::TimeoutHeight; -use crate::channel::State; +use crate::commitment::PacketCommitment; use crate::timeout::TimeoutTimestamp; use crate::Version; #[derive(Debug, Display)] pub enum ChannelError { - /// invalid channel end: `{channel_end}` - InvalidChannelEnd { channel_end: String }, + /// application module error: `{description}` + AppModule { description: String }, + /// identifier error: `{0}` + InvalidIdentifier(IdentifierError), /// invalid channel id: expected `{expected}`, actual `{actual}` InvalidChannelId { expected: String, actual: String }, /// invalid channel state: expected `{expected}`, actual `{actual}` InvalidState { expected: String, actual: String }, /// invalid channel order type: expected `{expected}`, actual `{actual}` InvalidOrderType { expected: String, actual: String }, - /// invalid connection hops length: expected `{expected}`; actual `{actual}` + /// invalid connection hops length: expected `{expected}`, actual `{actual}` InvalidConnectionHopsLength { expected: u64, actual: u64 }, - /// invalid signer error: `{reason}` - InvalidSigner { reason: String }, - /// invalid proof: missing height - MissingHeight, - /// packet data bytes must be valid UTF-8 (this restriction will be lifted in the future) - NonUtf8PacketData, + /// invalid counterparty: expected `{expected}`, actual `{actual}` + InvalidCounterparty { + expected: Counterparty, + actual: Counterparty, + }, + /// missing proof + MissingProof, + /// missing proof height + MissingProofHeight, /// missing counterparty MissingCounterparty, + /// missing channel end in raw message + MissingRawChannelEnd, + /// missing channel counter + MissingCounter, /// unsupported channel upgrade sequence UnsupportedChannelUpgradeSequence, - /// version not supported: expected `{expected}`, actual `{actual}` - VersionNotSupported { expected: Version, actual: Version }, - /// missing channel end - MissingChannel, - /// the channel end (`{port_id}`, `{channel_id}`) does not exist - ChannelNotFound { + /// unsupported version: expected `{expected}`, actual `{actual}` + UnsupportedVersion { expected: Version, actual: Version }, + /// non-existent channel end: (`{port_id}`, `{channel_id}`) + NonexistentChannel { port_id: PortId, channel_id: ChannelId, }, - /// Verification fails for the packet with the sequence number `{sequence}`, error: `{client_error}` - PacketVerificationFailed { + /// packet data bytes must be valid UTF-8 + NonUtf8PacketData, + /// failed packet verification for packet with sequence `{sequence}`: `{client_error}` + FailedPacketVerification { sequence: Sequence, client_error: ClientError, }, - /// Error verifying channel state error: `{0}` - VerifyChannelFailed(ClientError), - /// String `{value}` cannot be converted to packet sequence, error: `{error}` - InvalidStringAsSequence { - value: String, - error: core::num::ParseIntError, - }, - /// invalid channel counterparty: expected `{expected}`, actual `{actual}` - InvalidCounterparty { - expected: Counterparty, - actual: Counterparty, - }, - /// application module error: `{description}` - AppModule { description: String }, - /// Undefined counterparty connection for `{connection_id}` - UndefinedConnectionCounterparty { connection_id: ConnectionId }, - /// invalid proof: empty proof - InvalidProof, - /// identifier error: `{0}` - InvalidIdentifier(IdentifierError), - /// channel counter overflow error - CounterOverflow, - /// other error: `{description}` - Other { description: String }, + /// failed proof verification: `{0}` + FailedProofVerification(ClientError), + + // TODO(seanchen1991): These two variants should be encoded by host-relevant error types + // once those have been defined. + /// failed to update counter: `{description}` + FailedToUpdateCounter { description: String }, + /// failed to store channel: `{description}` + FailedToStoreChannel { description: String }, } #[derive(Debug, Display)] pub enum PacketError { - /// connection error: `{0}` - Connection(connection_error::ConnectionError), + /// application module error: `{description}` + AppModule { description: String }, /// channel error: `{0}` Channel(ChannelError), - /// Receiving chain block height `{chain_height}` >= packet timeout height `{timeout_height}` - LowPacketHeight { + /// insufficient packet timeout height: should have `{timeout_height}` > `{chain_height}` + InsufficientPacketHeight { chain_height: Height, timeout_height: TimeoutHeight, }, - /// Receiving chain block timestamp >= packet timeout timestamp - LowPacketTimestamp, - /// Invalid packet sequence `{given_sequence}` ≠ next send sequence `{next_sequence}` - InvalidPacketSequence { - given_sequence: Sequence, - next_sequence: Sequence, + /// insufficient packet timestamp: should be greater than chain block timestamp + InsufficientPacketTimestamp, + /// mismatched packet sequences: expected `{expected}`, actual `{actual}` + MismatchedPacketSequences { + expected: Sequence, + actual: Sequence, }, - /// Channel `{channel_id}` should not be state `{state}` - InvalidChannelState { channel_id: ChannelId, state: State }, - /// the associated connection `{connection_id}` is not OPEN - ConnectionNotOpen { connection_id: ConnectionId }, - /// Receipt for the packet `{sequence}` not found - PacketReceiptNotFound { sequence: Sequence }, - /// The stored commitment of the packet `{sequence}` is incorrect - IncorrectPacketCommitment { sequence: Sequence }, - /// implementation-specific error - ImplementationSpecific, - /// Undefined counterparty connection for `{connection_id}` - UndefinedConnectionCounterparty { connection_id: ConnectionId }, - /// invalid proof: empty proof - InvalidProof, - /// Packet timeout height `{timeout_height}` > chain height `{chain_height} and timeout timestamp `{timeout_timestamp}` > chain timestamp `{chain_timestamp}` + /// mismatched commitments for packet `{sequence}`: expected `{expected:?}`, actual `{actual:?}` + MismatchedPacketCommitments { + sequence: Sequence, + expected: PacketCommitment, + actual: PacketCommitment, + }, + /// missing packet receipt for packet `{0}` + MissingPacketReceipt(Sequence), + /// missing proof + MissingProof, + /// missing acknowledgment for packet `{0}` + MissingPacketAcknowledgment(Sequence), + /// missing proof height + MissingProofHeight, + /// missing timeout + MissingTimeout, + /// invalid timeout height: `{0}` + InvalidTimeoutHeight(ClientError), + /// invalid timeout timestamp: `{0}` + InvalidTimeoutTimestamp(TimestampError), + /// invalid identifier: `{0}` + InvalidIdentifier(IdentifierError), + /// empty acknowledgment not allowed + EmptyAcknowledgment, + /// empty acknowledgment status not allowed + EmptyAcknowledgmentStatus, + /// packet data bytes cannot be empty + EmptyPacketData, + /// packet acknowledgment for sequence `{0}` already exists + DuplicateAcknowledgment(Sequence), + /// packet sequence cannot be 0 + ZeroPacketSequence, + /// packet timeout height `{timeout_height}` > chain height `{chain_height} and timeout timestamp `{timeout_timestamp}` > chain timestamp `{chain_timestamp}` PacketTimeoutNotReached { timeout_height: TimeoutHeight, chain_height: Height, timeout_timestamp: TimeoutTimestamp, chain_timestamp: Timestamp, }, - /// Packet acknowledgement exists for the packet with the sequence `{sequence}` - AcknowledgementExists { sequence: Sequence }, - /// Acknowledgment cannot be empty - InvalidAcknowledgement, - /// Acknowledgment status cannot be empty - EmptyAcknowledgementStatus, - /// Acknowledgment for the packet `{sequence}` not found - PacketAcknowledgementNotFound { sequence: Sequence }, - /// invalid proof: missing height - MissingHeight, - /// there is no packet in this message - MissingPacket, - /// invalid signer error: `{reason}` - InvalidSigner { reason: String }, - /// application module error: `{description}` - AppModule { description: String }, - /// route not found - RouteNotFound, - /// packet sequence cannot be 0 - ZeroPacketSequence, - /// packet data bytes cannot be empty - ZeroPacketData, - /// invalid timeout height with error: `{0}` - InvalidTimeoutHeight(ClientError), - /// Invalid timeout timestamp with error: `{0}` - InvalidTimeoutTimestamp(TimestampError), - /// missing timeout - MissingTimeout, - /// invalid identifier error: `{0}` - InvalidIdentifier(IdentifierError), - /// Missing sequence number for sending packets on port `{port_id}` and channel `{channel_id}` - MissingNextSendSeq { - port_id: PortId, - channel_id: ChannelId, - }, - /// the channel end (`{port_id}`, `{channel_id}`) does not exist - ChannelNotFound { - port_id: PortId, - channel_id: ChannelId, - }, - /// Commitment for the packet `{sequence}` not found - PacketCommitmentNotFound { sequence: Sequence }, - /// Missing sequence number for receiving packets on port `{port_id}` and channel `{channel_id}` - MissingNextRecvSeq { - port_id: PortId, - channel_id: ChannelId, - }, - /// Missing sequence number for ack packets on port `{port_id}` and channel `{channel_id}` - MissingNextAckSeq { - port_id: PortId, - channel_id: ChannelId, - }, - /// other error: `{description}` - Other { description: String }, + /// implementation-specific error + ImplementationSpecific, } impl From for ChannelError { @@ -194,7 +153,6 @@ impl From for PacketError { impl std::error::Error for PacketError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::Connection(e) => Some(e), Self::Channel(e) => Some(e), Self::InvalidIdentifier(e) => Some(e), _ => None, @@ -207,10 +165,9 @@ impl std::error::Error for ChannelError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { Self::InvalidIdentifier(e) => Some(e), - Self::PacketVerificationFailed { + Self::FailedPacketVerification { client_error: e, .. } => Some(e), - Self::InvalidStringAsSequence { error: e, .. } => Some(e), _ => None, } } diff --git a/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs b/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs index a93f7a622..2446395d7 100644 --- a/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs +++ b/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs @@ -39,17 +39,17 @@ impl TryFrom for MsgAcknowledgement { Ok(MsgAcknowledgement { packet: raw_msg .packet - .ok_or(PacketError::MissingPacket)? + .ok_or(PacketError::EmptyPacketData)? .try_into()?, acknowledgement: raw_msg.acknowledgement.try_into()?, proof_acked_on_b: raw_msg .proof_acked .try_into() - .map_err(|_| PacketError::InvalidProof)?, + .map_err(|_| PacketError::MissingProof)?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(PacketError::MissingHeight)?, + .ok_or(PacketError::MissingProofHeight)?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs b/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs index c533fc59c..5074f552a 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs @@ -45,11 +45,11 @@ impl TryFrom for MsgChannelCloseConfirm { proof_chan_end_on_a: raw_msg .proof_init .try_into() - .map_err(|_| ChannelError::InvalidProof)?, + .map_err(|_| ChannelError::MissingProof)?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ChannelError::MissingHeight)?, + .ok_or(ChannelError::MissingProofHeight)?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs index 432ca92fe..8634eb3e8 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs @@ -44,11 +44,11 @@ impl TryFrom for MsgChannelOpenAck { proof_chan_end_on_b: raw_msg .proof_try .try_into() - .map_err(|_| ChannelError::InvalidProof)?, + .map_err(|_| ChannelError::MissingProof)?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ChannelError::MissingHeight)?, + .ok_or(ChannelError::MissingProofHeight)?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs index 6070eb1a2..9b6de510a 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs @@ -41,11 +41,11 @@ impl TryFrom for MsgChannelOpenConfirm { proof_chan_end_on_a: raw_msg .proof_ack .try_into() - .map_err(|_| ChannelError::InvalidProof)?, + .map_err(|_| ChannelError::MissingProof)?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ChannelError::MissingHeight)?, + .ok_or(ChannelError::MissingProofHeight)?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs index 7ab3f1598..afac87752 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs @@ -47,7 +47,7 @@ impl TryFrom for MsgChannelOpenInit { fn try_from(raw_msg: RawMsgChannelOpenInit) -> Result { let chan_end_on_a: ChannelEnd = raw_msg .channel - .ok_or(ChannelError::MissingChannel)? + .ok_or(ChannelError::MissingRawChannelEnd)? .try_into()?; chan_end_on_a.verify_state_matches(&State::Init)?; chan_end_on_a.counterparty().verify_empty_channel_id()?; diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs index c6cbd918b..8d85d1fa3 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs @@ -55,7 +55,7 @@ impl TryFrom for MsgChannelOpenTry { fn try_from(raw_msg: RawMsgChannelOpenTry) -> Result { let chan_end_on_b: ChannelEnd = raw_msg .channel - .ok_or(ChannelError::MissingChannel)? + .ok_or(ChannelError::MissingRawChannelEnd)? .try_into()?; chan_end_on_b.verify_state_matches(&State::TryOpen)?; @@ -82,11 +82,11 @@ impl TryFrom for MsgChannelOpenTry { proof_chan_end_on_a: raw_msg .proof_init .try_into() - .map_err(|_| ChannelError::InvalidProof)?, + .map_err(|_| ChannelError::MissingProof)?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ChannelError::MissingHeight)?, + .ok_or(ChannelError::MissingProofHeight)?, signer: raw_msg.signer.into(), version_proposal: chan_end_on_b.version, }; diff --git a/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs b/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs index 5295e1807..53e4a6716 100644 --- a/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs +++ b/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs @@ -39,16 +39,16 @@ impl TryFrom for MsgRecvPacket { Ok(MsgRecvPacket { packet: raw_msg .packet - .ok_or(PacketError::MissingPacket)? + .ok_or(PacketError::EmptyPacketData)? .try_into()?, proof_commitment_on_a: raw_msg .proof_commitment .try_into() - .map_err(|_| PacketError::InvalidProof)?, + .map_err(|_| PacketError::MissingProof)?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(PacketError::MissingHeight)?, + .ok_or(PacketError::MissingProofHeight)?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/timeout.rs b/ibc-core/ics04-channel/types/src/msgs/timeout.rs index 362630ff0..657e8233e 100644 --- a/ibc-core/ics04-channel/types/src/msgs/timeout.rs +++ b/ibc-core/ics04-channel/types/src/msgs/timeout.rs @@ -41,17 +41,17 @@ impl TryFrom for MsgTimeout { Ok(MsgTimeout { packet: raw_msg .packet - .ok_or(PacketError::MissingPacket)? + .ok_or(PacketError::EmptyPacketData)? .try_into()?, next_seq_recv_on_b: Sequence::from(raw_msg.next_sequence_recv), proof_unreceived_on_b: raw_msg .proof_unreceived .try_into() - .map_err(|_| PacketError::InvalidProof)?, + .map_err(|_| PacketError::MissingProof)?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(PacketError::MissingHeight)?, + .ok_or(PacketError::MissingProofHeight)?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs b/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs index 7673d5f33..670205716 100644 --- a/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs +++ b/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs @@ -48,21 +48,21 @@ impl TryFrom for MsgTimeoutOnClose { Ok(MsgTimeoutOnClose { packet: raw_msg .packet - .ok_or(PacketError::MissingPacket)? + .ok_or(PacketError::EmptyPacketData)? .try_into()?, next_seq_recv_on_b: Sequence::from(raw_msg.next_sequence_recv), proof_unreceived_on_b: raw_msg .proof_unreceived .try_into() - .map_err(|_| PacketError::InvalidProof)?, + .map_err(|_| PacketError::MissingProof)?, proof_close_on_b: raw_msg .proof_close .try_into() - .map_err(|_| PacketError::InvalidProof)?, + .map_err(|_| PacketError::MissingProof)?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(PacketError::MissingHeight)?, + .ok_or(PacketError::MissingProofHeight)?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/packet.rs b/ibc-core/ics04-channel/types/src/packet.rs index d07746b77..dfd6f0358 100644 --- a/ibc-core/ics04-channel/types/src/packet.rs +++ b/ibc-core/ics04-channel/types/src/packet.rs @@ -172,7 +172,7 @@ impl TryFrom for Packet { } if raw_pkt.data.is_empty() { - return Err(PacketError::ZeroPacketData); + return Err(PacketError::EmptyPacketData); } // Note: ibc-go currently (July 2022) incorrectly treats the timeout @@ -282,7 +282,7 @@ impl TryFrom for PacketState { } if raw_pkt.data.is_empty() { - return Err(PacketError::ZeroPacketData); + return Err(PacketError::EmptyPacketData); } Ok(PacketState { diff --git a/ibc-core/ics04-channel/types/src/version.rs b/ibc-core/ics04-channel/types/src/version.rs index 2cfc1e46c..1cf5c894a 100644 --- a/ibc-core/ics04-channel/types/src/version.rs +++ b/ibc-core/ics04-channel/types/src/version.rs @@ -51,7 +51,7 @@ impl Version { pub fn verify_is_expected(&self, expected: Version) -> Result<(), ChannelError> { if self != &expected { - return Err(ChannelError::VersionNotSupported { + return Err(ChannelError::UnsupportedVersion { expected, actual: self.clone(), }); diff --git a/ibc-core/ics23-commitment/types/src/commitment.rs b/ibc-core/ics23-commitment/types/src/commitment.rs index 2555f89ac..43506a798 100644 --- a/ibc-core/ics23-commitment/types/src/commitment.rs +++ b/ibc-core/ics23-commitment/types/src/commitment.rs @@ -122,7 +122,7 @@ impl<'a> TryFrom<&'a CommitmentProofBytes> for MerkleProof { fn try_from(value: &'a CommitmentProofBytes) -> Result { Protobuf::::decode(value.as_ref()) - .map_err(|e| CommitmentError::DecodingFailure(e.to_string())) + .map_err(|e| CommitmentError::FailedDecoding(e.to_string())) } } diff --git a/ibc-core/ics23-commitment/types/src/error.rs b/ibc-core/ics23-commitment/types/src/error.rs index fdbdd24c7..81ee26e06 100644 --- a/ibc-core/ics23-commitment/types/src/error.rs +++ b/ibc-core/ics23-commitment/types/src/error.rs @@ -7,6 +7,8 @@ use ibc_primitives::prelude::*; pub enum CommitmentError { /// empty commitment prefix EmptyCommitmentPrefix, + /// empty commitment root + EmptyCommitmentRoot, /// empty merkle proof EmptyMerkleProof, /// empty merkle root @@ -15,28 +17,24 @@ pub enum CommitmentError { EmptyVerifiedValue, /// empty proof specs EmptyProofSpecs, - /// invalid depth range: [{0}, {1}] - InvalidDepthRange(i32, i32), - /// mismatch between the number of proofs with that of specs - NumberOfSpecsMismatch, - /// mismatch between the number of proofs with that of keys - NumberOfKeysMismatch, + /// mismatched number of proofs: expected `{expected}`, actual `{actual}` + MismatchedNumberOfProofs { expected: usize, actual: usize }, + /// mismatched proofs: expected `{expected}`, actual `{actual}` + MismatchedProofs { expected: String, actual: String }, + /// invalid range: [`{min}`, `{max}`] + InvalidRange { min: i32, max: i32 }, /// invalid merkle proof InvalidMerkleProof, - /// proof verification failed - VerificationFailure, - /// encoded commitment prefix is not a valid hex string: `{0}` - EncodingFailure(String), - /// decoding commitment proof bytes failed: `{0}` - DecodingFailure(String), - /// invalid prefix length range: `[{0}, {1}]` - InvalidPrefixLengthRange(i32, i32), /// invalid child size: `{0}` InvalidChildSize(i32), /// invalid hash operation: `{0}` InvalidHashOp(i32), /// invalid length operation: `{0}` InvalidLengthOp(i32), + /// failed decoding commitment proof: `{0}` + FailedDecoding(String), + /// failed to verify membership + FailedToVerifyMembership, } #[cfg(feature = "std")] diff --git a/ibc-core/ics23-commitment/types/src/merkle.rs b/ibc-core/ics23-commitment/types/src/merkle.rs index d597ef1c8..69aad45e5 100644 --- a/ibc-core/ics23-commitment/types/src/merkle.rs +++ b/ibc-core/ics23-commitment/types/src/merkle.rs @@ -106,10 +106,16 @@ impl MerkleProof { let num = self.proofs.len(); let ics23_specs = Vec::::from(specs.clone()); if ics23_specs.len() != num { - return Err(CommitmentError::NumberOfSpecsMismatch); + return Err(CommitmentError::MismatchedNumberOfProofs { + expected: ics23_specs.len(), + actual: num, + }); } if keys.key_path.len() != num { - return Err(CommitmentError::NumberOfKeysMismatch); + return Err(CommitmentError::MismatchedNumberOfProofs { + expected: keys.key_path.len(), + actual: num, + }); } if value.is_empty() { return Err(CommitmentError::EmptyVerifiedValue); @@ -135,7 +141,7 @@ impl MerkleProof { .map_err(|_| CommitmentError::InvalidMerkleProof)?; if !verify_membership::(proof, spec, &subroot, key.as_ref(), &value) { - return Err(CommitmentError::VerificationFailure); + return Err(CommitmentError::FailedToVerifyMembership); } value.clone_from(&subroot); } @@ -144,7 +150,7 @@ impl MerkleProof { } if root.hash != subroot { - return Err(CommitmentError::VerificationFailure); + return Err(CommitmentError::FailedToVerifyMembership); } Ok(()) @@ -166,10 +172,16 @@ impl MerkleProof { let num = self.proofs.len(); let ics23_specs = Vec::::from(specs.clone()); if ics23_specs.len() != num { - return Err(CommitmentError::NumberOfSpecsMismatch); + return Err(CommitmentError::MismatchedNumberOfProofs { + actual: num, + expected: ics23_specs.len(), + }); } if keys.key_path.len() != num { - return Err(CommitmentError::NumberOfKeysMismatch); + return Err(CommitmentError::MismatchedNumberOfProofs { + actual: num, + expected: keys.key_path.len(), + }); } // verify the absence of key in lowest subtree @@ -190,7 +202,7 @@ impl MerkleProof { let subroot = calculate_non_existence_root::(non_existence_proof)?; if !verify_non_membership::(proof, spec, &subroot, key.as_ref()) { - return Err(CommitmentError::VerificationFailure); + return Err(CommitmentError::FailedToVerifyMembership); } // verify membership proofs starting from index 1 with value = subroot diff --git a/ibc-core/ics23-commitment/types/src/specs.rs b/ibc-core/ics23-commitment/types/src/specs.rs index 46bf79a95..a37abf6cc 100644 --- a/ibc-core/ics23-commitment/types/src/specs.rs +++ b/ibc-core/ics23-commitment/types/src/specs.rs @@ -43,10 +43,10 @@ impl ProofSpecs { && 0 < proof_spec.0.max_depth && proof_spec.0.max_depth < proof_spec.0.min_depth) { - return Err(CommitmentError::InvalidDepthRange( - proof_spec.0.min_depth, - proof_spec.0.max_depth, - )); + return Err(CommitmentError::InvalidRange { + min: proof_spec.0.min_depth, + max: proof_spec.0.max_depth, + }); } } Ok(()) @@ -90,10 +90,10 @@ impl TryFrom for ProofSpec { || spec.min_depth < 0 || (0 < spec.min_depth && 0 < spec.max_depth && spec.max_depth < spec.min_depth) { - return Err(CommitmentError::InvalidDepthRange( - spec.min_depth, - spec.max_depth, - )); + return Err(CommitmentError::InvalidRange { + min: spec.min_depth, + max: spec.max_depth, + }); } let leaf_spec = spec @@ -166,10 +166,10 @@ impl TryFrom for InnerSpec { || inner_spec.max_prefix_length < 0 || inner_spec.max_prefix_length < inner_spec.min_prefix_length { - return Err(CommitmentError::InvalidPrefixLengthRange( - inner_spec.min_prefix_length, - inner_spec.max_prefix_length, - )); + return Err(CommitmentError::InvalidRange { + min: inner_spec.min_prefix_length, + max: inner_spec.max_prefix_length, + }); } Ok(Self(RawInnerSpec { @@ -200,15 +200,15 @@ mod tests { #[case(0, 0)] #[case(2, 2)] #[case(5, 6)] - #[should_panic(expected = "InvalidDepthRange")] + #[should_panic(expected = "InvalidRange")] #[case(-3,3)] - #[should_panic(expected = "InvalidDepthRange")] + #[should_panic(expected = "InvalidRange")] #[case(2,-6)] - #[should_panic(expected = "InvalidDepthRange")] + #[should_panic(expected = "InvalidRange")] #[case(-2,-6)] - #[should_panic(expected = "InvalidDepthRange")] + #[should_panic(expected = "InvalidRange")] #[case(-6,-2)] - #[should_panic(expected = "InvalidDepthRange")] + #[should_panic(expected = "InvalidRange")] #[case(5, 3)] fn test_proof_specs_try_from(#[case] min_depth: i32, #[case] max_depth: i32) { let raw_proof_spec = RawProofSpec { @@ -225,15 +225,15 @@ mod tests { #[case(0, 0)] #[case(1, 2)] #[case(2, 2)] - #[should_panic(expected = "InvalidPrefixLengthRange")] + #[should_panic(expected = "InvalidRange")] #[case(2, 1)] - #[should_panic(expected = "InvalidPrefixLengthRange")] + #[should_panic(expected = "InvalidRange")] #[case(-2,1)] - #[should_panic(expected = "InvalidPrefixLengthRange")] + #[should_panic(expected = "InvalidRange")] #[case(2,-1)] - #[should_panic(expected = "InvalidPrefixLengthRange")] + #[should_panic(expected = "InvalidRange")] #[case(-2,-1)] - #[should_panic(expected = "InvalidPrefixLengthRange")] + #[should_panic(expected = "InvalidRange")] #[case(-1,-2)] fn test_inner_specs_try_from(#[case] min_prefix_length: i32, #[case] max_prefix_length: i32) { let raw_inner_spec = RawInnerSpec { diff --git a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/handler.rs b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/handler.rs index 3f27bad12..419a1e46c 100644 --- a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/handler.rs +++ b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/handler.rs @@ -29,7 +29,7 @@ where let mut client_state = TmClientState::try_from(proposal.upgraded_client_state).map_err(|e| { UpgradeClientError::InvalidUpgradeProposal { - reason: e.to_string(), + description: e.to_string(), } })?; diff --git a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs index d1a25adcc..f66487cc7 100644 --- a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs +++ b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs @@ -33,21 +33,21 @@ impl TryFrom for Plan { fn try_from(raw: RawPlan) -> Result { if raw.name.is_empty() { return Err(UpgradeClientError::InvalidUpgradePlan { - reason: "name field cannot be empty".to_string(), + description: "name field cannot be empty".to_string(), }); } #[allow(deprecated)] if raw.time.is_some() { return Err(UpgradeClientError::InvalidUpgradePlan { - reason: "time field must be empty".to_string(), + description: "time field must be empty".to_string(), }); } #[allow(deprecated)] if raw.upgraded_client_state.is_some() { return Err(UpgradeClientError::InvalidUpgradePlan { - reason: "upgraded_client_state field must be empty".to_string(), + description: "upgraded_client_state field must be empty".to_string(), }); } @@ -55,7 +55,7 @@ impl TryFrom for Plan { name: raw.name, height: u64::try_from(raw.height).map_err(|_| { UpgradeClientError::InvalidUpgradePlan { - reason: "height plan overflow".to_string(), + description: "height plan overflow".to_string(), } })?, info: raw.info, @@ -83,17 +83,15 @@ impl TryFrom for Plan { fn try_from(any: Any) -> Result { if any.type_url != TYPE_URL { - return Err(UpgradeClientError::InvalidUpgradePlan { - reason: format!( - "type_url do not match: expected {}, got {}", - TYPE_URL, any.type_url - ), + return Err(UpgradeClientError::MismatchedTypeUrls { + expected: TYPE_URL.to_string(), + actual: any.type_url, }); } let plan = Protobuf::::decode_vec(&any.value).map_err(|e| { - UpgradeClientError::InvalidUpgradePlan { - reason: format!("raw plan decode error: {}", e), + UpgradeClientError::FailedToDecodeRawUpgradePlan { + description: e.to_string(), } })?; diff --git a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs index a12f4fab4..4a72af753 100644 --- a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs +++ b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs @@ -33,13 +33,13 @@ impl TryFrom for UpgradeProposal { fn try_from(raw: RawUpgradeProposal) -> Result { if raw.title.is_empty() { return Err(UpgradeClientError::InvalidUpgradeProposal { - reason: "title field cannot be empty".to_string(), + description: "title field cannot be empty".to_string(), }); } if raw.description.is_empty() { return Err(UpgradeClientError::InvalidUpgradeProposal { - reason: "description field cannot be empty".to_string(), + description: "description field cannot be empty".to_string(), }); } @@ -47,13 +47,13 @@ impl TryFrom for UpgradeProposal { plan.try_into()? } else { return Err(UpgradeClientError::InvalidUpgradeProposal { - reason: "plan field cannot be empty".to_string(), + description: "plan field cannot be empty".to_string(), }); }; let upgraded_client_state = raw.upgraded_client_state.ok_or_else(|| { UpgradeClientError::InvalidUpgradeProposal { - reason: "upgraded client state cannot be empty".to_string(), + description: "upgraded client state cannot be empty".to_string(), } })?; diff --git a/ibc-core/ics24-host/cosmos/src/validate_self_client.rs b/ibc-core/ics24-host/cosmos/src/validate_self_client.rs index 7064fdcd8..d2f2d2eba 100644 --- a/ibc-core/ics24-host/cosmos/src/validate_self_client.rs +++ b/ibc-core/ics24-host/cosmos/src/validate_self_client.rs @@ -2,7 +2,7 @@ use core::time::Duration; use ibc_client_tendermint::types::ClientState as TmClientState; use ibc_core_client_types::error::ClientError; -use ibc_core_client_types::Height; +use ibc_core_client_types::{Height, Status}; use ibc_core_commitment_types::specs::ProofSpecs; use ibc_core_connection_types::error::ConnectionError; use ibc_core_handler_types::error::ContextError; @@ -25,17 +25,14 @@ pub trait ValidateSelfClientContext { .map_err(ClientError::from)?; if client_state_of_host_on_counterparty.is_frozen() { - return Err(ClientError::ClientFrozen { - description: String::new(), - } - .into()); + return Err(ClientError::InvalidStatus(Status::Frozen).into()); } let self_chain_id = self.chain_id(); if self_chain_id != &client_state_of_host_on_counterparty.chain_id { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { - reason: format!( + description: format!( "invalid chain-id. expected: {}, got: {}", self_chain_id, client_state_of_host_on_counterparty.chain_id ), @@ -48,7 +45,7 @@ pub trait ValidateSelfClientContext { if self_revision_number != latest_height.revision_number() { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { - reason: format!( + description: format!( "client is not in the same revision as the chain. expected: {}, got: {}", self_revision_number, latest_height.revision_number() @@ -60,7 +57,7 @@ pub trait ValidateSelfClientContext { if latest_height >= self.host_current_height() { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { - reason: format!( + description: format!( "client has latest height {} greater than or equal to chain height {}", latest_height, self.host_current_height() @@ -72,7 +69,7 @@ pub trait ValidateSelfClientContext { if self.proof_specs() != &client_state_of_host_on_counterparty.proof_specs { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { - reason: format!( + description: format!( "client has invalid proof specs. expected: {:?}, got: {:?}", self.proof_specs(), client_state_of_host_on_counterparty.proof_specs @@ -89,14 +86,14 @@ pub trait ValidateSelfClientContext { trust_level.denominator(), ) .map_err(|_| ConnectionError::InvalidClientState { - reason: "invalid trust level".to_string(), + description: "invalid trust level".to_string(), })? }; if self.unbonding_period() != client_state_of_host_on_counterparty.unbonding_period { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { - reason: format!( + description: format!( "invalid unbonding period. expected: {:?}, got: {:?}", self.unbonding_period(), client_state_of_host_on_counterparty.unbonding_period, @@ -108,7 +105,7 @@ pub trait ValidateSelfClientContext { if client_state_of_host_on_counterparty.unbonding_period < client_state_of_host_on_counterparty.trusting_period { - return Err(ContextError::ConnectionError(ConnectionError::InvalidClientState{ reason: format!( + return Err(ContextError::ConnectionError(ConnectionError::InvalidClientState{ description: format!( "unbonding period must be greater than trusting period. unbonding period ({:?}) < trusting period ({:?})", client_state_of_host_on_counterparty.unbonding_period, client_state_of_host_on_counterparty.trusting_period @@ -120,7 +117,7 @@ pub trait ValidateSelfClientContext { { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { - reason: format!( + description: format!( "invalid upgrade path. expected: {:?}, got: {:?}", self.upgrade_path(), client_state_of_host_on_counterparty.upgrade_path diff --git a/ibc-core/ics24-host/types/src/error.rs b/ibc-core/ics24-host/types/src/error.rs index 4df4c4dd9..72d8535c2 100644 --- a/ibc-core/ics24-host/types/src/error.rs +++ b/ibc-core/ics24-host/types/src/error.rs @@ -1,21 +1,20 @@ use displaydoc::Display; use ibc_primitives::prelude::*; +/// Errors that arise when parsing identifiers. #[cfg_attr(feature = "serde", derive(serde::Serialize))] #[derive(Debug, Display)] pub enum IdentifierError { - /// identifier `{id}` has invalid length; must be between `{min}` and `{max}` characters - InvalidLength { id: String, min: u64, max: u64 }, - /// identifier `{id}` must only contain alphanumeric characters or `.`, `_`, `+`, `-`, `#`, - `[`, `]`, `<`, `>` - InvalidCharacter { id: String }, - /// identifier prefix `{prefix}` is invalid - InvalidPrefix { prefix: String }, - /// chain identifier is not formatted with revision number - UnformattedRevisionNumber { chain_id: String }, - /// revision number overflowed - RevisionNumberOverflow, - /// String `{value}` cannot be converted to packet sequence, error: `{reason}` - InvalidStringAsSequence { value: String, reason: String }, + /// id `{actual}` has invalid length; must be between [`{min}`,`{max}`) + InvalidLength { actual: String, min: u64, max: u64 }, + /// id `{0}` can only contain alphanumeric characters or `.`, `_`, `+`, `-`, `#`, - `[`, `]`, `<`, `>` + InvalidCharacter(String), + /// invalid prefix: `{0}` + InvalidPrefix(String), + /// failed to parse `{value}`: `{description}` + FailedToParse { value: String, description: String }, + /// overflowed revision number + OverflowedRevisionNumber, } #[cfg(feature = "std")] diff --git a/ibc-core/ics24-host/types/src/identifiers/chain_id.rs b/ibc-core/ics24-host/types/src/identifiers/chain_id.rs index d37ad4e1f..eeae43a6a 100644 --- a/ibc-core/ics24-host/types/src/identifiers/chain_id.rs +++ b/ibc-core/ics24-host/types/src/identifiers/chain_id.rs @@ -98,7 +98,7 @@ impl ChainId { let inc_revision_number = self .revision_number .checked_add(1) - .ok_or(IdentifierError::RevisionNumberOverflow)?; + .ok_or(IdentifierError::OverflowedRevisionNumber)?; self.id = format!("{}-{}", chain_name, inc_revision_number); self.revision_number = inc_revision_number; Ok(()) @@ -312,8 +312,9 @@ fn parse_chain_id_string(chain_id_str: &str) -> Result<(&str, u64), IdentifierEr .ok() .map(|revision_number| (chain_name, revision_number)) }) - .ok_or(IdentifierError::UnformattedRevisionNumber { - chain_id: chain_id_str.to_string(), + .ok_or(IdentifierError::FailedToParse { + value: chain_id_str.to_string(), + description: "invalid revision number".to_string(), }) } diff --git a/ibc-core/ics24-host/types/src/identifiers/sequence.rs b/ibc-core/ics24-host/types/src/identifiers/sequence.rs index 9e8b2ccbc..146a978d7 100644 --- a/ibc-core/ics24-host/types/src/identifiers/sequence.rs +++ b/ibc-core/ics24-host/types/src/identifiers/sequence.rs @@ -25,9 +25,9 @@ impl core::str::FromStr for Sequence { fn from_str(s: &str) -> Result { Ok(Self::from(s.parse::().map_err(|e| { - IdentifierError::InvalidStringAsSequence { + IdentifierError::FailedToParse { value: s.to_string(), - reason: e.to_string(), + description: e.to_string(), } })?)) } diff --git a/ibc-core/ics24-host/types/src/validate.rs b/ibc-core/ics24-host/types/src/validate.rs index 75e3494ef..3c1557d6a 100644 --- a/ibc-core/ics24-host/types/src/validate.rs +++ b/ibc-core/ics24-host/types/src/validate.rs @@ -17,7 +17,7 @@ pub fn validate_identifier_chars(id: &str) -> Result<(), Error> { .chars() .all(|c| c.is_alphanumeric() || VALID_SPECIAL_CHARS.contains(c)) { - return Err(Error::InvalidCharacter { id: id.into() }); + return Err(Error::InvalidCharacter(id.into())); } // All good! @@ -35,7 +35,7 @@ pub fn validate_identifier_length(id: &str, min: u64, max: u64) -> Result<(), Er Ok(()) } else { Err(Error::InvalidLength { - id: id.into(), + actual: id.into(), min, max, }) @@ -67,17 +67,18 @@ pub fn validate_prefix_length( pub fn validate_named_u64_index(id: &str, name: &str) -> Result<(), Error> { let number_s = id .strip_prefix(name) - .ok_or_else(|| Error::InvalidPrefix { prefix: id.into() })? + .ok_or_else(|| Error::InvalidPrefix(id.into()))? .strip_prefix('-') - .ok_or_else(|| Error::InvalidPrefix { prefix: id.into() })?; + .ok_or_else(|| Error::InvalidPrefix(id.into()))?; if number_s.starts_with('0') && number_s.len() > 1 { - return Err(Error::InvalidPrefix { prefix: id.into() }); + return Err(Error::InvalidPrefix(id.into())); } - _ = number_s - .parse::() - .map_err(|_| Error::InvalidPrefix { prefix: id.into() })?; + _ = number_s.parse::().map_err(|_| Error::FailedToParse { + value: id.into(), + description: "invalid prefix".to_string(), + })?; Ok(()) } diff --git a/ibc-core/ics25-handler/src/entrypoint.rs b/ibc-core/ics25-handler/src/entrypoint.rs index 3c271a9bb..575e5e096 100644 --- a/ibc-core/ics25-handler/src/entrypoint.rs +++ b/ibc-core/ics25-handler/src/entrypoint.rs @@ -80,12 +80,10 @@ where let port_id = channel_msg_to_port_id(&msg); let module_id = router .lookup_module(port_id) - .ok_or(RouterError::UnknownPort { - port_id: port_id.clone(), - })?; + .ok_or(RouterError::UnknownPort(port_id.clone()))?; let module = router .get_route(&module_id) - .ok_or(RouterError::ModuleNotFound)?; + .ok_or(RouterError::MissingModule)?; match msg { ChannelMsg::OpenInit(msg) => chan_open_init_validate(ctx, module, msg), @@ -100,12 +98,10 @@ where let port_id = packet_msg_to_port_id(&msg); let module_id = router .lookup_module(port_id) - .ok_or(RouterError::UnknownPort { - port_id: port_id.clone(), - })?; + .ok_or(RouterError::UnknownPort(port_id.clone()))?; let module = router .get_route(&module_id) - .ok_or(RouterError::ModuleNotFound)?; + .ok_or(RouterError::MissingModule)?; match msg { PacketMsg::Recv(msg) => recv_packet_validate(ctx, msg), @@ -157,12 +153,10 @@ where let port_id = channel_msg_to_port_id(&msg); let module_id = router .lookup_module(port_id) - .ok_or(RouterError::UnknownPort { - port_id: port_id.clone(), - })?; + .ok_or(RouterError::UnknownPort(port_id.clone()))?; let module = router .get_route_mut(&module_id) - .ok_or(RouterError::ModuleNotFound)?; + .ok_or(RouterError::MissingModule)?; match msg { ChannelMsg::OpenInit(msg) => chan_open_init_execute(ctx, module, msg), @@ -177,12 +171,10 @@ where let port_id = packet_msg_to_port_id(&msg); let module_id = router .lookup_module(port_id) - .ok_or(RouterError::UnknownPort { - port_id: port_id.clone(), - })?; + .ok_or(RouterError::UnknownPort(port_id.clone()))?; let module = router .get_route_mut(&module_id) - .ok_or(RouterError::ModuleNotFound)?; + .ok_or(RouterError::MissingModule)?; match msg { PacketMsg::Recv(msg) => recv_packet_execute(ctx, module, msg), diff --git a/ibc-core/ics25-handler/types/src/events.rs b/ibc-core/ics25-handler/types/src/events.rs index aa62ea813..28480c375 100644 --- a/ibc-core/ics25-handler/types/src/events.rs +++ b/ibc-core/ics25-handler/types/src/events.rs @@ -1,51 +1,13 @@ //! Defines events emitted during handling of IBC messages -use displaydoc::Display; -use ibc_core_channel_types::{error as channel_error, events as ChannelEvents}; -use ibc_core_client_types::error as client_error; +use ibc_core_channel_types::error::ChannelError; +use ibc_core_channel_types::events as ChannelEvents; use ibc_core_client_types::events::{self as ClientEvents}; -use ibc_core_connection_types::{error as connection_error, events as ConnectionEvents}; -use ibc_core_host_types::error::IdentifierError; +use ibc_core_connection_types::events as ConnectionEvents; use ibc_core_router_types::event::ModuleEvent; use ibc_primitives::prelude::*; -use ibc_primitives::TimestampError; use tendermint::abci; -/// All error variants related to IBC events -#[derive(Debug, Display)] -pub enum Error { - /// error parsing height - Height, - /// parse error: `{0}` - Parse(IdentifierError), - /// client error: `{0}` - Client(client_error::ClientError), - /// connection error: `{0}` - Connection(connection_error::ConnectionError), - /// channel error: `{0}` - Channel(channel_error::ChannelError), - /// parsing timestamp error: `{0}` - Timestamp(TimestampError), - /// incorrect event type: `{event}` - IncorrectEventType { event: String }, - /// module event cannot use core event types: `{event:?}` - MalformedModuleEvent { event: ModuleEvent }, -} - -#[cfg(feature = "std")] -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match &self { - Self::Parse(e) => Some(e), - Self::Client(e) => Some(e), - Self::Connection(e) => Some(e), - Self::Channel(e) => Some(e), - Self::Timestamp(e) => Some(e), - _ => None, - } - } -} - const MESSAGE_EVENT: &str = "message"; /// Events created by the IBC component of a chain, destined for a relayer. @@ -93,7 +55,7 @@ pub enum IbcEvent { } impl TryFrom for abci::Event { - type Error = Error; + type Error = ChannelError; fn try_from(event: IbcEvent) -> Result { Ok(match event { @@ -111,11 +73,11 @@ impl TryFrom for abci::Event { IbcEvent::OpenConfirmChannel(event) => event.into(), IbcEvent::CloseInitChannel(event) => event.into(), IbcEvent::CloseConfirmChannel(event) => event.into(), - IbcEvent::SendPacket(event) => event.try_into().map_err(Error::Channel)?, - IbcEvent::ReceivePacket(event) => event.try_into().map_err(Error::Channel)?, - IbcEvent::WriteAcknowledgement(event) => event.try_into().map_err(Error::Channel)?, - IbcEvent::AcknowledgePacket(event) => event.try_into().map_err(Error::Channel)?, - IbcEvent::TimeoutPacket(event) => event.try_into().map_err(Error::Channel)?, + IbcEvent::SendPacket(event) => event.try_into()?, + IbcEvent::ReceivePacket(event) => event.try_into()?, + IbcEvent::WriteAcknowledgement(event) => event.try_into()?, + IbcEvent::AcknowledgePacket(event) => event.try_into()?, + IbcEvent::TimeoutPacket(event) => event.try_into()?, IbcEvent::ChannelClosed(event) => event.into(), IbcEvent::Module(event) => event.into(), IbcEvent::Message(event) => abci::Event { diff --git a/ibc-core/ics25-handler/types/src/msgs.rs b/ibc-core/ics25-handler/types/src/msgs.rs index 1272c0aff..e3276b951 100644 --- a/ibc-core/ics25-handler/types/src/msgs.rs +++ b/ibc-core/ics25-handler/types/src/msgs.rs @@ -47,7 +47,7 @@ impl TryFrom for MsgEnvelope { // Pop out the message and then wrap it in the corresponding type. let domain_msg = MsgCreateClient::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Client(ClientMsg::CreateClient(domain_msg))) @@ -55,7 +55,7 @@ impl TryFrom for MsgEnvelope { UPDATE_CLIENT_TYPE_URL => { let domain_msg = MsgUpdateClient::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Client(ClientMsg::UpdateClient(domain_msg))) @@ -63,7 +63,7 @@ impl TryFrom for MsgEnvelope { UPGRADE_CLIENT_TYPE_URL => { let domain_msg = MsgUpgradeClient::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Client(ClientMsg::UpgradeClient(domain_msg))) @@ -72,7 +72,7 @@ impl TryFrom for MsgEnvelope { let domain_msg = MsgSubmitMisbehaviour::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Client(ClientMsg::Misbehaviour(domain_msg))) @@ -83,7 +83,7 @@ impl TryFrom for MsgEnvelope { let domain_msg = MsgConnectionOpenInit::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Connection(ConnectionMsg::OpenInit(domain_msg))) @@ -91,7 +91,7 @@ impl TryFrom for MsgEnvelope { CONN_OPEN_TRY_TYPE_URL => { let domain_msg = MsgConnectionOpenTry::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Connection(ConnectionMsg::OpenTry(domain_msg))) @@ -99,7 +99,7 @@ impl TryFrom for MsgEnvelope { CONN_OPEN_ACK_TYPE_URL => { let domain_msg = MsgConnectionOpenAck::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Connection(ConnectionMsg::OpenAck(domain_msg))) @@ -108,7 +108,7 @@ impl TryFrom for MsgEnvelope { let domain_msg = MsgConnectionOpenConfirm::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Connection(ConnectionMsg::OpenConfirm( @@ -120,7 +120,7 @@ impl TryFrom for MsgEnvelope { CHAN_OPEN_INIT_TYPE_URL => { let domain_msg = MsgChannelOpenInit::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Channel(ChannelMsg::OpenInit(domain_msg))) @@ -128,7 +128,7 @@ impl TryFrom for MsgEnvelope { CHAN_OPEN_TRY_TYPE_URL => { let domain_msg = MsgChannelOpenTry::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Channel(ChannelMsg::OpenTry(domain_msg))) @@ -136,7 +136,7 @@ impl TryFrom for MsgEnvelope { CHAN_OPEN_ACK_TYPE_URL => { let domain_msg = MsgChannelOpenAck::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Channel(ChannelMsg::OpenAck(domain_msg))) @@ -145,7 +145,7 @@ impl TryFrom for MsgEnvelope { let domain_msg = MsgChannelOpenConfirm::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Channel(ChannelMsg::OpenConfirm(domain_msg))) @@ -153,7 +153,7 @@ impl TryFrom for MsgEnvelope { CHAN_CLOSE_INIT_TYPE_URL => { let domain_msg = MsgChannelCloseInit::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Channel(ChannelMsg::CloseInit(domain_msg))) @@ -162,7 +162,7 @@ impl TryFrom for MsgEnvelope { let domain_msg = MsgChannelCloseConfirm::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Channel(ChannelMsg::CloseConfirm(domain_msg))) @@ -171,7 +171,7 @@ impl TryFrom for MsgEnvelope { RECV_PACKET_TYPE_URL => { let domain_msg = MsgRecvPacket::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Packet(PacketMsg::Recv(domain_msg))) @@ -179,7 +179,7 @@ impl TryFrom for MsgEnvelope { ACKNOWLEDGEMENT_TYPE_URL => { let domain_msg = MsgAcknowledgement::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Packet(PacketMsg::Ack(domain_msg))) @@ -187,7 +187,7 @@ impl TryFrom for MsgEnvelope { TIMEOUT_TYPE_URL => { let domain_msg = MsgTimeout::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Packet(PacketMsg::Timeout(domain_msg))) @@ -195,14 +195,12 @@ impl TryFrom for MsgEnvelope { TIMEOUT_ON_CLOSE_TYPE_URL => { let domain_msg = MsgTimeoutOnClose::decode_vec(&any_msg.value).map_err(|e| { RouterError::MalformedMessageBytes { - reason: e.to_string(), + description: e.to_string(), } })?; Ok(MsgEnvelope::Packet(PacketMsg::TimeoutOnClose(domain_msg))) } - _ => Err(RouterError::UnknownMessageTypeUrl { - url: any_msg.type_url, - }), + _ => Err(RouterError::UnknownMessageTypeUrl(any_msg.type_url)), } } } diff --git a/ibc-core/ics26-routing/types/src/error.rs b/ibc-core/ics26-routing/types/src/error.rs index 01fb3c6c6..663cbcc6a 100644 --- a/ibc-core/ics26-routing/types/src/error.rs +++ b/ibc-core/ics26-routing/types/src/error.rs @@ -5,14 +5,14 @@ use ibc_primitives::prelude::*; /// Error type for the router module. #[derive(Debug, Display)] pub enum RouterError { - /// unknown type URL `{url}` - UnknownMessageTypeUrl { url: String }, - /// the message is malformed and cannot be decoded error: `{reason}` - MalformedMessageBytes { reason: String }, - /// port `{port_id}` is unknown - UnknownPort { port_id: PortId }, - /// module not found - ModuleNotFound, + /// malformed message that could not be decoded: `{description}` + MalformedMessageBytes { description: String }, + /// missing module + MissingModule, + /// unknown message type URL `{0}` + UnknownMessageTypeUrl(String), + /// unknown port `{0}` + UnknownPort(PortId), } #[cfg(feature = "std")] diff --git a/ibc-testkit/src/fixtures/clients/tendermint.rs b/ibc-testkit/src/fixtures/clients/tendermint.rs index 89d870f72..74c5a14d9 100644 --- a/ibc-testkit/src/fixtures/clients/tendermint.rs +++ b/ibc-testkit/src/fixtures/clients/tendermint.rs @@ -3,7 +3,7 @@ use core::time::Duration; use basecoin_store::avl::get_proof_spec as basecoin_proof_spec; use ibc::clients::tendermint::client_state::ClientState as TmClientState; -use ibc::clients::tendermint::types::error::{Error as ClientError, Error}; +use ibc::clients::tendermint::types::error::TendermintClientError; use ibc::clients::tendermint::types::proto::v1::{ClientState as RawTmClientState, Fraction}; #[cfg(feature = "serde")] use ibc::clients::tendermint::types::Header; @@ -19,7 +19,9 @@ use tendermint::block::Header as TmHeader; use typed_builder::TypedBuilder; /// Returns a dummy tendermint `ClientState` by given `frozen_height`, for testing purposes only! -pub fn dummy_tm_client_state_from_raw(frozen_height: RawHeight) -> Result { +pub fn dummy_tm_client_state_from_raw( + frozen_height: RawHeight, +) -> Result { ClientStateType::try_from(dummy_raw_tm_client_state(frozen_height)).map(TmClientState::from) } @@ -95,7 +97,7 @@ impl ClientStateConfig { self, chain_id: ChainId, latest_height: Height, - ) -> Result { + ) -> Result { Ok(ClientStateType::new( chain_id, self.trust_level, diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs index c10a14210..780392577 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs @@ -136,9 +136,7 @@ impl TryFrom for MockClientState { } match raw.type_url.as_str() { MOCK_CLIENT_STATE_TYPE_URL => decode_client_state(&raw.value), - _ => Err(ClientError::UnknownClientStateType { - client_state_type: raw.type_url, - }), + _ => Err(ClientError::InvalidClientStateType(raw.type_url)), } } } @@ -171,9 +169,7 @@ impl ClientStateCommon for MockClientState { if consensus_state_status(&mock_consensus_state, host_timestamp, self.trusting_period)? .is_expired() { - return Err(ClientError::ClientNotActive { - status: Status::Expired, - }); + return Err(ClientError::InvalidStatus(Status::Expired)); } Ok(()) @@ -190,8 +186,8 @@ impl ClientStateCommon for MockClientState { fn validate_proof_height(&self, proof_height: Height) -> Result<(), ClientError> { if self.latest_height() < proof_height { return Err(ClientError::InvalidProofHeight { - latest_height: self.latest_height(), - proof_height, + actual: self.latest_height(), + expected: proof_height, }); } Ok(()) @@ -212,7 +208,7 @@ impl ClientStateCommon for MockClientState { let upgraded_mock_client_state = Self::try_from(upgraded_client_state)?; MockConsensusState::try_from(upgraded_consensus_state)?; if self.latest_height() >= upgraded_mock_client_state.latest_height() { - return Err(UpgradeClientError::LowUpgradeHeight { + return Err(UpgradeClientError::InsufficientUpgradeHeight { upgraded_height: self.latest_height(), client_height: upgraded_mock_client_state.latest_height(), })?; @@ -285,9 +281,7 @@ where Ok(header_heights_equal && headers_are_in_future) } - header_type => Err(ClientError::UnknownHeaderType { - header_type: header_type.to_owned(), - }), + header_type => Err(ClientError::InvalidHeaderType(header_type.to_owned())), } } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs index 82536d2d6..96273f780 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs @@ -75,9 +75,7 @@ impl TryFrom for MockConsensusState { } match raw.type_url.as_str() { MOCK_CONSENSUS_STATE_TYPE_URL => decode_consensus_state(&raw.value), - _ => Err(ClientError::UnknownConsensusStateType { - consensus_state_type: raw.type_url, - }), + _ => Err(ClientError::InvalidConsensusStateType(raw.type_url)), } } } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/header.rs b/ibc-testkit/src/testapp/ibc/clients/mock/header.rs index d45e11827..fac7bf00c 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/header.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/header.rs @@ -97,12 +97,10 @@ impl TryFrom for MockHeader { match raw.type_url.as_str() { MOCK_HEADER_TYPE_URL => Ok(Protobuf::::decode_vec(&raw.value).map_err( |e| ClientError::InvalidRawHeader { - reason: e.to_string(), + description: e.to_string(), }, )?), - _ => Err(ClientError::UnknownHeaderType { - header_type: raw.type_url, - }), + _ => Err(ClientError::InvalidHeaderType(raw.type_url)), } } } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs b/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs index ff4664da4..e07c310a1 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs @@ -61,9 +61,7 @@ impl TryFrom for Misbehaviour { } match raw.type_url.as_str() { MOCK_MISBEHAVIOUR_TYPE_URL => decode_misbehaviour(&raw.value), - _ => Err(ClientError::UnknownMisbehaviourType { - misbehaviour_type: raw.type_url, - }), + _ => Err(ClientError::InvalidMisbehaviourType(raw.type_url)), } } } diff --git a/ibc-testkit/src/testapp/ibc/core/client_ctx.rs b/ibc-testkit/src/testapp/ibc/core/client_ctx.rs index 8c7bd8dd2..a2c9d59d7 100644 --- a/ibc-testkit/src/testapp/ibc/core/client_ctx.rs +++ b/ibc-testkit/src/testapp/ibc/core/client_ctx.rs @@ -108,7 +108,7 @@ where .map(|path| { self.consensus_state_store .get(StoreHeight::Pending, &path) - .ok_or_else(|| ClientError::ConsensusStateNotFound { + .ok_or_else(|| ClientError::MissingConsensusState { client_id: client_id.clone(), height: *height, }) @@ -141,7 +141,7 @@ where .map(|path| { self.consensus_state_store .get(StoreHeight::Pending, &path) - .ok_or_else(|| ClientError::ConsensusStateNotFound { + .ok_or_else(|| ClientError::MissingConsensusState { client_id: client_id.clone(), height: *height, }) @@ -163,9 +163,7 @@ where Ok(self .client_state_store .get(StoreHeight::Pending, &ClientStatePath(client_id.clone())) - .ok_or(ClientError::ClientStateNotFound { - client_id: client_id.clone(), - })?) + .ok_or(ClientError::MissingClientState(client_id.clone()))?) } fn consensus_state( @@ -180,7 +178,7 @@ where let consensus_state = self .consensus_state_store .get(StoreHeight::Pending, client_cons_state_path) - .ok_or(ClientError::ConsensusStateNotFound { + .ok_or(ClientError::MissingConsensusState { client_id: client_cons_state_path.client_id.clone(), height, })?; @@ -203,7 +201,7 @@ where let processed_timestamp = self .client_processed_times .get(StoreHeight::Pending, &client_update_time_path) - .ok_or(ClientError::UpdateMetaDataNotFound { + .ok_or(ClientError::MissingUpdateMetaData { client_id: client_id.clone(), height: *height, })?; @@ -215,7 +213,7 @@ where let processed_height = self .client_processed_heights .get(StoreHeight::Pending, &client_update_height_path) - .ok_or(ClientError::UpdateMetaDataNotFound { + .ok_or(ClientError::MissingUpdateMetaData { client_id: client_id.clone(), height: *height, })?; diff --git a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs index a475f90d7..5f572cf6b 100644 --- a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs +++ b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs @@ -11,7 +11,7 @@ use ibc::core::channel::types::error::{ChannelError, PacketError}; use ibc::core::channel::types::packet::{PacketState, Receipt}; use ibc::core::client::context::consensus_state::ConsensusState; use ibc::core::client::types::error::ClientError; -use ibc::core::client::types::Height; +use ibc::core::client::types::{Height, Status}; use ibc::core::commitment_types::commitment::CommitmentPrefix; use ibc::core::commitment_types::merkle::MerkleProof; use ibc::core::connection::types::error::ConnectionError; @@ -72,7 +72,7 @@ where Ok(consensus_states_binding .get(&height.revision_height()) .cloned() - .ok_or(ClientError::MissingLocalConsensusState { height: *height })?) + .ok_or(ClientError::MissingLocalConsensusState(*height))?) } fn validate_self_client( @@ -80,10 +80,7 @@ where client_state_of_host_on_counterparty: Self::HostClientState, ) -> Result<(), ContextError> { if client_state_of_host_on_counterparty.is_frozen() { - return Err(ClientError::ClientFrozen { - description: String::new(), - } - .into()); + return Err(ClientError::InvalidStatus(Status::Frozen).into()); } let latest_height = self.host_height()?; @@ -96,7 +93,7 @@ where { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { - reason: format!( + description: format!( "client is not in the same revision as the chain. expected: {}, got: {}", self_revision_number, client_state_of_host_on_counterparty @@ -111,7 +108,7 @@ where if client_state_of_host_on_counterparty.latest_height() >= host_current_height { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { - reason: format!( + description: format!( "client has latest height {} greater than or equal to chain height {}", client_state_of_host_on_counterparty.latest_height(), host_current_height @@ -127,9 +124,7 @@ where Ok(self .connection_end_store .get(StoreHeight::Pending, &ConnectionPath::new(conn_id)) - .ok_or(ConnectionError::ConnectionNotFound { - connection_id: conn_id.clone(), - })?) + .ok_or(ConnectionError::MissingConnection(conn_id.clone()))?) } fn commitment_prefix(&self) -> CommitmentPrefix { @@ -142,9 +137,7 @@ where Ok(self .conn_counter .get(StoreHeight::Pending, &NextConnectionSequencePath) - .ok_or(ConnectionError::Other { - description: "connection counter not found".into(), - })?) + .ok_or(ConnectionError::MissingConnectionCounter)?) } fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result { @@ -154,7 +147,10 @@ where StoreHeight::Pending, &ChannelEndPath::new(&channel_end_path.0, &channel_end_path.1), ) - .ok_or(ChannelError::MissingChannel)?) + .ok_or(ChannelError::NonexistentChannel { + port_id: channel_end_path.0.clone(), + channel_id: channel_end_path.1.clone(), + })?) } fn get_next_sequence_send( @@ -222,9 +218,7 @@ where ), ) .then_some(Receipt::Ok) - .ok_or(PacketError::PacketReceiptNotFound { - sequence: receipt_path.sequence, - })?) + .ok_or(PacketError::MissingPacketReceipt(receipt_path.sequence))?) } fn get_packet_acknowledgement( @@ -237,9 +231,7 @@ where StoreHeight::Pending, &AckPath::new(&ack_path.port_id, &ack_path.channel_id, ack_path.sequence), ) - .ok_or(PacketError::PacketAcknowledgementNotFound { - sequence: ack_path.sequence, - })?) + .ok_or(PacketError::MissingPacketAcknowledgment(ack_path.sequence))?) } /// Returns a counter of the number of channel ids that have been created thus far. @@ -249,9 +241,7 @@ where Ok(self .channel_counter .get(StoreHeight::Pending, &NextChannelSequencePath) - .ok_or(ChannelError::Other { - description: "channel counter not found".into(), - })?) + .ok_or(ChannelError::MissingCounter)?) } /// Returns the maximum expected time per block @@ -316,9 +306,7 @@ where let client_state = self .client_state_store .get(StoreHeight::Pending, &client_state_path) - .ok_or_else(|| ClientError::ClientStateNotFound { - client_id: client_state_path.0.clone(), - })?; + .ok_or_else(|| ClientError::MissingClientState(client_state_path.0.clone()))?; Ok((client_state_path.0, client_state)) }) .collect() @@ -354,7 +342,7 @@ where .consensus_state_store .get(StoreHeight::Pending, &consensus_path) .ok_or({ - ClientError::ConsensusStateNotFound { + ClientError::MissingConsensusState { client_id: consensus_path.client_id, height, } @@ -409,9 +397,7 @@ where let connection_end = self .connection_end_store .get(StoreHeight::Pending, &connection_path) - .ok_or_else(|| ConnectionError::ConnectionNotFound { - connection_id: connection_path.0.clone(), - })?; + .ok_or_else(|| ConnectionError::MissingConnection(connection_path.0.clone()))?; Ok(IdentifiedConnectionEnd { connection_id: connection_path.0, connection_end, @@ -451,7 +437,7 @@ where let channel_end = self .channel_end_store .get(StoreHeight::Pending, &channel_path) - .ok_or_else(|| ChannelError::ChannelNotFound { + .ok_or_else(|| ChannelError::NonexistentChannel { port_id: channel_path.0.clone(), channel_id: channel_path.1.clone(), })?; @@ -473,10 +459,7 @@ where "commitments/ports/{}/channels/{}/sequences", channel_end_path.0, channel_end_path.1 ) - .try_into() - .map_err(|_| PacketError::Other { - description: "Invalid commitment path".into(), - })?; + .into(); self.packet_commitment_store .get_keys(&path) @@ -520,10 +503,7 @@ where "acks/ports/{}/channels/{}/sequences", channel_end_path.0, channel_end_path.1 ) - .try_into() - .map_err(|_| PacketError::Other { - description: "Invalid ack path".into(), - })?; + .into(); self.packet_ack_store .get_keys(&ack_path_prefix) @@ -601,10 +581,7 @@ where "commitments/ports/{}/channels/{}/sequences", channel_end_path.0, channel_end_path.1 ) - .try_into() - .map_err(|_| PacketError::Other { - description: "Invalid commitment path".into(), - })?; + .into(); self.packet_commitment_store .get_keys(&commitment_path_prefix) @@ -673,9 +650,7 @@ where ) -> Result<(), ContextError> { self.connection_end_store .set(connection_path.clone(), connection_end) - .map_err(|_| ConnectionError::Other { - description: "Connection end store error".to_string(), - })?; + .map_err(|_| ConnectionError::FailedToStoreConnectionEnd)?; Ok(()) } @@ -692,9 +667,7 @@ where conn_ids.push(conn_id); self.connection_ids_store .set(client_connection_path.clone(), conn_ids) - .map_err(|_| ConnectionError::Other { - description: "Connection ids store error".to_string(), - })?; + .map_err(|_| ConnectionError::FailedToStoreConnectionIds)?; Ok(()) } @@ -704,15 +677,11 @@ where let current_sequence = self .conn_counter .get(StoreHeight::Pending, &NextConnectionSequencePath) - .ok_or(ConnectionError::Other { - description: "connection counter not found".into(), - })?; + .ok_or(ConnectionError::MissingConnectionCounter)?; self.conn_counter .set(NextConnectionSequencePath, current_sequence + 1) - .map_err(|e| ConnectionError::Other { - description: format!("connection counter update failed: {e:?}"), - })?; + .map_err(|_| ConnectionError::FailedToUpdateConnectionCounter)?; Ok(()) } @@ -770,8 +739,8 @@ where ) -> Result<(), ContextError> { self.channel_end_store .set(channel_end_path.clone(), channel_end) - .map_err(|_| ChannelError::Other { - description: "Channel end store error".to_string(), + .map_err(|e| ChannelError::FailedToStoreChannel { + description: format!("{e:?}"), })?; Ok(()) } @@ -813,14 +782,12 @@ where let current_sequence = self .channel_counter .get(StoreHeight::Pending, &NextChannelSequencePath) - .ok_or(ChannelError::Other { - description: "channel counter not found".into(), - })?; + .ok_or(ChannelError::MissingCounter)?; self.channel_counter .set(NextChannelSequencePath, current_sequence + 1) - .map_err(|e| ChannelError::Other { - description: format!("channel counter update failed: {e:?}"), + .map_err(|e| ChannelError::FailedToUpdateCounter { + description: format!("{e:?}"), })?; Ok(()) diff --git a/tests-integration/tests/core/ics02_client/create_client.rs b/tests-integration/tests/core/ics02_client/create_client.rs index 71b40718c..78c4f8392 100644 --- a/tests-integration/tests/core/ics02_client/create_client.rs +++ b/tests-integration/tests/core/ics02_client/create_client.rs @@ -180,11 +180,9 @@ fn test_create_expired_mock_client() { let fxt = create_client_fixture(Ctx::Default, Msg::ExpiredMockHeader); create_client_validate( &fxt, - Expect::Failure(Some(ContextError::ClientError( - ClientError::ClientNotActive { - status: Status::Expired, - }, - ))), + Expect::Failure(Some(ContextError::ClientError(ClientError::InvalidStatus( + Status::Expired, + )))), ); } @@ -208,11 +206,9 @@ fn test_create_expired_tm_client() { let fxt = create_client_fixture(Ctx::Default, Msg::ExpiredTendermintHeader); create_client_validate( &fxt, - Expect::Failure(Some(ContextError::ClientError( - ClientError::ClientNotActive { - status: Status::Expired, - }, - ))), + Expect::Failure(Some(ContextError::ClientError(ClientError::InvalidStatus( + Status::Expired, + )))), ); } @@ -222,9 +218,9 @@ fn test_create_frozen_tm_client() { let fxt = create_client_fixture(Ctx::Default, Msg::FrozenTendermintHeader); create_client_validate( &fxt, - Expect::Failure(Some(ContextError::ClientError(ClientError::ClientFrozen { - description: "the client is frozen".to_string(), - }))), + Expect::Failure(Some(ContextError::ClientError(ClientError::InvalidStatus( + Status::Frozen, + )))), ); } @@ -306,6 +302,6 @@ fn test_tm_create_client_proof_verification_ok() { serde_json::to_vec(&(next_client_seq_value + 1)).expect("valid json serialization"), ) .expect_err("proof verification fails"), - ClientError::Ics23Verification(CommitmentError::VerificationFailure) + ClientError::FailedICS23Verification(CommitmentError::FailedToVerifyMembership) )); } diff --git a/tests-integration/tests/core/ics02_client/upgrade_client.rs b/tests-integration/tests/core/ics02_client/upgrade_client.rs index c59a7686a..153d69e42 100644 --- a/tests-integration/tests/core/ics02_client/upgrade_client.rs +++ b/tests-integration/tests/core/ics02_client/upgrade_client.rs @@ -142,9 +142,8 @@ fn msg_upgrade_client_healthy() { #[test] fn upgrade_client_fail_nonexisting_client() { let fxt = msg_upgrade_client_fixture(Ctx::Default, Msg::Default); - let expected_err = ContextError::ClientError(ClientError::ClientStateNotFound { - client_id: fxt.msg.client_id.clone(), - }); + let expected_err = + ContextError::ClientError(ClientError::MissingClientState(fxt.msg.client_id.clone())); upgrade_client_validate(&fxt, Expect::Failure(Some(expected_err))); } @@ -152,7 +151,7 @@ fn upgrade_client_fail_nonexisting_client() { fn upgrade_client_fail_low_upgrade_height() { let fxt: Fixture = msg_upgrade_client_fixture(Ctx::WithClient, Msg::LowUpgradeHeight); - let expected_err: ClientError = UpgradeClientError::LowUpgradeHeight { + let expected_err: ClientError = UpgradeClientError::InsufficientUpgradeHeight { upgraded_height: Height::new(0, 26).unwrap(), client_height: fxt.ctx.host_height().unwrap(), } @@ -166,8 +165,8 @@ fn upgrade_client_fail_low_upgrade_height() { #[test] fn upgrade_client_fail_unknown_upgraded_client_state() { let fxt = msg_upgrade_client_fixture(Ctx::WithClient, Msg::UnknownUpgradedClientStateType); - let expected_err = ContextError::ClientError(ClientError::UnknownClientStateType { - client_state_type: client_type().to_string(), - }); + let expected_err = ContextError::ClientError(ClientError::InvalidClientStateType( + client_type().to_string(), + )); upgrade_client_validate(&fxt, Expect::Failure(Some(expected_err))); } diff --git a/tests-integration/tests/core/ics03_connection/conn_open_ack.rs b/tests-integration/tests/core/ics03_connection/conn_open_ack.rs index 651ab378f..5d292b3f7 100644 --- a/tests-integration/tests/core/ics03_connection/conn_open_ack.rs +++ b/tests-integration/tests/core/ics03_connection/conn_open_ack.rs @@ -126,16 +126,16 @@ fn conn_open_ack_validate(fxt: &Fixture, expect: Expect) { let cons_state_height = fxt.msg.consensus_height_of_a_on_b; match res.unwrap_err() { - ContextError::ConnectionError(ConnectionError::ConnectionNotFound { connection_id }) => { + ContextError::ConnectionError(ConnectionError::MissingConnection(connection_id)) => { assert_eq!(connection_id, right_connection_id) } - ContextError::ConnectionError(ConnectionError::InvalidConsensusHeight { + ContextError::ConnectionError(ConnectionError::InsufficientConsensusHeight { target_height, current_height: _, }) => { assert_eq!(cons_state_height, target_height); } - ContextError::ConnectionError(ConnectionError::InvalidState { + ContextError::ConnectionError(ConnectionError::MismatchedConnectionStates { expected: _, actual: _, }) => {} @@ -187,26 +187,27 @@ fn conn_open_ack_healthy() { #[test] fn conn_open_ack_no_connection() { let fxt = conn_open_ack_fixture(Ctx::New); - let expected_err = ContextError::ConnectionError(ConnectionError::ConnectionNotFound { - connection_id: fxt.msg.conn_id_on_a.clone(), - }); + let expected_err = ContextError::ConnectionError(ConnectionError::MissingConnection( + fxt.msg.conn_id_on_a.clone(), + )); conn_open_ack_validate(&fxt, Expect::Failure(Some(expected_err))); } #[test] fn conn_open_ack_invalid_consensus_height() { let fxt = conn_open_ack_fixture(Ctx::DefaultWithConnection); - let expected_err = ContextError::ConnectionError(ConnectionError::InvalidConsensusHeight { - target_height: fxt.msg.consensus_height_of_a_on_b, - current_height: Height::new(0, 10).unwrap(), - }); + let expected_err = + ContextError::ConnectionError(ConnectionError::InsufficientConsensusHeight { + target_height: fxt.msg.consensus_height_of_a_on_b, + current_height: Height::new(0, 10).unwrap(), + }); conn_open_ack_validate(&fxt, Expect::Failure(Some(expected_err))); } #[test] fn conn_open_ack_connection_mismatch() { let fxt = conn_open_ack_fixture(Ctx::NewWithConnectionEndOpen); - let expected_err = ContextError::ConnectionError(ConnectionError::InvalidState { + let expected_err = ContextError::ConnectionError(ConnectionError::MismatchedConnectionStates { expected: State::Init.to_string(), actual: State::Open.to_string(), }); From 466c13d5457dd49b683750ee9df6929d4469e0f2 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Tue, 27 Aug 2024 14:44:14 -0500 Subject: [PATCH 03/18] Clean up `QueryError` and `RelayerError` types (#1321) * Clean up ibc-query QueryError type * Clean up ibc-testkit RelayerError * Clean up ibc-testkit RelayerError * Change wording of a doc comment * Remove RelayerError --- ibc-query/src/core/channel/query.rs | 20 +++++----- ibc-query/src/core/client/query.rs | 10 ++--- ibc-query/src/core/connection/query.rs | 8 ++-- ibc-query/src/error.rs | 19 ++++++---- ibc-testkit/src/context.rs | 7 ++-- ibc-testkit/src/relayer/error.rs | 38 ------------------- ibc-testkit/src/relayer/mod.rs | 1 - .../tests/core/ics02_client/update_client.rs | 29 +++++--------- 8 files changed, 43 insertions(+), 89 deletions(-) delete mode 100644 ibc-testkit/src/relayer/error.rs diff --git a/ibc-query/src/core/channel/query.rs b/ibc-query/src/core/channel/query.rs index 793ce5700..61cce7c35 100644 --- a/ibc-query/src/core/channel/query.rs +++ b/ibc-query/src/core/channel/query.rs @@ -47,7 +47,7 @@ where let proof = ibc_ctx .get_proof(proof_height, &Path::ChannelEnd(channel_end_path.clone())) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for channel end path {channel_end_path:?}" )) })?; @@ -119,7 +119,7 @@ where .first() .map(|connection_id| ibc_ctx.connection_end(connection_id)) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Channel {} does not have a connection", request.channel_id )) @@ -140,7 +140,7 @@ where &Path::ClientState(ClientStatePath::new(connection_end.client_id().clone())), ) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for client state path: {:?}", connection_end.client_id() )) @@ -172,7 +172,7 @@ where .first() .map(|connection_id| ibc_ctx.connection_end(connection_id)) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Channel {} does not have a connection", request.channel_id )) @@ -198,7 +198,7 @@ where &Path::ClientConsensusState(consensus_path.clone()), ) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for client consensus state path: {consensus_path:?}" )) })?; @@ -233,7 +233,7 @@ where let proof = ibc_ctx .get_proof(proof_height, &Path::Commitment(commitment_path.clone())) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for packet commitment path: {commitment_path:?}" )) })?; @@ -291,7 +291,7 @@ where let proof = ibc_ctx .get_proof(proof_height, &Path::Receipt(receipt_path.clone())) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for packet receipt path: {receipt_path:?}" )) })?; @@ -325,7 +325,7 @@ where let proof = ibc_ctx .get_proof(proof_height, &Path::Ack(acknowledgement_path.clone())) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for packet acknowledgement path: {acknowledgement_path:?}" )) })?; @@ -431,7 +431,7 @@ where let proof = ibc_ctx .get_proof(proof_height, &Path::SeqSend(next_seq_send_path)) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Next sequence send proof not found for channel {}", request.channel_id )) @@ -464,7 +464,7 @@ where let proof = ibc_ctx .get_proof(proof_height, &Path::SeqRecv(next_seq_recv_path)) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Next sequence receive proof not found for channel {}", request.channel_id )) diff --git a/ibc-query/src/core/client/query.rs b/ibc-query/src/core/client/query.rs index 27e64a33f..728e2ee26 100644 --- a/ibc-query/src/core/client/query.rs +++ b/ibc-query/src/core/client/query.rs @@ -50,7 +50,7 @@ where &Path::ClientState(ClientStatePath::new(client_id.clone())), ) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for client state path: {client_id:?}" )) })?; @@ -109,7 +109,7 @@ where .into_iter() .max_by_key(|&(h, _)| h) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "No consensus state found for client: {client_id:?}" )) })? @@ -130,7 +130,7 @@ where )), ) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for consensus state path: {client_id:?}" )) })?; @@ -242,7 +242,7 @@ where &Path::UpgradeClientState(upgraded_client_state_path), ) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for upgraded client state at: {proof_height:?}" )) })?; @@ -301,7 +301,7 @@ where &Path::UpgradeConsensusState(upgraded_consensus_state_path), ) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for upgraded consensus state at: {proof_height:?}" )) })?; diff --git a/ibc-query/src/core/connection/query.rs b/ibc-query/src/core/connection/query.rs index d156c4c1c..ed1657869 100644 --- a/ibc-query/src/core/connection/query.rs +++ b/ibc-query/src/core/connection/query.rs @@ -41,7 +41,7 @@ where &Path::Connection(ConnectionPath::new(&request.connection_id)), ) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for connection path: {:?}", request.connection_id )) @@ -92,7 +92,7 @@ where &Path::ClientConnection(ClientConnectionPath::new(request.client_id.clone())), ) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for client connection path: {:?}", request.client_id )) @@ -130,7 +130,7 @@ where &Path::ClientState(ClientStatePath::new(connection_end.client_id().clone())), ) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for client state path: {:?}", connection_end.client_id() )) @@ -172,7 +172,7 @@ where let proof = ibc_ctx .get_proof(proof_height, &Path::ClientConsensusState(consensus_path)) .ok_or_else(|| { - QueryError::proof_not_found(format!( + QueryError::missing_proof(format!( "Proof not found for consensus state path: {:?}", connection_end.client_id() )) diff --git a/ibc-query/src/error.rs b/ibc-query/src/error.rs index 6d11fd2d8..4c41120eb 100644 --- a/ibc-query/src/error.rs +++ b/ibc-query/src/error.rs @@ -8,21 +8,24 @@ use ibc::core::handler::types::error::ContextError; use ibc::core::host::types::error::IdentifierError; use tonic::Status; +/// The main error type of the ibc-query crate. This type mainly +/// serves to surface lower-level errors that occur when executing +/// ibc-query's codepaths. #[derive(Debug, Display)] pub enum QueryError { - /// Context error: {0} + /// context error: `{0}` ContextError(ContextError), - /// Identifier error: {0} + /// identifier error: `{0}` IdentifierError(IdentifierError), - /// Proof not found: {0} - ProofNotFound(String), - /// Missing field: {0} + /// missing proof: `{0}` + MissingProof(String), + /// missing field: `{0}` MissingField(String), } impl QueryError { - pub fn proof_not_found(description: T) -> Self { - Self::ProofNotFound(description.to_string()) + pub fn missing_proof(description: T) -> Self { + Self::MissingProof(description.to_string()) } pub fn missing_field(description: T) -> Self { @@ -35,7 +38,7 @@ impl From for Status { match e { QueryError::ContextError(ctx_err) => Self::internal(ctx_err.to_string()), QueryError::IdentifierError(id_err) => Self::internal(id_err.to_string()), - QueryError::ProofNotFound(description) => Self::not_found(description), + QueryError::MissingProof(description) => Self::not_found(description), QueryError::MissingField(description) => Self::invalid_argument(description), } } diff --git a/ibc-testkit/src/context.rs b/ibc-testkit/src/context.rs index 4380de474..92255ba3d 100644 --- a/ibc-testkit/src/context.rs +++ b/ibc-testkit/src/context.rs @@ -25,7 +25,6 @@ use ibc::primitives::Timestamp; use super::testapp::ibc::core::types::{LightClientState, MockIbcStore}; use crate::fixtures::core::context::TestContextConfig; use crate::hosts::{HostClientState, MockHost, TendermintHost, TestBlock, TestHeader, TestHost}; -use crate::relayer::error::RelayerError; use crate::testapp::ibc::clients::{AnyClientState, AnyConsensusState}; use crate::testapp::ibc::core::router::MockRouter; use crate::testapp::ibc::core::types::DEFAULT_BLOCK_TIME_SECS; @@ -480,9 +479,9 @@ where /// A datagram passes from the relayer to the IBC module (on host chain). /// Alternative method to `Ics18Context::send` that does not exercise any serialization. /// Used in testing the Ics18 algorithms, hence this may return an Ics18Error. - pub fn deliver(&mut self, msg: MsgEnvelope) -> Result<(), RelayerError> { - self.dispatch(msg) - .map_err(RelayerError::TransactionFailed)?; + pub fn deliver(&mut self, msg: MsgEnvelope) -> Result<(), ContextError> { + self.dispatch(msg)?; + // Create a new block. self.advance_block_height(); Ok(()) diff --git a/ibc-testkit/src/relayer/error.rs b/ibc-testkit/src/relayer/error.rs deleted file mode 100644 index 20a995461..000000000 --- a/ibc-testkit/src/relayer/error.rs +++ /dev/null @@ -1,38 +0,0 @@ -use displaydoc::Display; -use ibc::core::client::types::Height; -use ibc::core::connection::types::error::ConnectionError; -use ibc::core::handler::types::error::ContextError; -use ibc::core::host::types::identifiers::ClientId; - -#[derive(Debug, Display)] -pub enum RelayerError { - /// client state on destination chain not found, (client id: `{client_id}`) - ClientStateNotFound { client_id: ClientId }, - /// the client on the destination chain is already up-to-date (client id: `{client_id}`, source height: `{source_height}`, dest height: `{destination_height}`) - ClientAlreadyUpToDate { - client_id: ClientId, - source_height: Height, - destination_height: Height, - }, - /// the client on the destination chain is at a higher height (client id: `{client_id}`, source height: `{source_height}`, dest height: `{destination_height}`) - ClientAtHigherHeight { - client_id: ClientId, - source_height: Height, - destination_height: Height, - }, - /// transaction processing by modules failed error: `{0}` - TransactionFailed(ContextError), - /// connection error: `{0}` - Connection(ConnectionError), -} - -#[cfg(feature = "std")] -impl std::error::Error for RelayerError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match &self { - Self::TransactionFailed(e) => Some(e), - Self::Connection(e) => Some(e), - _ => None, - } - } -} diff --git a/ibc-testkit/src/relayer/mod.rs b/ibc-testkit/src/relayer/mod.rs index 961de7885..309d094da 100644 --- a/ibc-testkit/src/relayer/mod.rs +++ b/ibc-testkit/src/relayer/mod.rs @@ -1,4 +1,3 @@ pub mod context; -pub mod error; pub mod integration; pub mod utils; diff --git a/tests-integration/tests/core/ics02_client/update_client.rs b/tests-integration/tests/core/ics02_client/update_client.rs index 2a4d64864..6afa73cb9 100644 --- a/tests-integration/tests/core/ics02_client/update_client.rs +++ b/tests-integration/tests/core/ics02_client/update_client.rs @@ -32,7 +32,6 @@ use ibc_testkit::hosts::tendermint::BlockParams; use ibc_testkit::hosts::{ HostClientState, MockHost, TendermintHost, TestBlock, TestHeader, TestHost, }; -use ibc_testkit::relayer::error::RelayerError; use ibc_testkit::testapp::ibc::clients::mock::client_state::{ client_type as mock_client_type, MockClientState, }; @@ -1527,7 +1526,7 @@ pub(crate) fn build_client_update_datagram( dest: &TestContext, client_id: &ClientId, src_header: &H, -) -> Result +) -> Option where HostClientState: ClientStateValidation, { @@ -1536,23 +1535,15 @@ where let dest_client_latest_height = dest.light_client_latest_height(client_id); if src_header.height() == dest_client_latest_height { - return Err(RelayerError::ClientAlreadyUpToDate { - client_id: client_id.clone(), - source_height: src_header.height(), - destination_height: dest_client_latest_height, - }); + return None; }; if dest_client_latest_height > src_header.height() { - return Err(RelayerError::ClientAtHigherHeight { - client_id: client_id.clone(), - source_height: src_header.height(), - destination_height: dest_client_latest_height, - }); + return None; }; // Client on destination chain can be updated. - Ok(ClientMsg::UpdateClient(MsgUpdateClient { + Some(ClientMsg::UpdateClient(MsgUpdateClient { client_id: client_id.clone(), client_message: src_header.clone().into(), signer: dummy_account_id(), @@ -1615,9 +1606,9 @@ fn client_update_ping_pong() { ); assert!( - client_msg_b_res.is_ok(), - "create_client_update failed for context destination {ctx_b:?}, error: {client_msg_b_res:?}", - ); + client_msg_b_res.is_some(), + "create_client_update failed for context destination {ctx_b:?}", + ); let client_msg_b = client_msg_b_res.unwrap(); @@ -1653,9 +1644,9 @@ fn client_update_ping_pong() { build_client_update_datagram(&ctx_a, &client_on_a_for_b, &b_latest_header); assert!( - client_msg_a_res.is_ok(), - "create_client_update failed for context destination {ctx_a:?}, error: {client_msg_a_res:?}", - ); + client_msg_a_res.is_some(), + "create_client_update failed for context destination {ctx_a:?}", + ); let client_msg_a = client_msg_a_res.unwrap(); From bfad72ff2c2a52c0b46d5510014d64d591a2ec3d Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Mon, 9 Sep 2024 15:24:56 -0500 Subject: [PATCH 04/18] Consolidate decoding-related errors into new `DecodingError` type (#1325) * Define DecodingError in ibc-primitives * Utilize DecodingError in ics721 * Start using DecodingError in ClientError * Define StatusError type * Wire up StatusError * Wiring up DecodingError * Add DecodingError to RouterError * Remove unused From impl * Change format of an import * Change format of an import * Change format of an import * Move DecodingError into ics24 * Cargo nightly fmt * Use DecodingError in more places * cargo fmt * cargo fmt * Update cw-check Cargo.lock * Add necessary wasm-client feature attribute * Move InvalidUri error variant back to NftTransferError * Regenerate cw hcheck cargo.lock * Add serde feature attribute * Remove ClientError::InvalidClientIdentifier error variant in favor of DecodingError::InvalidIdentifier * Add derive_more::From on NftTransferError * Stashing changes * Revert "Add derive_more::From on NftTransferError" This reverts commit 234ebeec9179151f5659e529f7d2bfc8e1d60966. * Remove RouterError::UnknownMessageTypeUrl * Add derive_more::From on TokenTransferError * Add derive_more to NftTransferError * Remove tendermint-proto dependency from ibc-primitives * Remove StatusError * Remove unnecessary ClientError::Decoding wrappings * Clean up TendermintClientError * Regenerate cw-check cargo.lock * taplo fmt * Apply PR feedback * Use ibc_proto::Error type instead of tendermint_proto::Error * Change FailedToParseType fields to make them more clear * Revert InvalidTrace and InvalidCoin TokenTransferError variants * Remove NftTransferError variants in favor of DecodingError::InvalidJson * cargo fmt * Regenerate cw-check cargo.lock * Separate out error variants that need to be moved to host-relevant errors * Consolidate TendermintClientError decoding errors * Consolidate Connection and Packet decoding errors * Remove WasmClientError * Consolidate Identifier variant naming * Remove HostError annotations in doc comments * Consolidate CommitmentError variants * Consolidate ConnectionError variants * Revert some CommitmentError variants * Change TryFrom for MsgEnvelope Error type to DecodingError * Remove ConnectionError::Identifier variant in favor of DecodingError::Identifier * Remove ChannelError::Identifier variant in favor of DecodingError::Identifier * Remove PacketError::Identifier variant in favor of DecodingError::Identifier * Revert TokenTransferError FailedToDeserializeAck and FailedToDeserializePacketData * Revert NftTransferError FailedToDeserializeAck and FailedToDeserializePacketData * Revert ics20 and ics721 on_recv_packet_execute impls * Remove additional Identifier error variants * Add TendermintClientError::InsufficientMisbehaviourHeaderHeight variant * Implement From for ClientError and ConnectionError * Incorporate PR feedback * Change TryFrom for ConsensusState error to DecodingError * Remove RouterError::Decoding variant * Revert AcknowledgementStatus tests * Cargo fmt * Fix test_ack_de * Fix typo in doc comment * Fix test_ack_de * Fix test_ack_de * fix: revert nft721 on module errors * fix: remove Identifier variant from few more enums * fix: remove unused tendermint-proto dep * chore: update Cargo.lock --------- Co-authored-by: Farhad Shabani --- Cargo.toml | 2 +- ci/cw-check/Cargo.lock | 6 +- ci/no-std-check/Cargo.lock | 87 +++++++------ ibc-apps/ics20-transfer/src/module.rs | 13 +- ibc-apps/ics20-transfer/types/src/coin.rs | 2 +- ibc-apps/ics20-transfer/types/src/denom.rs | 2 +- ibc-apps/ics20-transfer/types/src/error.rs | 43 ++++--- .../ics20-transfer/types/src/msgs/transfer.rs | 12 +- .../ics721-nft-transfer/types/src/data.rs | 8 +- .../ics721-nft-transfer/types/src/error.rs | 42 +++--- .../types/src/msgs/transfer.rs | 12 +- .../ics721-nft-transfer/types/src/packet.rs | 23 +--- .../src/client_state/common.rs | 7 +- .../types/src/client_state.rs | 68 ++++++---- .../types/src/consensus_state.rs | 41 +++--- .../ics07-tendermint/types/src/error.rs | 46 +++---- .../ics07-tendermint/types/src/header.rs | 42 ++++-- .../types/src/misbehaviour.rs | 43 ++++--- .../ics08-wasm/types/src/client_state.rs | 29 ++--- .../ics08-wasm/types/src/consensus_state.rs | 19 +-- ibc-clients/ics08-wasm/types/src/error.rs | 36 ------ ibc-clients/ics08-wasm/types/src/lib.rs | 1 - .../types/src/msgs/migrate_contract.rs | 4 +- .../ics02-client/src/handler/create_client.rs | 4 +- ibc-core/ics02-client/types/src/error.rs | 103 ++++++++------- .../types/src/msgs/create_client.rs | 11 +- .../types/src/msgs/misbehaviour.rs | 12 +- .../types/src/msgs/recover_client.rs | 10 +- .../types/src/msgs/update_client.rs | 12 +- .../types/src/msgs/upgrade_client.rs | 22 +++- ibc-core/ics02-client/types/src/status.rs | 8 +- .../src/handler/conn_open_ack.rs | 1 + .../src/handler/conn_open_confirm.rs | 1 + .../src/handler/conn_open_try.rs | 1 + ibc-core/ics03-connection/src/handler/mod.rs | 8 +- .../ics03-connection/types/src/connection.rs | 40 +++--- ibc-core/ics03-connection/types/src/error.rs | 46 +++---- .../types/src/msgs/conn_open_ack.rs | 66 +++++----- .../types/src/msgs/conn_open_confirm.rs | 19 +-- .../types/src/msgs/conn_open_init.rs | 10 +- .../types/src/msgs/conn_open_try.rs | 65 ++++++---- .../ics03-connection/types/src/version.rs | 6 +- .../src/handler/acknowledgement.rs | 1 + .../src/handler/chan_close_confirm.rs | 1 + .../src/handler/chan_open_ack.rs | 1 + .../src/handler/chan_open_confirm.rs | 1 + .../types/src/acknowledgement.rs | 5 +- ibc-core/ics04-channel/types/src/error.rs | 74 +++++------ .../types/src/events/packet_attributes.rs | 6 +- .../types/src/msgs/acknowledgement.rs | 18 ++- .../types/src/msgs/chan_open_ack.rs | 14 +- .../types/src/msgs/chan_open_init.rs | 5 +- .../types/src/msgs/chan_open_try.rs | 10 +- .../types/src/msgs/recv_packet.rs | 18 ++- .../ics04-channel/types/src/msgs/timeout.rs | 18 ++- .../types/src/msgs/timeout_on_close.rs | 27 ++-- ibc-core/ics04-channel/types/src/packet.rs | 9 +- .../ics23-commitment/types/src/commitment.rs | 8 +- ibc-core/ics23-commitment/types/src/error.rs | 13 +- ibc-core/ics23-commitment/types/src/specs.rs | 2 + .../cosmos/src/upgrade_proposal/plan.rs | 18 +-- .../cosmos/src/upgrade_proposal/proposal.rs | 8 +- .../cosmos/src/validate_self_client.rs | 2 +- ibc-core/ics24-host/types/Cargo.toml | 2 + ibc-core/ics24-host/types/src/error.rs | 52 ++++++++ ibc-core/ics24-host/types/src/lib.rs | 2 + ibc-core/ics25-handler/types/src/error.rs | 1 + ibc-core/ics25-handler/types/src/msgs.rs | 120 ++++-------------- ibc-core/ics26-routing/types/src/error.rs | 8 +- ibc-primitives/src/lib.rs | 2 +- .../testapp/ibc/clients/mock/client_state.rs | 19 +-- .../ibc/clients/mock/consensus_state.rs | 23 ++-- .../src/testapp/ibc/clients/mock/header.rs | 13 +- .../testapp/ibc/clients/mock/misbehaviour.rs | 25 ++-- ibc-testkit/src/testapp/ibc/core/core_ctx.rs | 2 +- .../tests/core/ics02_client/create_client.rs | 18 +-- 76 files changed, 817 insertions(+), 762 deletions(-) delete mode 100644 ibc-clients/ics08-wasm/types/src/error.rs diff --git a/Cargo.toml b/Cargo.toml index 454378242..f38401ab3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -105,7 +105,7 @@ ibc-client-wasm-types = { version = "0.54.0", path = "./ibc-clients/ics08- ibc-app-transfer-types = { version = "0.54.0", path = "./ibc-apps/ics20-transfer/types", default-features = false } ibc-app-nft-transfer-types = { version = "0.54.0", path = "./ibc-apps/ics721-nft-transfer/types", default-features = false } -ibc-proto = { version = "0.47.0", default-features = false } +ibc-proto = { version = "0.47.1", default-features = false } # cosmos dependencies tendermint = { version = "0.38.0", default-features = false } diff --git a/ci/cw-check/Cargo.lock b/ci/cw-check/Cargo.lock index 2ba932c42..89ffc3d40 100644 --- a/ci/cw-check/Cargo.lock +++ b/ci/cw-check/Cargo.lock @@ -1031,10 +1031,12 @@ dependencies = [ name = "ibc-core-host-types" version = "0.54.0" dependencies = [ + "base64 0.22.1", "derive_more 0.99.18", "displaydoc", "ibc-primitives", "parity-scale-codec", + "prost", "scale-info", "schemars", "serde", @@ -1097,9 +1099,9 @@ dependencies = [ [[package]] name = "ibc-proto" -version = "0.47.0" +version = "0.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1678333cf68c9094ca66aaf9a271269f1f6bf5c26881161def8bd88cee831a23" +checksum = "c852d22b782d2d793f4a646f968de419be635e02bc8798d5d74a6e44eef27733" dependencies = [ "base64 0.22.1", "bytes", diff --git a/ci/no-std-check/Cargo.lock b/ci/no-std-check/Cargo.lock index 01ea501f8..be243bc1b 100644 --- a/ci/no-std-check/Cargo.lock +++ b/ci/no-std-check/Cargo.lock @@ -1170,7 +1170,7 @@ dependencies = [ [[package]] name = "ibc" -version = "0.53.0" +version = "0.54.0" dependencies = [ "ibc-apps", "ibc-clients", @@ -1182,7 +1182,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer" -version = "0.53.0" +version = "0.54.0" dependencies = [ "ibc-app-transfer-types", "ibc-core", @@ -1191,7 +1191,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer-types" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1204,14 +1204,14 @@ dependencies = [ [[package]] name = "ibc-apps" -version = "0.53.0" +version = "0.54.0" dependencies = [ "ibc-app-transfer", ] [[package]] name = "ibc-client-tendermint" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "ibc-client-tendermint-types", @@ -1227,7 +1227,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint-types" -version = "0.53.0" +version = "0.54.0" dependencies = [ "displaydoc", "ibc-core-client-types", @@ -1243,7 +1243,7 @@ dependencies = [ [[package]] name = "ibc-client-wasm-types" -version = "0.53.0" +version = "0.54.0" dependencies = [ "base64 0.22.1", "displaydoc", @@ -1256,7 +1256,7 @@ dependencies = [ [[package]] name = "ibc-clients" -version = "0.53.0" +version = "0.54.0" dependencies = [ "ibc-client-tendermint", "ibc-client-wasm-types", @@ -1264,7 +1264,7 @@ dependencies = [ [[package]] name = "ibc-core" -version = "0.53.0" +version = "0.54.0" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -1279,12 +1279,13 @@ dependencies = [ [[package]] name = "ibc-core-channel" -version = "0.53.0" +version = "0.54.0" dependencies = [ "ibc-core-channel-types", "ibc-core-client", "ibc-core-commitment-types", "ibc-core-connection", + "ibc-core-connection-types", "ibc-core-handler-types", "ibc-core-host", "ibc-core-router", @@ -1293,7 +1294,7 @@ dependencies = [ [[package]] name = "ibc-core-channel-types" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1311,7 +1312,7 @@ dependencies = [ [[package]] name = "ibc-core-client" -version = "0.53.0" +version = "0.54.0" dependencies = [ "ibc-core-client-context", "ibc-core-client-types", @@ -1323,7 +1324,7 @@ dependencies = [ [[package]] name = "ibc-core-client-context" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1338,7 +1339,7 @@ dependencies = [ [[package]] name = "ibc-core-client-types" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1353,7 +1354,7 @@ dependencies = [ [[package]] name = "ibc-core-commitment-types" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1367,7 +1368,7 @@ dependencies = [ [[package]] name = "ibc-core-connection" -version = "0.53.0" +version = "0.54.0" dependencies = [ "ibc-core-client", "ibc-core-connection-types", @@ -1378,7 +1379,7 @@ dependencies = [ [[package]] name = "ibc-core-connection-types" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1394,7 +1395,7 @@ dependencies = [ [[package]] name = "ibc-core-handler" -version = "0.53.0" +version = "0.54.0" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -1408,7 +1409,7 @@ dependencies = [ [[package]] name = "ibc-core-handler-types" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1427,7 +1428,7 @@ dependencies = [ [[package]] name = "ibc-core-host" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1444,7 +1445,7 @@ dependencies = [ [[package]] name = "ibc-core-host-cosmos" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1466,17 +1467,19 @@ dependencies = [ [[package]] name = "ibc-core-host-types" -version = "0.53.0" +version = "0.54.0" dependencies = [ + "base64 0.22.1", "derive_more", "displaydoc", "ibc-primitives", + "prost", "serde", ] [[package]] name = "ibc-core-router" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1489,7 +1492,7 @@ dependencies = [ [[package]] name = "ibc-core-router-types" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1503,7 +1506,7 @@ dependencies = [ [[package]] name = "ibc-derive" -version = "0.7.0" +version = "0.8.0" dependencies = [ "proc-macro2", "quote", @@ -1512,7 +1515,7 @@ dependencies = [ [[package]] name = "ibc-primitives" -version = "0.53.0" +version = "0.54.0" dependencies = [ "derive_more", "displaydoc", @@ -1525,9 +1528,9 @@ dependencies = [ [[package]] name = "ibc-proto" -version = "0.46.0" +version = "0.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb09e0b52b8a16e98ce98845e7c15b018440f3c56defa12fa44782cd66bab65" +checksum = "c852d22b782d2d793f4a646f968de419be635e02bc8798d5d74a6e44eef27733" dependencies = [ "base64 0.22.1", "borsh", @@ -1545,9 +1548,9 @@ dependencies = [ [[package]] name = "ics23" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc3b8be84e7285c73b88effdc3294b552277d6b0ec728ee016c861b7b9a2c19c" +checksum = "73b17f1a5bd7d12ad30a21445cfa5f52fd7651cb3243ba866f9916b1ec112f12" dependencies = [ "anyhow", "blake2", @@ -2130,9 +2133,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.6" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" dependencies = [ "bytes", "prost-derive", @@ -2140,9 +2143,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.6" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ "anyhow", "itertools 0.12.1", @@ -2153,9 +2156,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.12.6" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" dependencies = [ "prost", ] @@ -3034,9 +3037,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tendermint" -version = "0.37.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "954496fbc9716eb4446cdd6d00c071a3e2f22578d62aa03b40c7e5b4fda3ed42" +checksum = "505d9d6ffeb83b1de47c307c6e0d2dff56c6256989299010ad03cd80a8491e97" dependencies = [ "bytes", "digest 0.10.7", @@ -3063,9 +3066,9 @@ dependencies = [ [[package]] name = "tendermint-light-client-verifier" -version = "0.37.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3848090df4502a09ee27cb1a00f1835e1111c8993b22c5e1e41ffb7f6f09d57e" +checksum = "7a2674adbf0dc51aa0c8eaf8462c7d6692ec79502713e50ed5432a442002be90" dependencies = [ "derive_more", "flex-error", @@ -3076,9 +3079,9 @@ dependencies = [ [[package]] name = "tendermint-proto" -version = "0.37.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc87024548c7f3da479885201e3da20ef29e85a3b13d04606b380ac4c7120d87" +checksum = "8ed14abe3b0502a3afe21ca74ca5cdd6c7e8d326d982c26f98a394445eb31d6e" dependencies = [ "bytes", "flex-error", diff --git a/ibc-apps/ics20-transfer/src/module.rs b/ibc-apps/ics20-transfer/src/module.rs index 66370f10c..5958184c7 100644 --- a/ibc-apps/ics20-transfer/src/module.rs +++ b/ibc-apps/ics20-transfer/src/module.rs @@ -7,6 +7,7 @@ use ibc_core::channel::types::channel::{Counterparty, Order}; use ibc_core::channel::types::packet::Packet; use ibc_core::channel::types::Version; use ibc_core::handler::types::error::ContextError; +use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc_core::primitives::prelude::*; use ibc_core::primitives::Signer; @@ -269,8 +270,11 @@ pub fn on_timeout_packet_validate( where Ctx: TokenTransferValidationContext, { - let data = serde_json::from_slice::(&packet.data) - .map_err(|_| TokenTransferError::FailedToDeserializePacketData)?; + let data = serde_json::from_slice::(&packet.data).map_err(|e| { + DecodingError::InvalidJson { + description: format!("failed to deserialize packet data: {e}"), + } + })?; refund_packet_token_validate(ctx, packet, &data)?; @@ -285,7 +289,10 @@ pub fn on_timeout_packet_execute( let Ok(data) = serde_json::from_slice::(&packet.data) else { return ( ModuleExtras::empty(), - Err(TokenTransferError::FailedToDeserializePacketData), + Err(DecodingError::InvalidJson { + description: "failed to deserialize packet data".to_string(), + } + .into()), ); }; diff --git a/ibc-apps/ics20-transfer/types/src/coin.rs b/ibc-apps/ics20-transfer/types/src/coin.rs index 9470bbdbc..3a8b7387f 100644 --- a/ibc-apps/ics20-transfer/types/src/coin.rs +++ b/ibc-apps/ics20-transfer/types/src/coin.rs @@ -76,7 +76,7 @@ where .chars() .all(|x| x.is_alphanumeric() || VALID_DENOM_CHARACTERS.contains(x)) }) - .ok_or_else(|| TokenTransferError::InvalidCoin(coin_str.to_string()))?; + .ok_or_else(|| TokenTransferError::InvalidCoin(coin_str.to_owned()))?; Ok(Coin { amount: amount.parse()?, diff --git a/ibc-apps/ics20-transfer/types/src/denom.rs b/ibc-apps/ics20-transfer/types/src/denom.rs index cc814280f..ce014ee68 100644 --- a/ibc-apps/ics20-transfer/types/src/denom.rs +++ b/ibc-apps/ics20-transfer/types/src/denom.rs @@ -219,7 +219,7 @@ impl FromStr for TracePath { remaining_parts .is_none() .then_some(trace_path) - .ok_or_else(|| TokenTransferError::InvalidTrace(s.to_string())) + .ok_or_else(|| TokenTransferError::InvalidTrace(s.to_owned())) } } diff --git a/ibc-apps/ics20-transfer/types/src/error.rs b/ibc-apps/ics20-transfer/types/src/error.rs index 7924e2609..15efb347f 100644 --- a/ibc-apps/ics20-transfer/types/src/error.rs +++ b/ibc-apps/ics20-transfer/types/src/error.rs @@ -5,7 +5,7 @@ use displaydoc::Display; use ibc_core::channel::types::acknowledgement::StatusValue; use ibc_core::channel::types::channel::Order; use ibc_core::handler::types::error::ContextError; -use ibc_core::host::types::error::IdentifierError; +use ibc_core::host::types::error::{DecodingError, IdentifierError}; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; use uint::FromDecStrErr; @@ -14,14 +14,14 @@ use uint::FromDecStrErr; pub enum TokenTransferError { /// context error: `{0}` ContextError(ContextError), - /// invalid identifier: `{0}` - InvalidIdentifier(IdentifierError), - /// invalid trace: `{0}` - InvalidTrace(String), + /// decoding error: `{0}` + Decoding(DecodingError), /// invalid amount: `{0}` InvalidAmount(FromDecStrErr), /// invalid coin: `{0}` InvalidCoin(String), + /// invalid trace: `{0}` + InvalidTrace(String), /// missing token MissingToken, /// missing destination channel `{channel_id}` on port `{port_id}` @@ -33,22 +33,19 @@ pub enum TokenTransferError { MismatchedChannelOrders { expected: Order, actual: Order }, /// mismatched port IDs: expected `{expected}`, actual `{actual}` MismatchedPortIds { expected: PortId, actual: PortId }, + /// channel cannot be closed + UnsupportedClosedChannel, + /// empty base denomination + EmptyBaseDenom, /// failed to deserialize packet data FailedToDeserializePacketData, /// failed to deserialize acknowledgement FailedToDeserializeAck, + // TODO(seanchen1991): Used in basecoin; this variant should be moved // to a host-relevant error /// failed to parse account ID FailedToParseAccount, - /// failed to decode raw msg: `{description}` - FailedToDecodeRawMsg { description: String }, - /// channel cannot be closed - UnsupportedClosedChannel, - /// empty base denomination - EmptyBaseDenom, - /// unknown msg type: `{0}` - UnknownMsgType(String), } #[cfg(feature = "std")] @@ -56,8 +53,8 @@ impl std::error::Error for TokenTransferError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { Self::ContextError(e) => Some(e), - Self::InvalidIdentifier(e) => Some(e), Self::InvalidAmount(e) => Some(e), + Self::Decoding(e) => Some(e), _ => None, } } @@ -70,19 +67,25 @@ impl From for TokenTransferError { } impl From for TokenTransferError { - fn from(err: ContextError) -> TokenTransferError { - Self::ContextError(err) + fn from(e: ContextError) -> Self { + Self::ContextError(e) } } impl From for TokenTransferError { - fn from(err: IdentifierError) -> TokenTransferError { - Self::InvalidIdentifier(err) + fn from(e: IdentifierError) -> Self { + Self::Decoding(DecodingError::Identifier(e)) + } +} + +impl From for TokenTransferError { + fn from(e: DecodingError) -> Self { + Self::Decoding(e) } } impl From for StatusValue { - fn from(err: TokenTransferError) -> Self { - StatusValue::new(err.to_string()).expect("error message must not be empty") + fn from(e: TokenTransferError) -> Self { + StatusValue::new(e.to_string()).expect("error message must not be empty") } } diff --git a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs index 048ea956c..fcc23863b 100644 --- a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs @@ -3,6 +3,7 @@ use ibc_core::channel::types::error::PacketError; use ibc_core::channel::types::timeout::{TimeoutHeight, TimeoutTimestamp}; use ibc_core::handler::types::error::ContextError; +use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; use ibc_proto::google::protobuf::Any; @@ -104,12 +105,11 @@ impl TryFrom for MsgTransfer { fn try_from(raw: Any) -> Result { match raw.type_url.as_str() { - TYPE_URL => MsgTransfer::decode_vec(&raw.value).map_err(|e| { - TokenTransferError::FailedToDecodeRawMsg { - description: e.to_string(), - } - }), - _ => Err(TokenTransferError::UnknownMsgType(raw.type_url)), + TYPE_URL => Ok(MsgTransfer::decode_vec(&raw.value).map_err(DecodingError::Protobuf)?), + _ => Err(DecodingError::MismatchedTypeUrls { + expected: TYPE_URL.to_string(), + actual: raw.type_url, + })?, } } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/data.rs b/ibc-apps/ics721-nft-transfer/types/src/data.rs index 8150545bb..a54d990af 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/data.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/data.rs @@ -6,6 +6,8 @@ use core::str::FromStr; use base64::prelude::BASE64_STANDARD; #[cfg(feature = "serde")] use base64::Engine; +#[cfg(feature = "serde")] +use ibc_core::host::types::error::DecodingError; use ibc_core::primitives::prelude::*; use mime::Mime; @@ -97,8 +99,10 @@ impl FromStr for Ics721Data { type Err = NftTransferError; fn from_str(s: &str) -> Result { - serde_json::from_str(s).map_err(|e| NftTransferError::InvalidJsonData { - description: e.to_string(), + serde_json::from_str(s).map_err(|e| { + NftTransferError::Decoding(DecodingError::InvalidJson { + description: e.to_string(), + }) }) } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/error.rs b/ibc-apps/ics721-nft-transfer/types/src/error.rs index 626eb9f6d..39d6463fb 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/error.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/error.rs @@ -2,25 +2,24 @@ use core::convert::Infallible; use displaydoc::Display; +use http::uri::InvalidUri; use ibc_core::channel::types::acknowledgement::StatusValue; use ibc_core::channel::types::channel::Order; use ibc_core::handler::types::error::ContextError; -use ibc_core::host::types::error::IdentifierError; +use ibc_core::host::types::error::{DecodingError, IdentifierError}; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; -#[derive(Display, Debug)] +#[derive(Display, Debug, derive_more::From)] pub enum NftTransferError { /// context error: `{0}` ContextError(ContextError), - /// invalid identifier: `{0}` - InvalidIdentifier(IdentifierError), - /// invalid URI: `{0}` - InvalidUri(http::uri::InvalidUri), - /// invalid json data: `{description}` - InvalidJsonData { description: String }, - /// invalid trace `{0}` + /// decoding error: `{0}` + Decoding(DecodingError), + /// invalid trace: `{0}` InvalidTrace(String), + /// invalid URI error: `{0}` + InvalidUri(InvalidUri), /// missing destination channel `{channel_id}` on port `{port_id}` MissingDestinationChannel { port_id: PortId, @@ -42,12 +41,8 @@ pub enum NftTransferError { FailedToDeserializeAck, /// failed to parse account ID FailedToParseAccount, - /// failed to decode raw msg: `{description}` - FailedToDecodeRawMsg { description: String }, /// channel cannot be closed UnsupportedClosedChannel, - /// unknown msg type: `{0}` - UnknownMsgType(String), } #[cfg(feature = "std")] @@ -55,28 +50,21 @@ impl std::error::Error for NftTransferError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { Self::ContextError(e) => Some(e), - Self::InvalidUri(e) => Some(e), - Self::InvalidIdentifier(e) => Some(e), + Self::Decoding(e) => Some(e), _ => None, } } } -impl From for NftTransferError { - fn from(e: Infallible) -> Self { - match e {} - } -} - -impl From for NftTransferError { - fn from(err: ContextError) -> NftTransferError { - Self::ContextError(err) +impl From for NftTransferError { + fn from(e: IdentifierError) -> Self { + Self::Decoding(DecodingError::Identifier(e)) } } -impl From for NftTransferError { - fn from(err: IdentifierError) -> NftTransferError { - Self::InvalidIdentifier(err) +impl From for NftTransferError { + fn from(e: Infallible) -> Self { + match e {} } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs index 499d7d448..5b2bfb077 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs @@ -3,6 +3,7 @@ use ibc_core::channel::types::error::PacketError; use ibc_core::channel::types::timeout::{TimeoutHeight, TimeoutTimestamp}; use ibc_core::handler::types::error::ContextError; +use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; use ibc_proto::google::protobuf::Any; @@ -122,12 +123,11 @@ impl TryFrom for MsgTransfer { fn try_from(raw: Any) -> Result { match raw.type_url.as_str() { - TYPE_URL => MsgTransfer::decode_vec(&raw.value).map_err(|e| { - NftTransferError::FailedToDecodeRawMsg { - description: e.to_string(), - } - }), - _ => Err(NftTransferError::UnknownMsgType(raw.type_url)), + TYPE_URL => Ok(MsgTransfer::decode_vec(&raw.value).map_err(DecodingError::Protobuf)?), + _ => Err(DecodingError::MismatchedTypeUrls { + expected: TYPE_URL.to_string(), + actual: raw.type_url, + })?, } } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/packet.rs b/ibc-apps/ics721-nft-transfer/types/src/packet.rs index 027e5fcb1..6a8813d07 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/packet.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/packet.rs @@ -2,6 +2,7 @@ use base64::prelude::BASE64_STANDARD; use base64::Engine; +use ibc_core::host::types::error::DecodingError; use ibc_core::primitives::prelude::*; #[cfg(feature = "serde")] use ibc_core::primitives::serializers; @@ -128,13 +129,8 @@ impl TryFrom for PacketData { } else { let decoded = BASE64_STANDARD .decode(raw_pkt_data.class_data) - .map_err(|e| NftTransferError::InvalidJsonData { - description: e.to_string(), - })?; - let data_str = - String::from_utf8(decoded).map_err(|e| NftTransferError::InvalidJsonData { - description: e.to_string(), - })?; + .map_err(DecodingError::Base64)?; + let data_str = String::from_utf8(decoded).map_err(DecodingError::StringUtf8)?; Some(data_str.parse()?) }; @@ -145,15 +141,10 @@ impl TryFrom for PacketData { .token_data .iter() .map(|data| { - let decoded = BASE64_STANDARD.decode(data).map_err(|e| { - NftTransferError::InvalidJsonData { - description: e.to_string(), - } - })?; - let data_str = - String::from_utf8(decoded).map_err(|e| NftTransferError::InvalidJsonData { - description: e.to_string(), - })?; + let decoded = BASE64_STANDARD + .decode(data) + .map_err(DecodingError::Base64)?; + let data_str = String::from_utf8(decoded).map_err(DecodingError::StringUtf8)?; data_str.parse() }) .collect(); diff --git a/ibc-clients/ics07-tendermint/src/client_state/common.rs b/ibc-clients/ics07-tendermint/src/client_state/common.rs index 66ac52aec..ca0a82eec 100644 --- a/ibc-clients/ics07-tendermint/src/client_state/common.rs +++ b/ibc-clients/ics07-tendermint/src/client_state/common.rs @@ -66,10 +66,7 @@ impl ClientStateCommon for ClientState { let upgrade_path = &self.inner().upgrade_path; let (upgrade_path_prefix, upgrade_path) = match upgrade_path.len() { 0 => { - return Err(UpgradeClientError::InvalidUpgradePath { - description: "no upgrade path has been set".to_string(), - } - .into()); + return Err(UpgradeClientError::MissingUpgradePath.into()); } 1 => (CommitmentPrefix::empty(), upgrade_path[0].clone()), 2 => ( @@ -166,7 +163,7 @@ pub fn verify_consensus_state( }; if consensus_state_status(&tm_consensus_state, host_timestamp, trusting_period)?.is_expired() { - return Err(ClientError::InvalidStatus(Status::Expired)); + return Err(ClientError::UnexpectedStatus(Status::Expired)); } Ok(()) diff --git a/ibc-clients/ics07-tendermint/types/src/client_state.rs b/ibc-clients/ics07-tendermint/types/src/client_state.rs index 98ce38460..91ab3d944 100644 --- a/ibc-clients/ics07-tendermint/types/src/client_state.rs +++ b/ibc-clients/ics07-tendermint/types/src/client_state.rs @@ -8,6 +8,7 @@ use ibc_core_client_types::error::ClientError; use ibc_core_client_types::proto::v1::Height as RawHeight; use ibc_core_client_types::Height; use ibc_core_commitment_types::specs::ProofSpecs; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ChainId; use ibc_primitives::prelude::*; use ibc_primitives::ZERO_DURATION; @@ -240,48 +241,64 @@ impl TryFrom for ClientState { let chain_id = ChainId::from_str(raw.chain_id.as_str())?; let trust_level = { - let trust_level = raw - .trust_level - .ok_or(TendermintClientError::MissingTrustingPeriod)?; + let trust_level = raw.trust_level.ok_or(DecodingError::MissingRawData { + description: "trust level not set".to_string(), + })?; trust_level .try_into() - .map_err(|e| TendermintClientError::InvalidTrustThreshold { - description: format!("{e}"), + .map_err(|e| DecodingError::InvalidRawData { + description: format!("failed to decoding trust threshold: {e}"), })? }; let trusting_period = raw .trusting_period - .ok_or(TendermintClientError::MissingTrustingPeriod)? + .ok_or(DecodingError::MissingRawData { + description: "trusting period not set".to_string(), + })? .try_into() - .map_err(|_| TendermintClientError::MissingTrustingPeriod)?; + .map_err(|_| DecodingError::InvalidRawData { + description: "failed to decode trusting period".to_string(), + })?; let unbonding_period = raw .unbonding_period - .ok_or(TendermintClientError::MissingUnbondingPeriod)? + .ok_or(DecodingError::MissingRawData { + description: "unbonding period not set".to_string(), + })? .try_into() - .map_err(|_| TendermintClientError::MissingUnbondingPeriod)?; + .map_err(|_| DecodingError::InvalidRawData { + description: "failed to decode unbonding period".to_string(), + })?; let max_clock_drift = raw .max_clock_drift - .ok_or(TendermintClientError::InvalidMaxClockDrift)? + .ok_or(DecodingError::MissingRawData { + description: "max clock drift not set".to_string(), + })? .try_into() - .map_err(|_| TendermintClientError::InvalidMaxClockDrift)?; + .map_err(|_| DecodingError::InvalidRawData { + description: "failed to decode max clock drift".to_string(), + })?; let latest_height = raw .latest_height - .ok_or(TendermintClientError::MissingLatestHeight)? + .ok_or(DecodingError::MissingRawData { + description: "latest height not set".to_string(), + })? .try_into() - .map_err(|_| TendermintClientError::MissingLatestHeight)?; + .map_err(|e| DecodingError::InvalidRawData { + description: format!("failed to decode latest height: {e}"), + })?; // NOTE: In `RawClientState`, a `frozen_height` of `0` means "not // frozen". See: // https://github.com/cosmos/ibc-go/blob/8422d0c4c35ef970539466c5bdec1cd27369bab3/modules/light-clients/07-tendermint/types/client_state.go#L74 - let frozen_height = Height::try_from( - raw.frozen_height - .ok_or(TendermintClientError::MissingFrozenHeight)?, - ) - .ok(); + let frozen_height = + Height::try_from(raw.frozen_height.ok_or(DecodingError::MissingRawData { + description: "frozen height not set".to_string(), + })?) + .ok(); // We use set this deprecated field just so that we can properly convert // it back in its raw form @@ -341,17 +358,20 @@ impl TryFrom for ClientState { type Error = ClientError; fn try_from(raw: Any) -> Result { - fn decode_client_state(value: &[u8]) -> Result { + fn decode_client_state(value: &[u8]) -> Result { let client_state = - Protobuf::::decode(value).map_err(|e| ClientError::Other { - description: e.to_string(), - })?; + Protobuf::::decode(value).map_err(DecodingError::Protobuf)?; Ok(client_state) } match raw.type_url.as_str() { - TENDERMINT_CLIENT_STATE_TYPE_URL => decode_client_state(&raw.value), - _ => Err(ClientError::InvalidClientStateType(raw.type_url)), + TENDERMINT_CLIENT_STATE_TYPE_URL => { + decode_client_state(&raw.value).map_err(ClientError::Decoding) + } + _ => Err(DecodingError::MismatchedTypeUrls { + expected: TENDERMINT_CLIENT_STATE_TYPE_URL.to_string(), + actual: raw.type_url, + })?, } } } diff --git a/ibc-clients/ics07-tendermint/types/src/consensus_state.rs b/ibc-clients/ics07-tendermint/types/src/consensus_state.rs index ec66fb264..723da3497 100644 --- a/ibc-clients/ics07-tendermint/types/src/consensus_state.rs +++ b/ibc-clients/ics07-tendermint/types/src/consensus_state.rs @@ -2,6 +2,7 @@ use ibc_core_client_types::error::ClientError; use ibc_core_commitment_types::commitment::CommitmentRoot; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::lightclients::tendermint::v1::ConsensusState as RawConsensusState; @@ -11,7 +12,6 @@ use tendermint::time::Time; use tendermint::Hash; use tendermint_proto::google::protobuf as tpb; -use crate::error::TendermintClientError; use crate::header::Header; pub const TENDERMINT_CONSENSUS_STATE_TYPE_URL: &str = @@ -47,32 +47,31 @@ impl ConsensusState { impl Protobuf for ConsensusState {} impl TryFrom for ConsensusState { - type Error = TendermintClientError; + type Error = DecodingError; fn try_from(raw: RawConsensusState) -> Result { let proto_root = raw .root - .ok_or(TendermintClientError::InvalidRawClientState { - description: "missing commitment root".into(), + .ok_or(DecodingError::MissingRawData { + description: "no commitment root set".into(), })? .hash; let ibc_proto::google::protobuf::Timestamp { seconds, nanos } = - raw.timestamp - .ok_or(TendermintClientError::InvalidRawClientState { - description: "missing timestamp".into(), - })?; + raw.timestamp.ok_or(DecodingError::MissingRawData { + description: "no timestamp set".into(), + })?; // FIXME: shunts like this are necessary due to // https://github.com/informalsystems/tendermint-rs/issues/1053 let proto_timestamp = tpb::Timestamp { seconds, nanos }; - let timestamp = proto_timestamp.try_into().map_err(|e| { - TendermintClientError::InvalidRawClientState { + let timestamp = proto_timestamp + .try_into() + .map_err(|e| DecodingError::InvalidRawData { description: format!("invalid timestamp: {e}"), - } - })?; + })?; let next_validators_hash = Hash::from_bytes(Algorithm::Sha256, &raw.next_validators_hash) - .map_err(|e| TendermintClientError::InvalidRawClientState { + .map_err(|e| DecodingError::InvalidHash { description: e.to_string(), })?; @@ -107,17 +106,19 @@ impl TryFrom for ConsensusState { type Error = ClientError; fn try_from(raw: Any) -> Result { - fn decode_consensus_state(value: &[u8]) -> Result { - let client_state = - Protobuf::::decode(value).map_err(|e| ClientError::Other { - description: e.to_string(), - })?; + fn decode_consensus_state(value: &[u8]) -> Result { + let client_state = Protobuf::::decode(value)?; Ok(client_state) } match raw.type_url.as_str() { - TENDERMINT_CONSENSUS_STATE_TYPE_URL => decode_consensus_state(&raw.value), - _ => Err(ClientError::InvalidConsensusStateType(raw.type_url)), + TENDERMINT_CONSENSUS_STATE_TYPE_URL => { + decode_consensus_state(&raw.value).map_err(ClientError::Decoding) + } + _ => Err(DecodingError::MismatchedTypeUrls { + expected: TENDERMINT_CONSENSUS_STATE_TYPE_URL.to_string(), + actual: raw.type_url, + })?, } } } diff --git a/ibc-clients/ics07-tendermint/types/src/error.rs b/ibc-clients/ics07-tendermint/types/src/error.rs index 45f00354e..eb4c2c67d 100644 --- a/ibc-clients/ics07-tendermint/types/src/error.rs +++ b/ibc-clients/ics07-tendermint/types/src/error.rs @@ -4,11 +4,12 @@ use core::time::Duration; use displaydoc::Display; use ibc_core_client_types::error::ClientError; +use ibc_core_client_types::Height; use ibc_core_commitment_types::error::CommitmentError; -use ibc_core_host_types::error::IdentifierError; +use ibc_core_host_types::error::{DecodingError, IdentifierError}; use ibc_primitives::prelude::*; use ibc_primitives::TimestampError; -use tendermint::{Error as TendermintError, Hash}; +use tendermint::Hash; use tendermint_light_client_verifier::errors::VerificationErrorDetail as LightClientErrorDetail; use tendermint_light_client_verifier::operations::VotingPowerTally; use tendermint_light_client_verifier::Verdict; @@ -16,40 +17,18 @@ use tendermint_light_client_verifier::Verdict; /// The main error type for the Tendermint light client #[derive(Debug, Display)] pub enum TendermintClientError { - /// invalid identifier: `{0}` - InvalidIdentifier(IdentifierError), + /// decoding error: `{0}` + Decoding(DecodingError), /// invalid client state trust threshold: `{description}` InvalidTrustThreshold { description: String }, /// invalid clock drift; must be greater than 0 InvalidMaxClockDrift, /// invalid client proof specs: `{0}` InvalidProofSpec(CommitmentError), - /// invalid raw client state: `{description}` - InvalidRawClientState { description: String }, - /// invalid raw header error: `{0}` - InvalidRawHeader(TendermintError), - /// invalid raw misbehaviour: `{description}` - InvalidRawMisbehaviour { description: String }, /// invalid header timestamp: `{0}` InvalidHeaderTimestamp(TimestampError), /// invalid header height: `{0}` InvalidHeaderHeight(u64), - /// missing signed header - MissingSignedHeader, - /// missing validator set - MissingValidatorSet, - /// missing trusted next validator set - MissingTrustedNextValidatorSet, - /// missing trusted height - MissingTrustedHeight, - /// missing trusting period - MissingTrustingPeriod, - /// missing unbonding period - MissingUnbondingPeriod, - /// missing the latest height - MissingLatestHeight, - /// missing frozen height - MissingFrozenHeight, /// mismatched revision heights: expected `{expected}`, actual `{actual}` MismatchedRevisionHeights { expected: u64, actual: u64 }, /// mismatched header chain ids: expected `{expected}`, actual `{actual}` @@ -67,19 +46,22 @@ pub enum TendermintClientError { duration_since_consensus_state: Duration, trusting_period: Duration, }, + /// insufficient misbehaviour header height: header1 height `{height_1}` should be >= header2 height `{height_2}` + InsufficientMisbehaviourHeaderHeight { height_1: Height, height_2: Height }, } #[cfg(feature = "std")] impl std::error::Error for TendermintClientError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::InvalidIdentifier(e) => Some(e), - Self::InvalidRawHeader(e) => Some(e), + Self::Decoding(e) => Some(e), _ => None, } } } +// TODO(seanchen1991): Should this impl be deprecated in favor of a +// From for TendermintClientError impl? impl From for ClientError { fn from(e: TendermintClientError) -> Self { Self::ClientSpecific { @@ -90,7 +72,7 @@ impl From for ClientError { impl From for TendermintClientError { fn from(e: IdentifierError) -> Self { - Self::InvalidIdentifier(e) + Self::Decoding(DecodingError::Identifier(e)) } } @@ -100,6 +82,12 @@ impl From for TendermintClientError { } } +impl From for TendermintClientError { + fn from(e: DecodingError) -> Self { + Self::Decoding(e) + } +} + pub trait IntoResult { fn into_result(self) -> Result; } diff --git a/ibc-clients/ics07-tendermint/types/src/header.rs b/ibc-clients/ics07-tendermint/types/src/header.rs index 72fc83333..aaadfde07 100644 --- a/ibc-clients/ics07-tendermint/types/src/header.rs +++ b/ibc-clients/ics07-tendermint/types/src/header.rs @@ -5,6 +5,7 @@ use core::str::FromStr; use ibc_core_client_types::error::ClientError; use ibc_core_client_types::Height; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ChainId; use ibc_primitives::prelude::*; use ibc_primitives::Timestamp; @@ -170,23 +171,37 @@ impl TryFrom for Header { let header = Self { signed_header: raw .signed_header - .ok_or(TendermintClientError::MissingSignedHeader)? + .ok_or(DecodingError::MissingRawData { + description: "signed header not set".to_string(), + })? .try_into() - .map_err(TendermintClientError::InvalidRawHeader)?, + .map_err(|e| DecodingError::InvalidRawData { + description: format!("failed to decode signed header: {e:?}"), + })?, validator_set: raw .validator_set - .ok_or(TendermintClientError::MissingValidatorSet)? + .ok_or(DecodingError::MissingRawData { + description: "validator set not set".to_string(), + })? .try_into() - .map_err(TendermintClientError::InvalidRawHeader)?, + .map_err(|e| DecodingError::InvalidRawData { + description: format!("failed to decode validator set: {e:?}"), + })?, trusted_height: raw .trusted_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(TendermintClientError::MissingTrustedHeight)?, + .ok_or(DecodingError::MissingRawData { + description: "trusted height not set".to_string(), + })?, trusted_next_validator_set: raw .trusted_validators - .ok_or(TendermintClientError::MissingTrustedNextValidatorSet)? + .ok_or(DecodingError::MissingRawData { + description: "trusted next validator set not set".to_string(), + })? .try_into() - .map_err(TendermintClientError::InvalidRawHeader)?, + .map_err(|e| DecodingError::InvalidRawData { + description: format!("failed to decode trusted next validator set: {e:?}"), + })?, }; Ok(header) @@ -199,15 +214,16 @@ impl TryFrom for Header { type Error = ClientError; fn try_from(raw: Any) -> Result { - fn decode_header(value: &[u8]) -> Result { - let header = Protobuf::::decode(value).map_err(|e| ClientError::Other { - description: e.to_string(), - })?; + fn decode_header(value: &[u8]) -> Result { + let header = Protobuf::::decode(value)?; Ok(header) } match raw.type_url.as_str() { - TENDERMINT_HEADER_TYPE_URL => decode_header(&raw.value), - _ => Err(ClientError::InvalidHeaderType(raw.type_url)), + TENDERMINT_HEADER_TYPE_URL => decode_header(&raw.value).map_err(ClientError::Decoding), + _ => Err(DecodingError::MismatchedTypeUrls { + expected: TENDERMINT_HEADER_TYPE_URL.to_string(), + actual: raw.type_url, + })?, } } } diff --git a/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs b/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs index dc35a34ec..17de928e7 100644 --- a/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs +++ b/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs @@ -1,6 +1,7 @@ //! Defines the misbehaviour type for the tendermint light client use ibc_core_client_types::error::ClientError; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_proto::google::protobuf::Any; @@ -52,19 +53,19 @@ impl Misbehaviour { if self.header1.signed_header.header.chain_id != self.header2.signed_header.header.chain_id { - return Err(TendermintClientError::InvalidRawMisbehaviour { - description: "headers must have identical chain_ids".to_owned(), + return Err(TendermintClientError::MismatchedHeaderChainIds { + expected: self.header1.signed_header.header.chain_id.to_string(), + actual: self.header2.signed_header.header.chain_id.to_string(), }); } if self.header1.height() < self.header2.height() { - return Err(TendermintClientError::InvalidRawMisbehaviour { - description: format!( - "header1 height is less than header2 height ({} < {})", - self.header1.height(), - self.header2.height() - ), - }); + return Err( + TendermintClientError::InsufficientMisbehaviourHeaderHeight { + height_1: self.header1.height(), + height_2: self.header2.height(), + }, + ); } Ok(()) @@ -81,15 +82,15 @@ impl TryFrom for Misbehaviour { let header1: Header = raw .header_1 - .ok_or_else(|| TendermintClientError::InvalidRawMisbehaviour { - description: "missing header1".into(), + .ok_or_else(|| DecodingError::MissingRawData { + description: "missing header1 in raw misbehaviour".into(), })? .try_into()?; let header2: Header = raw .header_2 - .ok_or_else(|| TendermintClientError::InvalidRawMisbehaviour { - description: "missing header2".into(), + .ok_or_else(|| DecodingError::MissingRawData { + description: "missing header2 in raw misbehaviour".into(), })? .try_into()?; @@ -114,16 +115,18 @@ impl TryFrom for Misbehaviour { type Error = ClientError; fn try_from(raw: Any) -> Result { - fn decode_misbehaviour(value: &[u8]) -> Result { - let misbehaviour = - Protobuf::::decode(value).map_err(|e| ClientError::Other { - description: e.to_string(), - })?; + fn decode_misbehaviour(value: &[u8]) -> Result { + let misbehaviour = Protobuf::::decode(value)?; Ok(misbehaviour) } match raw.type_url.as_str() { - TENDERMINT_MISBEHAVIOUR_TYPE_URL => decode_misbehaviour(&raw.value), - _ => Err(ClientError::InvalidMisbehaviourType(raw.type_url)), + TENDERMINT_MISBEHAVIOUR_TYPE_URL => { + decode_misbehaviour(&raw.value).map_err(ClientError::Decoding) + } + _ => Err(DecodingError::MismatchedTypeUrls { + expected: TENDERMINT_MISBEHAVIOUR_TYPE_URL.to_string(), + actual: raw.type_url, + })?, } } } diff --git a/ibc-clients/ics08-wasm/types/src/client_state.rs b/ibc-clients/ics08-wasm/types/src/client_state.rs index c8c4aca41..b7506267a 100644 --- a/ibc-clients/ics08-wasm/types/src/client_state.rs +++ b/ibc-clients/ics08-wasm/types/src/client_state.rs @@ -1,11 +1,11 @@ //! Defines the client state type for the ICS-08 Wasm light client. use ibc_core_client::types::Height; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_primitives::proto::{Any, Protobuf}; use ibc_proto::ibc::lightclients::wasm::v1::ClientState as RawClientState; -use crate::error::WasmClientError; #[cfg(feature = "serde")] use crate::serializer::Base64; use crate::Bytes; @@ -38,14 +38,18 @@ impl From for RawClientState { } impl TryFrom for ClientState { - type Error = WasmClientError; + type Error = DecodingError; fn try_from(raw: RawClientState) -> Result { let latest_height = raw .latest_height - .ok_or(WasmClientError::MissingLatestHeight)? + .ok_or(DecodingError::MissingRawData { + description: "latest height not set".to_string(), + })? .try_into() - .map_err(|_| WasmClientError::InvalidLatestHeight)?; + .map_err(|e| DecodingError::InvalidRawData { + description: format!("failed to decode latest height: {e}"), + })?; Ok(Self { data: raw.data, checksum: raw.checksum, @@ -66,25 +70,20 @@ impl From for Any { } impl TryFrom for ClientState { - type Error = WasmClientError; + type Error = DecodingError; fn try_from(any: Any) -> Result { - fn decode_client_state(value: &[u8]) -> Result { - let client_state = Protobuf::::decode(value).map_err(|e| { - WasmClientError::DecodingError { - description: e.to_string(), - } - })?; - + fn decode_client_state(value: &[u8]) -> Result { + let client_state = Protobuf::::decode(value)?; Ok(client_state) } match any.type_url.as_str() { WASM_CLIENT_STATE_TYPE_URL => decode_client_state(&any.value), - other_type_url => Err(WasmClientError::MismatchedTypeUrls { + _ => Err(DecodingError::MismatchedTypeUrls { expected: WASM_CLIENT_STATE_TYPE_URL.to_string(), - actual: other_type_url.to_string(), - }), + actual: any.type_url, + })?, } } } diff --git a/ibc-clients/ics08-wasm/types/src/consensus_state.rs b/ibc-clients/ics08-wasm/types/src/consensus_state.rs index 597cc4e87..a1346cb32 100644 --- a/ibc-clients/ics08-wasm/types/src/consensus_state.rs +++ b/ibc-clients/ics08-wasm/types/src/consensus_state.rs @@ -1,6 +1,7 @@ //! Defines the consensus state type for the ICS-08 Wasm light client. use ibc_core_client::types::error::ClientError; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_primitives::proto::{Any, Protobuf}; use ibc_proto::ibc::lightclients::wasm::v1::ConsensusState as RawConsensusState; @@ -57,18 +58,18 @@ impl TryFrom for ConsensusState { type Error = ClientError; fn try_from(any: Any) -> Result { - fn decode_consensus_state(value: &[u8]) -> Result { - let consensus_state = - Protobuf::::decode(value).map_err(|e| ClientError::Other { - description: e.to_string(), - })?; + fn decode_consensus_state(value: &[u8]) -> Result { + let consensus_state = Protobuf::::decode(value)?; Ok(consensus_state) } match any.type_url.as_str() { - WASM_CONSENSUS_STATE_TYPE_URL => decode_consensus_state(&any.value), - _ => Err(ClientError::Other { - description: "type_url does not match".into(), - }), + WASM_CONSENSUS_STATE_TYPE_URL => { + decode_consensus_state(&any.value).map_err(ClientError::Decoding) + } + _ => Err(DecodingError::MismatchedTypeUrls { + expected: WASM_CONSENSUS_STATE_TYPE_URL.to_string(), + actual: any.type_url.to_string(), + })?, } } } diff --git a/ibc-clients/ics08-wasm/types/src/error.rs b/ibc-clients/ics08-wasm/types/src/error.rs deleted file mode 100644 index ecb3e1984..000000000 --- a/ibc-clients/ics08-wasm/types/src/error.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Defines the error type for the ICS-08 Wasm light client. - -use displaydoc::Display; -use ibc_core_host_types::error::IdentifierError; -use ibc_primitives::prelude::*; - -/// The main error type -#[derive(Debug, Display)] -pub enum WasmClientError { - /// invalid identifier: `{0}` - InvalidIdentifier(IdentifierError), - /// invalid client state latest height - InvalidLatestHeight, - /// missing latest height - MissingLatestHeight, - /// mismatched type URLs: expected `{expected}`, actual `{actual}` - MismatchedTypeUrls { expected: String, actual: String }, - /// decoding error: `{description}` - DecodingError { description: String }, -} - -#[cfg(feature = "std")] -impl std::error::Error for WasmClientError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::InvalidIdentifier(err) => Some(err), - _ => None, - } - } -} - -impl From for WasmClientError { - fn from(e: IdentifierError) -> Self { - Self::InvalidIdentifier(e) - } -} diff --git a/ibc-clients/ics08-wasm/types/src/lib.rs b/ibc-clients/ics08-wasm/types/src/lib.rs index 169eb3b30..3a88d0431 100644 --- a/ibc-clients/ics08-wasm/types/src/lib.rs +++ b/ibc-clients/ics08-wasm/types/src/lib.rs @@ -15,7 +15,6 @@ pub mod client_message; pub mod client_state; pub mod consensus_state; -pub mod error; pub mod msgs; #[cfg(feature = "serde")] diff --git a/ibc-clients/ics08-wasm/types/src/msgs/migrate_contract.rs b/ibc-clients/ics08-wasm/types/src/msgs/migrate_contract.rs index cd0bd9d3d..3f7bc6a93 100644 --- a/ibc-clients/ics08-wasm/types/src/msgs/migrate_contract.rs +++ b/ibc-clients/ics08-wasm/types/src/msgs/migrate_contract.rs @@ -1,12 +1,12 @@ use core::str::FromStr; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_primitives::Signer; use ibc_proto::ibc::lightclients::wasm::v1::MsgMigrateContract as RawMsgMigrateContract; use ibc_proto::Protobuf; -use crate::error::WasmClientError; use crate::Bytes; pub const MIGRATE_CONTRACT_TYPE_URL: &str = "/ibc.lightclients.wasm.v1.MsgMigrateContract"; @@ -34,7 +34,7 @@ impl From for RawMsgMigrateContract { } impl TryFrom for MsgMigrateContract { - type Error = WasmClientError; + type Error = DecodingError; fn try_from(value: RawMsgMigrateContract) -> Result { Ok(Self { diff --git a/ibc-core/ics02-client/src/handler/create_client.rs b/ibc-core/ics02-client/src/handler/create_client.rs index 263f8ffa4..47f5bab4a 100644 --- a/ibc-core/ics02-client/src/handler/create_client.rs +++ b/ibc-core/ics02-client/src/handler/create_client.rs @@ -36,7 +36,7 @@ where let status = client_state.status(client_val_ctx, &client_id)?; if status.is_frozen() { - return Err(ClientError::InvalidStatus(Status::Frozen).into()); + return Err(ClientError::UnexpectedStatus(Status::Frozen).into()); }; let host_timestamp = ctx.host_timestamp()?; @@ -44,7 +44,7 @@ where client_state.verify_consensus_state(consensus_state, &host_timestamp)?; if client_val_ctx.client_state(&client_id).is_ok() { - return Err(ClientError::AlreadyExistingClientState(client_id).into()); + return Err(ClientError::DuplicateClientState(client_id).into()); }; Ok(()) diff --git a/ibc-core/ics02-client/types/src/error.rs b/ibc-core/ics02-client/types/src/error.rs index 9b16557ad..06f0cfb53 100644 --- a/ibc-core/ics02-client/types/src/error.rs +++ b/ibc-core/ics02-client/types/src/error.rs @@ -4,37 +4,28 @@ use core::convert::Infallible; use displaydoc::Display; use ibc_core_commitment_types::error::CommitmentError; -use ibc_core_host_types::error::IdentifierError; +use ibc_core_host_types::error::{DecodingError, IdentifierError}; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_primitives::Timestamp; +use tendermint::Error as TendermintError; -use super::status::Status; use crate::height::Height; +use crate::Status; /// Encodes all the possible client errors #[derive(Debug, Display)] pub enum ClientError { /// upgrade client error: `{0}` Upgrade(UpgradeClientError), - /// invalid client status: `{0}` - InvalidStatus(Status), + /// decoding error: `{0}` + Decoding(DecodingError), /// invalid trust threshold: `{numerator}`/`{denominator}` InvalidTrustThreshold { numerator: u64, denominator: u64 }, /// invalid client state type: `{0}` InvalidClientStateType(String), - /// invalid client consensus state type: `{0}` - InvalidConsensusStateType(String), - /// invalid header type: `{0}` - InvalidHeaderType(String), /// invalid update client message InvalidUpdateClientMessage, - /// invalid client identifier: `{0}` - InvalidClientIdentifier(IdentifierError), - /// invalid raw header: `{description}` - InvalidRawHeader { description: String }, - /// invalid misbehaviour type: `{0}` - InvalidMisbehaviourType(String), /// invalid height; cannot be zero or negative InvalidHeight, /// invalid proof height; expected `{actual}` >= `{expected}` @@ -45,28 +36,18 @@ pub enum ClientError { InvalidAttributeKey(String), /// invalid attribute value: `{0}` InvalidAttributeValue(String), - /// missing client state for client: `{0}` - MissingClientState(ClientId), - /// missing consensus state for client `{client_id}` at height `{height}` - MissingConsensusState { client_id: ClientId, height: Height }, - /// missing update client metadata for client `{client_id}` at height `{height}` - MissingUpdateMetaData { client_id: ClientId, height: Height }, - /// missing raw client state - MissingRawClientState, - /// missing raw client consensus state - MissingRawConsensusState, - /// missing raw client message - MissingRawClientMessage, - /// missing raw misbehaviour - MissingRawMisbehaviour, + /// invalid status: `{0}` + InvalidStatus(String), /// missing local consensus state at `{0}` MissingLocalConsensusState(Height), /// missing attribute key MissingAttributeKey, /// missing attribute value MissingAttributeValue, + /// unexpected status found: `{0}` + UnexpectedStatus(Status), /// client state already exists: `{0}` - AlreadyExistingClientState(ClientId), + DuplicateClientState(ClientId), /// mismatched client recovery states MismatchedClientRecoveryStates, /// client recovery heights not allowed: expected substitute client height `{substitute_height}` > subject client height `{subject_height}` @@ -83,7 +64,18 @@ pub enum ClientError { /// client-specific error: `{description}` ClientSpecific { description: String }, - // TODO(seanchen1991): Incorporate these errors into their own variants + // TODO(seanchen1991): Add these to host-relevant errors + /// missing client state for client: `{0}` + MissingClientState(ClientId), + /// missing consensus state for client `{client_id}` at height `{height}` + MissingConsensusState { client_id: ClientId, height: Height }, + /// missing update client metadata for client `{client_id}` at height `{height}` + MissingUpdateMetaData { client_id: ClientId, height: Height }, + /// invalid raw header: `{0}` + InvalidRawHeader(TendermintError), + /// invalid header type: `{0}` + InvalidHeaderType(String), + // TODO(seanchen1991): Incorporate this error into its own variants /// other error: `{description}` Other { description: String }, } @@ -108,12 +100,24 @@ impl From for ClientError { } } +impl From for ClientError { + fn from(e: DecodingError) -> Self { + Self::Decoding(e) + } +} + +impl From for ClientError { + fn from(e: IdentifierError) -> Self { + Self::Decoding(DecodingError::Identifier(e)) + } +} + #[cfg(feature = "std")] impl std::error::Error for ClientError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::InvalidClientIdentifier(e) => Some(e), Self::FailedICS23Verification(e) => Some(e), + Self::Decoding(e) => Some(e), _ => None, } } @@ -122,35 +126,37 @@ impl std::error::Error for ClientError { /// Encodes all the possible upgrade client errors #[derive(Debug, Display)] pub enum UpgradeClientError { + /// decoding error: `{0}` + Decoding(DecodingError), /// invalid proof for the upgraded client state: `{0}` - InvalidUpgradeClientProof(CommitmentError), + InvalidUpgradeClientStateProof(CommitmentError), /// invalid proof for the upgraded consensus state: `{0}` InvalidUpgradeConsensusStateProof(CommitmentError), /// invalid upgrade path: `{description}` InvalidUpgradePath { description: String }, - /// invalid upgrade proposal: `{description}` - InvalidUpgradeProposal { description: String }, + /// missing upgrade path + MissingUpgradePath, + /// insufficient upgrade client height `{upgraded_height}`; must be greater than current client height `{client_height}` + InsufficientUpgradeHeight { + upgraded_height: Height, + client_height: Height, + }, + + // TODO(seanchen1991): Move these variants to host-relevant errors /// invalid upgrade plan: `{description}` InvalidUpgradePlan { description: String }, - /// mismatched type URLs: expected `{expected}`, actual `{actual}` - MismatchedTypeUrls { expected: String, actual: String }, + /// invalid upgrade proposal: `{description}` + InvalidUpgradeProposal { description: String }, /// missing upgraded client state MissingUpgradedClientState, /// missing upgraded consensus state MissingUpgradedConsensusState, - /// failed to decode raw upgrade plan: `{description}` - FailedToDecodeRawUpgradePlan { description: String }, /// failed to store upgrade plan: `{description}` FailedToStoreUpgradePlan { description: String }, /// failed to store upgraded client state: `{description}` FailedToStoreUpgradedClientState { description: String }, /// failed to store upgraded consensus state: `{description}` FailedToStoreUpgradedConsensusState { description: String }, - /// insufficient upgrade client height `{upgraded_height}`; must be greater than current client height `{client_height}` - InsufficientUpgradeHeight { - upgraded_height: Height, - client_height: Height, - }, } impl From for ClientError { @@ -159,13 +165,18 @@ impl From for ClientError { } } +impl From for UpgradeClientError { + fn from(e: DecodingError) -> Self { + Self::Decoding(e) + } +} + #[cfg(feature = "std")] impl std::error::Error for UpgradeClientError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::InvalidUpgradeClientProof(e) | Self::InvalidUpgradeConsensusStateProof(e) => { - Some(e) - } + Self::InvalidUpgradeClientStateProof(e) + | Self::InvalidUpgradeConsensusStateProof(e) => Some(e), _ => None, } } diff --git a/ibc-core/ics02-client/types/src/msgs/create_client.rs b/ibc-core/ics02-client/types/src/msgs/create_client.rs index fe6944b3d..72a035c9e 100644 --- a/ibc-core/ics02-client/types/src/msgs/create_client.rs +++ b/ibc-core/ics02-client/types/src/msgs/create_client.rs @@ -1,5 +1,6 @@ //! Definition of domain type message `MsgCreateClient`. +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_primitives::Signer; use ibc_proto::google::protobuf::Any; @@ -39,11 +40,13 @@ impl TryFrom for MsgCreateClient { type Error = ClientError; fn try_from(raw: RawMsgCreateClient) -> Result { - let raw_client_state = raw.client_state.ok_or(ClientError::MissingRawClientState)?; + let raw_client_state = raw.client_state.ok_or(DecodingError::MissingRawData { + description: "no raw client state set".to_string(), + })?; - let raw_consensus_state = raw - .consensus_state - .ok_or(ClientError::MissingRawConsensusState)?; + let raw_consensus_state = raw.consensus_state.ok_or(DecodingError::MissingRawData { + description: "no raw consensus state set".to_string(), + })?; Ok(MsgCreateClient::new( raw_client_state, diff --git a/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs b/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs index 7d14f133f..dd627ae02 100644 --- a/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs +++ b/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs @@ -1,5 +1,6 @@ //! Definition of domain type message `MsgSubmitMisbehaviour`. +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -40,15 +41,12 @@ impl TryFrom for MsgSubmitMisbehaviour { type Error = ClientError; fn try_from(raw: RawMsgSubmitMisbehaviour) -> Result { - let raw_misbehaviour = raw - .misbehaviour - .ok_or(ClientError::MissingRawMisbehaviour)?; + let raw_misbehaviour = raw.misbehaviour.ok_or(DecodingError::MissingRawData { + description: "misbehaviour not set".to_string(), + })?; Ok(MsgSubmitMisbehaviour { - client_id: raw - .client_id - .parse() - .map_err(ClientError::InvalidClientIdentifier)?, + client_id: raw.client_id.parse()?, misbehaviour: raw_misbehaviour, signer: raw.signer.into(), }) diff --git a/ibc-core/ics02-client/types/src/msgs/recover_client.rs b/ibc-core/ics02-client/types/src/msgs/recover_client.rs index 62fc738fe..df371e63a 100644 --- a/ibc-core/ics02-client/types/src/msgs/recover_client.rs +++ b/ibc-core/ics02-client/types/src/msgs/recover_client.rs @@ -42,14 +42,8 @@ impl TryFrom for MsgRecoverClient { fn try_from(raw: RawMsgRecoverClient) -> Result { Ok(MsgRecoverClient { - subject_client_id: raw - .subject_client_id - .parse() - .map_err(ClientError::InvalidClientIdentifier)?, - substitute_client_id: raw - .substitute_client_id - .parse() - .map_err(ClientError::InvalidClientIdentifier)?, + subject_client_id: raw.subject_client_id.parse()?, + substitute_client_id: raw.substitute_client_id.parse()?, signer: raw.signer.into(), }) } diff --git a/ibc-core/ics02-client/types/src/msgs/update_client.rs b/ibc-core/ics02-client/types/src/msgs/update_client.rs index 9eb088017..fc99faf9a 100644 --- a/ibc-core/ics02-client/types/src/msgs/update_client.rs +++ b/ibc-core/ics02-client/types/src/msgs/update_client.rs @@ -1,5 +1,6 @@ //! Definition of domain type message `MsgUpdateClient`. +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -34,13 +35,10 @@ impl TryFrom for MsgUpdateClient { fn try_from(raw: RawMsgUpdateClient) -> Result { Ok(MsgUpdateClient { - client_id: raw - .client_id - .parse() - .map_err(ClientError::InvalidClientIdentifier)?, - client_message: raw - .client_message - .ok_or(ClientError::MissingRawClientMessage)?, + client_id: raw.client_id.parse()?, + client_message: raw.client_message.ok_or(DecodingError::MissingRawData { + description: "client message not set".to_string(), + })?, signer: raw.signer.into(), }) } diff --git a/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs b/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs index c3d9a956b..90bc14837 100644 --- a/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs +++ b/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs @@ -4,6 +4,7 @@ use core::str::FromStr; use ibc_core_commitment_types::commitment::CommitmentProofBytes; use ibc_core_commitment_types::error::CommitmentError; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -59,16 +60,24 @@ impl TryFrom for MsgUpgradeClient { fn try_from(proto_msg: RawMsgUpgradeClient) -> Result { let raw_client_state = proto_msg .client_state - .ok_or(ClientError::MissingRawClientState)?; + .ok_or(DecodingError::MissingRawData { + description: "client state not set".to_string(), + })?; - let raw_consensus_state = proto_msg - .consensus_state - .ok_or(ClientError::MissingRawConsensusState)?; + let raw_consensus_state = + proto_msg + .consensus_state + .ok_or(DecodingError::MissingRawData { + description: "consensus state not set".to_string(), + })?; let c_bytes = CommitmentProofBytes::try_from(proto_msg.proof_upgrade_client).map_err(|_| { - UpgradeClientError::InvalidUpgradeClientProof(CommitmentError::EmptyMerkleProof) + UpgradeClientError::InvalidUpgradeClientStateProof( + CommitmentError::InvalidMerkleProof, + ) })?; + let cs_bytes = CommitmentProofBytes::try_from(proto_msg.proof_upgrade_consensus_state) .map_err(|_| { UpgradeClientError::InvalidUpgradeConsensusStateProof( @@ -77,8 +86,7 @@ impl TryFrom for MsgUpgradeClient { })?; Ok(MsgUpgradeClient { - client_id: ClientId::from_str(&proto_msg.client_id) - .map_err(ClientError::InvalidClientIdentifier)?, + client_id: ClientId::from_str(&proto_msg.client_id)?, upgraded_client_state: raw_client_state, upgraded_consensus_state: raw_consensus_state, proof_upgrade_client: c_bytes, diff --git a/ibc-core/ics02-client/types/src/status.rs b/ibc-core/ics02-client/types/src/status.rs index 5fe9b9e0a..25f28d3cf 100644 --- a/ibc-core/ics02-client/types/src/status.rs +++ b/ibc-core/ics02-client/types/src/status.rs @@ -50,7 +50,7 @@ impl Status { pub fn verify_is_active(&self) -> Result<(), ClientError> { match self { Self::Active => Ok(()), - &status => Err(ClientError::InvalidStatus(status)), + &status => Err(ClientError::UnexpectedStatus(status)), } } @@ -58,7 +58,7 @@ impl Status { pub fn verify_is_inactive(&self) -> Result<(), ClientError> { match self { Self::Frozen | Self::Expired => Ok(()), - &status => Err(ClientError::InvalidStatus(status)), + &status => Err(ClientError::UnexpectedStatus(status)), } } } @@ -78,9 +78,7 @@ impl FromStr for Status { "FROZEN" => Ok(Status::Frozen), "EXPIRED" => Ok(Status::Expired), "UNAUTHORIZED" => Ok(Status::Unauthorized), - _ => Err(ClientError::Other { - description: format!("invalid status string: {s}"), - }), + _ => Err(ClientError::InvalidStatus(s.to_string())), } } } diff --git a/ibc-core/ics03-connection/src/handler/conn_open_ack.rs b/ibc-core/ics03-connection/src/handler/conn_open_ack.rs index a061b3f06..91027ff43 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_ack.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_ack.rs @@ -68,6 +68,7 @@ where client_state_of_b_on_a .status(client_val_ctx_a, vars.client_id_on_a())? .verify_is_active()?; + client_state_of_b_on_a.validate_proof_height(msg.proofs_height_on_b)?; let client_cons_state_path_on_a = ClientConsensusStatePath::new( diff --git a/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs b/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs index e1751cfc9..1987c047f 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs @@ -48,6 +48,7 @@ where client_state_of_a_on_b .status(client_val_ctx_b, client_id_on_b)? .verify_is_active()?; + client_state_of_a_on_b.validate_proof_height(msg.proof_height_on_a)?; let client_cons_state_path_on_b = ClientConsensusStatePath::new( diff --git a/ibc-core/ics03-connection/src/handler/conn_open_try.rs b/ibc-core/ics03-connection/src/handler/conn_open_try.rs index 34bb18ae0..fbb013824 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_try.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_try.rs @@ -68,6 +68,7 @@ where client_state_of_a_on_b .status(client_val_ctx_b, &msg.client_id_on_b)? .verify_is_active()?; + client_state_of_a_on_b.validate_proof_height(msg.proofs_height_on_a)?; let client_cons_state_path_on_b = ClientConsensusStatePath::new( diff --git a/ibc-core/ics03-connection/src/handler/mod.rs b/ibc-core/ics03-connection/src/handler/mod.rs index effc57fda..f780295e4 100644 --- a/ibc-core/ics03-connection/src/handler/mod.rs +++ b/ibc-core/ics03-connection/src/handler/mod.rs @@ -1,5 +1,7 @@ use ibc_core_client::types::error::ClientError; use ibc_core_handler_types::error::ContextError; +#[cfg(feature = "wasm-client")] +use ibc_core_host::types::error::DecodingError; use ibc_core_host::types::identifiers::ClientId; use ibc_primitives::proto::Any; @@ -35,11 +37,7 @@ where })?; let any_client_state = ::decode(wasm_client_state.data.as_slice()) - .map_err(|e| { - ContextError::ConnectionError(ConnectionError::InvalidClientState { - description: e.to_string(), - }) - })?; + .map_err(|e| ConnectionError::Decoding(DecodingError::Prost(e)))?; Ok(CS::try_from(any_client_state).map_err(Into::::into)?) } else { diff --git a/ibc-core/ics03-connection/types/src/connection.rs b/ibc-core/ics03-connection/types/src/connection.rs index 2602c456d..4ffd8002b 100644 --- a/ibc-core/ics03-connection/types/src/connection.rs +++ b/ibc-core/ics03-connection/types/src/connection.rs @@ -4,6 +4,7 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use core::time::Duration; use ibc_core_commitment_types::commitment::CommitmentPrefix; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ClientId, ConnectionId}; use ibc_primitives::prelude::*; use ibc_proto::ibc::core::connection::v1::{ @@ -67,10 +68,7 @@ impl TryFrom for IdentifiedConnectionEnd { }; Ok(IdentifiedConnectionEnd { - connection_id: value - .id - .parse() - .map_err(ConnectionError::InvalidIdentifier)?, + connection_id: value.id.parse()?, connection_end: raw_connection_end.try_into()?, }) } @@ -198,26 +196,30 @@ impl Protobuf for ConnectionEnd {} impl TryFrom for ConnectionEnd { type Error = ConnectionError; + fn try_from(value: RawConnectionEnd) -> Result { let state = value.state.try_into()?; if value.client_id.is_empty() { - return Err(ConnectionError::EmptyProtoConnectionEnd); + return Err(DecodingError::MissingRawData { + description: "connection end is empty".to_string(), + })?; } if value.versions.is_empty() { - return Err(ConnectionError::EmptyVersions); + return Err(DecodingError::MissingRawData { + description: "connection versions is empty".to_string(), + })?; } Self::new( state, - value - .client_id - .parse() - .map_err(ConnectionError::InvalidIdentifier)?, + value.client_id.parse()?, value .counterparty - .ok_or(ConnectionError::MissingCounterparty)? + .ok_or(DecodingError::MissingRawData { + description: "counterparty not set".to_string(), + })? .try_into()?, value .versions @@ -374,22 +376,16 @@ impl TryFrom for Counterparty { let connection_id: Option = if raw_counterparty.connection_id.is_empty() { None } else { - Some( - raw_counterparty - .connection_id - .parse() - .map_err(ConnectionError::InvalidIdentifier)?, - ) + Some(raw_counterparty.connection_id.parse()?) }; Ok(Counterparty::new( - raw_counterparty - .client_id - .parse() - .map_err(ConnectionError::InvalidIdentifier)?, + raw_counterparty.client_id.parse()?, connection_id, raw_counterparty .prefix - .ok_or(ConnectionError::MissingCounterparty)? + .ok_or(DecodingError::MissingRawData { + description: "counterparty prefix not set".to_string(), + })? .key_prefix .into(), )) diff --git a/ibc-core/ics03-connection/types/src/error.rs b/ibc-core/ics03-connection/types/src/error.rs index 6062dfae6..7a4342c74 100644 --- a/ibc-core/ics03-connection/types/src/error.rs +++ b/ibc-core/ics03-connection/types/src/error.rs @@ -3,7 +3,7 @@ use displaydoc::Display; use ibc_core_client_types::error::ClientError; use ibc_core_client_types::Height; -use ibc_core_host_types::error::IdentifierError; +use ibc_core_host_types::error::{DecodingError, IdentifierError}; use ibc_core_host_types::identifiers::ConnectionId; use ibc_primitives::prelude::*; use ibc_primitives::{Timestamp, TimestampError}; @@ -12,22 +12,16 @@ use crate::version::Version; #[derive(Debug, Display)] pub enum ConnectionError { - /// invalid identifier: `{0}` - InvalidIdentifier(IdentifierError), + /// decoding error: `{0}` + Decoding(DecodingError), /// invalid state for initializing new ConnectionEnd; expected `Init` connection state and a single version InvalidStateForConnectionEndInit, - /// invalid connection proof - InvalidProof, /// invalid counterparty InvalidCounterparty, /// invalid client state: `{description}` InvalidClientState { description: String }, /// mismatched connection states: expected `{expected}`, actual `{actual}` MismatchedConnectionStates { expected: String, actual: String }, - /// empty proto connection end; failed to construct ConnectionEnd domain object - EmptyProtoConnectionEnd, - /// empty supported versions - EmptyVersions, /// empty supported features EmptyFeatures, /// unsupported version \"`{0}`\" @@ -38,18 +32,8 @@ pub enum ConnectionError { MissingCommonVersion, /// missing common features MissingCommonFeatures, - /// missing proof height - MissingProofHeight, - /// missing consensus height - MissingConsensusHeight, - /// missing connection `{0}` - MissingConnection(ConnectionId), - /// missing connection counter - MissingConnectionCounter, /// missing counterparty MissingCounterparty, - /// missing client state - MissingClientState, /// insufficient consensus height `{current_height}` for host chain; needs to meet counterparty's height `{target_height}` InsufficientConsensusHeight { target_height: Height, @@ -71,14 +55,32 @@ pub enum ConnectionError { FailedToVerifyConsensusState(ClientError), /// failed to verify client state: `{0}` FailedToVerifyClientState(ClientError), + /// overflowed timestamp: `{0}` + OverflowedTimestamp(TimestampError), + + // TODO(seanchen1991): Move these variants to host-relevant error types + /// missing connection `{0}` + MissingConnection(ConnectionId), + /// missing connection counter + MissingConnectionCounter, /// failed to store connection IDs FailedToStoreConnectionIds, /// failed to store connection end FailedToStoreConnectionEnd, /// failed to update connection counter FailedToUpdateConnectionCounter, - /// overflowed timestamp: `{0}` - OverflowedTimestamp(TimestampError), +} + +impl From for ConnectionError { + fn from(e: DecodingError) -> Self { + Self::Decoding(e) + } +} + +impl From for ConnectionError { + fn from(e: IdentifierError) -> Self { + Self::Decoding(DecodingError::Identifier(e)) + } } #[cfg(feature = "std")] @@ -88,8 +90,6 @@ impl std::error::Error for ConnectionError { Self::FailedToVerifyConnectionState(e) | Self::FailedToVerifyConsensusState(e) | Self::FailedToVerifyClientState(e) => Some(e), - // Self::InvalidIdentifier(e) => Some(e), - // Self::OverflowedTimestamp(e) => Some(e), _ => None, } } diff --git a/ibc-core/ics03-connection/types/src/msgs/conn_open_ack.rs b/ibc-core/ics03-connection/types/src/msgs/conn_open_ack.rs index dc3056b2a..39cd8e712 100644 --- a/ibc-core/ics03-connection/types/src/msgs/conn_open_ack.rs +++ b/ibc-core/ics03-connection/types/src/msgs/conn_open_ack.rs @@ -1,5 +1,6 @@ use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ConnectionId; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -51,50 +52,53 @@ impl TryFrom for MsgConnectionOpenAck { fn try_from(msg: RawMsgConnectionOpenAck) -> Result { Ok(Self { - conn_id_on_a: msg - .connection_id - .parse() - .map_err(ConnectionError::InvalidIdentifier)?, - conn_id_on_b: msg - .counterparty_connection_id - .parse() - .map_err(ConnectionError::InvalidIdentifier)?, - client_state_of_a_on_b: msg - .client_state - .ok_or(ConnectionError::MissingClientState)?, + conn_id_on_a: msg.connection_id.parse()?, + conn_id_on_b: msg.counterparty_connection_id.parse()?, + client_state_of_a_on_b: msg.client_state.ok_or(DecodingError::MissingRawData { + description: "client state not set".to_string(), + })?, version: msg .version - .ok_or(ConnectionError::EmptyVersions)? + .ok_or(DecodingError::MissingRawData { + description: "connection version not set".to_string(), + })? .try_into()?, - proof_conn_end_on_b: msg - .proof_try - .try_into() - .map_err(|_| ConnectionError::InvalidProof)?, - proof_client_state_of_a_on_b: msg - .proof_client - .try_into() - .map_err(|_| ConnectionError::InvalidProof)?, - proof_consensus_state_of_a_on_b: msg - .proof_consensus - .try_into() - .map_err(|_| ConnectionError::InvalidProof)?, + proof_conn_end_on_b: msg.proof_try.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode connection end proof: {e}"), + } + })?, + proof_client_state_of_a_on_b: msg.proof_client.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode client state proof: {e}"), + } + })?, + proof_consensus_state_of_a_on_b: msg.proof_consensus.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode consensus state proof: {e}"), + } + })?, proofs_height_on_b: msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ConnectionError::MissingProofHeight)?, + .ok_or(DecodingError::MissingRawData { + description: "proof height not set".to_string(), + })?, consensus_height_of_a_on_b: msg .consensus_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ConnectionError::MissingConsensusHeight)?, + .ok_or(DecodingError::MissingRawData { + description: "consensus height not set".to_string(), + })?, signer: msg.signer.into(), proof_consensus_state_of_a: if msg.host_consensus_state_proof.is_empty() { None } else { - Some( - msg.host_consensus_state_proof - .try_into() - .map_err(|_| ConnectionError::InvalidProof)?, - ) + Some(msg.host_consensus_state_proof.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode host consensus state proof: {e}"), + } + })?) }, }) } diff --git a/ibc-core/ics03-connection/types/src/msgs/conn_open_confirm.rs b/ibc-core/ics03-connection/types/src/msgs/conn_open_confirm.rs index e18821d57..982e8f15c 100644 --- a/ibc-core/ics03-connection/types/src/msgs/conn_open_confirm.rs +++ b/ibc-core/ics03-connection/types/src/msgs/conn_open_confirm.rs @@ -1,5 +1,6 @@ use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ConnectionId; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -35,18 +36,18 @@ impl TryFrom for MsgConnectionOpenConfirm { fn try_from(msg: RawMsgConnectionOpenConfirm) -> Result { Ok(Self { - conn_id_on_b: msg - .connection_id - .parse() - .map_err(ConnectionError::InvalidIdentifier)?, - proof_conn_end_on_a: msg - .proof_ack - .try_into() - .map_err(|_| ConnectionError::InvalidProof)?, + conn_id_on_b: msg.connection_id.parse()?, + proof_conn_end_on_a: msg.proof_ack.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode connection end proof: {e}"), + } + })?, proof_height_on_a: msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ConnectionError::MissingProofHeight)?, + .ok_or(DecodingError::InvalidRawData { + description: "failed to decode proof height".to_string(), + })?, signer: msg.signer.into(), }) } diff --git a/ibc-core/ics03-connection/types/src/msgs/conn_open_init.rs b/ibc-core/ics03-connection/types/src/msgs/conn_open_init.rs index 7d9affcfd..672f419da 100644 --- a/ibc-core/ics03-connection/types/src/msgs/conn_open_init.rs +++ b/ibc-core/ics03-connection/types/src/msgs/conn_open_init.rs @@ -1,5 +1,6 @@ use core::time::Duration; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -89,16 +90,15 @@ impl TryFrom for MsgConnectionOpenInit { fn try_from(msg: RawMsgConnectionOpenInit) -> Result { let counterparty: Counterparty = msg .counterparty - .ok_or(ConnectionError::MissingCounterparty)? + .ok_or(DecodingError::MissingRawData { + description: "counterparty not set".to_string(), + })? .try_into()?; counterparty.verify_empty_connection_id()?; Ok(Self { - client_id_on_a: msg - .client_id - .parse() - .map_err(ConnectionError::InvalidIdentifier)?, + client_id_on_a: msg.client_id.parse()?, counterparty, version: msg.version.map(TryInto::try_into).transpose()?, delay_period: Duration::from_nanos(msg.delay_period), diff --git a/ibc-core/ics03-connection/types/src/msgs/conn_open_try.rs b/ibc-core/ics03-connection/types/src/msgs/conn_open_try.rs index 6686b806a..5714784c4 100644 --- a/ibc-core/ics03-connection/types/src/msgs/conn_open_try.rs +++ b/ibc-core/ics03-connection/types/src/msgs/conn_open_try.rs @@ -2,6 +2,7 @@ use core::time::Duration; use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -154,7 +155,9 @@ impl TryFrom for MsgConnectionOpenTry { .collect::, _>>()?; if counterparty_versions.is_empty() { - return Err(ConnectionError::EmptyVersions); + return Err(DecodingError::MissingRawData { + description: "connection versions not set".to_string(), + })?; } // We set the deprecated `previous_connection_id` field so that we can @@ -162,48 +165,54 @@ impl TryFrom for MsgConnectionOpenTry { #[allow(deprecated)] Ok(Self { previous_connection_id: msg.previous_connection_id, - client_id_on_b: msg - .client_id - .parse() - .map_err(ConnectionError::InvalidIdentifier)?, - client_state_of_b_on_a: msg - .client_state - .ok_or(ConnectionError::MissingClientState)?, + client_id_on_b: msg.client_id.parse()?, + client_state_of_b_on_a: msg.client_state.ok_or(DecodingError::MissingRawData { + description: "client state not set".to_string(), + })?, counterparty: msg .counterparty - .ok_or(ConnectionError::MissingCounterparty)? + .ok_or(DecodingError::MissingRawData { + description: "counterparty not set".to_string(), + })? .try_into()?, versions_on_a: counterparty_versions, - proof_conn_end_on_a: msg - .proof_init - .try_into() - .map_err(|_| ConnectionError::InvalidProof)?, - proof_client_state_of_b_on_a: msg - .proof_client - .try_into() - .map_err(|_| ConnectionError::InvalidProof)?, - proof_consensus_state_of_b_on_a: msg - .proof_consensus - .try_into() - .map_err(|_| ConnectionError::InvalidProof)?, + proof_conn_end_on_a: msg.proof_init.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode connection end proof: {e}"), + } + })?, + proof_client_state_of_b_on_a: msg.proof_client.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode client state proof: {e}"), + } + })?, + proof_consensus_state_of_b_on_a: msg.proof_consensus.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode consensus state proof: {e}"), + } + })?, proofs_height_on_a: msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ConnectionError::MissingProofHeight)?, + .ok_or(DecodingError::InvalidRawData { + description: "failed to decode proof height".to_string(), + })?, consensus_height_of_b_on_a: msg .consensus_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ConnectionError::MissingConsensusHeight)?, + .ok_or(DecodingError::InvalidRawData { + description: "failed to decode consensus height".to_string(), + })?, delay_period: Duration::from_nanos(msg.delay_period), signer: msg.signer.into(), proof_consensus_state_of_b: if msg.host_consensus_state_proof.is_empty() { None } else { - Some( - msg.host_consensus_state_proof - .try_into() - .map_err(|_| ConnectionError::InvalidProof)?, - ) + Some(msg.host_consensus_state_proof.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode consensus state proof: {e}"), + } + })?) }, }) } diff --git a/ibc-core/ics03-connection/types/src/version.rs b/ibc-core/ics03-connection/types/src/version.rs index aa6f5316a..ac8f9d975 100644 --- a/ibc-core/ics03-connection/types/src/version.rs +++ b/ibc-core/ics03-connection/types/src/version.rs @@ -2,6 +2,7 @@ use core::fmt::Display; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_primitives::utils::PrettySlice; use ibc_proto::ibc::core::connection::v1::Version as RawVersion; @@ -72,9 +73,12 @@ impl Protobuf for Version {} impl TryFrom for Version { type Error = ConnectionError; + fn try_from(value: RawVersion) -> Result { if value.identifier.trim().is_empty() { - return Err(ConnectionError::EmptyVersions); + return Err(DecodingError::MissingRawData { + description: "version is empty".to_string(), + })?; } for feature in value.features.iter() { if feature.trim().is_empty() { diff --git a/ibc-core/ics04-channel/src/handler/acknowledgement.rs b/ibc-core/ics04-channel/src/handler/acknowledgement.rs index 68bc43128..e5f484f2b 100644 --- a/ibc-core/ics04-channel/src/handler/acknowledgement.rs +++ b/ibc-core/ics04-channel/src/handler/acknowledgement.rs @@ -177,6 +177,7 @@ where client_state_of_b_on_a .status(ctx_a.get_client_validation_context(), client_id_on_a)? .verify_is_active()?; + client_state_of_b_on_a.validate_proof_height(msg.proof_height_on_b)?; let client_cons_state_path_on_a = ClientConsensusStatePath::new( diff --git a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs index 4f2dc0293..5b315ecbf 100644 --- a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs @@ -114,6 +114,7 @@ where client_state_of_a_on_b .status(ctx_b.get_client_validation_context(), client_id_on_b)? .verify_is_active()?; + client_state_of_a_on_b.validate_proof_height(msg.proof_height_on_a)?; let client_cons_state_path_on_b = ClientConsensusStatePath::new( diff --git a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs index 9369733a0..f6271bcd0 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs @@ -115,6 +115,7 @@ where client_state_of_b_on_a .status(ctx_a.get_client_validation_context(), client_id_on_a)? .verify_is_active()?; + client_state_of_b_on_a.validate_proof_height(msg.proof_height_on_b)?; let client_cons_state_path_on_a = ClientConsensusStatePath::new( diff --git a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs index 9d375a295..2ea7078a4 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs @@ -119,6 +119,7 @@ where client_state_of_a_on_b .status(ctx_b.get_client_validation_context(), client_id_on_b)? .verify_is_active()?; + client_state_of_a_on_b.validate_proof_height(msg.proof_height_on_a)?; let client_cons_state_path_on_b = ClientConsensusStatePath::new( diff --git a/ibc-core/ics04-channel/types/src/acknowledgement.rs b/ibc-core/ics04-channel/types/src/acknowledgement.rs index 0e983b0ce..c061f2be5 100644 --- a/ibc-core/ics04-channel/types/src/acknowledgement.rs +++ b/ibc-core/ics04-channel/types/src/acknowledgement.rs @@ -3,6 +3,7 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use derive_more::Into; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use super::error::PacketError; @@ -45,7 +46,9 @@ impl TryFrom> for Acknowledgement { fn try_from(bytes: Vec) -> Result { if bytes.is_empty() { - Err(PacketError::EmptyAcknowledgment) + Err(DecodingError::MissingRawData { + description: "acknowledgment not set".to_string(), + })? } else { Ok(Self(bytes)) } diff --git a/ibc-core/ics04-channel/types/src/error.rs b/ibc-core/ics04-channel/types/src/error.rs index 56cdadcd5..4e0551e66 100644 --- a/ibc-core/ics04-channel/types/src/error.rs +++ b/ibc-core/ics04-channel/types/src/error.rs @@ -3,7 +3,7 @@ use displaydoc::Display; use ibc_core_client_types::error::ClientError; use ibc_core_client_types::Height; -use ibc_core_host_types::error::IdentifierError; +use ibc_core_host_types::error::{DecodingError, IdentifierError}; use ibc_core_host_types::identifiers::{ChannelId, PortId, Sequence}; use ibc_primitives::prelude::*; use ibc_primitives::{Timestamp, TimestampError}; @@ -16,10 +16,8 @@ use crate::Version; #[derive(Debug, Display)] pub enum ChannelError { - /// application module error: `{description}` - AppModule { description: String }, - /// identifier error: `{0}` - InvalidIdentifier(IdentifierError), + /// decoding error: `{0}` + Decoding(DecodingError), /// invalid channel id: expected `{expected}`, actual `{actual}` InvalidChannelId { expected: String, actual: String }, /// invalid channel state: expected `{expected}`, actual `{actual}` @@ -39,10 +37,6 @@ pub enum ChannelError { MissingProofHeight, /// missing counterparty MissingCounterparty, - /// missing channel end in raw message - MissingRawChannelEnd, - /// missing channel counter - MissingCounter, /// unsupported channel upgrade sequence UnsupportedChannelUpgradeSequence, /// unsupported version: expected `{expected}`, actual `{actual}` @@ -52,8 +46,6 @@ pub enum ChannelError { port_id: PortId, channel_id: ChannelId, }, - /// packet data bytes must be valid UTF-8 - NonUtf8PacketData, /// failed packet verification for packet with sequence `{sequence}`: `{client_error}` FailedPacketVerification { sequence: Sequence, @@ -62,8 +54,12 @@ pub enum ChannelError { /// failed proof verification: `{0}` FailedProofVerification(ClientError), - // TODO(seanchen1991): These two variants should be encoded by host-relevant error types + // TODO(seanchen1991): These variants should be encoded by host-relevant error types // once those have been defined. + /// application module error: `{description}` + AppModule { description: String }, + /// missing channel counter + MissingCounter, /// failed to update counter: `{description}` FailedToUpdateCounter { description: String }, /// failed to store channel: `{description}` @@ -72,10 +68,10 @@ pub enum ChannelError { #[derive(Debug, Display)] pub enum PacketError { - /// application module error: `{description}` - AppModule { description: String }, /// channel error: `{0}` Channel(ChannelError), + /// decoding error: `{0}` + Decoding(DecodingError), /// insufficient packet timeout height: should have `{timeout_height}` > `{chain_height}` InsufficientPacketHeight { chain_height: Height, @@ -94,28 +90,14 @@ pub enum PacketError { expected: PacketCommitment, actual: PacketCommitment, }, - /// missing packet receipt for packet `{0}` - MissingPacketReceipt(Sequence), - /// missing proof - MissingProof, - /// missing acknowledgment for packet `{0}` - MissingPacketAcknowledgment(Sequence), - /// missing proof height - MissingProofHeight, /// missing timeout MissingTimeout, /// invalid timeout height: `{0}` InvalidTimeoutHeight(ClientError), /// invalid timeout timestamp: `{0}` InvalidTimeoutTimestamp(TimestampError), - /// invalid identifier: `{0}` - InvalidIdentifier(IdentifierError), - /// empty acknowledgment not allowed - EmptyAcknowledgment, /// empty acknowledgment status not allowed EmptyAcknowledgmentStatus, - /// packet data bytes cannot be empty - EmptyPacketData, /// packet acknowledgment for sequence `{0}` already exists DuplicateAcknowledgment(Sequence), /// packet sequence cannot be 0 @@ -127,25 +109,45 @@ pub enum PacketError { timeout_timestamp: TimeoutTimestamp, chain_timestamp: Timestamp, }, + + // TODO(seanchen1991): Move these variants to host-relevant error types + /// application module error: `{description}` + AppModule { description: String }, + /// missing acknowledgment for packet `{0}` + MissingPacketAcknowledgment(Sequence), + /// missing packet receipt for packet `{0}` + MissingPacketReceipt(Sequence), /// implementation-specific error ImplementationSpecific, } impl From for ChannelError { - fn from(err: IdentifierError) -> Self { - Self::InvalidIdentifier(err) + fn from(e: IdentifierError) -> Self { + Self::Decoding(DecodingError::Identifier(e)) } } impl From for PacketError { - fn from(err: IdentifierError) -> Self { - Self::InvalidIdentifier(err) + fn from(e: IdentifierError) -> Self { + Self::Decoding(DecodingError::Identifier(e)) + } +} + +impl From for ChannelError { + fn from(e: DecodingError) -> Self { + Self::Decoding(e) + } +} + +impl From for PacketError { + fn from(e: DecodingError) -> Self { + Self::Decoding(e) } } impl From for PacketError { - fn from(err: TimestampError) -> Self { - Self::InvalidTimeoutTimestamp(err) + fn from(e: TimestampError) -> Self { + Self::InvalidTimeoutTimestamp(e) } } @@ -154,7 +156,7 @@ impl std::error::Error for PacketError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { Self::Channel(e) => Some(e), - Self::InvalidIdentifier(e) => Some(e), + Self::Decoding(e) => Some(e), _ => None, } } @@ -164,7 +166,7 @@ impl std::error::Error for PacketError { impl std::error::Error for ChannelError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::InvalidIdentifier(e) => Some(e), + Self::Decoding(e) => Some(e), Self::FailedPacketVerification { client_error: e, .. } => Some(e), diff --git a/ibc-core/ics04-channel/types/src/events/packet_attributes.rs b/ibc-core/ics04-channel/types/src/events/packet_attributes.rs index a15a31220..35fb84a7f 100644 --- a/ibc-core/ics04-channel/types/src/events/packet_attributes.rs +++ b/ibc-core/ics04-channel/types/src/events/packet_attributes.rs @@ -4,6 +4,7 @@ use core::str; use derive_more::From; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId, Sequence}; use ibc_primitives::prelude::*; use subtle_encoding::hex; @@ -53,7 +54,7 @@ impl TryFrom for Vec { let tags = vec![ ( PKT_DATA_ATTRIBUTE_KEY, - str::from_utf8(&attr.packet_data).map_err(|_| ChannelError::NonUtf8PacketData)?, + str::from_utf8(&attr.packet_data).map_err(DecodingError::StrUtf8)?, ) .into(), ( @@ -322,8 +323,7 @@ impl TryFrom for Vec { // is valid UTF-8, even though the standard doesn't require // it. It has been deprecated in ibc-go. It will be removed // in the future. - str::from_utf8(attr.acknowledgement.as_bytes()) - .map_err(|_| ChannelError::NonUtf8PacketData)?, + str::from_utf8(attr.acknowledgement.as_bytes()).map_err(DecodingError::StrUtf8)?, ) .into(), ( diff --git a/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs b/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs index 2446395d7..b9f7d119e 100644 --- a/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs +++ b/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs @@ -1,5 +1,6 @@ use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_primitives::Signer; use ibc_proto::ibc::core::channel::v1::MsgAcknowledgement as RawMsgAcknowledgement; @@ -39,17 +40,22 @@ impl TryFrom for MsgAcknowledgement { Ok(MsgAcknowledgement { packet: raw_msg .packet - .ok_or(PacketError::EmptyPacketData)? + .ok_or(DecodingError::MissingRawData { + description: "packet data not set".to_string(), + })? .try_into()?, acknowledgement: raw_msg.acknowledgement.try_into()?, - proof_acked_on_b: raw_msg - .proof_acked - .try_into() - .map_err(|_| PacketError::MissingProof)?, + proof_acked_on_b: raw_msg.proof_acked.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode proof: {e}"), + } + })?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(PacketError::MissingProofHeight)?, + .ok_or(DecodingError::InvalidRawData { + description: "failed to decode proof height".to_string(), + })?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs index 8634eb3e8..cb13fe9cb 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs @@ -1,5 +1,6 @@ use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ChannelId, PortId}; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -41,14 +42,17 @@ impl TryFrom for MsgChannelOpenAck { chan_id_on_a: raw_msg.channel_id.parse()?, chan_id_on_b: raw_msg.counterparty_channel_id.parse()?, version_on_b: raw_msg.counterparty_version.into(), - proof_chan_end_on_b: raw_msg - .proof_try - .try_into() - .map_err(|_| ChannelError::MissingProof)?, + proof_chan_end_on_b: raw_msg.proof_try.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode proof: {e}"), + } + })?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ChannelError::MissingProofHeight)?, + .ok_or(DecodingError::MissingRawData { + description: "proof height not set".to_string(), + })?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs index afac87752..c264ddabe 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs @@ -1,3 +1,4 @@ +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ConnectionId, PortId}; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -47,7 +48,9 @@ impl TryFrom for MsgChannelOpenInit { fn try_from(raw_msg: RawMsgChannelOpenInit) -> Result { let chan_end_on_a: ChannelEnd = raw_msg .channel - .ok_or(ChannelError::MissingRawChannelEnd)? + .ok_or(DecodingError::MissingRawData { + description: "channel end not set".to_string(), + })? .try_into()?; chan_end_on_a.verify_state_matches(&State::Init)?; chan_end_on_a.counterparty().verify_empty_channel_id()?; diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs index 8d85d1fa3..77e5afd89 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs @@ -1,5 +1,6 @@ use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -55,17 +56,16 @@ impl TryFrom for MsgChannelOpenTry { fn try_from(raw_msg: RawMsgChannelOpenTry) -> Result { let chan_end_on_b: ChannelEnd = raw_msg .channel - .ok_or(ChannelError::MissingRawChannelEnd)? + .ok_or(DecodingError::MissingRawData { + description: "channel end not set".to_string(), + })? .try_into()?; chan_end_on_b.verify_state_matches(&State::TryOpen)?; #[allow(deprecated)] if !raw_msg.previous_channel_id.is_empty() { - return Err(ChannelError::InvalidChannelId { - expected: "previous channel id must be empty. It has been deprecated as crossing hellos are no longer supported".to_string(), - actual: raw_msg.previous_channel_id, - }); + return Err(DecodingError::InvalidRawData { description: "previous channel id must be empty. It has been deprecated as crossing hellos are no longer supported".to_string() })?; } #[allow(deprecated)] diff --git a/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs b/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs index 53e4a6716..030449b72 100644 --- a/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs +++ b/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs @@ -1,5 +1,6 @@ use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_primitives::Signer; use ibc_proto::ibc::core::channel::v1::MsgRecvPacket as RawMsgRecvPacket; @@ -39,16 +40,21 @@ impl TryFrom for MsgRecvPacket { Ok(MsgRecvPacket { packet: raw_msg .packet - .ok_or(PacketError::EmptyPacketData)? + .ok_or(DecodingError::MissingRawData { + description: "packet data not set".to_string(), + })? .try_into()?, - proof_commitment_on_a: raw_msg - .proof_commitment - .try_into() - .map_err(|_| PacketError::MissingProof)?, + proof_commitment_on_a: raw_msg.proof_commitment.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode proof: {e}"), + } + })?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(PacketError::MissingProofHeight)?, + .ok_or(DecodingError::InvalidRawData { + description: "failed to decode proof height".to_string(), + })?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/timeout.rs b/ibc-core/ics04-channel/types/src/msgs/timeout.rs index 657e8233e..aaa24bd05 100644 --- a/ibc-core/ics04-channel/types/src/msgs/timeout.rs +++ b/ibc-core/ics04-channel/types/src/msgs/timeout.rs @@ -1,5 +1,6 @@ use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::Sequence; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -41,17 +42,22 @@ impl TryFrom for MsgTimeout { Ok(MsgTimeout { packet: raw_msg .packet - .ok_or(PacketError::EmptyPacketData)? + .ok_or(DecodingError::MissingRawData { + description: "packet data not set".to_string(), + })? .try_into()?, next_seq_recv_on_b: Sequence::from(raw_msg.next_sequence_recv), - proof_unreceived_on_b: raw_msg - .proof_unreceived - .try_into() - .map_err(|_| PacketError::MissingProof)?, + proof_unreceived_on_b: raw_msg.proof_unreceived.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode proof: {e}"), + } + })?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(PacketError::MissingProofHeight)?, + .ok_or(DecodingError::MissingRawData { + description: "proof height not set".to_string(), + })?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs b/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs index 670205716..fd1142a7c 100644 --- a/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs +++ b/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs @@ -1,5 +1,6 @@ use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::Sequence; use ibc_primitives::prelude::*; use ibc_primitives::Signer; @@ -48,21 +49,27 @@ impl TryFrom for MsgTimeoutOnClose { Ok(MsgTimeoutOnClose { packet: raw_msg .packet - .ok_or(PacketError::EmptyPacketData)? + .ok_or(DecodingError::MissingRawData { + description: "packet data not set".to_string(), + })? .try_into()?, next_seq_recv_on_b: Sequence::from(raw_msg.next_sequence_recv), - proof_unreceived_on_b: raw_msg - .proof_unreceived - .try_into() - .map_err(|_| PacketError::MissingProof)?, - proof_close_on_b: raw_msg - .proof_close - .try_into() - .map_err(|_| PacketError::MissingProof)?, + proof_unreceived_on_b: raw_msg.proof_unreceived.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode proof: {e}"), + } + })?, + proof_close_on_b: raw_msg.proof_close.try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("failed to decode proof: {e}"), + } + })?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(PacketError::MissingProofHeight)?, + .ok_or(DecodingError::InvalidRawData { + description: "failed to decode proof height".to_string(), + })?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/packet.rs b/ibc-core/ics04-channel/types/src/packet.rs index dfd6f0358..e1be45ef3 100644 --- a/ibc-core/ics04-channel/types/src/packet.rs +++ b/ibc-core/ics04-channel/types/src/packet.rs @@ -1,5 +1,6 @@ //! Defines the packet type use ibc_core_client_types::Height; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ChannelId, PortId, Sequence}; use ibc_primitives::prelude::*; use ibc_primitives::Timestamp; @@ -172,7 +173,9 @@ impl TryFrom for Packet { } if raw_pkt.data.is_empty() { - return Err(PacketError::EmptyPacketData); + return Err(DecodingError::MissingRawData { + description: "packet data is not set".to_string(), + })?; } // Note: ibc-go currently (July 2022) incorrectly treats the timeout @@ -282,7 +285,9 @@ impl TryFrom for PacketState { } if raw_pkt.data.is_empty() { - return Err(PacketError::EmptyPacketData); + return Err(DecodingError::MissingRawData { + description: "packet data not set".to_string(), + })?; } Ok(PacketState { diff --git a/ibc-core/ics23-commitment/types/src/commitment.rs b/ibc-core/ics23-commitment/types/src/commitment.rs index 43506a798..004c09152 100644 --- a/ibc-core/ics23-commitment/types/src/commitment.rs +++ b/ibc-core/ics23-commitment/types/src/commitment.rs @@ -2,6 +2,7 @@ use core::fmt; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_primitives::ToVec; use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; @@ -94,7 +95,9 @@ impl TryFrom> for CommitmentProofBytes { fn try_from(bytes: Vec) -> Result { if bytes.is_empty() { - Err(Self::Error::EmptyMerkleProof) + Err(DecodingError::MissingRawData { + description: "empty commitment proof bytes".to_string(), + })? } else { Ok(Self { bytes }) } @@ -121,8 +124,7 @@ impl<'a> TryFrom<&'a CommitmentProofBytes> for MerkleProof { type Error = CommitmentError; fn try_from(value: &'a CommitmentProofBytes) -> Result { - Protobuf::::decode(value.as_ref()) - .map_err(|e| CommitmentError::FailedDecoding(e.to_string())) + Ok(Protobuf::::decode(value.as_ref()).map_err(DecodingError::Protobuf)?) } } diff --git a/ibc-core/ics23-commitment/types/src/error.rs b/ibc-core/ics23-commitment/types/src/error.rs index 81ee26e06..c367a0817 100644 --- a/ibc-core/ics23-commitment/types/src/error.rs +++ b/ibc-core/ics23-commitment/types/src/error.rs @@ -1,10 +1,13 @@ //! Defines the commitment error type use displaydoc::Display; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; #[derive(Debug, Display)] pub enum CommitmentError { + /// decoding error: `{0}` + Decoding(DecodingError), /// empty commitment prefix EmptyCommitmentPrefix, /// empty commitment root @@ -19,8 +22,6 @@ pub enum CommitmentError { EmptyProofSpecs, /// mismatched number of proofs: expected `{expected}`, actual `{actual}` MismatchedNumberOfProofs { expected: usize, actual: usize }, - /// mismatched proofs: expected `{expected}`, actual `{actual}` - MismatchedProofs { expected: String, actual: String }, /// invalid range: [`{min}`, `{max}`] InvalidRange { min: i32, max: i32 }, /// invalid merkle proof @@ -31,11 +32,15 @@ pub enum CommitmentError { InvalidHashOp(i32), /// invalid length operation: `{0}` InvalidLengthOp(i32), - /// failed decoding commitment proof: `{0}` - FailedDecoding(String), /// failed to verify membership FailedToVerifyMembership, } +impl From for CommitmentError { + fn from(e: DecodingError) -> Self { + Self::Decoding(e) + } +} + #[cfg(feature = "std")] impl std::error::Error for CommitmentError {} diff --git a/ibc-core/ics23-commitment/types/src/specs.rs b/ibc-core/ics23-commitment/types/src/specs.rs index a37abf6cc..d163c6bf8 100644 --- a/ibc-core/ics23-commitment/types/src/specs.rs +++ b/ibc-core/ics23-commitment/types/src/specs.rs @@ -129,6 +129,7 @@ struct LeafOp(RawLeafOp); impl TryFrom for LeafOp { type Error = CommitmentError; + fn try_from(leaf_op: RawLeafOp) -> Result { let _ = HashOp::try_from(leaf_op.hash) .map_err(|_| CommitmentError::InvalidHashOp(leaf_op.hash))?; @@ -155,6 +156,7 @@ struct InnerSpec(RawInnerSpec); impl TryFrom for InnerSpec { type Error = CommitmentError; + fn try_from(inner_spec: RawInnerSpec) -> Result { if inner_spec.child_size <= 0 { return Err(CommitmentError::InvalidChildSize(inner_spec.child_size)); diff --git a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs index f66487cc7..48ceaf0e5 100644 --- a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs +++ b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs @@ -1,6 +1,7 @@ //! Definition of domain `Plan` type. use ibc_core_client_types::error::UpgradeClientError; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_proto::cosmos::upgrade::v1beta1::Plan as RawPlan; use ibc_proto::google::protobuf::Any; @@ -82,20 +83,15 @@ impl TryFrom for Plan { type Error = UpgradeClientError; fn try_from(any: Any) -> Result { - if any.type_url != TYPE_URL { - return Err(UpgradeClientError::MismatchedTypeUrls { + match any.type_url.as_str() { + TYPE_URL => { + Ok(Protobuf::::decode_vec(&any.value).map_err(DecodingError::Protobuf)?) + } + _ => Err(DecodingError::MismatchedTypeUrls { expected: TYPE_URL.to_string(), actual: any.type_url, - }); + })?, } - - let plan = Protobuf::::decode_vec(&any.value).map_err(|e| { - UpgradeClientError::FailedToDecodeRawUpgradePlan { - description: e.to_string(), - } - })?; - - Ok(plan) } } diff --git a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs index 4a72af753..f069e6852 100644 --- a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs +++ b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs @@ -33,13 +33,13 @@ impl TryFrom for UpgradeProposal { fn try_from(raw: RawUpgradeProposal) -> Result { if raw.title.is_empty() { return Err(UpgradeClientError::InvalidUpgradeProposal { - description: "title field cannot be empty".to_string(), + description: "missing title field".to_string(), }); } if raw.description.is_empty() { return Err(UpgradeClientError::InvalidUpgradeProposal { - description: "description field cannot be empty".to_string(), + description: "missing description field".to_string(), }); } @@ -47,13 +47,13 @@ impl TryFrom for UpgradeProposal { plan.try_into()? } else { return Err(UpgradeClientError::InvalidUpgradeProposal { - description: "plan field cannot be empty".to_string(), + description: "missing plan field".to_string(), }); }; let upgraded_client_state = raw.upgraded_client_state.ok_or_else(|| { UpgradeClientError::InvalidUpgradeProposal { - description: "upgraded client state cannot be empty".to_string(), + description: "missing upgraded client state".to_string(), } })?; diff --git a/ibc-core/ics24-host/cosmos/src/validate_self_client.rs b/ibc-core/ics24-host/cosmos/src/validate_self_client.rs index d2f2d2eba..f6d66994d 100644 --- a/ibc-core/ics24-host/cosmos/src/validate_self_client.rs +++ b/ibc-core/ics24-host/cosmos/src/validate_self_client.rs @@ -25,7 +25,7 @@ pub trait ValidateSelfClientContext { .map_err(ClientError::from)?; if client_state_of_host_on_counterparty.is_frozen() { - return Err(ClientError::InvalidStatus(Status::Frozen).into()); + return Err(ClientError::UnexpectedStatus(Status::Frozen).into()); } let self_chain_id = self.chain_id(); diff --git a/ibc-core/ics24-host/types/Cargo.toml b/ibc-core/ics24-host/types/Cargo.toml index 7ad95dcc0..e4953c720 100644 --- a/ibc-core/ics24-host/types/Cargo.toml +++ b/ibc-core/ics24-host/types/Cargo.toml @@ -20,9 +20,11 @@ all-features = true [dependencies] # external dependencies +base64 = { workspace = true } borsh = { workspace = true, optional = true } derive_more = { workspace = true } displaydoc = { workspace = true } +prost = { workspace = true } schemars = { workspace = true, optional = true } serde = { workspace = true, optional = true } diff --git a/ibc-core/ics24-host/types/src/error.rs b/ibc-core/ics24-host/types/src/error.rs index 72d8535c2..2356d7363 100644 --- a/ibc-core/ics24-host/types/src/error.rs +++ b/ibc-core/ics24-host/types/src/error.rs @@ -1,5 +1,13 @@ +//! Foundational error types that are applicable across multiple ibc-rs workspaces. + +use alloc::string::{FromUtf8Error, String}; +use core::str::Utf8Error; + +use base64::DecodeError as Base64Error; use displaydoc::Display; use ibc_primitives::prelude::*; +use ibc_primitives::proto::Error as ProtoError; +use prost::DecodeError as ProstError; /// Errors that arise when parsing identifiers. #[cfg_attr(feature = "serde", derive(serde::Serialize))] @@ -17,5 +25,49 @@ pub enum IdentifierError { OverflowedRevisionNumber, } +/// Errors that result in decoding failures +#[derive(Debug, Display)] +pub enum DecodingError { + /// identifier error: `{0}` + Identifier(IdentifierError), + /// base64 decoding error: `{0}` + Base64(Base64Error), + /// utf-8 String decoding error: `{0}` + StringUtf8(FromUtf8Error), + /// utf-8 str decoding error: `{0}` + StrUtf8(Utf8Error), + /// protobuf decoding error: `{0}` + Protobuf(ProtoError), + /// prost decoding error: `{0}` + Prost(ProstError), + /// invalid hash bytes: `{description}` + InvalidHash { description: String }, + /// invalid JSON data: `{description}` + InvalidJson { description: String }, + /// invalid raw data: `{description}` + InvalidRawData { description: String }, + /// missing raw data: `{description}` + MissingRawData { description: String }, + /// mismatched type URLs: expected `{expected}`, actual `{actual}` + MismatchedTypeUrls { expected: String, actual: String }, + /// unknown type URL: `{0}` + UnknownTypeUrl(String), +} + +impl From for DecodingError { + fn from(e: ProtoError) -> Self { + Self::Protobuf(e) + } +} + +impl From for DecodingError { + fn from(e: IdentifierError) -> Self { + Self::Identifier(e) + } +} + #[cfg(feature = "std")] impl std::error::Error for IdentifierError {} + +#[cfg(feature = "std")] +impl std::error::Error for DecodingError {} diff --git a/ibc-core/ics24-host/types/src/lib.rs b/ibc-core/ics24-host/types/src/lib.rs index f466de4c2..1fae79ac6 100644 --- a/ibc-core/ics24-host/types/src/lib.rs +++ b/ibc-core/ics24-host/types/src/lib.rs @@ -12,6 +12,8 @@ rust_2018_idioms )] +extern crate alloc; + #[cfg(feature = "std")] extern crate std; diff --git a/ibc-core/ics25-handler/types/src/error.rs b/ibc-core/ics25-handler/types/src/error.rs index 5bea4b54d..84bc0b939 100644 --- a/ibc-core/ics25-handler/types/src/error.rs +++ b/ibc-core/ics25-handler/types/src/error.rs @@ -23,6 +23,7 @@ pub enum ContextError { RouterError(RouterError), } +// TODO(seanchen1991): Figure out how to remove this impl From for ClientError { fn from(context_error: ContextError) -> Self { match context_error { diff --git a/ibc-core/ics25-handler/types/src/msgs.rs b/ibc-core/ics25-handler/types/src/msgs.rs index e3276b951..a47a9b702 100644 --- a/ibc-core/ics25-handler/types/src/msgs.rs +++ b/ibc-core/ics25-handler/types/src/msgs.rs @@ -17,7 +17,7 @@ use ibc_core_connection_types::msgs::{ MsgConnectionOpenTry, CONN_OPEN_ACK_TYPE_URL, CONN_OPEN_CONFIRM_TYPE_URL, CONN_OPEN_INIT_TYPE_URL, CONN_OPEN_TRY_TYPE_URL, }; -use ibc_core_router_types::error::RouterError; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_proto::google::protobuf::Any; use ibc_proto::Protobuf; @@ -38,79 +38,44 @@ pub enum MsgEnvelope { #[allow(deprecated)] impl TryFrom for MsgEnvelope { - type Error = RouterError; + type Error = DecodingError; fn try_from(any_msg: Any) -> Result { match any_msg.type_url.as_str() { // ICS2 messages CREATE_CLIENT_TYPE_URL => { // Pop out the message and then wrap it in the corresponding type. - let domain_msg = MsgCreateClient::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgCreateClient::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Client(ClientMsg::CreateClient(domain_msg))) } UPDATE_CLIENT_TYPE_URL => { - let domain_msg = MsgUpdateClient::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgUpdateClient::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Client(ClientMsg::UpdateClient(domain_msg))) } UPGRADE_CLIENT_TYPE_URL => { - let domain_msg = MsgUpgradeClient::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgUpgradeClient::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Client(ClientMsg::UpgradeClient(domain_msg))) } SUBMIT_MISBEHAVIOUR_TYPE_URL => { - let domain_msg = - MsgSubmitMisbehaviour::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgSubmitMisbehaviour::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Client(ClientMsg::Misbehaviour(domain_msg))) } // ICS03 CONN_OPEN_INIT_TYPE_URL => { - let domain_msg = - MsgConnectionOpenInit::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgConnectionOpenInit::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Connection(ConnectionMsg::OpenInit(domain_msg))) } CONN_OPEN_TRY_TYPE_URL => { - let domain_msg = MsgConnectionOpenTry::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgConnectionOpenTry::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Connection(ConnectionMsg::OpenTry(domain_msg))) } CONN_OPEN_ACK_TYPE_URL => { - let domain_msg = MsgConnectionOpenAck::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgConnectionOpenAck::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Connection(ConnectionMsg::OpenAck(domain_msg))) } CONN_OPEN_CONFIRM_TYPE_URL => { - let domain_msg = - MsgConnectionOpenConfirm::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgConnectionOpenConfirm::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Connection(ConnectionMsg::OpenConfirm( domain_msg, ))) @@ -118,89 +83,48 @@ impl TryFrom for MsgEnvelope { // ICS04 channel messages CHAN_OPEN_INIT_TYPE_URL => { - let domain_msg = MsgChannelOpenInit::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgChannelOpenInit::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Channel(ChannelMsg::OpenInit(domain_msg))) } CHAN_OPEN_TRY_TYPE_URL => { - let domain_msg = MsgChannelOpenTry::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgChannelOpenTry::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Channel(ChannelMsg::OpenTry(domain_msg))) } CHAN_OPEN_ACK_TYPE_URL => { - let domain_msg = MsgChannelOpenAck::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgChannelOpenAck::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Channel(ChannelMsg::OpenAck(domain_msg))) } CHAN_OPEN_CONFIRM_TYPE_URL => { - let domain_msg = - MsgChannelOpenConfirm::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgChannelOpenConfirm::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Channel(ChannelMsg::OpenConfirm(domain_msg))) } CHAN_CLOSE_INIT_TYPE_URL => { - let domain_msg = MsgChannelCloseInit::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgChannelCloseInit::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Channel(ChannelMsg::CloseInit(domain_msg))) } CHAN_CLOSE_CONFIRM_TYPE_URL => { - let domain_msg = - MsgChannelCloseConfirm::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgChannelCloseConfirm::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Channel(ChannelMsg::CloseConfirm(domain_msg))) } // ICS04 packet messages RECV_PACKET_TYPE_URL => { - let domain_msg = MsgRecvPacket::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgRecvPacket::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Packet(PacketMsg::Recv(domain_msg))) } ACKNOWLEDGEMENT_TYPE_URL => { - let domain_msg = MsgAcknowledgement::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgAcknowledgement::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Packet(PacketMsg::Ack(domain_msg))) } TIMEOUT_TYPE_URL => { - let domain_msg = MsgTimeout::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgTimeout::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Packet(PacketMsg::Timeout(domain_msg))) } TIMEOUT_ON_CLOSE_TYPE_URL => { - let domain_msg = MsgTimeoutOnClose::decode_vec(&any_msg.value).map_err(|e| { - RouterError::MalformedMessageBytes { - description: e.to_string(), - } - })?; + let domain_msg = MsgTimeoutOnClose::decode_vec(&any_msg.value)?; Ok(MsgEnvelope::Packet(PacketMsg::TimeoutOnClose(domain_msg))) } - _ => Err(RouterError::UnknownMessageTypeUrl(any_msg.type_url)), + + _ => Err(DecodingError::UnknownTypeUrl(any_msg.type_url))?, } } } diff --git a/ibc-core/ics26-routing/types/src/error.rs b/ibc-core/ics26-routing/types/src/error.rs index 663cbcc6a..97650e147 100644 --- a/ibc-core/ics26-routing/types/src/error.rs +++ b/ibc-core/ics26-routing/types/src/error.rs @@ -3,14 +3,12 @@ use ibc_core_host_types::identifiers::PortId; use ibc_primitives::prelude::*; /// Error type for the router module. -#[derive(Debug, Display)] +#[derive(Debug, Display, derive_more::From)] pub enum RouterError { - /// malformed message that could not be decoded: `{description}` - MalformedMessageBytes { description: String }, /// missing module MissingModule, - /// unknown message type URL `{0}` - UnknownMessageTypeUrl(String), + + // TODO(seanchen1991): This variant needs to be moved to HostError /// unknown port `{0}` UnknownPort(PortId), } diff --git a/ibc-primitives/src/lib.rs b/ibc-primitives/src/lib.rs index 5aa99f4e5..277c794cd 100644 --- a/ibc-primitives/src/lib.rs +++ b/ibc-primitives/src/lib.rs @@ -32,5 +32,5 @@ pub mod serializers; pub mod proto { pub use ibc_proto::google::protobuf::{Any, Duration, Timestamp}; - pub use ibc_proto::Protobuf; + pub use ibc_proto::{Error, Protobuf}; } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs index 780392577..dff68ecd9 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs @@ -9,6 +9,7 @@ use ibc::core::commitment_types::commitment::{ CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, }; use ibc::core::handler::types::error::ContextError; +use ibc::core::host::types::error::DecodingError; use ibc::core::host::types::identifiers::{ClientId, ClientType}; use ibc::core::host::types::path::{ClientConsensusStatePath, ClientStatePath, Path, PathBytes}; use ibc::core::primitives::prelude::*; @@ -127,16 +128,18 @@ impl TryFrom for MockClientState { type Error = ClientError; fn try_from(raw: Any) -> Result { - fn decode_client_state(value: &[u8]) -> Result { - let client_state = - Protobuf::::decode(value).map_err(|e| ClientError::Other { - description: e.to_string(), - })?; + fn decode_client_state(value: &[u8]) -> Result { + let client_state = Protobuf::::decode(value)?; Ok(client_state) } match raw.type_url.as_str() { - MOCK_CLIENT_STATE_TYPE_URL => decode_client_state(&raw.value), - _ => Err(ClientError::InvalidClientStateType(raw.type_url)), + MOCK_CLIENT_STATE_TYPE_URL => { + decode_client_state(&raw.value).map_err(ClientError::Decoding) + } + _ => Err(DecodingError::MismatchedTypeUrls { + expected: MOCK_CLIENT_STATE_TYPE_URL.to_string(), + actual: raw.type_url, + })?, } } } @@ -169,7 +172,7 @@ impl ClientStateCommon for MockClientState { if consensus_state_status(&mock_consensus_state, host_timestamp, self.trusting_period)? .is_expired() { - return Err(ClientError::InvalidStatus(Status::Expired)); + return Err(ClientError::UnexpectedStatus(Status::Expired)); } Ok(()) diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs index 96273f780..66d53d595 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs @@ -1,6 +1,7 @@ use ibc::core::client::context::consensus_state::ConsensusState; use ibc::core::client::types::error::ClientError; use ibc::core::commitment_types::commitment::CommitmentRoot; +use ibc::core::host::types::error::DecodingError; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Timestamp; use ibc::primitives::proto::{Any, Protobuf}; @@ -41,7 +42,9 @@ impl TryFrom for MockConsensusState { type Error = ClientError; fn try_from(raw: RawMockConsensusState) -> Result { - let raw_header = raw.header.ok_or(ClientError::MissingRawConsensusState)?; + let raw_header = raw.header.ok_or(DecodingError::MissingRawData { + description: "no raw header set".to_string(), + })?; Ok(Self { header: raw_header.try_into()?, @@ -64,18 +67,18 @@ impl TryFrom for MockConsensusState { type Error = ClientError; fn try_from(raw: Any) -> Result { - fn decode_consensus_state(value: &[u8]) -> Result { - let mock_consensus_state = - Protobuf::::decode(value).map_err(|e| { - ClientError::Other { - description: e.to_string(), - } - })?; + fn decode_consensus_state(value: &[u8]) -> Result { + let mock_consensus_state = Protobuf::::decode(value)?; Ok(mock_consensus_state) } match raw.type_url.as_str() { - MOCK_CONSENSUS_STATE_TYPE_URL => decode_consensus_state(&raw.value), - _ => Err(ClientError::InvalidConsensusStateType(raw.type_url)), + MOCK_CONSENSUS_STATE_TYPE_URL => { + decode_consensus_state(&raw.value).map_err(ClientError::Decoding) + } + _ => Err(DecodingError::MismatchedTypeUrls { + expected: MOCK_CONSENSUS_STATE_TYPE_URL.to_string(), + actual: raw.type_url, + })?, } } } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/header.rs b/ibc-testkit/src/testapp/ibc/clients/mock/header.rs index fac7bf00c..9f46592e4 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/header.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/header.rs @@ -3,6 +3,7 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use ibc::core::client::types::error::ClientError; use ibc::core::client::types::Height; +use ibc::core::host::types::error::DecodingError; use ibc::core::primitives::Timestamp; use ibc::primitives::proto::{Any, Protobuf}; @@ -95,12 +96,12 @@ impl TryFrom for MockHeader { fn try_from(raw: Any) -> Result { match raw.type_url.as_str() { - MOCK_HEADER_TYPE_URL => Ok(Protobuf::::decode_vec(&raw.value).map_err( - |e| ClientError::InvalidRawHeader { - description: e.to_string(), - }, - )?), - _ => Err(ClientError::InvalidHeaderType(raw.type_url)), + MOCK_HEADER_TYPE_URL => Ok(Protobuf::::decode_vec(&raw.value) + .map_err(DecodingError::Protobuf)?), + _ => Err(DecodingError::MismatchedTypeUrls { + expected: MOCK_HEADER_TYPE_URL.to_string(), + actual: raw.type_url, + })?, } } } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs b/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs index e07c310a1..d537e8209 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs @@ -1,4 +1,5 @@ use ibc::core::client::types::error::ClientError; +use ibc::core::host::types::error::DecodingError; use ibc::core::host::types::identifiers::ClientId; use ibc::core::primitives::prelude::*; use ibc::primitives::proto::{Any, Protobuf}; @@ -26,11 +27,15 @@ impl TryFrom for Misbehaviour { client_id: ClientId::new("07-tendermint", 0).expect("no error"), header1: raw .header1 - .ok_or(ClientError::MissingRawMisbehaviour)? + .ok_or(DecodingError::MissingRawData { + description: "missing header1 in raw misbehaviour".into(), + })? .try_into()?, header2: raw .header2 - .ok_or(ClientError::MissingRawMisbehaviour)? + .ok_or(DecodingError::MissingRawData { + description: "missing header2 in raw misbehaviour".into(), + })? .try_into()?, }) } @@ -52,16 +57,18 @@ impl TryFrom for Misbehaviour { type Error = ClientError; fn try_from(raw: Any) -> Result { - fn decode_misbehaviour(value: &[u8]) -> Result { - let raw_misbehaviour = - Protobuf::::decode(value).map_err(|e| ClientError::Other { - description: e.to_string(), - })?; + fn decode_misbehaviour(value: &[u8]) -> Result { + let raw_misbehaviour = Protobuf::::decode(value)?; Ok(raw_misbehaviour) } match raw.type_url.as_str() { - MOCK_MISBEHAVIOUR_TYPE_URL => decode_misbehaviour(&raw.value), - _ => Err(ClientError::InvalidMisbehaviourType(raw.type_url)), + MOCK_MISBEHAVIOUR_TYPE_URL => { + decode_misbehaviour(&raw.value).map_err(ClientError::Decoding) + } + _ => Err(DecodingError::MismatchedTypeUrls { + expected: MOCK_MISBEHAVIOUR_TYPE_URL.to_string(), + actual: raw.type_url, + })?, } } } diff --git a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs index 5f572cf6b..aef595159 100644 --- a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs +++ b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs @@ -80,7 +80,7 @@ where client_state_of_host_on_counterparty: Self::HostClientState, ) -> Result<(), ContextError> { if client_state_of_host_on_counterparty.is_frozen() { - return Err(ClientError::InvalidStatus(Status::Frozen).into()); + return Err(ClientError::UnexpectedStatus(Status::Frozen).into()); } let latest_height = self.host_height()?; diff --git a/tests-integration/tests/core/ics02_client/create_client.rs b/tests-integration/tests/core/ics02_client/create_client.rs index 78c4f8392..c78fef45c 100644 --- a/tests-integration/tests/core/ics02_client/create_client.rs +++ b/tests-integration/tests/core/ics02_client/create_client.rs @@ -180,9 +180,9 @@ fn test_create_expired_mock_client() { let fxt = create_client_fixture(Ctx::Default, Msg::ExpiredMockHeader); create_client_validate( &fxt, - Expect::Failure(Some(ContextError::ClientError(ClientError::InvalidStatus( - Status::Expired, - )))), + Expect::Failure(Some(ContextError::ClientError( + ClientError::UnexpectedStatus(Status::Expired), + ))), ); } @@ -206,9 +206,9 @@ fn test_create_expired_tm_client() { let fxt = create_client_fixture(Ctx::Default, Msg::ExpiredTendermintHeader); create_client_validate( &fxt, - Expect::Failure(Some(ContextError::ClientError(ClientError::InvalidStatus( - Status::Expired, - )))), + Expect::Failure(Some(ContextError::ClientError( + ClientError::UnexpectedStatus(Status::Expired), + ))), ); } @@ -218,9 +218,9 @@ fn test_create_frozen_tm_client() { let fxt = create_client_fixture(Ctx::Default, Msg::FrozenTendermintHeader); create_client_validate( &fxt, - Expect::Failure(Some(ContextError::ClientError(ClientError::InvalidStatus( - Status::Frozen, - )))), + Expect::Failure(Some(ContextError::ClientError( + ClientError::UnexpectedStatus(Status::Frozen), + ))), ); } From 6db56ccb41673d9cb21b9b22bfbf7129905aa648 Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Fri, 13 Sep 2024 10:01:41 -0700 Subject: [PATCH 05/18] imp(ibc-apps): migrate to `DecodingError` in `TryFrom` conversions (#1335) * imp: migrate to DecodingError in TryFrom conversions, ibc-apps * imp: apply on TryFrom * fix: missing import * fix: apply review comments * imp: move away from From --- ibc-apps/ics20-transfer/types/src/amount.rs | 12 ++++-- ibc-apps/ics20-transfer/types/src/coin.rs | 24 ++++++------ ibc-apps/ics20-transfer/types/src/denom.rs | 25 ++++++------ ibc-apps/ics20-transfer/types/src/error.rs | 28 +------------- .../ics20-transfer/types/src/msgs/transfer.rs | 23 +++++------ ibc-apps/ics20-transfer/types/src/packet.rs | 4 +- .../ics721-nft-transfer/types/src/class.rs | 27 ++++++------- .../ics721-nft-transfer/types/src/data.rs | 15 +++----- .../ics721-nft-transfer/types/src/error.rs | 23 +---------- .../types/src/msgs/transfer.rs | 13 +++---- .../ics721-nft-transfer/types/src/packet.rs | 15 +++----- .../ics721-nft-transfer/types/src/token.rs | 29 +++++++------- ibc-core/ics02-client/types/src/height.rs | 4 +- .../ics04-channel/types/src/timeout/height.rs | 11 ++---- ibc-core/ics24-host/types/src/error.rs | 38 +++++++++++++++++-- ibc-query/src/error.rs | 16 +++++--- 16 files changed, 144 insertions(+), 163 deletions(-) diff --git a/ibc-apps/ics20-transfer/types/src/amount.rs b/ibc-apps/ics20-transfer/types/src/amount.rs index 6952be514..a4efd39bd 100644 --- a/ibc-apps/ics20-transfer/types/src/amount.rs +++ b/ibc-apps/ics20-transfer/types/src/amount.rs @@ -3,13 +3,12 @@ use core::ops::Deref; use core::str::FromStr; use derive_more::{Display, From, Into}; +use ibc_core::host::types::error::DecodingError; use ibc_core::primitives::prelude::*; #[cfg(feature = "serde")] use ibc_core::primitives::serializers; use primitive_types::U256; -use super::error::TokenTransferError; - /// A type for representing token transfer amounts. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] @@ -103,10 +102,15 @@ impl AsRef for Amount { } impl FromStr for Amount { - type Err = TokenTransferError; + type Err = DecodingError; fn from_str(s: &str) -> Result { - let amount = U256::from_dec_str(s).map_err(TokenTransferError::InvalidAmount)?; + let amount = U256::from_dec_str(s).map_err(|e| { + DecodingError::invalid_raw_data(format!( + "invalid amount that could not be parsed as a U256: {e}" + )) + })?; + Ok(Self(amount)) } } diff --git a/ibc-apps/ics20-transfer/types/src/coin.rs b/ibc-apps/ics20-transfer/types/src/coin.rs index 3a8b7387f..6ebabc0f7 100644 --- a/ibc-apps/ics20-transfer/types/src/coin.rs +++ b/ibc-apps/ics20-transfer/types/src/coin.rs @@ -2,12 +2,12 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; +use ibc_core::host::types::error::DecodingError; use ibc_core::primitives::prelude::*; use ibc_proto::cosmos::base::v1beta1::Coin as ProtoCoin; use super::amount::Amount; use super::denom::{BaseDenom, PrefixedDenom}; -use super::error::TokenTransferError; /// A `Coin` type with fully qualified `PrefixedDenom`. pub type PrefixedCoin = Coin; @@ -41,21 +41,21 @@ pub struct Coin { impl Coin where - D::Err: Into, + D::Err: Display, { - pub fn from_string_list(coin_str: &str) -> Result, TokenTransferError> { + pub fn from_string_list(coin_str: &str) -> Result, DecodingError> { coin_str.split(',').map(FromStr::from_str).collect() } } impl FromStr for Coin where - D::Err: Into, + D::Err: Display, { - type Err = TokenTransferError; + type Err = DecodingError; #[allow(clippy::assign_op_pattern)] - fn from_str(coin_str: &str) -> Result { + fn from_str(coin_str: &str) -> Result { // Denominations can be 3 ~ 128 characters long and support letters, followed by either // a letter, a number or a separator ('/', ':', '.', '_' or '-'). // Loosely copy the regex from here: @@ -76,20 +76,22 @@ where .chars() .all(|x| x.is_alphanumeric() || VALID_DENOM_CHARACTERS.contains(x)) }) - .ok_or_else(|| TokenTransferError::InvalidCoin(coin_str.to_owned()))?; + .ok_or(DecodingError::invalid_raw_data(format!( + "invalid coin: {coin_str}" + )))?; Ok(Coin { amount: amount.parse()?, - denom: denom.parse().map_err(Into::into)?, + denom: denom.parse().map_err(DecodingError::invalid_raw_data)?, }) } } impl TryFrom for Coin where - D::Err: Into, + D::Err: Into, { - type Error = TokenTransferError; + type Error = DecodingError; fn try_from(proto: ProtoCoin) -> Result, Self::Error> { let denom = D::from_str(&proto.denom).map_err(Into::into)?; @@ -176,7 +178,7 @@ mod tests { fn test_parse_raw_coin_list( #[case] coins_str: &str, #[case] coins: &[(u64, &str)], - ) -> Result<(), TokenTransferError> { + ) -> Result<(), DecodingError> { assert_eq!( RawCoin::from_string_list(coins_str)?, coins diff --git a/ibc-apps/ics20-transfer/types/src/denom.rs b/ibc-apps/ics20-transfer/types/src/denom.rs index ce014ee68..0a951ca79 100644 --- a/ibc-apps/ics20-transfer/types/src/denom.rs +++ b/ibc-apps/ics20-transfer/types/src/denom.rs @@ -3,14 +3,13 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; use derive_more::{Display, From}; +use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; #[cfg(feature = "serde")] use ibc_core::primitives::serializers; use ibc_proto::ibc::applications::transfer::v1::DenomTrace as RawDenomTrace; -use super::error::TokenTransferError; - /// The "base" of a denomination. /// /// For example, given the token `my_port-1/my_channel-1/my_port-2/my_channel-2/base_denom`, @@ -40,11 +39,11 @@ impl BaseDenom { } impl FromStr for BaseDenom { - type Err = TokenTransferError; + type Err = DecodingError; fn from_str(s: &str) -> Result { if s.trim().is_empty() { - Err(TokenTransferError::EmptyBaseDenom) + Err(DecodingError::missing_raw_data("empty base denom")) } else { Ok(BaseDenom(s.to_owned())) } @@ -208,7 +207,7 @@ impl TracePath { } impl FromStr for TracePath { - type Err = TokenTransferError; + type Err = DecodingError; fn from_str(s: &str) -> Result { if s.is_empty() { @@ -219,7 +218,9 @@ impl FromStr for TracePath { remaining_parts .is_none() .then_some(trace_path) - .ok_or_else(|| TokenTransferError::InvalidTrace(s.to_owned())) + .ok_or(DecodingError::invalid_raw_data(format!( + "invalid trace path: {s}" + ))) } } @@ -323,7 +324,7 @@ pub fn is_receiver_chain_source( } impl FromStr for PrefixedDenom { - type Err = TokenTransferError; + type Err = DecodingError; /// Initializes a [`PrefixedDenom`] from a string that adheres to the format /// `{nth-port-id/channel-}/{(n-1)th-port-id/channel-}/.../{1st-port-id/channel-}/`. @@ -361,7 +362,7 @@ impl FromStr for PrefixedDenom { } impl TryFrom for PrefixedDenom { - type Error = TokenTransferError; + type Error = DecodingError; fn try_from(value: RawDenomTrace) -> Result { let base_denom = BaseDenom::from_str(&value.base_denom)?; @@ -483,7 +484,7 @@ mod tests { fn test_strange_but_accepted_prefixed_denom( #[case] prefix: &str, #[case] denom: &str, - ) -> Result<(), TokenTransferError> { + ) -> Result<(), DecodingError> { let pd_s = if prefix.is_empty() { denom.to_owned() } else { @@ -505,9 +506,9 @@ mod tests { #[case("transfer/channel-1/transfer/channel-2/")] #[case("transfer/channel-21/transfer/channel-23/ ")] #[case("transfer/channel-0/")] - #[should_panic(expected = "EmptyBaseDenom")] fn test_prefixed_empty_base_denom(#[case] pd_s: &str) { - PrefixedDenom::from_str(pd_s).expect("error"); + PrefixedDenom::from_str(pd_s) + .expect_err("error: MissingRawData { description: \"empty base denom\" }"); } #[rstest] @@ -617,7 +618,7 @@ mod tests { } #[test] - fn test_trace_path() -> Result<(), TokenTransferError> { + fn test_trace_path() -> Result<(), DecodingError> { assert!(TracePath::from_str("").is_ok(), "empty trace path"); assert!( TracePath::from_str("transfer/uatom").is_err(), diff --git a/ibc-apps/ics20-transfer/types/src/error.rs b/ibc-apps/ics20-transfer/types/src/error.rs index 15efb347f..31dcebdd5 100644 --- a/ibc-apps/ics20-transfer/types/src/error.rs +++ b/ibc-apps/ics20-transfer/types/src/error.rs @@ -1,14 +1,11 @@ //! Defines the token transfer error type -use core::convert::Infallible; - use displaydoc::Display; use ibc_core::channel::types::acknowledgement::StatusValue; use ibc_core::channel::types::channel::Order; use ibc_core::handler::types::error::ContextError; -use ibc_core::host::types::error::{DecodingError, IdentifierError}; +use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; -use uint::FromDecStrErr; #[derive(Display, Debug)] pub enum TokenTransferError { @@ -16,14 +13,6 @@ pub enum TokenTransferError { ContextError(ContextError), /// decoding error: `{0}` Decoding(DecodingError), - /// invalid amount: `{0}` - InvalidAmount(FromDecStrErr), - /// invalid coin: `{0}` - InvalidCoin(String), - /// invalid trace: `{0}` - InvalidTrace(String), - /// missing token - MissingToken, /// missing destination channel `{channel_id}` on port `{port_id}` MissingDestinationChannel { port_id: PortId, @@ -35,8 +24,6 @@ pub enum TokenTransferError { MismatchedPortIds { expected: PortId, actual: PortId }, /// channel cannot be closed UnsupportedClosedChannel, - /// empty base denomination - EmptyBaseDenom, /// failed to deserialize packet data FailedToDeserializePacketData, /// failed to deserialize acknowledgement @@ -53,31 +40,18 @@ impl std::error::Error for TokenTransferError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { Self::ContextError(e) => Some(e), - Self::InvalidAmount(e) => Some(e), Self::Decoding(e) => Some(e), _ => None, } } } -impl From for TokenTransferError { - fn from(e: Infallible) -> Self { - match e {} - } -} - impl From for TokenTransferError { fn from(e: ContextError) -> Self { Self::ContextError(e) } } -impl From for TokenTransferError { - fn from(e: IdentifierError) -> Self { - Self::Decoding(DecodingError::Identifier(e)) - } -} - impl From for TokenTransferError { fn from(e: DecodingError) -> Self { Self::Decoding(e) diff --git a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs index fcc23863b..d5c1d4eae 100644 --- a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs @@ -1,8 +1,6 @@ //! Defines the token transfer message type -use ibc_core::channel::types::error::PacketError; use ibc_core::channel::types::timeout::{TimeoutHeight, TimeoutTimestamp}; -use ibc_core::handler::types::error::ContextError; use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; @@ -10,7 +8,6 @@ use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::applications::transfer::v1::MsgTransfer as RawMsgTransfer; use ibc_proto::Protobuf; -use crate::error::TokenTransferError; use crate::packet::PacketData; pub(crate) const TYPE_URL: &str = "/ibc.applications.transfer.v1.MsgTransfer"; @@ -49,19 +46,18 @@ pub struct MsgTransfer { } impl TryFrom for MsgTransfer { - type Error = TokenTransferError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgTransfer) -> Result { - let timeout_height_on_b: TimeoutHeight = raw_msg - .timeout_height - .try_into() - .map_err(ContextError::from)?; + let timeout_height_on_b: TimeoutHeight = raw_msg.timeout_height.try_into()?; let timeout_timestamp_on_b: TimeoutTimestamp = raw_msg.timeout_timestamp.into(); // Packet timeout height and packet timeout timestamp cannot both be unset. if !timeout_height_on_b.is_set() && !timeout_timestamp_on_b.is_set() { - return Err(ContextError::from(PacketError::MissingTimeout))?; + return Err(DecodingError::missing_raw_data( + "missing timeout height or timeout timestamp", + )); } Ok(MsgTransfer { @@ -70,9 +66,8 @@ impl TryFrom for MsgTransfer { packet_data: PacketData { token: raw_msg .token - .ok_or(TokenTransferError::MissingToken)? - .try_into() - .map_err(|_| TokenTransferError::MissingToken)?, + .ok_or(DecodingError::missing_raw_data("missing token"))? + .try_into()?, sender: raw_msg.sender.into(), receiver: raw_msg.receiver.into(), memo: raw_msg.memo.into(), @@ -101,11 +96,11 @@ impl From for RawMsgTransfer { impl Protobuf for MsgTransfer {} impl TryFrom for MsgTransfer { - type Error = TokenTransferError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { match raw.type_url.as_str() { - TYPE_URL => Ok(MsgTransfer::decode_vec(&raw.value).map_err(DecodingError::Protobuf)?), + TYPE_URL => Ok(MsgTransfer::decode_vec(&raw.value)?), _ => Err(DecodingError::MismatchedTypeUrls { expected: TYPE_URL.to_string(), actual: raw.type_url, diff --git a/ibc-apps/ics20-transfer/types/src/packet.rs b/ibc-apps/ics20-transfer/types/src/packet.rs index a3615a090..8d4d5192c 100644 --- a/ibc-apps/ics20-transfer/types/src/packet.rs +++ b/ibc-apps/ics20-transfer/types/src/packet.rs @@ -2,11 +2,11 @@ use core::str::FromStr; +use ibc_core::host::types::error::DecodingError; use ibc_core::primitives::prelude::*; use ibc_core::primitives::Signer; use ibc_proto::ibc::applications::transfer::v2::FungibleTokenPacketData as RawPacketData; -use super::error::TokenTransferError; use super::{Amount, Memo, PrefixedCoin, PrefixedDenom}; /// Defines the structure of token transfers' packet bytes @@ -33,7 +33,7 @@ pub struct PacketData { } impl TryFrom for PacketData { - type Error = TokenTransferError; + type Error = DecodingError; fn try_from(raw_pkt_data: RawPacketData) -> Result { // This denom may be prefixed or unprefixed. diff --git a/ibc-apps/ics721-nft-transfer/types/src/class.rs b/ibc-apps/ics721-nft-transfer/types/src/class.rs index 8a7c941e6..17c0d9c98 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/class.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/class.rs @@ -4,6 +4,7 @@ use core::str::FromStr; use http::Uri; pub use ibc_app_transfer_types::{TracePath, TracePrefix}; +use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; #[cfg(feature = "serde")] @@ -11,7 +12,6 @@ use ibc_core::primitives::serializers; use ibc_proto::ibc::applications::nft_transfer::v1::ClassTrace as RawClassTrace; use crate::data::Data; -use crate::error::NftTransferError; /// Class ID for an NFT #[cfg_attr( @@ -44,11 +44,11 @@ impl Display for ClassId { } impl FromStr for ClassId { - type Err = NftTransferError; + type Err = DecodingError; fn from_str(class_id: &str) -> Result { if class_id.trim().is_empty() { - Err(NftTransferError::EmptyBaseClassId) + Err(DecodingError::missing_raw_data("empty base class ID")) } else { Ok(Self(class_id.to_string())) } @@ -119,7 +119,7 @@ pub fn is_receiver_chain_source( } impl FromStr for PrefixedClassId { - type Err = NftTransferError; + type Err = DecodingError; /// The parsing logic is same as [`FromStr`] impl of /// [`PrefixedDenom`](ibc_app_transfer_types::PrefixedDenom) from ICS-20. @@ -138,12 +138,11 @@ impl FromStr for PrefixedClassId { } impl TryFrom for PrefixedClassId { - type Error = NftTransferError; + type Error = DecodingError; fn try_from(value: RawClassTrace) -> Result { let base_class_id = ClassId::from_str(&value.base_class_id)?; - let trace_path = TracePath::from_str(&value.path) - .map_err(|_| NftTransferError::InvalidTrace(value.path))?; + let trace_path = TracePath::from_str(&value.path)?; Ok(Self { trace_path, @@ -243,12 +242,14 @@ impl Display for ClassUri { } impl FromStr for ClassUri { - type Err = NftTransferError; + type Err = DecodingError; fn from_str(class_uri: &str) -> Result { match Uri::from_str(class_uri) { Ok(uri) => Ok(Self(uri)), - Err(err) => Err(NftTransferError::InvalidUri(err)), + Err(err) => Err(DecodingError::invalid_raw_data(format!( + "invalid class URI: {err}" + ))), } } } @@ -278,7 +279,7 @@ impl Display for ClassData { } impl FromStr for ClassData { - type Err = NftTransferError; + type Err = DecodingError; fn from_str(class_data: &str) -> Result { // validate the data @@ -336,7 +337,7 @@ mod tests { } #[test] - fn test_class_id_trace() -> Result<(), NftTransferError> { + fn test_class_id_trace() -> Result<(), DecodingError> { assert_eq!( PrefixedClassId::from_str("transfer/channel-0/myclass")?, PrefixedClassId { @@ -360,7 +361,7 @@ mod tests { } #[test] - fn test_class_id_serde() -> Result<(), NftTransferError> { + fn test_class_id_serde() -> Result<(), DecodingError> { let dt_str = "transfer/channel-0/myclass"; let dt = PrefixedClassId::from_str(dt_str)?; assert_eq!(dt.to_string(), dt_str, "valid single trace info"); @@ -373,7 +374,7 @@ mod tests { } #[test] - fn test_trace_path() -> Result<(), NftTransferError> { + fn test_trace_path() -> Result<(), DecodingError> { assert!(TracePath::from_str("").is_ok(), "empty trace path"); assert!( TracePath::from_str("transfer/myclass").is_err(), diff --git a/ibc-apps/ics721-nft-transfer/types/src/data.rs b/ibc-apps/ics721-nft-transfer/types/src/data.rs index a54d990af..5151203f3 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/data.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/data.rs @@ -6,13 +6,10 @@ use core::str::FromStr; use base64::prelude::BASE64_STANDARD; #[cfg(feature = "serde")] use base64::Engine; -#[cfg(feature = "serde")] use ibc_core::host::types::error::DecodingError; use ibc_core::primitives::prelude::*; use mime::Mime; -use crate::error::NftTransferError; - #[cfg_attr( feature = "parity-scale-codec", derive( @@ -32,7 +29,7 @@ pub struct Data(String); #[cfg(feature = "serde")] impl Data { /// Parses the data in the format specified by ICS-721. - pub fn parse_as_ics721_data(&self) -> Result { + pub fn parse_as_ics721_data(&self) -> Result { self.0.parse::() } } @@ -44,7 +41,7 @@ impl Display for Data { } impl FromStr for Data { - type Err = NftTransferError; + type Err = DecodingError; fn from_str(s: &str) -> Result { Ok(Self(s.to_string())) @@ -96,13 +93,11 @@ pub struct Ics721Data(BTreeMap); #[cfg(feature = "serde")] impl FromStr for Ics721Data { - type Err = NftTransferError; + type Err = DecodingError; fn from_str(s: &str) -> Result { - serde_json::from_str(s).map_err(|e| { - NftTransferError::Decoding(DecodingError::InvalidJson { - description: e.to_string(), - }) + serde_json::from_str(s).map_err(|e| DecodingError::InvalidJson { + description: e.to_string(), }) } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/error.rs b/ibc-apps/ics721-nft-transfer/types/src/error.rs index 39d6463fb..d7b112a64 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/error.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/error.rs @@ -1,12 +1,9 @@ //! Defines the Non-Fungible Token Transfer (ICS-721) error types. -use core::convert::Infallible; - use displaydoc::Display; -use http::uri::InvalidUri; use ibc_core::channel::types::acknowledgement::StatusValue; use ibc_core::channel::types::channel::Order; use ibc_core::handler::types::error::ContextError; -use ibc_core::host::types::error::{DecodingError, IdentifierError}; +use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; @@ -16,17 +13,11 @@ pub enum NftTransferError { ContextError(ContextError), /// decoding error: `{0}` Decoding(DecodingError), - /// invalid trace: `{0}` - InvalidTrace(String), - /// invalid URI error: `{0}` - InvalidUri(InvalidUri), /// missing destination channel `{channel_id}` on port `{port_id}` MissingDestinationChannel { port_id: PortId, channel_id: ChannelId, }, - /// empty base class ID - EmptyBaseClassId, /// empty token ID EmptyTokenId, /// mismatched number of token IDs: expected `{expected}`, actual `{actual}` @@ -56,18 +47,6 @@ impl std::error::Error for NftTransferError { } } -impl From for NftTransferError { - fn from(e: IdentifierError) -> Self { - Self::Decoding(DecodingError::Identifier(e)) - } -} - -impl From for NftTransferError { - fn from(e: Infallible) -> Self { - match e {} - } -} - impl From for StatusValue { fn from(err: NftTransferError) -> Self { StatusValue::new(err.to_string()).expect("error message must not be empty") diff --git a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs index 5b2bfb077..fb717018c 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs @@ -1,8 +1,6 @@ //! Defines the Non-Fungible Token Transfer message type -use ibc_core::channel::types::error::PacketError; use ibc_core::channel::types::timeout::{TimeoutHeight, TimeoutTimestamp}; -use ibc_core::handler::types::error::ContextError; use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; @@ -49,19 +47,18 @@ pub struct MsgTransfer { } impl TryFrom for MsgTransfer { - type Error = NftTransferError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgTransfer) -> Result { - let timeout_height_on_b: TimeoutHeight = raw_msg - .timeout_height - .try_into() - .map_err(ContextError::from)?; + let timeout_height_on_b: TimeoutHeight = raw_msg.timeout_height.try_into()?; let timeout_timestamp_on_b: TimeoutTimestamp = raw_msg.timeout_timestamp.into(); // Packet timeout height and packet timeout timestamp cannot both be unset. if !timeout_height_on_b.is_set() && !timeout_timestamp_on_b.is_set() { - return Err(ContextError::from(PacketError::MissingTimeout))?; + return Err(DecodingError::missing_raw_data( + "missing timeout height or timeout timestamp", + )); } let memo = if raw_msg.memo.is_empty() { diff --git a/ibc-apps/ics721-nft-transfer/types/src/packet.rs b/ibc-apps/ics721-nft-transfer/types/src/packet.rs index 6a8813d07..5d9871768 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/packet.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/packet.rs @@ -116,7 +116,7 @@ impl PacketData { } impl TryFrom for PacketData { - type Error = NftTransferError; + type Error = DecodingError; fn try_from(raw_pkt_data: RawPacketData) -> Result { let class_uri = if raw_pkt_data.class_uri.is_empty() { @@ -127,10 +127,8 @@ impl TryFrom for PacketData { let class_data = if raw_pkt_data.class_data.is_empty() { None } else { - let decoded = BASE64_STANDARD - .decode(raw_pkt_data.class_data) - .map_err(DecodingError::Base64)?; - let data_str = String::from_utf8(decoded).map_err(DecodingError::StringUtf8)?; + let decoded = BASE64_STANDARD.decode(raw_pkt_data.class_data)?; + let data_str = String::from_utf8(decoded)?; Some(data_str.parse()?) }; @@ -141,10 +139,8 @@ impl TryFrom for PacketData { .token_data .iter() .map(|data| { - let decoded = BASE64_STANDARD - .decode(data) - .map_err(DecodingError::Base64)?; - let data_str = String::from_utf8(decoded).map_err(DecodingError::StringUtf8)?; + let decoded = BASE64_STANDARD.decode(data)?; + let data_str = String::from_utf8(decoded)?; data_str.parse() }) .collect(); @@ -159,6 +155,7 @@ impl TryFrom for PacketData { raw_pkt_data.receiver.into(), raw_pkt_data.memo.into(), ) + .map_err(DecodingError::invalid_raw_data) } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/token.rs b/ibc-apps/ics721-nft-transfer/types/src/token.rs index fa11e93a1..b865ed126 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/token.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/token.rs @@ -3,12 +3,12 @@ use core::fmt::{self, Display}; use core::str::FromStr; use http::Uri; +use ibc_core::host::types::error::DecodingError; use ibc_core::primitives::prelude::*; #[cfg(feature = "serde")] use ibc_core::primitives::serializers; use crate::data::Data; -use crate::error::NftTransferError; /// Token ID for an NFT #[cfg_attr( @@ -41,11 +41,11 @@ impl Display for TokenId { } impl FromStr for TokenId { - type Err = NftTransferError; + type Err = DecodingError; fn from_str(token_id: &str) -> Result { if token_id.trim().is_empty() { - Err(NftTransferError::EmptyTokenId) + Err(DecodingError::missing_raw_data("empty token ID")) } else { Ok(Self(token_id.to_string())) } @@ -90,11 +90,11 @@ impl Display for TokenIds { } impl TryFrom> for TokenIds { - type Error = NftTransferError; + type Error = DecodingError; fn try_from(token_ids: Vec) -> Result { if token_ids.is_empty() { - return Err(NftTransferError::EmptyTokenId); + return Err(DecodingError::missing_raw_data("empty token IDs")); } let ids: Result, _> = token_ids.iter().map(|t| t.parse()).collect(); @@ -104,10 +104,11 @@ impl TryFrom> for TokenIds { ids.dedup(); if ids.len() != token_ids.len() { - return Err(NftTransferError::MismatchedNumberOfTokenIds { - expected: token_ids.len(), - actual: ids.len(), - }); + return Err(DecodingError::invalid_raw_data(format!( + "mismatched number of token IDs: expected {}, actual {}", + token_ids.len(), + ids.len() + ))); } Ok(Self(ids)) @@ -177,13 +178,11 @@ impl Display for TokenUri { } impl FromStr for TokenUri { - type Err = NftTransferError; + type Err = DecodingError; fn from_str(token_uri: &str) -> Result { - match Uri::from_str(token_uri) { - Ok(uri) => Ok(Self(uri)), - Err(err) => Err(NftTransferError::InvalidUri(err)), - } + let token_uri = Uri::from_str(token_uri).map_err(DecodingError::invalid_raw_data)?; + Ok(Self(token_uri)) } } @@ -212,7 +211,7 @@ impl Display for TokenData { } impl FromStr for TokenData { - type Err = NftTransferError; + type Err = DecodingError; fn from_str(token_data: &str) -> Result { let data = Data::from_str(token_data)?; diff --git a/ibc-core/ics02-client/types/src/height.rs b/ibc-core/ics02-client/types/src/height.rs index 8785a89d8..92da357ee 100644 --- a/ibc-core/ics02-client/types/src/height.rs +++ b/ibc-core/ics02-client/types/src/height.rs @@ -5,6 +5,7 @@ use core::num::ParseIntError; use core::str::FromStr; use displaydoc::Display; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_proto::ibc::core::client::v1::Height as RawHeight; use ibc_proto::Protobuf; @@ -116,10 +117,11 @@ impl Ord for Height { impl Protobuf for Height {} impl TryFrom for Height { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw_height: RawHeight) -> Result { Height::new(raw_height.revision_number, raw_height.revision_height) + .map_err(DecodingError::invalid_raw_data) } } diff --git a/ibc-core/ics04-channel/types/src/timeout/height.rs b/ibc-core/ics04-channel/types/src/timeout/height.rs index 43dfe3bf3..46d6ab49a 100644 --- a/ibc-core/ics04-channel/types/src/timeout/height.rs +++ b/ibc-core/ics04-channel/types/src/timeout/height.rs @@ -3,11 +3,10 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use ibc_core_client_types::Height; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_proto::ibc::core::client::v1::Height as RawHeight; -use crate::error::PacketError; - /// Indicates a consensus height on the destination chain after which the packet /// will no longer be processed, and will instead count as having timed-out. /// @@ -86,7 +85,7 @@ impl TimeoutHeight { } impl TryFrom for TimeoutHeight { - type Error = PacketError; + type Error = DecodingError; // Note: it is important for `revision_number` to also be `0`, otherwise // packet commitment proofs will be incorrect (proof construction in @@ -96,16 +95,14 @@ impl TryFrom for TimeoutHeight { if raw_height.revision_number == 0 && raw_height.revision_height == 0 { Ok(TimeoutHeight::Never) } else { - let height = raw_height - .try_into() - .map_err(PacketError::InvalidTimeoutHeight)?; + let height = raw_height.try_into()?; Ok(TimeoutHeight::At(height)) } } } impl TryFrom> for TimeoutHeight { - type Error = PacketError; + type Error = DecodingError; fn try_from(maybe_raw_height: Option) -> Result { match maybe_raw_height { diff --git a/ibc-core/ics24-host/types/src/error.rs b/ibc-core/ics24-host/types/src/error.rs index 2356d7363..b3738e952 100644 --- a/ibc-core/ics24-host/types/src/error.rs +++ b/ibc-core/ics24-host/types/src/error.rs @@ -54,9 +54,17 @@ pub enum DecodingError { UnknownTypeUrl(String), } -impl From for DecodingError { - fn from(e: ProtoError) -> Self { - Self::Protobuf(e) +impl DecodingError { + pub fn invalid_raw_data(description: T) -> Self { + Self::InvalidRawData { + description: description.to_string(), + } + } + + pub fn missing_raw_data(description: T) -> Self { + Self::MissingRawData { + description: description.to_string(), + } } } @@ -66,6 +74,30 @@ impl From for DecodingError { } } +impl From for DecodingError { + fn from(e: ProtoError) -> Self { + Self::Protobuf(e) + } +} + +impl From for DecodingError { + fn from(e: Base64Error) -> Self { + Self::Base64(e) + } +} + +impl From for DecodingError { + fn from(e: FromUtf8Error) -> Self { + Self::StringUtf8(e) + } +} + +impl From for DecodingError { + fn from(e: Utf8Error) -> Self { + Self::StrUtf8(e) + } +} + #[cfg(feature = "std")] impl std::error::Error for IdentifierError {} diff --git a/ibc-query/src/error.rs b/ibc-query/src/error.rs index 4c41120eb..a16bda8e7 100644 --- a/ibc-query/src/error.rs +++ b/ibc-query/src/error.rs @@ -5,7 +5,7 @@ use ibc::core::channel::types::error::{ChannelError, PacketError}; use ibc::core::client::types::error::ClientError; use ibc::core::connection::types::error::ConnectionError; use ibc::core::handler::types::error::ContextError; -use ibc::core::host::types::error::IdentifierError; +use ibc::core::host::types::error::{DecodingError, IdentifierError}; use tonic::Status; /// The main error type of the ibc-query crate. This type mainly @@ -15,8 +15,8 @@ use tonic::Status; pub enum QueryError { /// context error: `{0}` ContextError(ContextError), - /// identifier error: `{0}` - IdentifierError(IdentifierError), + /// decoding error: `{0}` + DecodingError(DecodingError), /// missing proof: `{0}` MissingProof(String), /// missing field: `{0}` @@ -36,8 +36,8 @@ impl QueryError { impl From for Status { fn from(e: QueryError) -> Self { match e { + QueryError::DecodingError(de) => Self::internal(de.to_string()), QueryError::ContextError(ctx_err) => Self::internal(ctx_err.to_string()), - QueryError::IdentifierError(id_err) => Self::internal(id_err.to_string()), QueryError::MissingProof(description) => Self::not_found(description), QueryError::MissingField(description) => Self::invalid_argument(description), } @@ -74,8 +74,14 @@ impl From for QueryError { } } +impl From for QueryError { + fn from(e: DecodingError) -> Self { + Self::DecodingError(e) + } +} + impl From for QueryError { fn from(e: IdentifierError) -> Self { - Self::IdentifierError(e) + Self::DecodingError(DecodingError::Identifier(e)) } } From 1cdd295e6c7f5f9c956115b3fe827246351e3139 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Mon, 16 Sep 2024 13:34:14 -0500 Subject: [PATCH 06/18] Define `HostError` type (#1331) * Define DecodingError in ibc-primitives * Utilize DecodingError in ics721 * Start using DecodingError in ClientError * Define StatusError type * Wire up StatusError * Wiring up DecodingError * Add DecodingError to RouterError * Remove unused From impl * Change format of an import * Change format of an import * Change format of an import * Move DecodingError into ics24 * Cargo nightly fmt * Use DecodingError in more places * cargo fmt * cargo fmt * Update cw-check Cargo.lock * Add necessary wasm-client feature attribute * Move InvalidUri error variant back to NftTransferError * Regenerate cw hcheck cargo.lock * Add serde feature attribute * Remove ClientError::InvalidClientIdentifier error variant in favor of DecodingError::InvalidIdentifier * Add derive_more::From on NftTransferError * Stashing changes * Revert "Add derive_more::From on NftTransferError" This reverts commit ea9c83d66ab8fed7f271b2bb387fd4e65d0170ba. * Remove RouterError::UnknownMessageTypeUrl * Add derive_more::From on TokenTransferError * Add derive_more to NftTransferError * Remove tendermint-proto dependency from ibc-primitives * Remove StatusError * Remove unnecessary ClientError::Decoding wrappings * Clean up TendermintClientError * Regenerate cw-check cargo.lock * taplo fmt * Apply PR feedback * Use ibc_proto::Error type instead of tendermint_proto::Error * Change FailedToParseType fields to make them more clear * Revert InvalidTrace and InvalidCoin TokenTransferError variants * Remove NftTransferError variants in favor of DecodingError::InvalidJson * cargo fmt * Regenerate cw-check cargo.lock * Separate out error variants that need to be moved to host-relevant errors * Consolidate TendermintClientError decoding errors * Consolidate Connection and Packet decoding errors * Remove WasmClientError * Consolidate Identifier variant naming * Remove HostError annotations in doc comments * Consolidate CommitmentError variants * Consolidate ConnectionError variants * Revert some CommitmentError variants * Change TryFrom for MsgEnvelope Error type to DecodingError * Define HostError type * Rename ContextError to HandlerError * Change `pick_version` impl * Update ValidationContext trait methods to return HostError type * Rename HandlerError variants throughout the code base * Remove match arm that is no longer relevant * Change ClientValidationContext trait methods to return HostErrors * Change TokenTransferValidationContext and NftTransferValidationContext trait error types * Updating validation contexts to return HostError types * Map errors to HostError variants * Update ValidateSelfClientContext trait * Update Upgrade validation and execution contexts to return HostErrors * Fix merge conflicts * Fix merge conflicts * Revert execute_upgrade_client_proposal error type to UpgradeClientError * cargo fmt * Remove unused alloc::string::ToString * Import ibc_core::primitives::prelude into handler/mod.rs * cargo fmt * Attempt to fix failing testkit test * Remove RouterError::UnknownPort variant * Remove some uses of ClientError::Other variants * Fix recv_packet_validate_happy_path test * Fix conn_open_ack_no_connection test * cargo fmt * fix conn_open_ack_no_connection test without adding new HostError variant * fix test_create_client_try_from test * Remove unnecessary import * Fix test_create_client_try_from * cargo fmt * fix: remove now unneeded with_packet_receipt * fix: revert unintended ack status changes in ICS-20 * fix: revert unintended ack status changes in ICS-721 * fix: remove unintended tendermint-proto * fix: update Cargo.lock for cw-check * Fix lingering issues from merge conflicts * Fix lingering issues from merge conflicts * Remove From for ClientError impl * cargo fmt * Rename HostError InvalidData and MissingData variants * Define helper functions for HostError * Use newly-define HostError helpers * Remove HostError::AppModule variant * Prune some HostError variants * Consolidate some HostError variants * Remove HostError::NonexistentType variant * Remove HostError::UnexpectedState variant * Consolidate HostError::UnknownResource variant * cargo fmt * Remove unnecessary to_string calls * Revert `pick_version` method's documentation * Remove some more HostError variants * Remove From for StatusValue impl * Fix AcknowledgementStatus tests * fix: revert errors in ICS721 callbacks * Change references to HandlerError in docs to refer to HostError where appropriate --------- Signed-off-by: Sean Chen Co-authored-by: Farhad Shabani --- .../1320-define-host-error-type.md | 2 + ...482-fix-validate-self-client-error-type.md | 6 +- .../v0.33.0/improvement/547-error-strings.md | 2 +- ...-use-result-for-safe-counters-increment.md | 2 +- ...-result-in-logger-event-emitter-methods.md | 2 +- CHANGELOG.md | 8 +- .../adr-006-upgrade-client-implementation.md | 4 +- .../adr-007-light-client-contexts.md | 6 +- ...010-enable-standalone-ics02-integration.md | 42 +-- ibc-apps/ics20-transfer/src/context.rs | 24 +- ibc-apps/ics20-transfer/src/handler/mod.rs | 13 +- .../src/handler/on_recv_packet.rs | 10 +- ibc-apps/ics20-transfer/src/module.rs | 8 +- ibc-apps/ics20-transfer/types/src/error.rs | 27 +- .../ics20-transfer/types/src/msgs/transfer.rs | 1 - ibc-apps/ics721-nft-transfer/src/context.rs | 33 +- .../ics721-nft-transfer/src/handler/mod.rs | 42 ++- .../src/handler/on_recv_packet.rs | 14 +- ibc-apps/ics721-nft-transfer/src/module.rs | 8 +- .../ics721-nft-transfer/types/src/error.rs | 19 +- .../types/src/msgs/transfer.rs | 1 - ibc-core/ics02-client/context/src/context.rs | 34 +- .../ics02-client/src/handler/create_client.rs | 6 +- .../src/handler/recover_client.rs | 6 +- .../ics02-client/src/handler/update_client.rs | 13 +- .../src/handler/upgrade_client.rs | 17 +- ibc-core/ics02-client/types/src/error.rs | 66 ++-- ibc-core/ics02-client/types/src/events.rs | 98 +++-- .../types/src/msgs/misbehaviour.rs | 4 +- .../types/src/msgs/recover_client.rs | 5 +- .../types/src/msgs/update_client.rs | 4 +- .../types/src/msgs/upgrade_client.rs | 19 +- ibc-core/ics03-connection/src/delay.rs | 8 +- .../src/handler/conn_open_ack.rs | 12 +- .../src/handler/conn_open_confirm.rs | 12 +- .../src/handler/conn_open_init.rs | 6 +- .../src/handler/conn_open_try.rs | 12 +- ibc-core/ics03-connection/src/handler/mod.rs | 6 +- .../ics03-connection/types/src/connection.rs | 4 +- ibc-core/ics03-connection/types/src/error.rs | 14 +- .../ics03-connection/types/src/version.rs | 4 +- ibc-core/ics04-channel/src/context.rs | 34 +- .../src/handler/acknowledgement.rs | 10 +- .../src/handler/chan_close_confirm.rs | 16 +- .../src/handler/chan_close_init.rs | 16 +- .../src/handler/chan_open_ack.rs | 8 +- .../src/handler/chan_open_confirm.rs | 21 +- .../src/handler/chan_open_init.rs | 8 +- .../src/handler/chan_open_try.rs | 8 +- .../ics04-channel/src/handler/recv_packet.rs | 14 +- .../ics04-channel/src/handler/send_packet.rs | 10 +- ibc-core/ics04-channel/src/handler/timeout.rs | 12 +- .../src/handler/timeout_on_close.rs | 6 +- ibc-core/ics04-channel/types/src/error.rs | 21 -- .../cosmos/src/upgrade_proposal/context.rs | 16 +- .../cosmos/src/upgrade_proposal/plan.rs | 20 +- .../cosmos/src/upgrade_proposal/proposal.rs | 27 +- .../cosmos/src/validate_self_client.rs | 110 +++--- ibc-core/ics24-host/src/context.rs | 79 ++--- ibc-core/ics24-host/types/src/error.rs | 47 ++- ibc-core/ics25-handler/src/entrypoint.rs | 30 +- ibc-core/ics25-handler/types/src/error.rs | 42 ++- ibc-core/ics26-routing/types/src/error.rs | 5 - ibc-query/src/core/context.rs | 25 +- ibc-query/src/error.rs | 38 +- ibc-testkit/src/context.rs | 10 +- ibc-testkit/src/fixtures/mod.rs | 6 +- .../ibc/applications/nft_transfer/context.rs | 35 +- .../ibc/applications/transfer/context.rs | 24 +- .../testapp/ibc/clients/mock/client_state.rs | 7 +- .../src/testapp/ibc/core/client_ctx.rs | 125 ++++--- ibc-testkit/src/testapp/ibc/core/core_ctx.rs | 334 +++++++++--------- .../tests/core/ics02_client/create_client.rs | 20 +- .../tests/core/ics02_client/upgrade_client.rs | 13 +- .../core/ics03_connection/conn_open_ack.rs | 29 +- tests-integration/tests/core/router.rs | 10 +- 76 files changed, 942 insertions(+), 918 deletions(-) create mode 100644 .changelog/unreleased/breaking-changes/1320-define-host-error-type.md diff --git a/.changelog/unreleased/breaking-changes/1320-define-host-error-type.md b/.changelog/unreleased/breaking-changes/1320-define-host-error-type.md new file mode 100644 index 000000000..ff8e02c75 --- /dev/null +++ b/.changelog/unreleased/breaking-changes/1320-define-host-error-type.md @@ -0,0 +1,2 @@ +- Defined a new `HostError` type in ics24 to draw distinction between protocol errors and host errors + ([\1320](https://github.com/cosmos/ibc-rs/issues/1320)) diff --git a/.changelog/v0.31.0/breaking-changes/482-fix-validate-self-client-error-type.md b/.changelog/v0.31.0/breaking-changes/482-fix-validate-self-client-error-type.md index b68e2b01c..f05961027 100644 --- a/.changelog/v0.31.0/breaking-changes/482-fix-validate-self-client-error-type.md +++ b/.changelog/v0.31.0/breaking-changes/482-fix-validate-self-client-error-type.md @@ -1,3 +1,3 @@ -- Modify `validate_self_client` error type to return `ContextError` instead of - `ConnectionError` - ([#482](https://github.com/cosmos/ibc-rs/issues/482)) \ No newline at end of file +- Modify `validate_self_client` error type to return `HostError` instead of + `ConnectionError` + ([#482](https://github.com/cosmos/ibc-rs/issues/482)) diff --git a/.changelog/v0.33.0/improvement/547-error-strings.md b/.changelog/v0.33.0/improvement/547-error-strings.md index 661201f75..064388cf1 100644 --- a/.changelog/v0.33.0/improvement/547-error-strings.md +++ b/.changelog/v0.33.0/improvement/547-error-strings.md @@ -1,2 +1,2 @@ -- Fix ContextError Display output +- Fix HandlerError Display output ([#547](https://github.com/cosmos/ibc-rs/issues/547)) diff --git a/.changelog/v0.45.0/breaking-changes/857-use-result-for-safe-counters-increment.md b/.changelog/v0.45.0/breaking-changes/857-use-result-for-safe-counters-increment.md index f0f87285e..c656a7fd9 100644 --- a/.changelog/v0.45.0/breaking-changes/857-use-result-for-safe-counters-increment.md +++ b/.changelog/v0.45.0/breaking-changes/857-use-result-for-safe-counters-increment.md @@ -1,3 +1,3 @@ - Allow hosts to handle overflow cases in `increase_*_counter` methods by - returning `Result<(),ContextError>` type. + returning `Result<(),HostError>` type. ([#857](https://github.com/cosmos/ibc-rs/issues/857)) diff --git a/.changelog/v0.45.0/breaking-changes/859-return-result-in-logger-event-emitter-methods.md b/.changelog/v0.45.0/breaking-changes/859-return-result-in-logger-event-emitter-methods.md index 9c25b1ba3..7157bd3be 100644 --- a/.changelog/v0.45.0/breaking-changes/859-return-result-in-logger-event-emitter-methods.md +++ b/.changelog/v0.45.0/breaking-changes/859-return-result-in-logger-event-emitter-methods.md @@ -1,2 +1,2 @@ -- logger and event emitter methods return `Result<(), ContextError>` type. +- logger and event emitter methods return `Result<(), HostError>` type. ([#859](https://github.com/cosmos/ibc-rs/issues/859)) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56e149579..2d4949e2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -641,9 +641,9 @@ There are no consensus-breaking changes. - Bump ibc-proto-rs to v0.34.0 ([#790](https://github.com/cosmos/ibc-rs/issues/790)) - Allow hosts to handle overflow cases in `increase_*_counter` methods by - returning `Result<(),ContextError>` type. + returning `Result<(),HandlerError>` type. ([#857](https://github.com/cosmos/ibc-rs/issues/857)) -- logger and event emitter methods return `Result<(), ContextError>` type. +- logger and event emitter methods return `Result<(), HandlerError>` type. ([#859](https://github.com/cosmos/ibc-rs/issues/859)) - Bump `ibc-proto-rs` to v0.35.0 along with some other minor dependency updates ([#873](https://github.com/cosmos/ibc-rs/issues/873)) @@ -1042,7 +1042,7 @@ There are no consensus-breaking changes. ### IMPROVEMENT -- Fix `ContextError` Display output +- Fix `HandlerError` Display output ([#547](https://github.com/cosmos/ibc-rs/issues/547)) ## v0.32.0 @@ -1099,7 +1099,7 @@ There are no consensus-breaking changes. ([#479](https://github.com/cosmos/ibc-rs/issues/479)) - Remove Send + Sync supertraits on the Module trait ([#480](https://github.com/cosmos/ibc-rs/issues/480)) -- Modify `validate_self_client` error type to return `ContextError` instead of +- Modify `validate_self_client` error type to return `HandlerError` instead of `ConnectionError` ([#482](https://github.com/cosmos/ibc-rs/issues/482)) diff --git a/docs/architecture/adr-006-upgrade-client-implementation.md b/docs/architecture/adr-006-upgrade-client-implementation.md index d1aa8fc86..fbfd86535 100644 --- a/docs/architecture/adr-006-upgrade-client-implementation.md +++ b/docs/architecture/adr-006-upgrade-client-implementation.md @@ -119,7 +119,7 @@ supported by `IBC-rs`: negotiated on connection handshake. 10. (U) Changing parameters that are customizable by relayers like `TrustLevel` and `TrustingPeriod`, `max_clock_drift` - + #### Upgrade Process Step-by-step An IBC-connected Tendermint chain will take the following steps to completely @@ -250,7 +250,7 @@ previous section as mentioned: 1. ```rust if old_client_state.is_frozen() { - return Err(ContextError::ClientError(ClientError::ClientFrozen { + return Err(HandlerError::Client(ClientError::ClientFrozen { client_id, })); } diff --git a/docs/architecture/adr-007-light-client-contexts.md b/docs/architecture/adr-007-light-client-contexts.md index b0caabdd5..5bf30de70 100644 --- a/docs/architecture/adr-007-light-client-contexts.md +++ b/docs/architecture/adr-007-light-client-contexts.md @@ -98,12 +98,12 @@ pub trait ClientExecutionContext: Sized { /// Called upon successful client creation and update fn store_client_state( ... - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Called upon successful client creation and update fn store_consensus_state( ... - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; } ``` @@ -120,7 +120,7 @@ pub trait ValidationContext: Router { type ClientValidationContext; type ClientExecutionContext; /// Enum that can contain a `ConsensusState` object of any supported light client - type AnyConsensusState: ConsensusState; + type AnyConsensusState: ConsensusState; /// Enum that can contain a `ClientState` object of any supported light client type AnyClientState: ClientState< Self::AnyConsensusState, diff --git a/docs/architecture/adr-010-enable-standalone-ics02-integration.md b/docs/architecture/adr-010-enable-standalone-ics02-integration.md index 24dbe1149..feb0c9695 100644 --- a/docs/architecture/adr-010-enable-standalone-ics02-integration.md +++ b/docs/architecture/adr-010-enable-standalone-ics02-integration.md @@ -129,26 +129,26 @@ pub trait ValidationContext { fn get_client_validation_context(&self) -> &Self::V; // This method will be removed and replaced by a `ClientStateDecoder` trait that will encapsulate the ability to decode a client state from an `Any` -- fn decode_client_state(&self, client_state: Any) -> Result; +- fn decode_client_state(&self, client_state: Any) -> Result; -- fn client_state(&self, client_id: &ClientId) -> Result; +- fn client_state(&self, client_id: &ClientId) -> Result; - fn consensus_state( - &self, - client_cons_state_path: &ClientConsensusStatePath, -- ) -> Result; +- ) -> Result; fn host_consensus_state( &self, height: &Height, -- ) -> Result; -+ ) -> Result; +- ) -> Result; ++ ) -> Result; fn validate_self_client( &self, - client_state_of_host_on_counterparty: Any, + client_state_of_host_on_counterparty: Self::HostClientState, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; ... // other methods } @@ -200,18 +200,18 @@ pub trait ClientValidationContext: Sized { + type ClientStateRef: ClientStateValidation; + type ConsensusStateRef: ConsensusState; -+ fn client_state(&self, client_id: &ClientId) -> Result; ++ fn client_state(&self, client_id: &ClientId) -> Result; + fn consensus_state( + &self, + client_cons_state_path: &ClientConsensusStatePath, -+ ) -> Result; ++ ) -> Result; fn client_update_meta( &self, client_id: &ClientId, height: &Height, - ) -> Result<(Timestamp, Height), ContextError>; + ) -> Result<(Timestamp, Height), HostError>; } pub trait ClientExecutionContext: @@ -222,7 +222,7 @@ pub trait ClientExecutionContext: - type AnyConsensusState: ConsensusState; + type ClientStateMut: ClientStateExecution; -+ fn client_state_mut(&self, client_id: &ClientId) -> Result { ++ fn client_state_mut(&self, client_id: &ClientId) -> Result { + self.client_state(client_id) + } @@ -230,18 +230,18 @@ pub trait ClientExecutionContext: &mut self, client_state_path: ClientStatePath, client_state: Self::ClientStateMut, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; fn store_consensus_state( &mut self, consensus_state_path: ClientConsensusStatePath, consensus_state: Self::ConsensusStateRef, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; fn delete_consensus_state( &mut self, consensus_state_path: ClientConsensusStatePath, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; fn store_update_meta( &mut self, @@ -249,13 +249,13 @@ pub trait ClientExecutionContext: height: Height, host_timestamp: Timestamp, host_height: Height, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; fn delete_update_meta( &mut self, client_id: ClientId, height: Height, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; } ``` @@ -306,28 +306,28 @@ pub trait ExtClientValidationContext: + type ConversionError: ToString; + type AnyConsensusState: TryInto; -+ fn host_timestamp(&self) -> Result; ++ fn host_timestamp(&self) -> Result; -+ fn host_height(&self) -> Result; ++ fn host_height(&self) -> Result; - fn consensus_state( - &self, - client_cons_state_path: &ClientConsensusStatePath, -- ) -> Result; +- ) -> Result; -+ fn consensus_state_heights(&self, client_id: &ClientId) -> Result, ContextError>; ++ fn consensus_state_heights(&self, client_id: &ClientId) -> Result, HostError>; fn next_consensus_state( &self, client_id: &ClientId, height: &Height, - ) -> Result, ContextError>; + ) -> Result, HostError>; fn prev_consensus_state( &self, client_id: &ClientId, height: &Height, - ) -> Result, ContextError>; + ) -> Result, HostError>; } -impl ExecutionContext for T where T: CommonContext + ClientExecutionContext {} diff --git a/ibc-apps/ics20-transfer/src/context.rs b/ibc-apps/ics20-transfer/src/context.rs index 8c22ad386..2917c9fe9 100644 --- a/ibc-apps/ics20-transfer/src/context.rs +++ b/ibc-apps/ics20-transfer/src/context.rs @@ -1,7 +1,7 @@ //! Defines the main context traits and IBC module callbacks -use ibc_app_transfer_types::error::TokenTransferError; use ibc_app_transfer_types::{Memo, PrefixedCoin, PrefixedDenom}; +use ibc_core::host::types::error::HostError; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; use ibc_core::primitives::Signer; @@ -11,13 +11,13 @@ pub trait TokenTransferValidationContext { type AccountId: TryFrom; /// get_port returns the portID for the transfer module. - fn get_port(&self) -> Result; + fn get_port(&self) -> Result; /// Returns Ok() if the host chain supports sending coins. - fn can_send_coins(&self) -> Result<(), TokenTransferError>; + fn can_send_coins(&self) -> Result<(), HostError>; /// Returns Ok() if the host chain supports receiving coins. - fn can_receive_coins(&self) -> Result<(), TokenTransferError>; + fn can_receive_coins(&self) -> Result<(), HostError>; /// Validates that the tokens can be escrowed successfully. /// @@ -30,7 +30,7 @@ pub trait TokenTransferValidationContext { channel_id: &ChannelId, coin: &PrefixedCoin, memo: &Memo, - ) -> Result<(), TokenTransferError>; + ) -> Result<(), HostError>; /// Validates that the tokens can be unescrowed successfully. fn unescrow_coins_validate( @@ -39,14 +39,14 @@ pub trait TokenTransferValidationContext { port_id: &PortId, channel_id: &ChannelId, coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; + ) -> Result<(), HostError>; /// Validates the receiver account and the coin input fn mint_coins_validate( &self, account: &Self::AccountId, coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; + ) -> Result<(), HostError>; /// Validates the sender account and the coin input before burning. /// @@ -57,7 +57,7 @@ pub trait TokenTransferValidationContext { account: &Self::AccountId, coin: &PrefixedCoin, memo: &Memo, - ) -> Result<(), TokenTransferError>; + ) -> Result<(), HostError>; /// Returns a hash of the prefixed denom. /// Implement only if the host chain supports hashed denominations. @@ -79,7 +79,7 @@ pub trait TokenTransferExecutionContext: TokenTransferValidationContext { channel_id: &ChannelId, coin: &PrefixedCoin, memo: &Memo, - ) -> Result<(), TokenTransferError>; + ) -> Result<(), HostError>; /// Executes the unescrow of the tokens in a user account. fn unescrow_coins_execute( @@ -88,14 +88,14 @@ pub trait TokenTransferExecutionContext: TokenTransferValidationContext { port_id: &PortId, channel_id: &ChannelId, coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; + ) -> Result<(), HostError>; /// Executes minting of the tokens in a user account. fn mint_coins_execute( &mut self, account: &Self::AccountId, coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; + ) -> Result<(), HostError>; /// Executes burning of the tokens in a user account. /// @@ -106,5 +106,5 @@ pub trait TokenTransferExecutionContext: TokenTransferValidationContext { account: &Self::AccountId, coin: &PrefixedCoin, memo: &Memo, - ) -> Result<(), TokenTransferError>; + ) -> Result<(), HostError>; } diff --git a/ibc-apps/ics20-transfer/src/handler/mod.rs b/ibc-apps/ics20-transfer/src/handler/mod.rs index 6d3cde510..95ed5441c 100644 --- a/ibc-apps/ics20-transfer/src/handler/mod.rs +++ b/ibc-apps/ics20-transfer/src/handler/mod.rs @@ -6,6 +6,7 @@ use ibc_app_transfer_types::error::TokenTransferError; use ibc_app_transfer_types::is_sender_chain_source; use ibc_app_transfer_types::packet::PacketData; use ibc_core::channel::types::packet::Packet; +use ibc_core::primitives::prelude::*; pub use on_recv_packet::*; pub use send_transfer::*; @@ -27,16 +28,16 @@ pub fn refund_packet_token_execute( packet.chan_id_on_a.clone(), &data.token.denom, ) { - ctx_a.unescrow_coins_execute( + Ok(ctx_a.unescrow_coins_execute( &sender, &packet.port_id_on_a, &packet.chan_id_on_a, &data.token, - ) + )?) } // mint vouchers back to sender else { - ctx_a.mint_coins_execute(&sender, &data.token) + Ok(ctx_a.mint_coins_execute(&sender, &data.token)?) } } @@ -56,13 +57,13 @@ pub fn refund_packet_token_validate( packet.chan_id_on_a.clone(), &data.token.denom, ) { - ctx_a.unescrow_coins_validate( + Ok(ctx_a.unescrow_coins_validate( &sender, &packet.port_id_on_a, &packet.chan_id_on_a, &data.token, - ) + )?) } else { - ctx_a.mint_coins_validate(&sender, &data.token) + Ok(ctx_a.mint_coins_validate(&sender, &data.token)?) } } diff --git a/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs b/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs index b0fcbd877..76e22b3b6 100644 --- a/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs +++ b/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs @@ -21,7 +21,7 @@ pub fn process_recv_packet_execute( ) -> Result { ctx_b .can_receive_coins() - .map_err(|err| (ModuleExtras::empty(), err))?; + .map_err(|err| (ModuleExtras::empty(), err.into()))?; let receiver_account = data.receiver.clone().try_into().map_err(|_| { ( @@ -60,7 +60,7 @@ pub fn process_recv_packet_execute( &packet.chan_id_on_b, &coin, ) - .map_err(|token_err| (ModuleExtras::empty(), token_err))?; + .map_err(|err| (ModuleExtras::empty(), err.into()))?; ctx_b .unescrow_coins_execute( &receiver_account, @@ -68,7 +68,7 @@ pub fn process_recv_packet_execute( &packet.chan_id_on_b, &coin, ) - .map_err(|token_err| (ModuleExtras::empty(), token_err))?; + .map_err(|err| (ModuleExtras::empty(), err.into()))?; ModuleExtras::empty() } else { @@ -103,11 +103,11 @@ pub fn process_recv_packet_execute( // can be refunded. ctx_b .mint_coins_validate(&receiver_account, &coin) - .map_err(|token_err| (extras.clone(), token_err))?; + .map_err(|err| (extras.clone(), err.into()))?; ctx_b .mint_coins_execute(&receiver_account, &coin) - .map_err(|token_err| (extras.clone(), token_err))?; + .map_err(|err| (extras.clone(), err.into()))?; extras }; diff --git a/ibc-apps/ics20-transfer/src/module.rs b/ibc-apps/ics20-transfer/src/module.rs index 5958184c7..2c24dc6fe 100644 --- a/ibc-apps/ics20-transfer/src/module.rs +++ b/ibc-apps/ics20-transfer/src/module.rs @@ -6,7 +6,7 @@ use ibc_core::channel::types::acknowledgement::{Acknowledgement, Acknowledgement use ibc_core::channel::types::channel::{Counterparty, Order}; use ibc_core::channel::types::packet::Packet; use ibc_core::channel::types::Version; -use ibc_core::handler::types::error::ContextError; +use ibc_core::handler::types::error::HandlerError; use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc_core::primitives::prelude::*; @@ -44,7 +44,7 @@ pub fn on_chan_open_init_validate( if !version.is_empty() { version .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(ContextError::from)?; + .map_err(HandlerError::from)?; } Ok(()) @@ -80,7 +80,7 @@ pub fn on_chan_open_try_validate( counterparty_version .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(ContextError::from)?; + .map_err(HandlerError::from)?; Ok(()) } @@ -105,7 +105,7 @@ pub fn on_chan_open_ack_validate( ) -> Result<(), TokenTransferError> { counterparty_version .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(ContextError::from)?; + .map_err(HandlerError::from)?; Ok(()) } diff --git a/ibc-apps/ics20-transfer/types/src/error.rs b/ibc-apps/ics20-transfer/types/src/error.rs index 31dcebdd5..00e81614b 100644 --- a/ibc-apps/ics20-transfer/types/src/error.rs +++ b/ibc-apps/ics20-transfer/types/src/error.rs @@ -2,15 +2,15 @@ use displaydoc::Display; use ibc_core::channel::types::acknowledgement::StatusValue; use ibc_core::channel::types::channel::Order; -use ibc_core::handler::types::error::ContextError; -use ibc_core::host::types::error::DecodingError; +use ibc_core::handler::types::error::HandlerError; +use ibc_core::host::types::error::{DecodingError, HostError}; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; #[derive(Display, Debug)] pub enum TokenTransferError { - /// context error: `{0}` - ContextError(ContextError), + /// host error: `{0}` + Handler(HandlerError), /// decoding error: `{0}` Decoding(DecodingError), /// missing destination channel `{channel_id}` on port `{port_id}` @@ -28,10 +28,7 @@ pub enum TokenTransferError { FailedToDeserializePacketData, /// failed to deserialize acknowledgement FailedToDeserializeAck, - - // TODO(seanchen1991): Used in basecoin; this variant should be moved - // to a host-relevant error - /// failed to parse account ID + /// failed to parse account FailedToParseAccount, } @@ -39,16 +36,22 @@ pub enum TokenTransferError { impl std::error::Error for TokenTransferError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::ContextError(e) => Some(e), + Self::Handler(e) => Some(e), Self::Decoding(e) => Some(e), _ => None, } } } -impl From for TokenTransferError { - fn from(e: ContextError) -> Self { - Self::ContextError(e) +impl From for TokenTransferError { + fn from(e: HandlerError) -> Self { + Self::Handler(e) + } +} + +impl From for TokenTransferError { + fn from(e: HostError) -> Self { + Self::Handler(HandlerError::Host(e)) } } diff --git a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs index d5c1d4eae..0bdaf0979 100644 --- a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs @@ -50,7 +50,6 @@ impl TryFrom for MsgTransfer { fn try_from(raw_msg: RawMsgTransfer) -> Result { let timeout_height_on_b: TimeoutHeight = raw_msg.timeout_height.try_into()?; - let timeout_timestamp_on_b: TimeoutTimestamp = raw_msg.timeout_timestamp.into(); // Packet timeout height and packet timeout timestamp cannot both be unset. diff --git a/ibc-apps/ics721-nft-transfer/src/context.rs b/ibc-apps/ics721-nft-transfer/src/context.rs index ede6ee898..201d342cb 100644 --- a/ibc-apps/ics721-nft-transfer/src/context.rs +++ b/ibc-apps/ics721-nft-transfer/src/context.rs @@ -1,10 +1,10 @@ //! Defines the required context traits for ICS-721 to interact with host //! machine. +use ibc_core::host::types::error::HostError; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; use ibc_core::primitives::Signer; -use crate::types::error::NftTransferError; use crate::types::{ ClassData, ClassId, ClassUri, Memo, PrefixedClassId, TokenData, TokenId, TokenUri, }; @@ -41,13 +41,13 @@ pub trait NftTransferValidationContext { type NftClass: NftClassContext; /// get_port returns the portID for the transfer module. - fn get_port(&self) -> Result; + fn get_port(&self) -> Result; /// Returns Ok() if the host chain supports sending NFTs. - fn can_send_nft(&self) -> Result<(), NftTransferError>; + fn can_send_nft(&self) -> Result<(), HostError>; /// Returns Ok() if the host chain supports receiving NFTs. - fn can_receive_nft(&self) -> Result<(), NftTransferError>; + fn can_receive_nft(&self) -> Result<(), HostError>; /// Validates that the NFT can be created or updated successfully. /// @@ -62,7 +62,7 @@ pub trait NftTransferValidationContext { class_id: &PrefixedClassId, class_uri: Option<&ClassUri>, class_data: Option<&ClassData>, - ) -> Result<(), NftTransferError>; + ) -> Result<(), HostError>; /// Validates that the tokens can be escrowed successfully. /// @@ -77,7 +77,7 @@ pub trait NftTransferValidationContext { class_id: &PrefixedClassId, token_id: &TokenId, memo: &Memo, - ) -> Result<(), NftTransferError>; + ) -> Result<(), HostError>; /// Validates that the NFT can be unescrowed successfully. fn unescrow_nft_validate( @@ -87,7 +87,7 @@ pub trait NftTransferValidationContext { channel_id: &ChannelId, class_id: &PrefixedClassId, token_id: &TokenId, - ) -> Result<(), NftTransferError>; + ) -> Result<(), HostError>; /// Validates the receiver account and the NFT input /// @@ -104,7 +104,7 @@ pub trait NftTransferValidationContext { token_id: &TokenId, token_uri: Option<&TokenUri>, token_data: Option<&TokenData>, - ) -> Result<(), NftTransferError>; + ) -> Result<(), HostError>; /// Validates the sender account and the coin input before burning. /// @@ -117,7 +117,7 @@ pub trait NftTransferValidationContext { class_id: &PrefixedClassId, token_id: &TokenId, memo: &Memo, - ) -> Result<(), NftTransferError>; + ) -> Result<(), HostError>; /// Returns a hash of the prefixed class ID and the token ID. /// Implement only if the host chain supports hashed class ID and token ID. @@ -134,11 +134,10 @@ pub trait NftTransferValidationContext { &self, class_id: &PrefixedClassId, token_id: &TokenId, - ) -> Result; + ) -> Result; /// Returns the NFT class - fn get_nft_class(&self, class_id: &PrefixedClassId) - -> Result; + fn get_nft_class(&self, class_id: &PrefixedClassId) -> Result; } /// Read-write methods required in NFT transfer execution context. @@ -149,7 +148,7 @@ pub trait NftTransferExecutionContext: NftTransferValidationContext { class_id: &PrefixedClassId, class_uri: Option<&ClassUri>, class_data: Option<&ClassData>, - ) -> Result<(), NftTransferError>; + ) -> Result<(), HostError>; /// Executes the escrow of the NFT in a user account. /// @@ -163,7 +162,7 @@ pub trait NftTransferExecutionContext: NftTransferValidationContext { class_id: &PrefixedClassId, token_id: &TokenId, memo: &Memo, - ) -> Result<(), NftTransferError>; + ) -> Result<(), HostError>; /// Executes the unescrow of the NFT in a user account. fn unescrow_nft_execute( @@ -173,7 +172,7 @@ pub trait NftTransferExecutionContext: NftTransferValidationContext { channel_id: &ChannelId, class_id: &PrefixedClassId, token_id: &TokenId, - ) -> Result<(), NftTransferError>; + ) -> Result<(), HostError>; /// Executes minting of the NFT in a user account. fn mint_nft_execute( @@ -183,7 +182,7 @@ pub trait NftTransferExecutionContext: NftTransferValidationContext { token_id: &TokenId, token_uri: Option<&TokenUri>, token_data: Option<&TokenData>, - ) -> Result<(), NftTransferError>; + ) -> Result<(), HostError>; /// Executes burning of the NFT in a user account. /// @@ -195,5 +194,5 @@ pub trait NftTransferExecutionContext: NftTransferValidationContext { class_id: &PrefixedClassId, token_id: &TokenId, memo: &Memo, - ) -> Result<(), NftTransferError>; + ) -> Result<(), HostError>; } diff --git a/ibc-apps/ics721-nft-transfer/src/handler/mod.rs b/ibc-apps/ics721-nft-transfer/src/handler/mod.rs index 8f8d0775c..9acca019f 100644 --- a/ibc-apps/ics721-nft-transfer/src/handler/mod.rs +++ b/ibc-apps/ics721-nft-transfer/src/handler/mod.rs @@ -29,13 +29,15 @@ pub fn refund_packet_nft_execute( &data.class_id, ) { data.token_ids.as_ref().iter().try_for_each(|token_id| { - ctx_a.unescrow_nft_execute( - &sender, - &packet.port_id_on_a, - &packet.chan_id_on_a, - &data.class_id, - token_id, - ) + ctx_a + .unescrow_nft_execute( + &sender, + &packet.port_id_on_a, + &packet.chan_id_on_a, + &data.class_id, + token_id, + ) + .map_err(NftTransferError::from) }) } // mint vouchers back to sender @@ -43,8 +45,11 @@ pub fn refund_packet_nft_execute( for (i, token_id) in data.token_ids.0.iter().enumerate() { let token_uri = data.token_uris.as_ref().and_then(|uris| uris.get(i)); let token_data = data.token_data.as_ref().and_then(|data| data.get(i)); - ctx_a.mint_nft_execute(&sender, &data.class_id, token_id, token_uri, token_data)?; + + let _ = + ctx_a.mint_nft_execute(&sender, &data.class_id, token_id, token_uri, token_data); } + Ok(()) } } @@ -66,20 +71,25 @@ pub fn refund_packet_nft_validate( &data.class_id, ) { data.token_ids.0.iter().try_for_each(|token_id| { - ctx_a.unescrow_nft_validate( - &sender, - &packet.port_id_on_a, - &packet.chan_id_on_a, - &data.class_id, - token_id, - ) + ctx_a + .unescrow_nft_validate( + &sender, + &packet.port_id_on_a, + &packet.chan_id_on_a, + &data.class_id, + token_id, + ) + .map_err(NftTransferError::from) }) } else { for (i, token_id) in data.token_ids.0.iter().enumerate() { let token_uri = data.token_uris.as_ref().and_then(|uris| uris.get(i)); let token_data = data.token_data.as_ref().and_then(|data| data.get(i)); - ctx_a.mint_nft_validate(&sender, &data.class_id, token_id, token_uri, token_data)?; + + let _ = + ctx_a.mint_nft_validate(&sender, &data.class_id, token_id, token_uri, token_data); } + Ok(()) } } diff --git a/ibc-apps/ics721-nft-transfer/src/handler/on_recv_packet.rs b/ibc-apps/ics721-nft-transfer/src/handler/on_recv_packet.rs index 59e6f3cb8..6d8eeb194 100644 --- a/ibc-apps/ics721-nft-transfer/src/handler/on_recv_packet.rs +++ b/ibc-apps/ics721-nft-transfer/src/handler/on_recv_packet.rs @@ -23,7 +23,7 @@ where { ctx_b .can_receive_nft() - .map_err(|err| (ModuleExtras::empty(), err))?; + .map_err(|err| (ModuleExtras::empty(), err.into()))?; let receiver_account = data.receiver.clone().try_into().map_err(|_| { ( @@ -56,7 +56,7 @@ where &class_id, token_id, ) - .map_err(|nft_error| (ModuleExtras::empty(), nft_error))?; + .map_err(|err| (ModuleExtras::empty(), err.into()))?; ctx_b .unescrow_nft_execute( &receiver_account, @@ -65,7 +65,7 @@ where &class_id, token_id, ) - .map_err(|nft_error| (ModuleExtras::empty(), nft_error))?; + .map_err(|err| (ModuleExtras::empty(), err.into()))?; } ModuleExtras::empty() @@ -102,14 +102,14 @@ where data.class_uri.as_ref(), data.class_data.as_ref(), ) - .map_err(|nft_error| (ModuleExtras::empty(), nft_error))?; + .map_err(|err| (ModuleExtras::empty(), err.into()))?; ctx_b .create_or_update_class_execute( &class_id, data.class_uri.as_ref(), data.class_data.as_ref(), ) - .map_err(|nft_error| (ModuleExtras::empty(), nft_error))?; + .map_err(|err| (ModuleExtras::empty(), err.into()))?; ctx_b .mint_nft_validate( @@ -119,7 +119,7 @@ where token_uri, token_data, ) - .map_err(|nft_error| (extras.clone(), nft_error))?; + .map_err(|err| (extras.clone(), err.into()))?; ctx_b .mint_nft_execute( &receiver_account, @@ -128,7 +128,7 @@ where token_uri, token_data, ) - .map_err(|nft_error| (extras.clone(), nft_error))?; + .map_err(|err| (extras.clone(), err.into()))?; } extras diff --git a/ibc-apps/ics721-nft-transfer/src/module.rs b/ibc-apps/ics721-nft-transfer/src/module.rs index 5560b686f..a1f479b51 100644 --- a/ibc-apps/ics721-nft-transfer/src/module.rs +++ b/ibc-apps/ics721-nft-transfer/src/module.rs @@ -3,7 +3,7 @@ use ibc_core::channel::types::acknowledgement::{Acknowledgement, Acknowledgement use ibc_core::channel::types::channel::{Counterparty, Order}; use ibc_core::channel::types::packet::Packet; use ibc_core::channel::types::Version; -use ibc_core::handler::types::error::ContextError; +use ibc_core::handler::types::error::HandlerError; use ibc_core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc_core::primitives::prelude::*; use ibc_core::primitives::Signer; @@ -44,7 +44,7 @@ pub fn on_chan_open_init_validate( if !version.is_empty() { version .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(ContextError::from)?; + .map_err(HandlerError::from)?; } Ok(()) @@ -80,7 +80,7 @@ pub fn on_chan_open_try_validate( counterparty_version .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(ContextError::from)?; + .map_err(HandlerError::from)?; Ok(()) } @@ -105,7 +105,7 @@ pub fn on_chan_open_ack_validate( ) -> Result<(), NftTransferError> { counterparty_version .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(ContextError::from)?; + .map_err(HandlerError::from)?; Ok(()) } diff --git a/ibc-apps/ics721-nft-transfer/types/src/error.rs b/ibc-apps/ics721-nft-transfer/types/src/error.rs index d7b112a64..bda017a9b 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/error.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/error.rs @@ -1,16 +1,17 @@ //! Defines the Non-Fungible Token Transfer (ICS-721) error types. +use derive_more::From; use displaydoc::Display; use ibc_core::channel::types::acknowledgement::StatusValue; use ibc_core::channel::types::channel::Order; -use ibc_core::handler::types::error::ContextError; -use ibc_core::host::types::error::DecodingError; +use ibc_core::handler::types::error::HandlerError; +use ibc_core::host::types::error::{DecodingError, HostError}; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; -#[derive(Display, Debug, derive_more::From)] +#[derive(Display, Debug, From)] pub enum NftTransferError { - /// context error: `{0}` - ContextError(ContextError), + /// handler error: `{0}` + Handler(HandlerError), /// decoding error: `{0}` Decoding(DecodingError), /// missing destination channel `{channel_id}` on port `{port_id}` @@ -40,13 +41,19 @@ pub enum NftTransferError { impl std::error::Error for NftTransferError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::ContextError(e) => Some(e), + Self::Handler(e) => Some(e), Self::Decoding(e) => Some(e), _ => None, } } } +impl From for NftTransferError { + fn from(e: HostError) -> Self { + Self::Handler(HandlerError::Host(e)) + } +} + impl From for StatusValue { fn from(err: NftTransferError) -> Self { StatusValue::new(err.to_string()).expect("error message must not be empty") diff --git a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs index fb717018c..ae9a31bc4 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs @@ -51,7 +51,6 @@ impl TryFrom for MsgTransfer { fn try_from(raw_msg: RawMsgTransfer) -> Result { let timeout_height_on_b: TimeoutHeight = raw_msg.timeout_height.try_into()?; - let timeout_timestamp_on_b: TimeoutTimestamp = raw_msg.timeout_timestamp.into(); // Packet timeout height and packet timeout timestamp cannot both be unset. diff --git a/ibc-core/ics02-client/context/src/context.rs b/ibc-core/ics02-client/context/src/context.rs index 972ec547e..e9a47bf0d 100644 --- a/ibc-core/ics02-client/context/src/context.rs +++ b/ibc-core/ics02-client/context/src/context.rs @@ -1,5 +1,5 @@ use ibc_core_client_types::Height; -use ibc_core_handler_types::error::ContextError; +use ibc_core_host_types::error::HostError; use ibc_core_host_types::identifiers::ClientId; use ibc_core_host_types::path::{ClientConsensusStatePath, ClientStatePath}; use ibc_primitives::prelude::*; @@ -19,7 +19,7 @@ pub trait ClientValidationContext: Sized { /// Returns the ClientState for the given identifier `client_id`. /// /// Note: Clients have the responsibility to store client states on client creation and update. - fn client_state(&self, client_id: &ClientId) -> Result; + fn client_state(&self, client_id: &ClientId) -> Result; /// Retrieve the consensus state for the given client ID at the specified /// height. @@ -30,7 +30,7 @@ pub trait ClientValidationContext: Sized { fn consensus_state( &self, client_cons_state_path: &ClientConsensusStatePath, - ) -> Result; + ) -> Result; /// Returns the timestamp and height of the host when it processed a client /// update request at the specified height. @@ -38,7 +38,7 @@ pub trait ClientValidationContext: Sized { &self, client_id: &ClientId, height: &Height, - ) -> Result<(Timestamp, Height), ContextError>; + ) -> Result<(Timestamp, Height), HostError>; } /// Defines the methods that all client `ExecutionContext`s (precisely the @@ -54,7 +54,7 @@ pub trait ClientExecutionContext: { type ClientStateMut: ClientStateExecution; - fn client_state_mut(&self, client_id: &ClientId) -> Result { + fn client_state_mut(&self, client_id: &ClientId) -> Result { self.client_state(client_id) } @@ -63,20 +63,20 @@ pub trait ClientExecutionContext: &mut self, client_state_path: ClientStatePath, client_state: Self::ClientStateRef, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Called upon successful client creation and update fn store_consensus_state( &mut self, consensus_state_path: ClientConsensusStatePath, consensus_state: Self::ConsensusStateRef, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Delete the consensus state from the store located at the given `ClientConsensusStatePath` fn delete_consensus_state( &mut self, consensus_state_path: ClientConsensusStatePath, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Called upon successful client update. /// @@ -88,7 +88,7 @@ pub trait ClientExecutionContext: height: Height, host_timestamp: Timestamp, host_height: Height, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Delete the update time and height associated with the client at the /// specified height. @@ -97,11 +97,7 @@ pub trait ClientExecutionContext: /// specified height. /// /// Note that this timestamp is determined by the host. - fn delete_update_meta( - &mut self, - client_id: ClientId, - height: Height, - ) -> Result<(), ContextError>; + fn delete_update_meta(&mut self, client_id: ClientId, height: Height) -> Result<(), HostError>; } /// An optional trait that extends the client validation context capabilities by @@ -115,27 +111,27 @@ pub trait ClientExecutionContext: /// specific light client requirements. pub trait ExtClientValidationContext: ClientValidationContext { /// Returns the current timestamp of the local chain. - fn host_timestamp(&self) -> Result; + fn host_timestamp(&self) -> Result; /// Returns the current height of the local chain. - fn host_height(&self) -> Result; + fn host_height(&self) -> Result; /// Returns all the heights at which a consensus state is stored. - fn consensus_state_heights(&self, client_id: &ClientId) -> Result, ContextError>; + fn consensus_state_heights(&self, client_id: &ClientId) -> Result, HostError>; /// Search for the lowest consensus state higher than `height`. fn next_consensus_state( &self, client_id: &ClientId, height: &Height, - ) -> Result, ContextError>; + ) -> Result, HostError>; /// Search for the highest consensus state lower than `height`. fn prev_consensus_state( &self, client_id: &ClientId, height: &Height, - ) -> Result, ContextError>; + ) -> Result, HostError>; } /// An optional trait that extends the client context required during execution. diff --git a/ibc-core/ics02-client/src/handler/create_client.rs b/ibc-core/ics02-client/src/handler/create_client.rs index 47f5bab4a..8ea87b2f1 100644 --- a/ibc-core/ics02-client/src/handler/create_client.rs +++ b/ibc-core/ics02-client/src/handler/create_client.rs @@ -5,13 +5,13 @@ use ibc_core_client_types::error::ClientError; use ibc_core_client_types::events::CreateClient; use ibc_core_client_types::msgs::MsgCreateClient; use ibc_core_client_types::Status; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::{ClientStateMut, ClientStateRef, ExecutionContext, ValidationContext}; use ibc_primitives::prelude::*; use ibc_primitives::proto::Any; -pub fn validate(ctx: &Ctx, msg: MsgCreateClient) -> Result<(), ContextError> +pub fn validate(ctx: &Ctx, msg: MsgCreateClient) -> Result<(), HandlerError> where Ctx: ValidationContext, as TryFrom>::Error: Into, @@ -50,7 +50,7 @@ where Ok(()) } -pub fn execute(ctx: &mut Ctx, msg: MsgCreateClient) -> Result<(), ContextError> +pub fn execute(ctx: &mut Ctx, msg: MsgCreateClient) -> Result<(), HandlerError> where Ctx: ExecutionContext, as TryFrom>::Error: Into, diff --git a/ibc-core/ics02-client/src/handler/recover_client.rs b/ibc-core/ics02-client/src/handler/recover_client.rs index 7994edab3..c3e2826b2 100644 --- a/ibc-core/ics02-client/src/handler/recover_client.rs +++ b/ibc-core/ics02-client/src/handler/recover_client.rs @@ -3,7 +3,7 @@ use ibc_core_client_context::prelude::*; use ibc_core_client_types::error::ClientError; use ibc_core_client_types::msgs::MsgRecoverClient; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_host::types::path::ClientConsensusStatePath; use ibc_core_host::{ExecutionContext, ValidationContext}; @@ -11,7 +11,7 @@ use ibc_core_host::{ExecutionContext, ValidationContext}; /// includes validating that the parameters of the subject and substitute clients match, /// as well as validating that the substitute client *is* active and that the subject /// client is *not* active. -pub fn validate(ctx: &Ctx, msg: MsgRecoverClient) -> Result<(), ContextError> +pub fn validate(ctx: &Ctx, msg: MsgRecoverClient) -> Result<(), HandlerError> where Ctx: ValidationContext, { @@ -62,7 +62,7 @@ where /// - copying the substitute client's consensus state as the subject's consensus state /// - setting the subject client's processed height and processed time values to match the substitute client's /// - setting the subject client's latest height, trusting period, and chain ID values to match the substitute client's -pub fn execute(ctx: &mut Ctx, msg: MsgRecoverClient) -> Result<(), ContextError> +pub fn execute(ctx: &mut Ctx, msg: MsgRecoverClient) -> Result<(), HandlerError> where Ctx: ExecutionContext, { diff --git a/ibc-core/ics02-client/src/handler/update_client.rs b/ibc-core/ics02-client/src/handler/update_client.rs index 66ce95ce1..b40d94a68 100644 --- a/ibc-core/ics02-client/src/handler/update_client.rs +++ b/ibc-core/ics02-client/src/handler/update_client.rs @@ -5,13 +5,14 @@ use ibc_core_client_types::error::ClientError; use ibc_core_client_types::events::{ClientMisbehaviour, UpdateClient}; use ibc_core_client_types::msgs::MsgUpdateOrMisbehaviour; use ibc_core_client_types::UpdateKind; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::error::HostError; use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_primitives::prelude::*; use ibc_primitives::ToVec; -pub fn validate(ctx: &Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ContextError> +pub fn validate(ctx: &Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), HandlerError> where Ctx: ValidationContext, { @@ -35,7 +36,7 @@ where Ok(()) } -pub fn execute(ctx: &mut Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ContextError> +pub fn execute(ctx: &mut Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), HandlerError> where Ctx: ExecutionContext, { @@ -77,9 +78,9 @@ where { let event = { - let consensus_height = consensus_heights.first().ok_or(ClientError::Other { - description: "client update state returned no updated height".to_string(), - })?; + let consensus_height = consensus_heights.first().ok_or( + HostError::missing_state("missing updated height in client update state"), + )?; IbcEvent::UpdateClient(UpdateClient::new( client_id, diff --git a/ibc-core/ics02-client/src/handler/upgrade_client.rs b/ibc-core/ics02-client/src/handler/upgrade_client.rs index 7dce4cdaa..3fe5f8b95 100644 --- a/ibc-core/ics02-client/src/handler/upgrade_client.rs +++ b/ibc-core/ics02-client/src/handler/upgrade_client.rs @@ -1,16 +1,16 @@ //! Protocol logic specific to processing ICS2 messages of type `MsgUpgradeAnyClient`. //! use ibc_core_client_context::prelude::*; -use ibc_core_client_types::error::ClientError; use ibc_core_client_types::events::UpgradeClient; use ibc_core_client_types::msgs::MsgUpgradeClient; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::error::HostError; use ibc_core_host::types::path::ClientConsensusStatePath; use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_primitives::prelude::*; -pub fn validate(ctx: &Ctx, msg: MsgUpgradeClient) -> Result<(), ContextError> +pub fn validate(ctx: &Ctx, msg: MsgUpgradeClient) -> Result<(), HandlerError> where Ctx: ValidationContext, { @@ -38,9 +38,12 @@ where ); let old_consensus_state = client_val_ctx .consensus_state(&old_client_cons_state_path) - .map_err(|_| ClientError::MissingConsensusState { - client_id, - height: old_client_state.latest_height(), + .map_err(|_| { + HostError::missing_state(format!( + "missing consensus state for client {} at height {}", + client_id, + old_client_state.latest_height() + )) })?; // Validate the upgraded client state and consensus state and verify proofs against the root @@ -55,7 +58,7 @@ where Ok(()) } -pub fn execute(ctx: &mut Ctx, msg: MsgUpgradeClient) -> Result<(), ContextError> +pub fn execute(ctx: &mut Ctx, msg: MsgUpgradeClient) -> Result<(), HandlerError> where Ctx: ExecutionContext, { diff --git a/ibc-core/ics02-client/types/src/error.rs b/ibc-core/ics02-client/types/src/error.rs index 06f0cfb53..0b15ac36c 100644 --- a/ibc-core/ics02-client/types/src/error.rs +++ b/ibc-core/ics02-client/types/src/error.rs @@ -1,14 +1,11 @@ //! Defines the client error type -use core::convert::Infallible; - use displaydoc::Display; use ibc_core_commitment_types::error::CommitmentError; -use ibc_core_host_types::error::{DecodingError, IdentifierError}; +use ibc_core_host_types::error::{DecodingError, HostError}; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_primitives::Timestamp; -use tendermint::Error as TendermintError; use crate::height::Height; use crate::Status; @@ -16,6 +13,8 @@ use crate::Status; /// Encodes all the possible client errors #[derive(Debug, Display)] pub enum ClientError { + /// host error : `{0}` + Host(HostError), /// upgrade client error: `{0}` Upgrade(UpgradeClientError), /// decoding error: `{0}` @@ -38,6 +37,8 @@ pub enum ClientError { InvalidAttributeValue(String), /// invalid status: `{0}` InvalidStatus(String), + /// invalid header type: `{0}` + InvalidHeaderType(String), /// missing local consensus state at `{0}` MissingLocalConsensusState(Height), /// missing attribute key @@ -61,21 +62,10 @@ pub enum ClientError { FailedHeaderVerification { description: String }, /// failed misbehaviour handling: `{description}` FailedMisbehaviourHandling { description: String }, - /// client-specific error: `{description}` - ClientSpecific { description: String }, - // TODO(seanchen1991): Add these to host-relevant errors - /// missing client state for client: `{0}` - MissingClientState(ClientId), - /// missing consensus state for client `{client_id}` at height `{height}` - MissingConsensusState { client_id: ClientId, height: Height }, - /// missing update client metadata for client `{client_id}` at height `{height}` - MissingUpdateMetaData { client_id: ClientId, height: Height }, - /// invalid raw header: `{0}` - InvalidRawHeader(TendermintError), - /// invalid header type: `{0}` - InvalidHeaderType(String), // TODO(seanchen1991): Incorporate this error into its own variants + /// client-specific error: `{description}` + ClientSpecific { description: String }, /// other error: `{description}` Other { description: String }, } @@ -88,12 +78,6 @@ impl From<&'static str> for ClientError { } } -impl From for ClientError { - fn from(value: Infallible) -> Self { - match value {} - } -} - impl From for ClientError { fn from(e: CommitmentError) -> Self { Self::FailedICS23Verification(e) @@ -106,9 +90,9 @@ impl From for ClientError { } } -impl From for ClientError { - fn from(e: IdentifierError) -> Self { - Self::Decoding(DecodingError::Identifier(e)) +impl From for ClientError { + fn from(e: HostError) -> Self { + Self::Host(e) } } @@ -118,6 +102,8 @@ impl std::error::Error for ClientError { match &self { Self::FailedICS23Verification(e) => Some(e), Self::Decoding(e) => Some(e), + Self::Upgrade(e) => Some(e), + Self::Host(e) => Some(e), _ => None, } } @@ -128,6 +114,10 @@ impl std::error::Error for ClientError { pub enum UpgradeClientError { /// decoding error: `{0}` Decoding(DecodingError), + /// host chain error: `{0}` + Host(HostError), + /// invalid upgrade proposal: `{description}` + InvalidUpgradeProposal { description: String }, /// invalid proof for the upgraded client state: `{0}` InvalidUpgradeClientStateProof(CommitmentError), /// invalid proof for the upgraded consensus state: `{0}` @@ -141,22 +131,6 @@ pub enum UpgradeClientError { upgraded_height: Height, client_height: Height, }, - - // TODO(seanchen1991): Move these variants to host-relevant errors - /// invalid upgrade plan: `{description}` - InvalidUpgradePlan { description: String }, - /// invalid upgrade proposal: `{description}` - InvalidUpgradeProposal { description: String }, - /// missing upgraded client state - MissingUpgradedClientState, - /// missing upgraded consensus state - MissingUpgradedConsensusState, - /// failed to store upgrade plan: `{description}` - FailedToStoreUpgradePlan { description: String }, - /// failed to store upgraded client state: `{description}` - FailedToStoreUpgradedClientState { description: String }, - /// failed to store upgraded consensus state: `{description}` - FailedToStoreUpgradedConsensusState { description: String }, } impl From for ClientError { @@ -171,10 +145,18 @@ impl From for UpgradeClientError { } } +impl From for UpgradeClientError { + fn from(e: HostError) -> Self { + Self::Host(e) + } +} + #[cfg(feature = "std")] impl std::error::Error for UpgradeClientError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { + Self::Decoding(e) => Some(e), + Self::Host(e) => Some(e), Self::InvalidUpgradeClientStateProof(e) | Self::InvalidUpgradeConsensusStateProof(e) => Some(e), _ => None, diff --git a/ibc-core/ics02-client/types/src/events.rs b/ibc-core/ics02-client/types/src/events.rs index 56585036a..c6c36dc3c 100644 --- a/ibc-core/ics02-client/types/src/events.rs +++ b/ibc-core/ics02-client/types/src/events.rs @@ -1,5 +1,7 @@ //! Types for the IBC events emitted from Tendermint Websocket by the client module. + use derive_more::From; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ClientId, ClientType}; use ibc_primitives::prelude::*; use subtle_encoding::hex; @@ -53,26 +55,30 @@ impl From for abci::EventAttribute { } } impl TryFrom for ClientIdAttribute { - type Error = ClientError; + type Error = DecodingError; fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != CLIENT_ID_ATTRIBUTE_KEY { - return Err(ClientError::InvalidAttributeKey(key_str.to_string())); + return Err(DecodingError::InvalidRawData { + description: format!("invalid attribute key {}", key_str), + }); } } else { - return Err(ClientError::MissingAttributeKey); + return Err(DecodingError::MissingRawData { + description: "missing attribute key".to_string(), + }); } value .value_str() .map(|value| { - let client_id = ClientId::from_str(value) - .map_err(|_| ClientError::InvalidAttributeValue(value.to_string()))?; - + let client_id = ClientId::from_str(value)?; Ok(ClientIdAttribute { client_id }) }) - .map_err(|_| ClientError::MissingAttributeValue)? + .map_err(|e| DecodingError::MissingRawData { + description: format!("missing attribute value: {e}"), + })? } } @@ -101,26 +107,30 @@ impl From for abci::EventAttribute { } impl TryFrom for ClientTypeAttribute { - type Error = ClientError; + type Error = DecodingError; fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != CLIENT_TYPE_ATTRIBUTE_KEY { - return Err(ClientError::InvalidAttributeKey(key_str.to_string())); + return Err(DecodingError::InvalidRawData { + description: format!("invalid attribute key {}", key_str), + }); } } else { - return Err(ClientError::MissingAttributeKey); + return Err(DecodingError::MissingRawData { + description: "missing attribute key".to_string(), + }); } value .value_str() .map(|value| { - let client_type = ClientType::from_str(value) - .map_err(|_| ClientError::InvalidAttributeValue(value.to_string()))?; - + let client_type = ClientType::from_str(value)?; Ok(ClientTypeAttribute { client_type }) }) - .map_err(|_| ClientError::MissingAttributeValue)? + .map_err(|e| DecodingError::MissingRawData { + description: format!("missing attribute value: {e}"), + })? } } @@ -149,25 +159,33 @@ impl From for abci::EventAttribute { } impl TryFrom for ConsensusHeightAttribute { - type Error = ClientError; + type Error = DecodingError; fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != CONSENSUS_HEIGHT_ATTRIBUTE_KEY { - return Err(ClientError::InvalidAttributeKey(key_str.to_string())); + return Err(DecodingError::InvalidRawData { + description: format!("invalid attribute key {}", key_str), + }); } } else { - return Err(ClientError::MissingAttributeKey); + return Err(DecodingError::MissingRawData { + description: "missing attribute key".to_string(), + }); } value .value_str() .map(|value| { - let consensus_height = Height::from_str(value) - .map_err(|_| ClientError::InvalidAttributeValue(value.to_string()))?; + let consensus_height = + Height::from_str(value).map_err(|e| DecodingError::InvalidRawData { + description: format!("invalid attribute value: {e}"), + })?; Ok(ConsensusHeightAttribute { consensus_height }) }) - .map_err(|_| ClientError::MissingAttributeValue)? + .map_err(|e| DecodingError::MissingRawData { + description: format!("missing attribute value: {e}"), + })? } } @@ -344,12 +362,12 @@ impl From for abci::Event { } impl TryFrom for CreateClient { - type Error = ClientError; + type Error = DecodingError; fn try_from(value: abci::Event) -> Result { if value.kind != CREATE_CLIENT_EVENT { - return Err(ClientError::Other { - description: "Error in parsing CreateClient event".to_string(), + return Err(DecodingError::InvalidRawData { + description: format!("invalid event kind: expected `{}`", CREATE_CLIENT_EVENT), }); } @@ -366,11 +384,17 @@ impl TryFrom for CreateClient { attribute| { let key = attribute .key_str() - .map_err(|_| ClientError::MissingAttributeKey)?; + .map_err(|_| DecodingError::MissingRawData { + description: "missing attribute key".to_string(), + })?; match key { CLIENT_ID_ATTRIBUTE_KEY => Ok(( - Some(attribute.clone().try_into()?), + Some(attribute.clone().try_into().map_err(|e| { + DecodingError::InvalidRawData { + description: format!("{e}"), + } + })?), client_type, consensus_height, )), @@ -392,10 +416,16 @@ impl TryFrom for CreateClient { Option, Option, )| { - let client_id = client_id.ok_or(ClientError::MissingAttributeKey)?; - let client_type = client_type.ok_or(ClientError::MissingAttributeKey)?; + let client_id = client_id.ok_or(DecodingError::MissingRawData { + description: "missing attribute key".to_string(), + })?; + let client_type = client_type.ok_or(DecodingError::MissingRawData { + description: "missing attribute key".to_string(), + })?; let consensus_height = - consensus_height.ok_or(ClientError::MissingAttributeKey)?; + consensus_height.ok_or(DecodingError::MissingRawData { + description: "missing attribute key".to_string(), + })?; Ok(CreateClient::new( client_id.client_id, @@ -699,6 +729,7 @@ impl From for abci::Event { mod tests { use core::any::Any; + use ibc_core_host_types::error::IdentifierError; use rstest::*; use super::*; @@ -728,9 +759,10 @@ mod tests { abci::EventAttribute::from(("consensus_height", "1-10")), ], }, - Err(ClientError::Other { - description: "Error in parsing CreateClient event".to_string(), - }), + Err(IdentifierError::FailedToParse { + value: "CreateClient".to_string(), + description: "failed to parse event".to_string() + }.into()) )] #[case( abci::Event { @@ -740,11 +772,11 @@ mod tests { abci::EventAttribute::from(("consensus_height", "1-10")), ], }, - Err(ClientError::MissingAttributeKey), + Err(DecodingError::MissingRawData { description: "missing attribute key".to_string() }), )] fn test_create_client_try_from( #[case] event: abci::Event, - #[case] expected: Result, + #[case] expected: Result, ) { let result = CreateClient::try_from(event); if expected.is_err() { diff --git a/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs b/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs index dd627ae02..f923902ba 100644 --- a/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs +++ b/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs @@ -8,8 +8,6 @@ use ibc_proto::google::protobuf::Any as ProtoAny; use ibc_proto::ibc::core::client::v1::MsgSubmitMisbehaviour as RawMsgSubmitMisbehaviour; use ibc_proto::Protobuf; -use crate::error::ClientError; - pub const SUBMIT_MISBEHAVIOUR_TYPE_URL: &str = "/ibc.core.client.v1.MsgSubmitMisbehaviour"; /// A type of message that submits client misbehaviour proof. @@ -38,7 +36,7 @@ pub struct MsgSubmitMisbehaviour { impl Protobuf for MsgSubmitMisbehaviour {} impl TryFrom for MsgSubmitMisbehaviour { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: RawMsgSubmitMisbehaviour) -> Result { let raw_misbehaviour = raw.misbehaviour.ok_or(DecodingError::MissingRawData { diff --git a/ibc-core/ics02-client/types/src/msgs/recover_client.rs b/ibc-core/ics02-client/types/src/msgs/recover_client.rs index df371e63a..5ef857cba 100644 --- a/ibc-core/ics02-client/types/src/msgs/recover_client.rs +++ b/ibc-core/ics02-client/types/src/msgs/recover_client.rs @@ -1,13 +1,12 @@ //! Definition of domain type message `MsgRecoverClient`. +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; use ibc_primitives::Signer; use ibc_proto::ibc::core::client::v1::MsgRecoverClient as RawMsgRecoverClient; use ibc_proto::Protobuf; -use crate::error::ClientError; - pub const RECOVER_CLIENT_TYPE_URL: &str = "/ibc.core.client.v1.MsgRecoverClient"; /// Defines the message used to recover a frozen or expired client. @@ -38,7 +37,7 @@ pub struct MsgRecoverClient { impl Protobuf for MsgRecoverClient {} impl TryFrom for MsgRecoverClient { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: RawMsgRecoverClient) -> Result { Ok(MsgRecoverClient { diff --git a/ibc-core/ics02-client/types/src/msgs/update_client.rs b/ibc-core/ics02-client/types/src/msgs/update_client.rs index fc99faf9a..16a5d250d 100644 --- a/ibc-core/ics02-client/types/src/msgs/update_client.rs +++ b/ibc-core/ics02-client/types/src/msgs/update_client.rs @@ -8,8 +8,6 @@ use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::client::v1::MsgUpdateClient as RawMsgUpdateClient; use ibc_proto::Protobuf; -use crate::error::ClientError; - pub const UPDATE_CLIENT_TYPE_URL: &str = "/ibc.core.client.v1.MsgUpdateClient"; /// Represents the message that triggers the update of an on-chain (IBC) client @@ -31,7 +29,7 @@ pub struct MsgUpdateClient { impl Protobuf for MsgUpdateClient {} impl TryFrom for MsgUpdateClient { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: RawMsgUpdateClient) -> Result { Ok(MsgUpdateClient { diff --git a/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs b/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs index 90bc14837..f5ed52afb 100644 --- a/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs +++ b/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs @@ -3,7 +3,6 @@ use core::str::FromStr; use ibc_core_commitment_types::commitment::CommitmentProofBytes; -use ibc_core_commitment_types::error::CommitmentError; use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; @@ -12,8 +11,6 @@ use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::client::v1::MsgUpgradeClient as RawMsgUpgradeClient; use ibc_proto::Protobuf; -use crate::error::{ClientError, UpgradeClientError}; - pub const UPGRADE_CLIENT_TYPE_URL: &str = "/ibc.core.client.v1.MsgUpgradeClient"; /// A type of message that triggers the upgrade of an on-chain (IBC) client. @@ -55,7 +52,7 @@ impl From for RawMsgUpgradeClient { } impl TryFrom for MsgUpgradeClient { - type Error = ClientError; + type Error = DecodingError; fn try_from(proto_msg: RawMsgUpgradeClient) -> Result { let raw_client_state = proto_msg @@ -72,17 +69,15 @@ impl TryFrom for MsgUpgradeClient { })?; let c_bytes = - CommitmentProofBytes::try_from(proto_msg.proof_upgrade_client).map_err(|_| { - UpgradeClientError::InvalidUpgradeClientStateProof( - CommitmentError::InvalidMerkleProof, - ) + CommitmentProofBytes::try_from(proto_msg.proof_upgrade_client).map_err(|e| { + DecodingError::InvalidRawData { + description: format!("invalid upgrade client state proof: {e}"), + } })?; let cs_bytes = CommitmentProofBytes::try_from(proto_msg.proof_upgrade_consensus_state) - .map_err(|_| { - UpgradeClientError::InvalidUpgradeConsensusStateProof( - CommitmentError::EmptyMerkleProof, - ) + .map_err(|e| DecodingError::InvalidRawData { + description: format!("invalid upgrade consensus state proof: {e}"), })?; Ok(MsgUpgradeClient { diff --git a/ibc-core/ics03-connection/src/delay.rs b/ibc-core/ics03-connection/src/delay.rs index 82c162e4f..b2c51158a 100644 --- a/ibc-core/ics03-connection/src/delay.rs +++ b/ibc-core/ics03-connection/src/delay.rs @@ -2,14 +2,14 @@ use ibc_core_client::context::ClientValidationContext; use ibc_core_client::types::Height; use ibc_core_connection_types::error::ConnectionError; use ibc_core_connection_types::ConnectionEnd; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_host::ValidationContext; pub fn verify_conn_delay_passed( ctx: &Ctx, packet_proof_height: Height, connection_end: &ConnectionEnd, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where Ctx: ValidationContext, { @@ -31,7 +31,7 @@ where let earliest_valid_time = (last_client_update.0 + conn_delay_time_period) .map_err(ConnectionError::OverflowedTimestamp)?; if current_host_time < earliest_valid_time { - return Err(ContextError::ConnectionError( + return Err(HandlerError::Connection( ConnectionError::InsufficientTimeElapsed { current_host_time, earliest_valid_time, @@ -42,7 +42,7 @@ where // Verify that the current host chain height is later than the last client update height let earliest_valid_height = last_client_update.1.add(conn_delay_height_period); if current_host_height < earliest_valid_height { - return Err(ContextError::ConnectionError( + return Err(HandlerError::Connection( ConnectionError::InsufficientBlocksElapsed { current_host_height, earliest_valid_height, diff --git a/ibc-core/ics03-connection/src/handler/conn_open_ack.rs b/ibc-core/ics03-connection/src/handler/conn_open_ack.rs index 91027ff43..470100833 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_ack.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_ack.rs @@ -6,7 +6,7 @@ use ibc_core_connection_types::error::ConnectionError; use ibc_core_connection_types::events::OpenAck; use ibc_core_connection_types::msgs::MsgConnectionOpenAck; use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::ClientId; use ibc_core_host::types::path::{ClientConsensusStatePath, ClientStatePath, ConnectionPath, Path}; @@ -17,7 +17,7 @@ use ibc_primitives::ToVec; use crate::handler::{pack_host_consensus_state, unpack_host_client_state}; -pub fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenAck) -> Result<(), ContextError> +pub fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenAck) -> Result<(), HandlerError> where Ctx: ValidationContext, >::Error: Into, @@ -30,7 +30,7 @@ fn validate_impl( ctx_a: &Ctx, msg: &MsgConnectionOpenAck, vars: &LocalVars, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where Ctx: ValidationContext, >::Error: Into, @@ -143,7 +143,7 @@ where Ok(()) } -pub fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenAck) -> Result<(), ContextError> +pub fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenAck) -> Result<(), HandlerError> where Ctx: ExecutionContext, { @@ -155,7 +155,7 @@ fn execute_impl( ctx_a: &mut Ctx, msg: MsgConnectionOpenAck, vars: LocalVars, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where Ctx: ExecutionContext, { @@ -193,7 +193,7 @@ struct LocalVars { } impl LocalVars { - fn new(ctx_a: &Ctx, msg: &MsgConnectionOpenAck) -> Result + fn new(ctx_a: &Ctx, msg: &MsgConnectionOpenAck) -> Result where Ctx: ValidationContext, { diff --git a/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs b/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs index 1987c047f..414b01006 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs @@ -5,7 +5,7 @@ use ibc_core_connection_types::error::ConnectionError; use ibc_core_connection_types::events::OpenConfirm; use ibc_core_connection_types::msgs::MsgConnectionOpenConfirm; use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::{ClientId, ConnectionId}; use ibc_core_host::types::path::{ClientConsensusStatePath, ConnectionPath, Path}; @@ -13,7 +13,7 @@ use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_primitives::prelude::*; use ibc_primitives::proto::Protobuf; -pub fn validate(ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm) -> Result<(), ContextError> +pub fn validate(ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm) -> Result<(), HandlerError> where Ctx: ValidationContext, { @@ -25,7 +25,7 @@ fn validate_impl( ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm, vars: &LocalVars, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where Ctx: ValidationContext, { @@ -88,7 +88,7 @@ where Ok(()) } -pub fn execute(ctx_b: &mut Ctx, msg: &MsgConnectionOpenConfirm) -> Result<(), ContextError> +pub fn execute(ctx_b: &mut Ctx, msg: &MsgConnectionOpenConfirm) -> Result<(), HandlerError> where Ctx: ExecutionContext, { @@ -100,7 +100,7 @@ fn execute_impl( ctx_b: &mut Ctx, msg: &MsgConnectionOpenConfirm, vars: LocalVars, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where Ctx: ExecutionContext, { @@ -137,7 +137,7 @@ struct LocalVars { } impl LocalVars { - fn new(ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm) -> Result + fn new(ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm) -> Result where Ctx: ValidationContext, { diff --git a/ibc-core/ics03-connection/src/handler/conn_open_init.rs b/ibc-core/ics03-connection/src/handler/conn_open_init.rs index 8d4286616..9a42ec556 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_init.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_init.rs @@ -3,14 +3,14 @@ use ibc_core_client::context::prelude::*; use ibc_core_connection_types::events::OpenInit; use ibc_core_connection_types::msgs::MsgConnectionOpenInit; use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::ConnectionId; use ibc_core_host::types::path::{ClientConnectionPath, ConnectionPath}; use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_primitives::prelude::*; -pub fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenInit) -> Result<(), ContextError> +pub fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenInit) -> Result<(), HandlerError> where Ctx: ValidationContext, { @@ -32,7 +32,7 @@ where Ok(()) } -pub fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenInit) -> Result<(), ContextError> +pub fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenInit) -> Result<(), HandlerError> where Ctx: ExecutionContext, { diff --git a/ibc-core/ics03-connection/src/handler/conn_open_try.rs b/ibc-core/ics03-connection/src/handler/conn_open_try.rs index fbb013824..93a963643 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_try.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_try.rs @@ -5,7 +5,7 @@ use ibc_core_connection_types::error::ConnectionError; use ibc_core_connection_types::events::OpenTry; use ibc_core_connection_types::msgs::MsgConnectionOpenTry; use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::{ClientId, ConnectionId}; use ibc_core_host::types::path::{ @@ -18,7 +18,7 @@ use ibc_primitives::ToVec; use crate::handler::{pack_host_consensus_state, unpack_host_client_state}; -pub fn validate(ctx_b: &Ctx, msg: MsgConnectionOpenTry) -> Result<(), ContextError> +pub fn validate(ctx_b: &Ctx, msg: MsgConnectionOpenTry) -> Result<(), HandlerError> where Ctx: ValidationContext, >::Error: Into, @@ -31,7 +31,7 @@ fn validate_impl( ctx_b: &Ctx, msg: &MsgConnectionOpenTry, vars: &LocalVars, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where Ctx: ValidationContext, >::Error: Into, @@ -139,7 +139,7 @@ where Ok(()) } -pub fn execute(ctx_b: &mut Ctx, msg: MsgConnectionOpenTry) -> Result<(), ContextError> +pub fn execute(ctx_b: &mut Ctx, msg: MsgConnectionOpenTry) -> Result<(), HandlerError> where Ctx: ExecutionContext, { @@ -151,7 +151,7 @@ fn execute_impl( ctx_b: &mut Ctx, msg: MsgConnectionOpenTry, vars: LocalVars, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where Ctx: ExecutionContext, { @@ -188,7 +188,7 @@ struct LocalVars { } impl LocalVars { - fn new(ctx_b: &Ctx, msg: &MsgConnectionOpenTry) -> Result + fn new(ctx_b: &Ctx, msg: &MsgConnectionOpenTry) -> Result where Ctx: ValidationContext, { diff --git a/ibc-core/ics03-connection/src/handler/mod.rs b/ibc-core/ics03-connection/src/handler/mod.rs index f780295e4..8026db244 100644 --- a/ibc-core/ics03-connection/src/handler/mod.rs +++ b/ibc-core/ics03-connection/src/handler/mod.rs @@ -1,5 +1,5 @@ use ibc_core_client::types::error::ClientError; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; #[cfg(feature = "wasm-client")] use ibc_core_host::types::error::DecodingError; use ibc_core_host::types::identifiers::ClientId; @@ -18,7 +18,7 @@ pub mod conn_open_try; pub(crate) fn unpack_host_client_state( value: Any, host_client_id_at_counterparty: &ClientId, -) -> Result +) -> Result where CS: TryFrom, >::Error: Into, @@ -31,7 +31,7 @@ where use prost::Message; let wasm_client_state = WasmClientState::try_from(value).map_err(|e| { - ContextError::ConnectionError(ConnectionError::InvalidClientState { + HandlerError::Connection(ConnectionError::InvalidClientState { description: e.to_string(), }) })?; diff --git a/ibc-core/ics03-connection/types/src/connection.rs b/ibc-core/ics03-connection/types/src/connection.rs index 4ffd8002b..2ce46ff52 100644 --- a/ibc-core/ics03-connection/types/src/connection.rs +++ b/ibc-core/ics03-connection/types/src/connection.rs @@ -208,7 +208,7 @@ impl TryFrom for ConnectionEnd { if value.versions.is_empty() { return Err(DecodingError::MissingRawData { - description: "connection versions is empty".to_string(), + description: "empty connection versions".to_string(), })?; } @@ -218,7 +218,7 @@ impl TryFrom for ConnectionEnd { value .counterparty .ok_or(DecodingError::MissingRawData { - description: "counterparty not set".to_string(), + description: "missing counterparty".to_string(), })? .try_into()?, value diff --git a/ibc-core/ics03-connection/types/src/error.rs b/ibc-core/ics03-connection/types/src/error.rs index 7a4342c74..96febd06f 100644 --- a/ibc-core/ics03-connection/types/src/error.rs +++ b/ibc-core/ics03-connection/types/src/error.rs @@ -34,6 +34,8 @@ pub enum ConnectionError { MissingCommonFeatures, /// missing counterparty MissingCounterparty, + /// missing connection `{0}` + MissingConnection(ConnectionId), /// insufficient consensus height `{current_height}` for host chain; needs to meet counterparty's height `{target_height}` InsufficientConsensusHeight { target_height: Height, @@ -57,18 +59,6 @@ pub enum ConnectionError { FailedToVerifyClientState(ClientError), /// overflowed timestamp: `{0}` OverflowedTimestamp(TimestampError), - - // TODO(seanchen1991): Move these variants to host-relevant error types - /// missing connection `{0}` - MissingConnection(ConnectionId), - /// missing connection counter - MissingConnectionCounter, - /// failed to store connection IDs - FailedToStoreConnectionIds, - /// failed to store connection end - FailedToStoreConnectionEnd, - /// failed to update connection counter - FailedToUpdateConnectionCounter, } impl From for ConnectionError { diff --git a/ibc-core/ics03-connection/types/src/version.rs b/ibc-core/ics03-connection/types/src/version.rs index ac8f9d975..5a2061edf 100644 --- a/ibc-core/ics03-connection/types/src/version.rs +++ b/ibc-core/ics03-connection/types/src/version.rs @@ -120,12 +120,13 @@ impl Display for Version { /// compatible version continues. This function is called in the `conn_open_try` /// handshake procedure. /// -/// NOTE: Empty feature set is not currently allowed for a chosen version. +/// NOTE: Empty feature sets are not currently allowed for a chosen version. pub fn pick_version( supported_versions: &[Version], counterparty_versions: &[Version], ) -> Result { let mut intersection: Vec = Vec::new(); + for sv in supported_versions.iter() { if let Ok(cv) = find_supported_version(sv, counterparty_versions) { if let Ok(feature_set) = get_feature_set_intersection(&sv.features, &cv.features) { @@ -142,6 +143,7 @@ pub fn pick_version( } intersection.sort_by(|a, b| a.identifier.cmp(&b.identifier)); + Ok(intersection[0].clone()) } diff --git a/ibc-core/ics04-channel/src/context.rs b/ibc-core/ics04-channel/src/context.rs index 1fba1de8f..92844b4d4 100644 --- a/ibc-core/ics04-channel/src/context.rs +++ b/ibc-core/ics04-channel/src/context.rs @@ -4,8 +4,8 @@ use ibc_core_channel_types::channel::ChannelEnd; use ibc_core_channel_types::commitment::PacketCommitment; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::ConnectionEnd; -use ibc_core_handler_types::error::ContextError; use ibc_core_handler_types::events::IbcEvent; +use ibc_core_host::types::error::HostError; use ibc_core_host::types::identifiers::{ConnectionId, Sequence}; use ibc_core_host::types::path::{ChannelEndPath, CommitmentPath, SeqSendPath}; use ibc_core_host::{ExecutionContext, ValidationContext}; @@ -19,13 +19,12 @@ pub trait SendPacketValidationContext { fn get_client_validation_context(&self) -> &Self::V; /// Returns the ChannelEnd for the given `port_id` and `chan_id`. - fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result; + fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result; /// Returns the ConnectionState for the given identifier `connection_id`. - fn connection_end(&self, connection_id: &ConnectionId) -> Result; + fn connection_end(&self, connection_id: &ConnectionId) -> Result; - fn get_next_sequence_send(&self, seq_send_path: &SeqSendPath) - -> Result; + fn get_next_sequence_send(&self, seq_send_path: &SeqSendPath) -> Result; } impl SendPacketValidationContext for T @@ -38,18 +37,15 @@ where self.get_client_validation_context() } - fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result { + fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result { self.channel_end(channel_end_path) } - fn connection_end(&self, connection_id: &ConnectionId) -> Result { + fn connection_end(&self, connection_id: &ConnectionId) -> Result { self.connection_end(connection_id) } - fn get_next_sequence_send( - &self, - seq_send_path: &SeqSendPath, - ) -> Result { + fn get_next_sequence_send(&self, seq_send_path: &SeqSendPath) -> Result { self.get_next_sequence_send(seq_send_path) } } @@ -60,19 +56,19 @@ pub trait SendPacketExecutionContext: SendPacketValidationContext { &mut self, seq_send_path: &SeqSendPath, seq: Sequence, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; fn store_packet_commitment( &mut self, commitment_path: &CommitmentPath, commitment: PacketCommitment, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Ibc events - fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), ContextError>; + fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), HostError>; /// Logging facility - fn log_message(&mut self, message: String) -> Result<(), ContextError>; + fn log_message(&mut self, message: String) -> Result<(), HostError>; } impl SendPacketExecutionContext for T @@ -83,7 +79,7 @@ where &mut self, seq_send_path: &SeqSendPath, seq: Sequence, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.store_next_sequence_send(seq_send_path, seq) } @@ -91,15 +87,15 @@ where &mut self, commitment_path: &CommitmentPath, commitment: PacketCommitment, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.store_packet_commitment(commitment_path, commitment) } - fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), ContextError> { + fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), HostError> { self.emit_ibc_event(event) } - fn log_message(&mut self, message: String) -> Result<(), ContextError> { + fn log_message(&mut self, message: String) -> Result<(), HostError> { self.log_message(message) } } diff --git a/ibc-core/ics04-channel/src/handler/acknowledgement.rs b/ibc-core/ics04-channel/src/handler/acknowledgement.rs index e5f484f2b..4c7b1c30e 100644 --- a/ibc-core/ics04-channel/src/handler/acknowledgement.rs +++ b/ibc-core/ics04-channel/src/handler/acknowledgement.rs @@ -6,7 +6,7 @@ use ibc_core_channel_types::msgs::MsgAcknowledgement; use ibc_core_client::context::prelude::*; use ibc_core_connection::delay::verify_conn_delay_passed; use ibc_core_connection::types::State as ConnectionState; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ AckPath, ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, SeqAckPath, @@ -19,7 +19,7 @@ pub fn acknowledgement_packet_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgAcknowledgement, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ValCtx: ValidationContext, { @@ -27,14 +27,14 @@ where module .on_acknowledgement_packet_validate(&msg.packet, &msg.acknowledgement, &msg.signer) - .map_err(ContextError::PacketError) + .map_err(HandlerError::Packet) } pub fn acknowledgement_packet_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgAcknowledgement, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ExecCtx: ExecutionContext, { @@ -103,7 +103,7 @@ where Ok(()) } -fn validate(ctx_a: &Ctx, msg: &MsgAcknowledgement) -> Result<(), ContextError> +fn validate(ctx_a: &Ctx, msg: &MsgAcknowledgement) -> Result<(), HandlerError> where Ctx: ValidationContext, { diff --git a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs index 5b315ecbf..e9cc78d5c 100644 --- a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs @@ -7,7 +7,7 @@ use ibc_core_channel_types::msgs::MsgChannelCloseConfirm; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; use ibc_core_connection_types::error::ConnectionError; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; use ibc_core_host::{ExecutionContext, ValidationContext}; @@ -19,7 +19,7 @@ pub fn chan_close_confirm_validate( ctx_b: &ValCtx, module: &dyn Module, msg: MsgChannelCloseConfirm, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ValCtx: ValidationContext, { @@ -34,7 +34,7 @@ pub fn chan_close_confirm_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelCloseConfirm, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ExecCtx: ExecutionContext, { @@ -58,9 +58,11 @@ where let core_event = { let port_id_on_a = chan_end_on_b.counterparty().port_id.clone(); - let chan_id_on_a = chan_end_on_b.counterparty().channel_id.clone().ok_or( - ContextError::ChannelError(ChannelError::MissingCounterparty), - )?; + let chan_id_on_a = chan_end_on_b + .counterparty() + .channel_id + .clone() + .ok_or(HandlerError::Channel(ChannelError::MissingCounterparty))?; let conn_id_on_b = chan_end_on_b.connection_hops[0].clone(); IbcEvent::CloseConfirmChannel(CloseConfirm::new( @@ -86,7 +88,7 @@ where Ok(()) } -fn validate(ctx_b: &Ctx, msg: &MsgChannelCloseConfirm) -> Result<(), ContextError> +fn validate(ctx_b: &Ctx, msg: &MsgChannelCloseConfirm) -> Result<(), HandlerError> where Ctx: ValidationContext, { diff --git a/ibc-core/ics04-channel/src/handler/chan_close_init.rs b/ibc-core/ics04-channel/src/handler/chan_close_init.rs index 6bdab73f6..0f0cd557d 100644 --- a/ibc-core/ics04-channel/src/handler/chan_close_init.rs +++ b/ibc-core/ics04-channel/src/handler/chan_close_init.rs @@ -5,7 +5,7 @@ use ibc_core_channel_types::events::CloseInit; use ibc_core_channel_types::msgs::MsgChannelCloseInit; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::ChannelEndPath; use ibc_core_host::{ExecutionContext, ValidationContext}; @@ -16,7 +16,7 @@ pub fn chan_close_init_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgChannelCloseInit, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ValCtx: ValidationContext, { @@ -31,7 +31,7 @@ pub fn chan_close_init_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelCloseInit, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ExecCtx: ExecutionContext, { @@ -56,9 +56,11 @@ where let core_event = { let port_id_on_b = chan_end_on_a.counterparty().port_id.clone(); - let chan_id_on_b = chan_end_on_a.counterparty().channel_id.clone().ok_or( - ContextError::ChannelError(ChannelError::MissingCounterparty), - )?; + let chan_id_on_b = chan_end_on_a + .counterparty() + .channel_id + .clone() + .ok_or(HandlerError::Channel(ChannelError::MissingCounterparty))?; let conn_id_on_a = chan_end_on_a.connection_hops[0].clone(); IbcEvent::CloseInitChannel(CloseInit::new( @@ -84,7 +86,7 @@ where Ok(()) } -fn validate(ctx_a: &Ctx, msg: &MsgChannelCloseInit) -> Result<(), ContextError> +fn validate(ctx_a: &Ctx, msg: &MsgChannelCloseInit) -> Result<(), HandlerError> where Ctx: ValidationContext, { diff --git a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs index f6271bcd0..64aff01d6 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs @@ -6,7 +6,7 @@ use ibc_core_channel_types::msgs::MsgChannelOpenAck; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; use ibc_core_connection_types::error::ConnectionError; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; use ibc_core_host::{ExecutionContext, ValidationContext}; @@ -18,7 +18,7 @@ pub fn chan_open_ack_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgChannelOpenAck, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ValCtx: ValidationContext, { @@ -33,7 +33,7 @@ pub fn chan_open_ack_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenAck, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ExecCtx: ExecutionContext, { @@ -87,7 +87,7 @@ where Ok(()) } -fn validate(ctx_a: &Ctx, msg: &MsgChannelOpenAck) -> Result<(), ContextError> +fn validate(ctx_a: &Ctx, msg: &MsgChannelOpenAck) -> Result<(), HandlerError> where Ctx: ValidationContext, { diff --git a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs index 2ea7078a4..e3ade9e35 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs @@ -7,7 +7,7 @@ use ibc_core_channel_types::msgs::MsgChannelOpenConfirm; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; use ibc_core_connection_types::error::ConnectionError; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; use ibc_core_host::{ExecutionContext, ValidationContext}; @@ -19,7 +19,7 @@ pub fn chan_open_confirm_validate( ctx_b: &ValCtx, module: &dyn Module, msg: MsgChannelOpenConfirm, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ValCtx: ValidationContext, { @@ -34,7 +34,7 @@ pub fn chan_open_confirm_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenConfirm, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ExecCtx: ExecutionContext, { @@ -59,14 +59,11 @@ where let conn_id_on_b = chan_end_on_b.connection_hops[0].clone(); let port_id_on_a = chan_end_on_b.counterparty().port_id.clone(); - let chan_id_on_a = - chan_end_on_b - .counterparty() - .channel_id - .clone() - .ok_or(ContextError::ChannelError( - ChannelError::MissingCounterparty, - ))?; + let chan_id_on_a = chan_end_on_b + .counterparty() + .channel_id + .clone() + .ok_or(HandlerError::Channel(ChannelError::MissingCounterparty))?; let core_event = IbcEvent::OpenConfirmChannel(OpenConfirm::new( msg.port_id_on_b.clone(), @@ -90,7 +87,7 @@ where Ok(()) } -fn validate(ctx_b: &Ctx, msg: &MsgChannelOpenConfirm) -> Result<(), ContextError> +fn validate(ctx_b: &Ctx, msg: &MsgChannelOpenConfirm) -> Result<(), HandlerError> where Ctx: ValidationContext, { diff --git a/ibc-core/ics04-channel/src/handler/chan_open_init.rs b/ibc-core/ics04-channel/src/handler/chan_open_init.rs index 58a161d0b..b952e7d1a 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_init.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_init.rs @@ -4,7 +4,7 @@ use ibc_core_channel_types::channel::{ChannelEnd, Counterparty, State}; use ibc_core_channel_types::events::OpenInit; use ibc_core_channel_types::msgs::MsgChannelOpenInit; use ibc_core_client::context::prelude::*; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::ChannelId; use ibc_core_host::types::path::{ChannelEndPath, SeqAckPath, SeqRecvPath, SeqSendPath}; @@ -16,7 +16,7 @@ pub fn chan_open_init_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgChannelOpenInit, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ValCtx: ValidationContext, { @@ -39,7 +39,7 @@ pub fn chan_open_init_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenInit, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ExecCtx: ExecutionContext, { @@ -107,7 +107,7 @@ where Ok(()) } -fn validate(ctx_a: &Ctx, msg: &MsgChannelOpenInit) -> Result<(), ContextError> +fn validate(ctx_a: &Ctx, msg: &MsgChannelOpenInit) -> Result<(), HandlerError> where Ctx: ValidationContext, { diff --git a/ibc-core/ics04-channel/src/handler/chan_open_try.rs b/ibc-core/ics04-channel/src/handler/chan_open_try.rs index 48138ce69..09ca21604 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_try.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_try.rs @@ -7,7 +7,7 @@ use ibc_core_channel_types::msgs::MsgChannelOpenTry; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; use ibc_core_connection_types::error::ConnectionError; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::ChannelId; use ibc_core_host::types::path::{ @@ -22,7 +22,7 @@ pub fn chan_open_try_validate( ctx_b: &ValCtx, module: &dyn Module, msg: MsgChannelOpenTry, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ValCtx: ValidationContext, { @@ -46,7 +46,7 @@ pub fn chan_open_try_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenTry, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ExecCtx: ExecutionContext, { @@ -116,7 +116,7 @@ where Ok(()) } -fn validate(ctx_b: &Ctx, msg: &MsgChannelOpenTry) -> Result<(), ContextError> +fn validate(ctx_b: &Ctx, msg: &MsgChannelOpenTry) -> Result<(), HandlerError> where Ctx: ValidationContext, { diff --git a/ibc-core/ics04-channel/src/handler/recv_packet.rs b/ibc-core/ics04-channel/src/handler/recv_packet.rs index 95a47dd49..faa0ffe02 100644 --- a/ibc-core/ics04-channel/src/handler/recv_packet.rs +++ b/ibc-core/ics04-channel/src/handler/recv_packet.rs @@ -7,7 +7,7 @@ use ibc_core_channel_types::packet::Receipt; use ibc_core_client::context::prelude::*; use ibc_core_connection::delay::verify_conn_delay_passed; use ibc_core_connection::types::State as ConnectionState; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ AckPath, ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, ReceiptPath, @@ -17,7 +17,7 @@ use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_core_router::module::Module; use ibc_primitives::prelude::*; -pub fn recv_packet_validate(ctx_b: &ValCtx, msg: MsgRecvPacket) -> Result<(), ContextError> +pub fn recv_packet_validate(ctx_b: &ValCtx, msg: MsgRecvPacket) -> Result<(), HandlerError> where ValCtx: ValidationContext, { @@ -32,7 +32,7 @@ pub fn recv_packet_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgRecvPacket, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ExecCtx: ExecutionContext, { @@ -136,7 +136,7 @@ where Ok(()) } -fn validate(ctx_b: &Ctx, msg: &MsgRecvPacket) -> Result<(), ContextError> +fn validate(ctx_b: &Ctx, msg: &MsgRecvPacket) -> Result<(), HandlerError> where Ctx: ValidationContext, { @@ -254,8 +254,8 @@ where validate_write_acknowledgement(ctx_b, msg)?; } Order::None => { - return Err(ContextError::ChannelError(ChannelError::InvalidOrderType { - expected: "Channel ordering cannot be None".to_string(), + return Err(HandlerError::Channel(ChannelError::InvalidOrderType { + expected: "Channel ordering to not be None".to_string(), actual: chan_end_on_b.ordering.to_string(), })) } @@ -264,7 +264,7 @@ where Ok(()) } -fn validate_write_acknowledgement(ctx_b: &Ctx, msg: &MsgRecvPacket) -> Result<(), ContextError> +fn validate_write_acknowledgement(ctx_b: &Ctx, msg: &MsgRecvPacket) -> Result<(), HandlerError> where Ctx: ValidationContext, { diff --git a/ibc-core/ics04-channel/src/handler/send_packet.rs b/ibc-core/ics04-channel/src/handler/send_packet.rs index 6680bf6fb..c15b03d21 100644 --- a/ibc-core/ics04-channel/src/handler/send_packet.rs +++ b/ibc-core/ics04-channel/src/handler/send_packet.rs @@ -4,7 +4,7 @@ use ibc_core_channel_types::error::PacketError; use ibc_core_channel_types::events::SendPacket; use ibc_core_channel_types::packet::Packet; use ibc_core_client::context::prelude::*; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, SeqSendPath, @@ -19,7 +19,7 @@ use crate::context::{SendPacketExecutionContext, SendPacketValidationContext}; pub fn send_packet( ctx_a: &mut impl SendPacketExecutionContext, packet: Packet, -) -> Result<(), ContextError> { +) -> Result<(), HandlerError> { send_packet_validate(ctx_a, &packet)?; send_packet_execute(ctx_a, packet) } @@ -28,9 +28,9 @@ pub fn send_packet( pub fn send_packet_validate( ctx_a: &impl SendPacketValidationContext, packet: &Packet, -) -> Result<(), ContextError> { +) -> Result<(), HandlerError> { if !packet.timeout_height_on_b.is_set() && !packet.timeout_timestamp_on_b.is_set() { - return Err(ContextError::PacketError(PacketError::MissingTimeout)); + return Err(HandlerError::Packet(PacketError::MissingTimeout)); } let chan_end_path_on_a = ChannelEndPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); @@ -104,7 +104,7 @@ pub fn send_packet_validate( pub fn send_packet_execute( ctx_a: &mut impl SendPacketExecutionContext, packet: Packet, -) -> Result<(), ContextError> { +) -> Result<(), HandlerError> { { let seq_send_path_on_a = SeqSendPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); let next_seq_send_on_a = ctx_a.get_next_sequence_send(&seq_send_path_on_a)?; diff --git a/ibc-core/ics04-channel/src/handler/timeout.rs b/ibc-core/ics04-channel/src/handler/timeout.rs index 9ce98bc0a..9e587256d 100644 --- a/ibc-core/ics04-channel/src/handler/timeout.rs +++ b/ibc-core/ics04-channel/src/handler/timeout.rs @@ -5,7 +5,7 @@ use ibc_core_channel_types::events::{ChannelClosed, TimeoutPacket}; use ibc_core_channel_types::msgs::{MsgTimeout, MsgTimeoutOnClose}; use ibc_core_client::context::prelude::*; use ibc_core_connection::delay::verify_conn_delay_passed; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, ReceiptPath, SeqRecvPath, @@ -25,7 +25,7 @@ pub fn timeout_packet_validate( ctx_a: &ValCtx, module: &dyn Module, timeout_msg_type: TimeoutMsgType, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ValCtx: ValidationContext, { @@ -41,14 +41,14 @@ where module .on_timeout_packet_validate(&packet, &signer) - .map_err(ContextError::PacketError) + .map_err(HandlerError::Packet) } pub fn timeout_packet_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, timeout_msg_type: TimeoutMsgType, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where ExecCtx: ExecutionContext, { @@ -126,7 +126,7 @@ where Ok(()) } -fn validate(ctx_a: &Ctx, msg: &MsgTimeout) -> Result<(), ContextError> +fn validate(ctx_a: &Ctx, msg: &MsgTimeout) -> Result<(), HandlerError> where Ctx: ValidationContext, { @@ -247,7 +247,7 @@ where ) } Order::None => { - return Err(ContextError::ChannelError(ChannelError::InvalidOrderType { + return Err(HandlerError::Channel(ChannelError::InvalidOrderType { expected: "Channel ordering cannot be None".to_string(), actual: chan_end_on_a.ordering.to_string(), })) diff --git a/ibc-core/ics04-channel/src/handler/timeout_on_close.rs b/ibc-core/ics04-channel/src/handler/timeout_on_close.rs index c52225f81..e6bd30724 100644 --- a/ibc-core/ics04-channel/src/handler/timeout_on_close.rs +++ b/ibc-core/ics04-channel/src/handler/timeout_on_close.rs @@ -5,7 +5,7 @@ use ibc_core_channel_types::msgs::MsgTimeoutOnClose; use ibc_core_client::context::prelude::*; use ibc_core_connection::delay::verify_conn_delay_passed; use ibc_core_connection::types::error::ConnectionError; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, ReceiptPath, SeqRecvPath, }; @@ -13,7 +13,7 @@ use ibc_core_host::ValidationContext; use ibc_primitives::prelude::*; use ibc_primitives::proto::Protobuf; -pub fn validate(ctx_a: &Ctx, msg: &MsgTimeoutOnClose) -> Result<(), ContextError> +pub fn validate(ctx_a: &Ctx, msg: &MsgTimeoutOnClose) -> Result<(), HandlerError> where Ctx: ValidationContext, { @@ -155,7 +155,7 @@ where ) } Order::None => { - return Err(ContextError::ChannelError(ChannelError::InvalidOrderType { + return Err(HandlerError::Channel(ChannelError::InvalidOrderType { expected: "Channel ordering cannot be None".to_string(), actual: chan_end_on_a.ordering.to_string(), })) diff --git a/ibc-core/ics04-channel/types/src/error.rs b/ibc-core/ics04-channel/types/src/error.rs index 4e0551e66..722c5bf26 100644 --- a/ibc-core/ics04-channel/types/src/error.rs +++ b/ibc-core/ics04-channel/types/src/error.rs @@ -53,17 +53,6 @@ pub enum ChannelError { }, /// failed proof verification: `{0}` FailedProofVerification(ClientError), - - // TODO(seanchen1991): These variants should be encoded by host-relevant error types - // once those have been defined. - /// application module error: `{description}` - AppModule { description: String }, - /// missing channel counter - MissingCounter, - /// failed to update counter: `{description}` - FailedToUpdateCounter { description: String }, - /// failed to store channel: `{description}` - FailedToStoreChannel { description: String }, } #[derive(Debug, Display)] @@ -109,16 +98,6 @@ pub enum PacketError { timeout_timestamp: TimeoutTimestamp, chain_timestamp: Timestamp, }, - - // TODO(seanchen1991): Move these variants to host-relevant error types - /// application module error: `{description}` - AppModule { description: String }, - /// missing acknowledgment for packet `{0}` - MissingPacketAcknowledgment(Sequence), - /// missing packet receipt for packet `{0}` - MissingPacketReceipt(Sequence), - /// implementation-specific error - ImplementationSpecific, } impl From for ChannelError { diff --git a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/context.rs b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/context.rs index 1328355e8..89ec14ff3 100644 --- a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/context.rs +++ b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/context.rs @@ -6,7 +6,7 @@ //! If it proves to be generic enough, we may move it to the ICS02 section. use ibc_core_client_context::ClientValidationContext; -use ibc_core_client_types::error::UpgradeClientError; +use ibc_core_host_types::error::HostError; use ibc_core_host_types::path::{UpgradeClientStatePath, UpgradeConsensusStatePath}; use super::Plan; @@ -23,41 +23,41 @@ pub trait UpgradeValidationContext { type V: ClientValidationContext; /// Returns the upgrade plan that is scheduled and has not been executed yet. - fn upgrade_plan(&self) -> Result; + fn upgrade_plan(&self) -> Result; /// Returns the upgraded client state at the specified upgrade path. fn upgraded_client_state( &self, upgrade_path: &UpgradeClientStatePath, - ) -> Result, UpgradeClientError>; + ) -> Result, HostError>; /// Returns the upgraded consensus state at the specified upgrade path. fn upgraded_consensus_state( &self, upgrade_path: &UpgradeConsensusStatePath, - ) -> Result, UpgradeClientError>; + ) -> Result, HostError>; } /// Helper context to execute client upgrades, providing methods to schedule /// an upgrade and store related upgraded client and consensus states. pub trait UpgradeExecutionContext: UpgradeValidationContext { /// Schedules an upgrade based on the specified plan. If there is another `Plan` it should be overwritten. - fn schedule_upgrade(&mut self, plan: Plan) -> Result<(), UpgradeClientError>; + fn schedule_upgrade(&mut self, plan: Plan) -> Result<(), HostError>; /// Clears the upgrade plan at the specified height. - fn clear_upgrade_plan(&mut self, plan_height: u64) -> Result<(), UpgradeClientError>; + fn clear_upgrade_plan(&mut self, plan_height: u64) -> Result<(), HostError>; /// Stores the upgraded client state at the specified upgrade path. fn store_upgraded_client_state( &mut self, upgrade_path: UpgradeClientStatePath, client_state: UpgradedClientStateRef, - ) -> Result<(), UpgradeClientError>; + ) -> Result<(), HostError>; /// Stores the upgraded consensus state at the specified upgrade path. fn store_upgraded_consensus_state( &mut self, upgrade_path: UpgradeConsensusStatePath, consensus_state: UpgradedConsensusStateRef, - ) -> Result<(), UpgradeClientError>; + ) -> Result<(), HostError>; } diff --git a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs index 48ceaf0e5..ccba17567 100644 --- a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs +++ b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs @@ -1,7 +1,7 @@ //! Definition of domain `Plan` type. use ibc_core_client_types::error::UpgradeClientError; -use ibc_core_host_types::error::DecodingError; +use ibc_core_host_types::error::{DecodingError, IdentifierError}; use ibc_primitives::prelude::*; use ibc_proto::cosmos::upgrade::v1beta1::Plan as RawPlan; use ibc_proto::google::protobuf::Any; @@ -29,35 +29,33 @@ pub struct Plan { impl Protobuf for Plan {} impl TryFrom for Plan { - type Error = UpgradeClientError; + type Error = DecodingError; fn try_from(raw: RawPlan) -> Result { if raw.name.is_empty() { - return Err(UpgradeClientError::InvalidUpgradePlan { - description: "name field cannot be empty".to_string(), + return Err(DecodingError::InvalidRawData { + description: "upgrade plan name cannot be empty".to_string(), }); } #[allow(deprecated)] if raw.time.is_some() { - return Err(UpgradeClientError::InvalidUpgradePlan { - description: "time field must be empty".to_string(), + return Err(DecodingError::InvalidRawData { + description: "upgrade plan time must be empty".to_string(), }); } #[allow(deprecated)] if raw.upgraded_client_state.is_some() { - return Err(UpgradeClientError::InvalidUpgradePlan { - description: "upgraded_client_state field must be empty".to_string(), + return Err(DecodingError::InvalidRawData { + description: "upgrade plan `upgraded_client_state` field must be empty".to_string(), }); } Ok(Self { name: raw.name, height: u64::try_from(raw.height).map_err(|_| { - UpgradeClientError::InvalidUpgradePlan { - description: "height plan overflow".to_string(), - } + DecodingError::Identifier(IdentifierError::OverflowedRevisionNumber) })?, info: raw.info, }) diff --git a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs index f069e6852..9de0a272a 100644 --- a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs +++ b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs @@ -1,6 +1,6 @@ //! Definition of domain `UpgradeProposal` type for handling upgrade client proposal -use ibc_core_client_types::error::UpgradeClientError; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::client::v1::UpgradeProposal as RawUpgradeProposal; @@ -28,34 +28,35 @@ pub struct UpgradeProposal { impl Protobuf for UpgradeProposal {} impl TryFrom for UpgradeProposal { - type Error = UpgradeClientError; + type Error = DecodingError; fn try_from(raw: RawUpgradeProposal) -> Result { if raw.title.is_empty() { - return Err(UpgradeClientError::InvalidUpgradeProposal { - description: "missing title field".to_string(), + return Err(DecodingError::InvalidRawData { + description: "invalid upgrade proposal: missing title field".to_string(), }); } if raw.description.is_empty() { - return Err(UpgradeClientError::InvalidUpgradeProposal { - description: "missing description field".to_string(), + return Err(DecodingError::InvalidRawData { + description: "invalid upgrade proposal: missing description field".to_string(), }); } let plan = if let Some(plan) = raw.plan { plan.try_into()? } else { - return Err(UpgradeClientError::InvalidUpgradeProposal { - description: "missing plan field".to_string(), + return Err(DecodingError::InvalidRawData { + description: "invalid upgrade proposal: missing plan field".to_string(), }); }; - let upgraded_client_state = raw.upgraded_client_state.ok_or_else(|| { - UpgradeClientError::InvalidUpgradeProposal { - description: "missing upgraded client state".to_string(), - } - })?; + let upgraded_client_state = + raw.upgraded_client_state + .ok_or_else(|| DecodingError::InvalidRawData { + description: "invalid upgrade proposal: missing upgraded client state" + .to_string(), + })?; Ok(Self { title: raw.title, diff --git a/ibc-core/ics24-host/cosmos/src/validate_self_client.rs b/ibc-core/ics24-host/cosmos/src/validate_self_client.rs index f6d66994d..d6c84e365 100644 --- a/ibc-core/ics24-host/cosmos/src/validate_self_client.rs +++ b/ibc-core/ics24-host/cosmos/src/validate_self_client.rs @@ -1,11 +1,9 @@ use core::time::Duration; use ibc_client_tendermint::types::ClientState as TmClientState; -use ibc_core_client_types::error::ClientError; -use ibc_core_client_types::{Height, Status}; +use ibc_core_client_types::Height; use ibc_core_commitment_types::specs::ProofSpecs; -use ibc_core_connection_types::error::ConnectionError; -use ibc_core_handler_types::error::ContextError; +use ibc_core_host_types::error::HostError; use ibc_core_host_types::identifiers::ChainId; use ibc_primitives::prelude::*; use tendermint::trust_threshold::TrustThresholdFraction as TendermintTrustThresholdFraction; @@ -19,63 +17,53 @@ pub trait ValidateSelfClientContext { fn validate_self_tendermint_client( &self, client_state_of_host_on_counterparty: TmClientState, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { client_state_of_host_on_counterparty .validate() - .map_err(ClientError::from)?; + .map_err(|e| { + HostError::invalid_state(format!( + "invalid counterparty client state that could not be validated: {e}" + )) + })?; if client_state_of_host_on_counterparty.is_frozen() { - return Err(ClientError::UnexpectedStatus(Status::Frozen).into()); + return Err(HostError::invalid_state("client unexpectedly frozen")); } let self_chain_id = self.chain_id(); + if self_chain_id != &client_state_of_host_on_counterparty.chain_id { - return Err(ContextError::ConnectionError( - ConnectionError::InvalidClientState { - description: format!( - "invalid chain-id. expected: {}, got: {}", - self_chain_id, client_state_of_host_on_counterparty.chain_id - ), - }, - )); + return Err(HostError::invalid_state(format!( + "invalid chain ID: expected {}, actual {}", + self_chain_id, client_state_of_host_on_counterparty.chain_id + ))); } let latest_height = client_state_of_host_on_counterparty.latest_height; let self_revision_number = self_chain_id.revision_number(); + if self_revision_number != latest_height.revision_number() { - return Err(ContextError::ConnectionError( - ConnectionError::InvalidClientState { - description: format!( - "client is not in the same revision as the chain. expected: {}, got: {}", - self_revision_number, - latest_height.revision_number() - ), - }, - )); + return Err(HostError::invalid_state(format!( + "mismatched client revision numbers; expected {}, actual {}", + self_revision_number, + latest_height.revision_number() + ))); } if latest_height >= self.host_current_height() { - return Err(ContextError::ConnectionError( - ConnectionError::InvalidClientState { - description: format!( - "client has latest height {} greater than or equal to chain height {}", - latest_height, - self.host_current_height() - ), - }, - )); + return Err(HostError::invalid_state(format!( + "client latest height {} should be less than chain height {}", + latest_height, + self.host_current_height() + ))); } if self.proof_specs() != &client_state_of_host_on_counterparty.proof_specs { - return Err(ContextError::ConnectionError( - ConnectionError::InvalidClientState { - description: format!( - "client has invalid proof specs. expected: {:?}, got: {:?}", - self.proof_specs(), - client_state_of_host_on_counterparty.proof_specs - ), - }, - )); + return Err(HostError::invalid_state(format!( + "invalid client proof specs; expected {:?}, actual {:?}", + self.proof_specs(), + client_state_of_host_on_counterparty.proof_specs + ))); } let _ = { @@ -85,45 +73,35 @@ pub trait ValidateSelfClientContext { trust_level.numerator(), trust_level.denominator(), ) - .map_err(|_| ConnectionError::InvalidClientState { - description: "invalid trust level".to_string(), - })? + .map_err(HostError::invalid_state)? }; if self.unbonding_period() != client_state_of_host_on_counterparty.unbonding_period { - return Err(ContextError::ConnectionError( - ConnectionError::InvalidClientState { - description: format!( - "invalid unbonding period. expected: {:?}, got: {:?}", - self.unbonding_period(), - client_state_of_host_on_counterparty.unbonding_period, - ), - }, - )); + return Err(HostError::invalid_state(format!( + "invalid unbonding period; expected {:?}, actual {:?}", + self.unbonding_period(), + client_state_of_host_on_counterparty.unbonding_period, + ))); } if client_state_of_host_on_counterparty.unbonding_period < client_state_of_host_on_counterparty.trusting_period { - return Err(ContextError::ConnectionError(ConnectionError::InvalidClientState{ description: format!( - "unbonding period must be greater than trusting period. unbonding period ({:?}) < trusting period ({:?})", + return Err(HostError::invalid_state(format!( + "invalid counterparty client state: unbonding period must be greater than trusting period; unbonding period ({:?}) < trusting period ({:?})", client_state_of_host_on_counterparty.unbonding_period, client_state_of_host_on_counterparty.trusting_period - )})); + ))); } if !client_state_of_host_on_counterparty.upgrade_path.is_empty() && self.upgrade_path() != client_state_of_host_on_counterparty.upgrade_path { - return Err(ContextError::ConnectionError( - ConnectionError::InvalidClientState { - description: format!( - "invalid upgrade path. expected: {:?}, got: {:?}", - self.upgrade_path(), - client_state_of_host_on_counterparty.upgrade_path - ), - }, - )); + return Err(HostError::invalid_state(format!( + "invalid upgrade path; expected {:?}, actual {:?}", + self.upgrade_path(), + client_state_of_host_on_counterparty.upgrade_path + ))); } Ok(()) diff --git a/ibc-core/ics24-host/src/context.rs b/ibc-core/ics24-host/src/context.rs index 44451c4f5..a9a84ab53 100644 --- a/ibc-core/ics24-host/src/context.rs +++ b/ibc-core/ics24-host/src/context.rs @@ -8,8 +8,8 @@ use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentPrefix; use ibc_core_connection_types::version::{pick_version, Version as ConnectionVersion}; use ibc_core_connection_types::ConnectionEnd; -use ibc_core_handler_types::error::ContextError; use ibc_core_handler_types::events::IbcEvent; +use ibc_core_host_types::error::HostError; use ibc_core_host_types::identifiers::{ConnectionId, Sequence}; use ibc_core_host_types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, CommitmentPath, ConnectionPath, ReceiptPath, @@ -34,24 +34,21 @@ pub trait ValidationContext { fn get_client_validation_context(&self) -> &Self::V; /// Returns the current height of the local chain. - fn host_height(&self) -> Result; + fn host_height(&self) -> Result; /// Returns the current timestamp of the local chain. - fn host_timestamp(&self) -> Result; + fn host_timestamp(&self) -> Result; /// Returns the `ConsensusState` of the host (local) chain at a specific height. - fn host_consensus_state( - &self, - height: &Height, - ) -> Result; + fn host_consensus_state(&self, height: &Height) -> Result; /// Returns a natural number, counting how many clients have been created /// thus far. The value of this counter should increase only via method /// `ExecutionContext::increase_client_counter`. - fn client_counter(&self) -> Result; + fn client_counter(&self) -> Result; /// Returns the ConnectionEnd for the given identifier `conn_id`. - fn connection_end(&self, conn_id: &ConnectionId) -> Result; + fn connection_end(&self, conn_id: &ConnectionId) -> Result; /// Validates the `ClientState` of the host chain stored on the counterparty /// chain against the host's internal state. @@ -65,13 +62,13 @@ pub trait ValidationContext { fn validate_self_client( &self, client_state_of_host_on_counterparty: Self::HostClientState, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Returns the prefix that the local chain uses in the KV store. fn commitment_prefix(&self) -> CommitmentPrefix; /// Returns a counter on how many connections have been created thus far. - fn connection_counter(&self) -> Result; + fn connection_counter(&self) -> Result; /// Function required by ICS-03. Returns the list of all possible versions that the connection /// handshake protocol supports. @@ -84,33 +81,31 @@ pub trait ValidationContext { fn pick_version( &self, counterparty_candidate_versions: &[ConnectionVersion], - ) -> Result { - let version = pick_version( + ) -> Result { + pick_version( &self.get_compatible_versions(), counterparty_candidate_versions, - )?; - Ok(version) + ) + .map_err(HostError::missing_state) } /// Returns the `ChannelEnd` for the given `port_id` and `chan_id`. - fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result; + fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result; /// Returns the sequence number for the next packet to be sent for the given store path - fn get_next_sequence_send(&self, seq_send_path: &SeqSendPath) - -> Result; + fn get_next_sequence_send(&self, seq_send_path: &SeqSendPath) -> Result; /// Returns the sequence number for the next packet to be received for the given store path - fn get_next_sequence_recv(&self, seq_recv_path: &SeqRecvPath) - -> Result; + fn get_next_sequence_recv(&self, seq_recv_path: &SeqRecvPath) -> Result; /// Returns the sequence number for the next packet to be acknowledged for the given store path - fn get_next_sequence_ack(&self, seq_ack_path: &SeqAckPath) -> Result; + fn get_next_sequence_ack(&self, seq_ack_path: &SeqAckPath) -> Result; /// Returns the packet commitment for the given store path fn get_packet_commitment( &self, commitment_path: &CommitmentPath, - ) -> Result; + ) -> Result; /// Returns the packet receipt for the given store path. This receipt is /// used to acknowledge the successful processing of a received packet, and @@ -120,18 +115,18 @@ pub trait ValidationContext { /// indicating the packet has already been processed. If the receipt is /// absent, return `Receipt::None`, indicating the packet has not been /// received. - fn get_packet_receipt(&self, receipt_path: &ReceiptPath) -> Result; + fn get_packet_receipt(&self, receipt_path: &ReceiptPath) -> Result; /// Returns the packet acknowledgement for the given store path fn get_packet_acknowledgement( &self, ack_path: &AckPath, - ) -> Result; + ) -> Result; /// Returns a counter on the number of channel ids have been created thus far. /// The value of this counter should increase only via method /// `ExecutionContext::increase_channel_counter`. - fn channel_counter(&self) -> Result; + fn channel_counter(&self) -> Result; /// Returns the maximum expected time per block fn max_expected_time_per_block(&self) -> Duration; @@ -144,7 +139,7 @@ pub trait ValidationContext { /// Validates the `signer` field of IBC messages, which represents the address /// of the user/relayer that signed the given message. - fn validate_message_signer(&self, signer: &Signer) -> Result<(), ContextError>; + fn validate_message_signer(&self, signer: &Signer) -> Result<(), HostError>; } /// Context to be implemented by the host that provides all "write-only" methods. @@ -158,93 +153,93 @@ pub trait ExecutionContext: ValidationContext { /// Called upon client creation. /// Increases the counter, that keeps track of how many clients have been created. - fn increase_client_counter(&mut self) -> Result<(), ContextError>; + fn increase_client_counter(&mut self) -> Result<(), HostError>; /// Stores the given connection_end at path fn store_connection( &mut self, connection_path: &ConnectionPath, connection_end: ConnectionEnd, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Stores the given connection_id at a path associated with the client_id. fn store_connection_to_client( &mut self, client_connection_path: &ClientConnectionPath, conn_id: ConnectionId, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Called upon connection identifier creation (Init or Try process). /// Increases the counter which keeps track of how many connections have been created. - fn increase_connection_counter(&mut self) -> Result<(), ContextError>; + fn increase_connection_counter(&mut self) -> Result<(), HostError>; /// Stores the given packet commitment at the given store path fn store_packet_commitment( &mut self, commitment_path: &CommitmentPath, commitment: PacketCommitment, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Deletes the packet commitment at the given store path fn delete_packet_commitment( &mut self, commitment_path: &CommitmentPath, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Stores the given packet receipt at the given store path fn store_packet_receipt( &mut self, receipt_path: &ReceiptPath, receipt: Receipt, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Stores the given packet acknowledgement at the given store path fn store_packet_acknowledgement( &mut self, ack_path: &AckPath, ack_commitment: AcknowledgementCommitment, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Deletes the packet acknowledgement at the given store path - fn delete_packet_acknowledgement(&mut self, ack_path: &AckPath) -> Result<(), ContextError>; + fn delete_packet_acknowledgement(&mut self, ack_path: &AckPath) -> Result<(), HostError>; /// Stores the given channel_end at a path associated with the port_id and channel_id. fn store_channel( &mut self, channel_end_path: &ChannelEndPath, channel_end: ChannelEnd, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Stores the given `nextSequenceSend` number at the given store path fn store_next_sequence_send( &mut self, seq_send_path: &SeqSendPath, seq: Sequence, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Stores the given `nextSequenceRecv` number at the given store path fn store_next_sequence_recv( &mut self, seq_recv_path: &SeqRecvPath, seq: Sequence, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Stores the given `nextSequenceAck` number at the given store path fn store_next_sequence_ack( &mut self, seq_ack_path: &SeqAckPath, seq: Sequence, - ) -> Result<(), ContextError>; + ) -> Result<(), HostError>; /// Called upon channel identifier creation (Init or Try message processing). /// Increases the counter, that keeps track of how many channels have been created. - fn increase_channel_counter(&mut self) -> Result<(), ContextError>; + fn increase_channel_counter(&mut self) -> Result<(), HostError>; /// Emit the given IBC event - fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), ContextError>; + fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), HostError>; /// Log the given message. - fn log_message(&mut self, message: String) -> Result<(), ContextError>; + fn log_message(&mut self, message: String) -> Result<(), HostError>; } /// Convenient type alias for `ClientStateRef`, providing access to client diff --git a/ibc-core/ics24-host/types/src/error.rs b/ibc-core/ics24-host/types/src/error.rs index b3738e952..7fd47c2cc 100644 --- a/ibc-core/ics24-host/types/src/error.rs +++ b/ibc-core/ics24-host/types/src/error.rs @@ -9,6 +9,47 @@ use ibc_primitives::prelude::*; use ibc_primitives::proto::Error as ProtoError; use prost::DecodeError as ProstError; +/// Errors that originate from host implementations. +#[derive(Debug, Display)] +pub enum HostError { + /// invalid state: `{description}` + InvalidState { description: String }, + /// missing state: `{description}` + MissingState { description: String }, + /// failed to update store: `{description}` + FailedToStore { description: String }, + /// failed to retrieve from store: `{description}` + FailedToRetrieve { description: String }, + /// other error: `{description}` + Other { description: String }, +} + +impl HostError { + pub fn invalid_state(description: T) -> Self { + Self::InvalidState { + description: description.to_string(), + } + } + + pub fn missing_state(description: T) -> Self { + Self::MissingState { + description: description.to_string(), + } + } + + pub fn failed_to_retrieve(description: T) -> Self { + Self::FailedToRetrieve { + description: description.to_string(), + } + } + + pub fn failed_to_store(description: T) -> Self { + Self::FailedToStore { + description: description.to_string(), + } + } +} + /// Errors that arise when parsing identifiers. #[cfg_attr(feature = "serde", derive(serde::Serialize))] #[derive(Debug, Display)] @@ -25,7 +66,8 @@ pub enum IdentifierError { OverflowedRevisionNumber, } -/// Errors that result in decoding failures +/// Errors that occur during the process of decoding, deserializing, +/// and/or converting raw types into domain types. #[derive(Debug, Display)] pub enum DecodingError { /// identifier error: `{0}` @@ -103,3 +145,6 @@ impl std::error::Error for IdentifierError {} #[cfg(feature = "std")] impl std::error::Error for DecodingError {} + +#[cfg(feature = "std")] +impl std::error::Error for HostError {} diff --git a/ibc-core/ics25-handler/src/entrypoint.rs b/ibc-core/ics25-handler/src/entrypoint.rs index 575e5e096..f3aa2323a 100644 --- a/ibc-core/ics25-handler/src/entrypoint.rs +++ b/ibc-core/ics25-handler/src/entrypoint.rs @@ -17,11 +17,13 @@ use ibc_core_connection::handler::{ conn_open_ack, conn_open_confirm, conn_open_init, conn_open_try, }; use ibc_core_connection::types::msgs::ConnectionMsg; -use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::msgs::MsgEnvelope; +use ibc_core_host::types::error::HostError; use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_core_router::router::Router; use ibc_core_router::types::error::RouterError; +use ibc_primitives::prelude::*; use ibc_primitives::proto::Any; /// Entrypoint which performs both validation and message execution @@ -29,7 +31,7 @@ pub fn dispatch( ctx: &mut Ctx, router: &mut impl Router, msg: MsgEnvelope, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where Ctx: ExecutionContext, <::ClientStateRef as TryFrom>::Error: Into, @@ -48,7 +50,7 @@ where /// That is, the state transition of message `i` must be applied before /// message `i+1` is validated. This is equivalent to calling /// `dispatch()` on each successively. -pub fn validate(ctx: &Ctx, router: &impl Router, msg: MsgEnvelope) -> Result<(), ContextError> +pub fn validate(ctx: &Ctx, router: &impl Router, msg: MsgEnvelope) -> Result<(), HandlerError> where Ctx: ValidationContext, <::ClientStateRef as TryFrom>::Error: Into, @@ -80,7 +82,10 @@ where let port_id = channel_msg_to_port_id(&msg); let module_id = router .lookup_module(port_id) - .ok_or(RouterError::UnknownPort(port_id.clone()))?; + .ok_or(HostError::missing_state(format!( + "failed to look up port {}", + port_id.clone() + )))?; let module = router .get_route(&module_id) .ok_or(RouterError::MissingModule)?; @@ -98,7 +103,10 @@ where let port_id = packet_msg_to_port_id(&msg); let module_id = router .lookup_module(port_id) - .ok_or(RouterError::UnknownPort(port_id.clone()))?; + .ok_or(HostError::missing_state(format!( + "failed to look up port {}", + port_id.clone() + )))?; let module = router .get_route(&module_id) .ok_or(RouterError::MissingModule)?; @@ -122,7 +130,7 @@ pub fn execute( ctx: &mut Ctx, router: &mut impl Router, msg: MsgEnvelope, -) -> Result<(), ContextError> +) -> Result<(), HandlerError> where Ctx: ExecutionContext, <::ClientStateMut as TryFrom>::Error: Into, @@ -153,7 +161,10 @@ where let port_id = channel_msg_to_port_id(&msg); let module_id = router .lookup_module(port_id) - .ok_or(RouterError::UnknownPort(port_id.clone()))?; + .ok_or(HostError::missing_state(format!( + "failed to look up port {}", + port_id.clone() + )))?; let module = router .get_route_mut(&module_id) .ok_or(RouterError::MissingModule)?; @@ -171,7 +182,10 @@ where let port_id = packet_msg_to_port_id(&msg); let module_id = router .lookup_module(port_id) - .ok_or(RouterError::UnknownPort(port_id.clone()))?; + .ok_or(HostError::missing_state(format!( + "failed to look up port {}", + port_id.clone() + )))?; let module = router .get_route_mut(&module_id) .ok_or(RouterError::MissingModule)?; diff --git a/ibc-core/ics25-handler/types/src/error.rs b/ibc-core/ics25-handler/types/src/error.rs index 84bc0b939..bc93d11f4 100644 --- a/ibc-core/ics25-handler/types/src/error.rs +++ b/ibc-core/ics25-handler/types/src/error.rs @@ -1,49 +1,53 @@ -//! Defines the context error type +//! Defines the handler error type use derive_more::From; use displaydoc::Display; use ibc_core_channel_types::error::{ChannelError, PacketError}; use ibc_core_client_types::error::ClientError; use ibc_core_connection_types::error::ConnectionError; +use ibc_core_host_types::error::HostError; use ibc_core_router_types::error::RouterError; use ibc_primitives::prelude::*; -/// Top-level error +/// Top-level type that surfaces errors from the core ibc-rs crates. #[derive(Debug, Display, From)] -pub enum ContextError { +pub enum HandlerError { /// ICS02 Client error: {0} - ClientError(ClientError), + Client(ClientError), /// ICS03 Connection error: {0} - ConnectionError(ConnectionError), + Connection(ConnectionError), /// ICS04 Channel error: {0} - ChannelError(ChannelError), + Channel(ChannelError), /// ICS04 Packet error: {0} - PacketError(PacketError), + Packet(PacketError), /// ICS26 Routing error: {0} - RouterError(RouterError), + Router(RouterError), + /// ICS25 Host error: {0} + Host(HostError), } // TODO(seanchen1991): Figure out how to remove this -impl From for ClientError { - fn from(context_error: ContextError) -> Self { - match context_error { - ContextError::ClientError(e) => e, +impl From for ClientError { + fn from(e: HandlerError) -> Self { + match e { + HandlerError::Client(e) => e, _ => ClientError::Other { - description: context_error.to_string(), + description: e.to_string(), }, } } } #[cfg(feature = "std")] -impl std::error::Error for ContextError { +impl std::error::Error for HandlerError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { - Self::ClientError(e) => Some(e), - Self::ConnectionError(e) => Some(e), - Self::ChannelError(e) => Some(e), - Self::PacketError(e) => Some(e), - Self::RouterError(e) => Some(e), + Self::Client(e) => Some(e), + Self::Connection(e) => Some(e), + Self::Channel(e) => Some(e), + Self::Packet(e) => Some(e), + Self::Router(e) => Some(e), + Self::Host(e) => Some(e), } } } diff --git a/ibc-core/ics26-routing/types/src/error.rs b/ibc-core/ics26-routing/types/src/error.rs index 97650e147..b49f70993 100644 --- a/ibc-core/ics26-routing/types/src/error.rs +++ b/ibc-core/ics26-routing/types/src/error.rs @@ -1,5 +1,4 @@ use displaydoc::Display; -use ibc_core_host_types::identifiers::PortId; use ibc_primitives::prelude::*; /// Error type for the router module. @@ -7,10 +6,6 @@ use ibc_primitives::prelude::*; pub enum RouterError { /// missing module MissingModule, - - // TODO(seanchen1991): This variant needs to be moved to HostError - /// unknown port `{0}` - UnknownPort(PortId), } #[cfg(feature = "std")] diff --git a/ibc-query/src/core/context.rs b/ibc-query/src/core/context.rs index 693dafec9..7f29306c6 100644 --- a/ibc-query/src/core/context.rs +++ b/ibc-query/src/core/context.rs @@ -4,7 +4,7 @@ use ibc::core::channel::types::channel::IdentifiedChannelEnd; use ibc::core::channel::types::packet::PacketState; use ibc::core::client::types::Height; use ibc::core::connection::types::IdentifiedConnectionEnd; -use ibc::core::handler::types::error::ContextError; +use ibc::core::host::types::error::HostError; use ibc::core::host::types::identifiers::{ClientId, ConnectionId, Sequence}; use ibc::core::host::types::path::{ChannelEndPath, Path}; use ibc::core::host::{ClientStateRef, ConsensusStateRef, ValidationContext}; @@ -22,32 +22,29 @@ pub trait QueryContext: ProvableContext + ValidationContext { // Client queries /// Returns the list of all clients. - fn client_states(&self) -> Result)>, ContextError>; + fn client_states(&self) -> Result)>, HostError>; /// Returns the list of all consensus states for the given client. fn consensus_states( &self, client_id: &ClientId, - ) -> Result)>, ContextError>; + ) -> Result)>, HostError>; /// Returns the list of all heights at which consensus states for the given client are. - fn consensus_state_heights(&self, client_id: &ClientId) -> Result, ContextError>; + fn consensus_state_heights(&self, client_id: &ClientId) -> Result, HostError>; // Connection queries /// Returns the list of all connection ends. - fn connection_ends(&self) -> Result, ContextError>; + fn connection_ends(&self) -> Result, HostError>; /// Returns the list of all connection ids of the given client. - fn client_connection_ends( - &self, - client_id: &ClientId, - ) -> Result, ContextError>; + fn client_connection_ends(&self, client_id: &ClientId) -> Result, HostError>; // Channel queries /// Returns the list of all channel ends. - fn channel_ends(&self) -> Result, ContextError>; + fn channel_ends(&self) -> Result, HostError>; // Packet queries @@ -55,7 +52,7 @@ pub trait QueryContext: ProvableContext + ValidationContext { fn packet_commitments( &self, channel_end_path: &ChannelEndPath, - ) -> Result, ContextError>; + ) -> Result, HostError>; /// Filters the list of packet sequences for the given channel end that are acknowledged. /// Returns all the packet acknowledgements if `sequences` is empty. @@ -63,14 +60,14 @@ pub trait QueryContext: ProvableContext + ValidationContext { &self, channel_end_path: &ChannelEndPath, sequences: impl ExactSizeIterator, - ) -> Result, ContextError>; + ) -> Result, HostError>; /// Filters the packet sequences for the given channel end that are not received. fn unreceived_packets( &self, channel_end_path: &ChannelEndPath, sequences: impl ExactSizeIterator, - ) -> Result, ContextError>; + ) -> Result, HostError>; /// Filters the list of packet sequences for the given channel end whose acknowledgement is not received. /// Returns all the unreceived acknowledgements if `sequences` is empty. @@ -78,5 +75,5 @@ pub trait QueryContext: ProvableContext + ValidationContext { &self, channel_end_path: &ChannelEndPath, sequences: impl ExactSizeIterator, - ) -> Result, ContextError>; + ) -> Result, HostError>; } diff --git a/ibc-query/src/error.rs b/ibc-query/src/error.rs index a16bda8e7..2d18a8547 100644 --- a/ibc-query/src/error.rs +++ b/ibc-query/src/error.rs @@ -4,8 +4,8 @@ use displaydoc::Display; use ibc::core::channel::types::error::{ChannelError, PacketError}; use ibc::core::client::types::error::ClientError; use ibc::core::connection::types::error::ConnectionError; -use ibc::core::handler::types::error::ContextError; -use ibc::core::host::types::error::{DecodingError, IdentifierError}; +use ibc::core::handler::types::error::HandlerError; +use ibc::core::host::types::error::{DecodingError, HostError, IdentifierError}; use tonic::Status; /// The main error type of the ibc-query crate. This type mainly @@ -13,10 +13,10 @@ use tonic::Status; /// ibc-query's codepaths. #[derive(Debug, Display)] pub enum QueryError { - /// context error: `{0}` - ContextError(ContextError), + /// handler error: `{0}` + Handler(HandlerError), /// decoding error: `{0}` - DecodingError(DecodingError), + Decoding(DecodingError), /// missing proof: `{0}` MissingProof(String), /// missing field: `{0}` @@ -36,52 +36,58 @@ impl QueryError { impl From for Status { fn from(e: QueryError) -> Self { match e { - QueryError::DecodingError(de) => Self::internal(de.to_string()), - QueryError::ContextError(ctx_err) => Self::internal(ctx_err.to_string()), + QueryError::Handler(ctx_err) => Self::internal(ctx_err.to_string()), + QueryError::Decoding(de) => Self::internal(de.to_string()), QueryError::MissingProof(description) => Self::not_found(description), QueryError::MissingField(description) => Self::invalid_argument(description), } } } -impl From for QueryError { - fn from(e: ContextError) -> Self { - Self::ContextError(e) +impl From for QueryError { + fn from(e: HandlerError) -> Self { + Self::Handler(e) } } impl From for QueryError { fn from(e: ClientError) -> Self { - Self::ContextError(ContextError::ClientError(e)) + Self::Handler(HandlerError::Client(e)) } } impl From for QueryError { fn from(e: ConnectionError) -> Self { - Self::ContextError(ContextError::ConnectionError(e)) + Self::Handler(HandlerError::Connection(e)) } } impl From for QueryError { fn from(e: ChannelError) -> Self { - Self::ContextError(ContextError::ChannelError(e)) + Self::Handler(HandlerError::Channel(e)) } } impl From for QueryError { fn from(e: PacketError) -> Self { - Self::ContextError(ContextError::PacketError(e)) + Self::Handler(HandlerError::Packet(e)) } } impl From for QueryError { fn from(e: DecodingError) -> Self { - Self::DecodingError(e) + Self::Decoding(e) } } impl From for QueryError { fn from(e: IdentifierError) -> Self { - Self::DecodingError(DecodingError::Identifier(e)) + Self::Decoding(DecodingError::Identifier(e)) + } +} + +impl From for QueryError { + fn from(e: HostError) -> Self { + Self::Handler(HandlerError::Host(e)) } } diff --git a/ibc-testkit/src/context.rs b/ibc-testkit/src/context.rs index 92255ba3d..92986d14f 100644 --- a/ibc-testkit/src/context.rs +++ b/ibc-testkit/src/context.rs @@ -10,7 +10,7 @@ use ibc::core::client::context::{ClientExecutionContext, ClientValidationContext use ibc::core::client::types::Height; use ibc::core::connection::types::ConnectionEnd; use ibc::core::entrypoint::{dispatch, execute, validate}; -use ibc::core::handler::types::error::ContextError; +use ibc::core::handler::types::error::HandlerError; use ibc::core::handler::types::events::IbcEvent; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::{ChannelId, ClientId, ConnectionId, PortId, Sequence}; @@ -462,24 +462,24 @@ where } /// Calls [`validate`] function on [`MsgEnvelope`] using the context's IBC store and router. - pub fn validate(&mut self, msg: MsgEnvelope) -> Result<(), ContextError> { + pub fn validate(&mut self, msg: MsgEnvelope) -> Result<(), HandlerError> { validate(&self.ibc_store, &self.ibc_router, msg) } /// Calls [`execute`] function on [`MsgEnvelope`] using the context's IBC store and router. - pub fn execute(&mut self, msg: MsgEnvelope) -> Result<(), ContextError> { + pub fn execute(&mut self, msg: MsgEnvelope) -> Result<(), HandlerError> { execute(&mut self.ibc_store, &mut self.ibc_router, msg) } /// Calls [`dispatch`] function on [`MsgEnvelope`] using the context's IBC store and router. - pub fn dispatch(&mut self, msg: MsgEnvelope) -> Result<(), ContextError> { + pub fn dispatch(&mut self, msg: MsgEnvelope) -> Result<(), HandlerError> { dispatch(&mut self.ibc_store, &mut self.ibc_router, msg) } /// A datagram passes from the relayer to the IBC module (on host chain). /// Alternative method to `Ics18Context::send` that does not exercise any serialization. /// Used in testing the Ics18 algorithms, hence this may return an Ics18Error. - pub fn deliver(&mut self, msg: MsgEnvelope) -> Result<(), ContextError> { + pub fn deliver(&mut self, msg: MsgEnvelope) -> Result<(), HandlerError> { self.dispatch(msg)?; // Create a new block. diff --git a/ibc-testkit/src/fixtures/mod.rs b/ibc-testkit/src/fixtures/mod.rs index f6b51ef46..c5e14f29a 100644 --- a/ibc-testkit/src/fixtures/mod.rs +++ b/ibc-testkit/src/fixtures/mod.rs @@ -3,13 +3,13 @@ pub mod clients; pub mod core; use alloc::fmt::Debug; -use ibc::core::handler::types::error::ContextError; +use ibc::core::handler::types::error::HandlerError; use ibc::core::primitives::prelude::*; use crate::testapp::ibc::core::types::DefaultIbcStore; pub enum Expect { Success, - Failure(Option), + Failure(Option), } #[derive(Debug)] @@ -23,7 +23,7 @@ impl Fixture { &self, expect: &Expect, process: &str, - res: &Result<(), ContextError>, + res: &Result<(), HandlerError>, ) -> String { let base_error = match expect { Expect::Success => "step failed!", diff --git a/ibc-testkit/src/testapp/ibc/applications/nft_transfer/context.rs b/ibc-testkit/src/testapp/ibc/applications/nft_transfer/context.rs index a526dcf45..84838d846 100644 --- a/ibc-testkit/src/testapp/ibc/applications/nft_transfer/context.rs +++ b/ibc-testkit/src/testapp/ibc/applications/nft_transfer/context.rs @@ -1,10 +1,10 @@ use ibc::apps::nft_transfer::context::{ NftClassContext, NftContext, NftTransferExecutionContext, NftTransferValidationContext, }; -use ibc::apps::nft_transfer::types::error::NftTransferError; use ibc::apps::nft_transfer::types::{ ClassData, ClassId, ClassUri, Memo, PrefixedClassId, TokenData, TokenId, TokenUri, }; +use ibc::core::host::types::error::HostError; use ibc::core::host::types::identifiers::{ChannelId, PortId}; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Signer; @@ -48,15 +48,15 @@ impl NftTransferValidationContext for DummyNftTransferModule { type Nft = DummyNft; type NftClass = DummyNftClass; - fn get_port(&self) -> Result { + fn get_port(&self) -> Result { Ok(PortId::transfer()) } - fn can_send_nft(&self) -> Result<(), NftTransferError> { + fn can_send_nft(&self) -> Result<(), HostError> { Ok(()) } - fn can_receive_nft(&self) -> Result<(), NftTransferError> { + fn can_receive_nft(&self) -> Result<(), HostError> { Ok(()) } @@ -65,7 +65,7 @@ impl NftTransferValidationContext for DummyNftTransferModule { _class_id: &PrefixedClassId, _class_uri: Option<&ClassUri>, _class_data: Option<&ClassData>, - ) -> Result<(), NftTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -77,7 +77,7 @@ impl NftTransferValidationContext for DummyNftTransferModule { _class_id: &PrefixedClassId, _token_id: &TokenId, _memo: &Memo, - ) -> Result<(), NftTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -88,7 +88,7 @@ impl NftTransferValidationContext for DummyNftTransferModule { _channel_id: &ChannelId, _class_id: &PrefixedClassId, _token_id: &TokenId, - ) -> Result<(), NftTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -99,7 +99,7 @@ impl NftTransferValidationContext for DummyNftTransferModule { _token_id: &TokenId, _token_uri: Option<&TokenUri>, _token_data: Option<&TokenData>, - ) -> Result<(), NftTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -109,7 +109,7 @@ impl NftTransferValidationContext for DummyNftTransferModule { _class_id: &PrefixedClassId, _token_id: &TokenId, _memo: &Memo, - ) -> Result<(), NftTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -117,14 +117,11 @@ impl NftTransferValidationContext for DummyNftTransferModule { &self, _class_id: &PrefixedClassId, _token_id: &TokenId, - ) -> Result { + ) -> Result { Ok(DummyNft::default()) } - fn get_nft_class( - &self, - _class_id: &PrefixedClassId, - ) -> Result { + fn get_nft_class(&self, _class_id: &PrefixedClassId) -> Result { Ok(DummyNftClass::default()) } } @@ -135,7 +132,7 @@ impl NftTransferExecutionContext for DummyNftTransferModule { _class_id: &PrefixedClassId, _class_uri: Option<&ClassUri>, _class_data: Option<&ClassData>, - ) -> Result<(), NftTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -147,7 +144,7 @@ impl NftTransferExecutionContext for DummyNftTransferModule { _class_id: &PrefixedClassId, _token_id: &TokenId, _memo: &Memo, - ) -> Result<(), NftTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -158,7 +155,7 @@ impl NftTransferExecutionContext for DummyNftTransferModule { _channel_id: &ChannelId, _class_id: &PrefixedClassId, _token_id: &TokenId, - ) -> Result<(), NftTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -169,7 +166,7 @@ impl NftTransferExecutionContext for DummyNftTransferModule { _token_id: &TokenId, _token_uri: Option<&TokenUri>, _token_data: Option<&TokenData>, - ) -> Result<(), NftTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -179,7 +176,7 @@ impl NftTransferExecutionContext for DummyNftTransferModule { _class_id: &PrefixedClassId, _token_id: &TokenId, _memo: &Memo, - ) -> Result<(), NftTransferError> { + ) -> Result<(), HostError> { Ok(()) } } diff --git a/ibc-testkit/src/testapp/ibc/applications/transfer/context.rs b/ibc-testkit/src/testapp/ibc/applications/transfer/context.rs index d8876b315..d4a9677ef 100644 --- a/ibc-testkit/src/testapp/ibc/applications/transfer/context.rs +++ b/ibc-testkit/src/testapp/ibc/applications/transfer/context.rs @@ -1,6 +1,6 @@ use ibc::apps::transfer::context::{TokenTransferExecutionContext, TokenTransferValidationContext}; -use ibc::apps::transfer::types::error::TokenTransferError; use ibc::apps::transfer::types::{Memo, PrefixedCoin}; +use ibc::core::host::types::error::HostError; use ibc::core::host::types::identifiers::{ChannelId, PortId}; use ibc::core::primitives::Signer; @@ -9,15 +9,15 @@ use super::types::DummyTransferModule; impl TokenTransferValidationContext for DummyTransferModule { type AccountId = Signer; - fn get_port(&self) -> Result { + fn get_port(&self) -> Result { Ok(PortId::transfer()) } - fn can_send_coins(&self) -> Result<(), TokenTransferError> { + fn can_send_coins(&self) -> Result<(), HostError> { Ok(()) } - fn can_receive_coins(&self) -> Result<(), TokenTransferError> { + fn can_receive_coins(&self) -> Result<(), HostError> { Ok(()) } fn escrow_coins_validate( @@ -27,7 +27,7 @@ impl TokenTransferValidationContext for DummyTransferModule { _channel_id: &ChannelId, _coin: &PrefixedCoin, _memo: &Memo, - ) -> Result<(), TokenTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -37,7 +37,7 @@ impl TokenTransferValidationContext for DummyTransferModule { _port_id: &PortId, _channel_id: &ChannelId, _coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -45,7 +45,7 @@ impl TokenTransferValidationContext for DummyTransferModule { &self, _account: &Self::AccountId, _coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -54,7 +54,7 @@ impl TokenTransferValidationContext for DummyTransferModule { _account: &Self::AccountId, _coin: &PrefixedCoin, _memo: &Memo, - ) -> Result<(), TokenTransferError> { + ) -> Result<(), HostError> { Ok(()) } } @@ -67,7 +67,7 @@ impl TokenTransferExecutionContext for DummyTransferModule { _channel_id: &ChannelId, _coin: &PrefixedCoin, _memo: &Memo, - ) -> Result<(), TokenTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -77,7 +77,7 @@ impl TokenTransferExecutionContext for DummyTransferModule { _port_id: &PortId, _channel_id: &ChannelId, _coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -85,7 +85,7 @@ impl TokenTransferExecutionContext for DummyTransferModule { &mut self, _account: &Self::AccountId, _coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError> { + ) -> Result<(), HostError> { Ok(()) } @@ -94,7 +94,7 @@ impl TokenTransferExecutionContext for DummyTransferModule { _account: &Self::AccountId, _coin: &PrefixedCoin, _memo: &Memo, - ) -> Result<(), TokenTransferError> { + ) -> Result<(), HostError> { Ok(()) } } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs index dff68ecd9..ef6f4c0f0 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs @@ -8,8 +8,7 @@ use ibc::core::client::types::{Height, Status}; use ibc::core::commitment_types::commitment::{ CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, }; -use ibc::core::handler::types::error::ContextError; -use ibc::core::host::types::error::DecodingError; +use ibc::core::host::types::error::{DecodingError, HostError}; use ibc::core::host::types::identifiers::{ClientId, ClientType}; use ibc::core::host::types::path::{ClientConsensusStatePath, ClientStatePath, Path, PathBytes}; use ibc::core::primitives::prelude::*; @@ -155,10 +154,10 @@ impl From for Any { pub trait MockClientContext { /// Returns the current timestamp of the local chain. - fn host_timestamp(&self) -> Result; + fn host_timestamp(&self) -> Result; /// Returns the current height of the local chain. - fn host_height(&self) -> Result; + fn host_height(&self) -> Result; } impl ClientStateCommon for MockClientState { diff --git a/ibc-testkit/src/testapp/ibc/core/client_ctx.rs b/ibc-testkit/src/testapp/ibc/core/client_ctx.rs index a2c9d59d7..f2dbe930c 100644 --- a/ibc-testkit/src/testapp/ibc/core/client_ctx.rs +++ b/ibc-testkit/src/testapp/ibc/core/client_ctx.rs @@ -5,9 +5,8 @@ use basecoin_store::types::Height as StoreHeight; use ibc::core::client::context::{ ClientExecutionContext, ClientValidationContext, ExtClientValidationContext, }; -use ibc::core::client::types::error::ClientError; use ibc::core::client::types::Height; -use ibc::core::handler::types::error::ContextError; +use ibc::core::host::types::error::HostError; use ibc::core::host::types::identifiers::{ChannelId, ClientId, PortId}; use ibc::core::host::types::path::{ ClientConsensusStatePath, ClientStatePath, ClientUpdateHeightPath, ClientUpdateTimePath, Path, @@ -37,11 +36,11 @@ impl MockClientContext for MockIbcStore where S: ProvableStore + Debug, { - fn host_timestamp(&self) -> Result { + fn host_timestamp(&self) -> Result { ValidationContext::host_timestamp(self) } - fn host_height(&self) -> Result { + fn host_height(&self) -> Result { ValidationContext::host_height(self) } } @@ -50,21 +49,17 @@ impl ExtClientValidationContext for MockIbcStore where S: ProvableStore + Debug, { - fn host_timestamp(&self) -> Result { + fn host_timestamp(&self) -> Result { ValidationContext::host_timestamp(self) } - fn host_height(&self) -> Result { + fn host_height(&self) -> Result { ValidationContext::host_height(self) } /// Returns the list of heights at which the consensus state of the given client was updated. - fn consensus_state_heights(&self, client_id: &ClientId) -> Result, ContextError> { - let path = format!("clients/{}/consensusStates", client_id) - .try_into() - .map_err(|_| ClientError::Other { - description: "Invalid consensus state path".into(), - })?; + fn consensus_state_heights(&self, client_id: &ClientId) -> Result, HostError> { + let path = format!("clients/{}/consensusStates", client_id).into(); self.consensus_state_store .get_keys(&path) @@ -77,10 +72,11 @@ where } }) .map(|consensus_path| { - Ok(Height::new( + Height::new( consensus_path.revision_number, consensus_path.revision_height, - )?) + ) + .map_err(HostError::invalid_state) }) .collect::, _>>() } @@ -89,7 +85,7 @@ where &self, client_id: &ClientId, height: &Height, - ) -> Result, ContextError> { + ) -> Result, HostError> { let path = format!("clients/{client_id}/consensusStates").into(); let keys = self.store.get_keys(&path); @@ -108,12 +104,16 @@ where .map(|path| { self.consensus_state_store .get(StoreHeight::Pending, &path) - .ok_or_else(|| ClientError::MissingConsensusState { - client_id: client_id.clone(), - height: *height, + .ok_or_else(|| { + HostError::failed_to_retrieve(format!( + "missing consensus state for client {} at height {}", + client_id.clone(), + *height + )) }) }) - .transpose()?; + .transpose() + .map_err(HostError::missing_state)?; Ok(consensus_state) } @@ -122,7 +122,7 @@ where &self, client_id: &ClientId, height: &Height, - ) -> Result, ContextError> { + ) -> Result, HostError> { let path = format!("clients/{client_id}/consensusStates").into(); let keys = self.store.get_keys(&path); @@ -141,12 +141,16 @@ where .map(|path| { self.consensus_state_store .get(StoreHeight::Pending, &path) - .ok_or_else(|| ClientError::MissingConsensusState { - client_id: client_id.clone(), - height: *height, + .ok_or_else(|| { + HostError::failed_to_retrieve(format!( + "missing consensus state for client {} at height {}", + client_id.clone(), + *height + )) }) }) - .transpose()?; + .transpose() + .map_err(HostError::missing_state)?; Ok(consensus_state) } @@ -159,29 +163,32 @@ where type ClientStateRef = AnyClientState; type ConsensusStateRef = AnyConsensusState; - fn client_state(&self, client_id: &ClientId) -> Result { - Ok(self - .client_state_store + fn client_state(&self, client_id: &ClientId) -> Result { + self.client_state_store .get(StoreHeight::Pending, &ClientStatePath(client_id.clone())) - .ok_or(ClientError::MissingClientState(client_id.clone()))?) + .ok_or(HostError::failed_to_retrieve(format!( + "missing client state for client {}", + client_id.clone() + ))) } fn consensus_state( &self, client_cons_state_path: &ClientConsensusStatePath, - ) -> Result { + ) -> Result { let height = Height::new( client_cons_state_path.revision_number, client_cons_state_path.revision_height, ) - .map_err(|_| ClientError::InvalidHeight)?; + .map_err(HostError::invalid_state)?; let consensus_state = self .consensus_state_store .get(StoreHeight::Pending, client_cons_state_path) - .ok_or(ClientError::MissingConsensusState { - client_id: client_cons_state_path.client_id.clone(), - height, - })?; + .ok_or(HostError::failed_to_retrieve(format!( + "missing consensus state for client {} at height {}", + client_cons_state_path.client_id.clone(), + height + )))?; Ok(consensus_state) } @@ -192,7 +199,7 @@ where &self, client_id: &ClientId, height: &Height, - ) -> Result<(Timestamp, Height), ContextError> { + ) -> Result<(Timestamp, Height), HostError> { let client_update_time_path = ClientUpdateTimePath::new( client_id.clone(), height.revision_number(), @@ -201,10 +208,11 @@ where let processed_timestamp = self .client_processed_times .get(StoreHeight::Pending, &client_update_time_path) - .ok_or(ClientError::MissingUpdateMetaData { - client_id: client_id.clone(), - height: *height, - })?; + .ok_or(HostError::failed_to_retrieve(format!( + "missing client update metadata for client {} at height {}", + client_id.clone(), + *height, + )))?; let client_update_height_path = ClientUpdateHeightPath::new( client_id.clone(), height.revision_number(), @@ -213,10 +221,11 @@ where let processed_height = self .client_processed_heights .get(StoreHeight::Pending, &client_update_height_path) - .ok_or(ClientError::MissingUpdateMetaData { - client_id: client_id.clone(), - height: *height, - })?; + .ok_or(HostError::failed_to_retrieve(format!( + "missing client update metadata for client {} at height {}", + client_id.clone(), + *height, + )))?; Ok((processed_timestamp, processed_height)) } @@ -233,12 +242,10 @@ where &mut self, client_state_path: ClientStatePath, client_state: Self::ClientStateRef, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.client_state_store .set(client_state_path, client_state) - .map_err(|_| ClientError::Other { - description: "Client state store error".to_string(), - })?; + .map_err(|e| HostError::failed_to_store(format!("{e:?}")))?; Ok(()) } @@ -248,30 +255,24 @@ where &mut self, consensus_state_path: ClientConsensusStatePath, consensus_state: Self::ConsensusStateRef, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.consensus_state_store .set(consensus_state_path, consensus_state) - .map_err(|_| ClientError::Other { - description: "Consensus state store error".to_string(), - })?; + .map_err(|e| HostError::failed_to_store(format!("{e:?}")))?; Ok(()) } fn delete_consensus_state( &mut self, consensus_state_path: ClientConsensusStatePath, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.consensus_state_store.delete(consensus_state_path); Ok(()) } /// Delete the update metadata associated with the client at the specified /// height. - fn delete_update_meta( - &mut self, - client_id: ClientId, - height: Height, - ) -> Result<(), ContextError> { + fn delete_update_meta(&mut self, client_id: ClientId, height: Height) -> Result<(), HostError> { let client_update_time_path = ClientUpdateTimePath::new( client_id.clone(), height.revision_number(), @@ -297,7 +298,7 @@ where height: Height, host_timestamp: Timestamp, host_height: Height, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { let client_update_time_path = ClientUpdateTimePath::new( client_id.clone(), height.revision_number(), @@ -305,9 +306,7 @@ where ); self.client_processed_times .set(client_update_time_path, host_timestamp) - .map_err(|_| ClientError::Other { - description: "store update error".into(), - })?; + .map_err(|e| HostError::failed_to_store(format!("{e:?}")))?; let client_update_height_path = ClientUpdateHeightPath::new( client_id, height.revision_number(), @@ -315,9 +314,7 @@ where ); self.client_processed_heights .set(client_update_height_path, host_height) - .map_err(|_| ClientError::Other { - description: "store update error".into(), - })?; + .map_err(|e| HostError::failed_to_store(format!("{e:?}")))?; Ok(()) } } diff --git a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs index 2791bc174..d97140764 100644 --- a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs +++ b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs @@ -7,17 +7,15 @@ use basecoin_store::context::{ProvableStore, Store}; use basecoin_store::types::Height as StoreHeight; use ibc::core::channel::types::channel::{ChannelEnd, IdentifiedChannelEnd}; use ibc::core::channel::types::commitment::{AcknowledgementCommitment, PacketCommitment}; -use ibc::core::channel::types::error::{ChannelError, PacketError}; use ibc::core::channel::types::packet::{PacketState, Receipt}; use ibc::core::client::context::consensus_state::ConsensusState; use ibc::core::client::types::error::ClientError; -use ibc::core::client::types::{Height, Status}; +use ibc::core::client::types::Height; use ibc::core::commitment_types::commitment::CommitmentPrefix; use ibc::core::commitment_types::merkle::MerkleProof; -use ibc::core::connection::types::error::ConnectionError; use ibc::core::connection::types::{ConnectionEnd, IdentifiedConnectionEnd}; -use ibc::core::handler::types::error::ContextError; use ibc::core::handler::types::events::IbcEvent; +use ibc::core::host::types::error::HostError; use ibc::core::host::types::identifiers::{ClientId, ConnectionId, Sequence}; use ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, CommitmentPath, ConnectionPath, @@ -42,45 +40,40 @@ where type HostClientState = AnyClientState; type HostConsensusState = AnyConsensusState; - fn host_height(&self) -> Result { - Ok(Height::new( - *self.revision_number.lock(), - self.store.current_height(), - )?) + fn host_height(&self) -> Result { + Height::new(*self.revision_number.lock(), self.store.current_height()) + .map_err(HostError::invalid_state) } - fn host_timestamp(&self) -> Result { + fn host_timestamp(&self) -> Result { let host_height = self.host_height()?; let host_cons_state = self.host_consensus_state(&host_height)?; Ok(host_cons_state.timestamp()) } - fn client_counter(&self) -> Result { - Ok(self - .client_counter + fn client_counter(&self) -> Result { + self.client_counter .get(StoreHeight::Pending, &NextClientSequencePath) - .ok_or(ClientError::Other { - description: "client counter not found".into(), - })?) + .ok_or(HostError::missing_state("missing client counter")) } - fn host_consensus_state( - &self, - height: &Height, - ) -> Result { + fn host_consensus_state(&self, height: &Height) -> Result { let consensus_states_binding = self.host_consensus_states.lock(); - Ok(consensus_states_binding + + consensus_states_binding .get(&height.revision_height()) .cloned() - .ok_or(ClientError::MissingLocalConsensusState(*height))?) + .ok_or(HostError::missing_state( + ClientError::MissingLocalConsensusState(*height), + )) } fn validate_self_client( &self, client_state_of_host_on_counterparty: Self::HostClientState, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { if client_state_of_host_on_counterparty.is_frozen() { - return Err(ClientError::UnexpectedStatus(Status::Frozen).into()); + return Err(HostError::invalid_state("client unexpectedly frozen")); } let latest_height = self.host_height()?; @@ -91,40 +84,36 @@ where .latest_height() .revision_number() { - return Err(ContextError::ConnectionError( - ConnectionError::InvalidClientState { - description: format!( - "client is not in the same revision as the chain. expected: {}, got: {}", - self_revision_number, - client_state_of_host_on_counterparty - .latest_height() - .revision_number() - ), - }, - )); + return Err(HostError::invalid_state(format!( + "client is not in the same revision as the chain; expected {}, actual {}", + self_revision_number, + client_state_of_host_on_counterparty + .latest_height() + .revision_number() + ))); } let host_current_height = latest_height.increment(); if client_state_of_host_on_counterparty.latest_height() >= host_current_height { - return Err(ContextError::ConnectionError( - ConnectionError::InvalidClientState { - description: format!( - "client has latest height {} greater than or equal to chain height {}", - client_state_of_host_on_counterparty.latest_height(), - host_current_height - ), - }, + return Err(HostError::invalid_state( + format!( + "invalid counterparty client state: client latest height {} should be less than chain height {}", + client_state_of_host_on_counterparty.latest_height(), + host_current_height + ), )); } Ok(()) } - fn connection_end(&self, conn_id: &ConnectionId) -> Result { - Ok(self - .connection_end_store + fn connection_end(&self, conn_id: &ConnectionId) -> Result { + self.connection_end_store .get(StoreHeight::Pending, &ConnectionPath::new(conn_id)) - .ok_or(ConnectionError::MissingConnection(conn_id.clone()))?) + .ok_or(HostError::missing_state(format!( + "missing connection end for connection {}", + conn_id.clone() + ))) } fn commitment_prefix(&self) -> CommitmentPrefix { @@ -133,68 +122,63 @@ where CommitmentPrefix::from(b"mock".to_vec()) } - fn connection_counter(&self) -> Result { - Ok(self - .conn_counter + fn connection_counter(&self) -> Result { + self.conn_counter .get(StoreHeight::Pending, &NextConnectionSequencePath) - .ok_or(ConnectionError::MissingConnectionCounter)?) + .ok_or(HostError::missing_state("missing connection counter")) } - fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result { - Ok(self - .channel_end_store + fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result { + self.channel_end_store .get( StoreHeight::Pending, &ChannelEndPath::new(&channel_end_path.0, &channel_end_path.1), ) - .ok_or(ChannelError::NonexistentChannel { - port_id: channel_end_path.0.clone(), - channel_id: channel_end_path.1.clone(), - })?) + .ok_or(HostError::missing_state(format!( + "missing channel {} in port {}", + channel_end_path.1.clone(), + channel_end_path.0.clone() + ))) } - fn get_next_sequence_send( - &self, - seq_send_path: &SeqSendPath, - ) -> Result { - Ok(self - .send_sequence_store + fn get_next_sequence_send(&self, seq_send_path: &SeqSendPath) -> Result { + self.send_sequence_store .get( StoreHeight::Pending, &SeqSendPath::new(&seq_send_path.0, &seq_send_path.1), ) - .ok_or(PacketError::ImplementationSpecific)?) + .ok_or(HostError::failed_to_retrieve( + "failed to retrieve send packet sequence", + )) } - fn get_next_sequence_recv( - &self, - seq_recv_path: &SeqRecvPath, - ) -> Result { - Ok(self - .recv_sequence_store + fn get_next_sequence_recv(&self, seq_recv_path: &SeqRecvPath) -> Result { + self.recv_sequence_store .get( StoreHeight::Pending, &SeqRecvPath::new(&seq_recv_path.0, &seq_recv_path.1), ) - .ok_or(PacketError::ImplementationSpecific)?) + .ok_or(HostError::failed_to_retrieve( + "failed to retrieve recv packet sequence", + )) } - fn get_next_sequence_ack(&self, seq_ack_path: &SeqAckPath) -> Result { - Ok(self - .ack_sequence_store + fn get_next_sequence_ack(&self, seq_ack_path: &SeqAckPath) -> Result { + self.ack_sequence_store .get( StoreHeight::Pending, &SeqAckPath::new(&seq_ack_path.0, &seq_ack_path.1), ) - .ok_or(PacketError::ImplementationSpecific)?) + .ok_or(HostError::failed_to_retrieve( + "failed to retrieve ack packet sequence", + )) } fn get_packet_commitment( &self, commitment_path: &CommitmentPath, - ) -> Result { - Ok(self - .packet_commitment_store + ) -> Result { + self.packet_commitment_store .get( StoreHeight::Pending, &CommitmentPath::new( @@ -203,10 +187,12 @@ where commitment_path.sequence, ), ) - .ok_or(PacketError::ImplementationSpecific)?) + .ok_or(HostError::failed_to_retrieve( + "failed to retrieve packet commitment", + )) } - fn get_packet_receipt(&self, receipt_path: &ReceiptPath) -> Result { + fn get_packet_receipt(&self, receipt_path: &ReceiptPath) -> Result { if self .packet_receipt_store .is_path_set(StoreHeight::Pending, receipt_path) @@ -220,24 +206,27 @@ where fn get_packet_acknowledgement( &self, ack_path: &AckPath, - ) -> Result { - Ok(self - .packet_ack_store + ) -> Result { + self.packet_ack_store .get( StoreHeight::Pending, &AckPath::new(&ack_path.port_id, &ack_path.channel_id, ack_path.sequence), ) - .ok_or(PacketError::MissingPacketAcknowledgment(ack_path.sequence))?) + .ok_or(HostError::failed_to_retrieve(format!( + "failed to retrieve packet acknowledgment {}", + ack_path.sequence + ))) } /// Returns a counter of the number of channel ids that have been created thus far. /// The value of this counter should increase only via the /// `ChannelKeeper::increase_channel_counter` method. - fn channel_counter(&self) -> Result { - Ok(self - .channel_counter + fn channel_counter(&self) -> Result { + self.channel_counter .get(StoreHeight::Pending, &NextChannelSequencePath) - .ok_or(ChannelError::MissingCounter)?) + .ok_or(HostError::failed_to_retrieve( + "failed to retrieve channel counter", + )) } /// Returns the maximum expected time per block @@ -245,7 +234,7 @@ where Duration::from_secs(DEFAULT_BLOCK_TIME_SECS) } - fn validate_message_signer(&self, _signer: &Signer) -> Result<(), ContextError> { + fn validate_message_signer(&self, _signer: &Signer) -> Result<(), HostError> { Ok(()) } @@ -285,7 +274,7 @@ where S: ProvableStore + Debug, { /// Returns the list of all client states. - fn client_states(&self) -> Result)>, ContextError> { + fn client_states(&self) -> Result)>, HostError> { let path = "clients".to_owned().into(); self.client_state_store @@ -302,7 +291,12 @@ where let client_state = self .client_state_store .get(StoreHeight::Pending, &client_state_path) - .ok_or_else(|| ClientError::MissingClientState(client_state_path.0.clone()))?; + .ok_or_else(|| { + HostError::failed_to_retrieve(format!( + "failed to retrieve client state from path {}", + client_state_path.0.clone() + )) + })?; Ok((client_state_path.0, client_state)) }) .collect() @@ -312,12 +306,8 @@ where fn consensus_states( &self, client_id: &ClientId, - ) -> Result)>, ContextError> { - let path = format!("clients/{}/consensusStates", client_id) - .try_into() - .map_err(|_| ClientError::Other { - description: "Invalid consensus state path".into(), - })?; + ) -> Result)>, HostError> { + let path = format!("clients/{}/consensusStates", client_id).into(); self.consensus_state_store .get_keys(&path) @@ -333,28 +323,23 @@ where let height = Height::new( consensus_path.revision_number, consensus_path.revision_height, - )?; + ) + .map_err(HostError::invalid_state)?; let client_state = self .consensus_state_store .get(StoreHeight::Pending, &consensus_path) - .ok_or({ - ClientError::MissingConsensusState { - client_id: consensus_path.client_id, - height, - } - })?; + .ok_or(HostError::failed_to_retrieve(format!( + "missing consensus state for client {} at height {}", + consensus_path.client_id, height, + )))?; Ok((height, client_state)) }) .collect() } /// Returns the list of heights at which the consensus state of the given client was updated. - fn consensus_state_heights(&self, client_id: &ClientId) -> Result, ContextError> { - let path = format!("clients/{}/consensusStates", client_id) - .try_into() - .map_err(|_| ClientError::Other { - description: "Invalid consensus state path".into(), - })?; + fn consensus_state_heights(&self, client_id: &ClientId) -> Result, HostError> { + let path = format!("clients/{}/consensusStates", client_id).into(); self.consensus_state_store .get_keys(&path) @@ -367,16 +352,17 @@ where } }) .map(|consensus_path| { - Ok(Height::new( + Height::new( consensus_path.revision_number, consensus_path.revision_height, - )?) + ) + .map_err(HostError::invalid_state) }) .collect::, _>>() } /// Returns all the IBC connection ends of a chain. - fn connection_ends(&self) -> Result, ContextError> { + fn connection_ends(&self) -> Result, HostError> { let path = "connections".to_owned().into(); self.connection_end_store @@ -393,7 +379,12 @@ where let connection_end = self .connection_end_store .get(StoreHeight::Pending, &connection_path) - .ok_or_else(|| ConnectionError::MissingConnection(connection_path.0.clone()))?; + .ok_or_else(|| { + HostError::failed_to_retrieve(format!( + "missing connection {}", + connection_path.0.clone() + )) + })?; Ok(IdentifiedConnectionEnd { connection_id: connection_path.0, connection_end, @@ -403,10 +394,7 @@ where } /// Returns all the IBC connection ends associated with a client. - fn client_connection_ends( - &self, - client_id: &ClientId, - ) -> Result, ContextError> { + fn client_connection_ends(&self, client_id: &ClientId) -> Result, HostError> { let client_connection_path = ClientConnectionPath::new(client_id.clone()); Ok(self @@ -416,7 +404,7 @@ where } /// Returns all the IBC channel ends of a chain. - fn channel_ends(&self) -> Result, ContextError> { + fn channel_ends(&self) -> Result, HostError> { let path = "channelEnds".to_owned().into(); self.channel_end_store @@ -433,9 +421,12 @@ where let channel_end = self .channel_end_store .get(StoreHeight::Pending, &channel_path) - .ok_or_else(|| ChannelError::NonexistentChannel { - port_id: channel_path.0.clone(), - channel_id: channel_path.1.clone(), + .ok_or_else(|| { + HostError::failed_to_retrieve(format!( + "missing channel {} with port {}", + channel_path.1.clone(), + channel_path.0.clone() + )) })?; Ok(IdentifiedChannelEnd { port_id: channel_path.0, @@ -450,7 +441,7 @@ where fn packet_commitments( &self, channel_end_path: &ChannelEndPath, - ) -> Result, ContextError> { + ) -> Result, HostError> { let path = format!( "commitments/ports/{}/channels/{}/sequences", channel_end_path.0, channel_end_path.1 @@ -492,7 +483,7 @@ where &self, channel_end_path: &ChannelEndPath, sequences: impl ExactSizeIterator, - ) -> Result, ContextError> { + ) -> Result, HostError> { let collected_paths: Vec<_> = if sequences.len() == 0 { // if sequences is empty, return all the acks let ack_path_prefix = format!( @@ -545,7 +536,7 @@ where &self, channel_end_path: &ChannelEndPath, sequences: impl ExactSizeIterator, - ) -> Result, ContextError> { + ) -> Result, HostError> { // QUESTION. Currently only works for unordered channels; ordered channels // don't use receipts. However, ibc-go does it this way. Investigate if // this query only ever makes sense on unordered channels. @@ -570,7 +561,7 @@ where &self, channel_end_path: &ChannelEndPath, sequences: impl ExactSizeIterator, - ) -> Result, ContextError> { + ) -> Result, HostError> { let collected_paths: Vec<_> = if sequences.len() == 0 { // if sequences is empty, return all the acks let commitment_path_prefix = format!( @@ -621,18 +612,16 @@ where /// Called upon client creation. /// Increases the counter, that keeps track of how many clients have been created. - fn increase_client_counter(&mut self) -> Result<(), ContextError> { + fn increase_client_counter(&mut self) -> Result<(), HostError> { let current_sequence = self .client_counter .get(StoreHeight::Pending, &NextClientSequencePath) - .ok_or(ClientError::Other { - description: "client counter not found".into(), - })?; + .ok_or(HostError::failed_to_retrieve("missing client counter"))?; self.client_counter .set(NextClientSequencePath, current_sequence + 1) - .map_err(|e| ClientError::Other { - description: format!("client counter update failed: {e:?}"), + .map_err(|e| { + HostError::failed_to_store(format!("failed to update client counter: {e:?}")) })?; Ok(()) @@ -643,10 +632,12 @@ where &mut self, connection_path: &ConnectionPath, connection_end: ConnectionEnd, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.connection_end_store .set(connection_path.clone(), connection_end) - .map_err(|_| ConnectionError::FailedToStoreConnectionEnd)?; + .map_err(|e| { + HostError::failed_to_store(format!("failed to set connection end: {e:?}")) + })?; Ok(()) } @@ -655,7 +646,7 @@ where &mut self, client_connection_path: &ClientConnectionPath, conn_id: ConnectionId, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { let mut conn_ids: Vec = self .connection_ids_store .get(StoreHeight::Pending, client_connection_path) @@ -663,21 +654,25 @@ where conn_ids.push(conn_id); self.connection_ids_store .set(client_connection_path.clone(), conn_ids) - .map_err(|_| ConnectionError::FailedToStoreConnectionIds)?; + .map_err(|e| { + HostError::failed_to_store(format!("failed to store connection IDs: {e:?}")) + })?; Ok(()) } /// Called upon connection identifier creation (Init or Try process). /// Increases the counter, that keeps track of how many connections have been created. - fn increase_connection_counter(&mut self) -> Result<(), ContextError> { + fn increase_connection_counter(&mut self) -> Result<(), HostError> { let current_sequence = self .conn_counter .get(StoreHeight::Pending, &NextConnectionSequencePath) - .ok_or(ConnectionError::MissingConnectionCounter)?; + .ok_or(HostError::failed_to_retrieve("missing connection counter"))?; self.conn_counter .set(NextConnectionSequencePath, current_sequence + 1) - .map_err(|_| ConnectionError::FailedToUpdateConnectionCounter)?; + .map_err(|e| { + HostError::failed_to_store(format!("failed to update connection counter: {e:?}")) + })?; Ok(()) } @@ -686,17 +681,19 @@ where &mut self, commitment_path: &CommitmentPath, commitment: PacketCommitment, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.packet_commitment_store .set(commitment_path.clone(), commitment) - .map_err(|_| PacketError::ImplementationSpecific)?; + .map_err(|e| { + HostError::failed_to_store(format!("failed to store packet commitment: {e:?}")) + })?; Ok(()) } fn delete_packet_commitment( &mut self, commitment_path: &CommitmentPath, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.packet_commitment_store.delete(commitment_path.clone()); Ok(()) } @@ -705,10 +702,12 @@ where &mut self, receipt_path: &ReceiptPath, _receipt: Receipt, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.packet_receipt_store .set_path(receipt_path.clone()) - .map_err(|_| PacketError::ImplementationSpecific)?; + .map_err(|e| { + HostError::failed_to_store(format!("failed to store packet receipt: {e:?}")) + })?; Ok(()) } @@ -716,14 +715,16 @@ where &mut self, ack_path: &AckPath, ack_commitment: AcknowledgementCommitment, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.packet_ack_store .set(ack_path.clone(), ack_commitment) - .map_err(|_| PacketError::ImplementationSpecific)?; + .map_err(|e| { + HostError::failed_to_store(format!("failed to store packet acknowledgment: {e:?}")) + })?; Ok(()) } - fn delete_packet_acknowledgement(&mut self, ack_path: &AckPath) -> Result<(), ContextError> { + fn delete_packet_acknowledgement(&mut self, ack_path: &AckPath) -> Result<(), HostError> { self.packet_ack_store.delete(ack_path.clone()); Ok(()) } @@ -732,12 +733,10 @@ where &mut self, channel_end_path: &ChannelEndPath, channel_end: ChannelEnd, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.channel_end_store .set(channel_end_path.clone(), channel_end) - .map_err(|e| ChannelError::FailedToStoreChannel { - description: format!("{e:?}"), - })?; + .map_err(|e| HostError::failed_to_store(format!("failed to store channel: {e:?}")))?; Ok(()) } @@ -745,10 +744,12 @@ where &mut self, seq_send_path: &SeqSendPath, seq: Sequence, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.send_sequence_store .set(seq_send_path.clone(), seq) - .map_err(|_| PacketError::ImplementationSpecific)?; + .map_err(|e| { + HostError::failed_to_store(format!("failed to store send sequence: {e:?}")) + })?; Ok(()) } @@ -756,10 +757,12 @@ where &mut self, seq_recv_path: &SeqRecvPath, seq: Sequence, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.recv_sequence_store .set(seq_recv_path.clone(), seq) - .map_err(|_| PacketError::ImplementationSpecific)?; + .map_err(|e| { + HostError::failed_to_store(format!("failed to store recv sequence: {e:?}")) + })?; Ok(()) } @@ -767,34 +770,33 @@ where &mut self, seq_ack_path: &SeqAckPath, seq: Sequence, - ) -> Result<(), ContextError> { + ) -> Result<(), HostError> { self.ack_sequence_store .set(seq_ack_path.clone(), seq) - .map_err(|_| PacketError::ImplementationSpecific)?; + .map_err(|e| { + HostError::failed_to_store(format!("failed to store ack sequence: {e:?}")) + })?; Ok(()) } - fn increase_channel_counter(&mut self) -> Result<(), ContextError> { + fn increase_channel_counter(&mut self) -> Result<(), HostError> { let current_sequence = self .channel_counter .get(StoreHeight::Pending, &NextChannelSequencePath) - .ok_or(ChannelError::MissingCounter)?; + .ok_or(HostError::failed_to_retrieve("missing counter"))?; self.channel_counter .set(NextChannelSequencePath, current_sequence + 1) - .map_err(|e| ChannelError::FailedToUpdateCounter { - description: format!("{e:?}"), - })?; - + .map_err(|e| HostError::failed_to_store(format!("failed to update counter: {e:?}")))?; Ok(()) } - fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), ContextError> { + fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), HostError> { self.events.lock().push(event); Ok(()) } - fn log_message(&mut self, message: String) -> Result<(), ContextError> { + fn log_message(&mut self, message: String) -> Result<(), HostError> { self.logs.lock().push(message); Ok(()) } diff --git a/tests-integration/tests/core/ics02_client/create_client.rs b/tests-integration/tests/core/ics02_client/create_client.rs index c78fef45c..baa9188c0 100644 --- a/tests-integration/tests/core/ics02_client/create_client.rs +++ b/tests-integration/tests/core/ics02_client/create_client.rs @@ -8,7 +8,7 @@ use ibc::core::client::types::msgs::{ClientMsg, MsgCreateClient}; use ibc::core::client::types::Height; use ibc::core::commitment_types::error::CommitmentError; use ibc::core::entrypoint::{execute, validate}; -use ibc::core::handler::types::error::ContextError; +use ibc::core::handler::types::error::HandlerError; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::ClientId; use ibc::core::host::types::path::{ClientConsensusStatePath, NextClientSequencePath}; @@ -180,9 +180,9 @@ fn test_create_expired_mock_client() { let fxt = create_client_fixture(Ctx::Default, Msg::ExpiredMockHeader); create_client_validate( &fxt, - Expect::Failure(Some(ContextError::ClientError( - ClientError::UnexpectedStatus(Status::Expired), - ))), + Expect::Failure(Some(HandlerError::Client(ClientError::UnexpectedStatus( + Status::Expired, + )))), ); } @@ -206,9 +206,9 @@ fn test_create_expired_tm_client() { let fxt = create_client_fixture(Ctx::Default, Msg::ExpiredTendermintHeader); create_client_validate( &fxt, - Expect::Failure(Some(ContextError::ClientError( - ClientError::UnexpectedStatus(Status::Expired), - ))), + Expect::Failure(Some(HandlerError::Client(ClientError::UnexpectedStatus( + Status::Expired, + )))), ); } @@ -218,9 +218,9 @@ fn test_create_frozen_tm_client() { let fxt = create_client_fixture(Ctx::Default, Msg::FrozenTendermintHeader); create_client_validate( &fxt, - Expect::Failure(Some(ContextError::ClientError( - ClientError::UnexpectedStatus(Status::Frozen), - ))), + Expect::Failure(Some(HandlerError::Client(ClientError::UnexpectedStatus( + Status::Frozen, + )))), ); } diff --git a/tests-integration/tests/core/ics02_client/upgrade_client.rs b/tests-integration/tests/core/ics02_client/upgrade_client.rs index 153d69e42..fb2e0f22b 100644 --- a/tests-integration/tests/core/ics02_client/upgrade_client.rs +++ b/tests-integration/tests/core/ics02_client/upgrade_client.rs @@ -4,10 +4,11 @@ use ibc::core::client::types::error::{ClientError, UpgradeClientError}; use ibc::core::client::types::msgs::{ClientMsg, MsgUpgradeClient}; use ibc::core::client::types::Height; use ibc::core::entrypoint::{execute, validate}; -use ibc::core::handler::types::error::ContextError; +use ibc::core::handler::types::error::HandlerError; use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::path::ClientConsensusStatePath; +use ibc_core_host_types::error::HostError; use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::clients::tendermint::{ dummy_tm_client_state_from_header, dummy_valid_tendermint_header, @@ -142,8 +143,10 @@ fn msg_upgrade_client_healthy() { #[test] fn upgrade_client_fail_nonexisting_client() { let fxt = msg_upgrade_client_fixture(Ctx::Default, Msg::Default); - let expected_err = - ContextError::ClientError(ClientError::MissingClientState(fxt.msg.client_id.clone())); + let expected_err = HandlerError::Host(HostError::missing_state(format!( + "missing client state for client {0}", + fxt.msg.client_id.clone() + ))); upgrade_client_validate(&fxt, Expect::Failure(Some(expected_err))); } @@ -158,14 +161,14 @@ fn upgrade_client_fail_low_upgrade_height() { .into(); upgrade_client_validate( &fxt, - Expect::Failure(Some(ContextError::from(expected_err))), + Expect::Failure(Some(HandlerError::from(expected_err))), ); } #[test] fn upgrade_client_fail_unknown_upgraded_client_state() { let fxt = msg_upgrade_client_fixture(Ctx::WithClient, Msg::UnknownUpgradedClientStateType); - let expected_err = ContextError::ClientError(ClientError::InvalidClientStateType( + let expected_err = HandlerError::Client(ClientError::InvalidClientStateType( client_type().to_string(), )); upgrade_client_validate(&fxt, Expect::Failure(Some(expected_err))); diff --git a/tests-integration/tests/core/ics03_connection/conn_open_ack.rs b/tests-integration/tests/core/ics03_connection/conn_open_ack.rs index 5d292b3f7..bf5064ad5 100644 --- a/tests-integration/tests/core/ics03_connection/conn_open_ack.rs +++ b/tests-integration/tests/core/ics03_connection/conn_open_ack.rs @@ -6,13 +6,14 @@ use ibc::core::connection::types::error::ConnectionError; use ibc::core::connection::types::msgs::{ConnectionMsg, MsgConnectionOpenAck}; use ibc::core::connection::types::{ConnectionEnd, Counterparty, State}; use ibc::core::entrypoint::{execute, validate}; -use ibc::core::handler::types::error::ContextError; +use ibc::core::handler::types::error::HandlerError; use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::{ChainId, ClientId}; use ibc::core::host::ValidationContext; use ibc::core::primitives::prelude::*; use ibc::core::primitives::ZERO_DURATION; +use ibc_core_host_types::error::HostError; use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::connection::dummy_msg_conn_open_ack; use ibc_testkit::fixtures::core::context::TestContextConfig; @@ -126,16 +127,16 @@ fn conn_open_ack_validate(fxt: &Fixture, expect: Expect) { let cons_state_height = fxt.msg.consensus_height_of_a_on_b; match res.unwrap_err() { - ContextError::ConnectionError(ConnectionError::MissingConnection(connection_id)) => { - assert_eq!(connection_id, right_connection_id) + HandlerError::Host(HostError::MissingState { ref description }) => { + assert!(description.contains(right_connection_id.to_string().as_str())) } - ContextError::ConnectionError(ConnectionError::InsufficientConsensusHeight { + HandlerError::Connection(ConnectionError::InsufficientConsensusHeight { target_height, current_height: _, }) => { assert_eq!(cons_state_height, target_height); } - ContextError::ConnectionError(ConnectionError::MismatchedConnectionStates { + HandlerError::Connection(ConnectionError::MismatchedConnectionStates { expected: _, actual: _, }) => {} @@ -187,27 +188,27 @@ fn conn_open_ack_healthy() { #[test] fn conn_open_ack_no_connection() { let fxt = conn_open_ack_fixture(Ctx::New); - let expected_err = ContextError::ConnectionError(ConnectionError::MissingConnection( - fxt.msg.conn_id_on_a.clone(), - )); + let expected_err = HandlerError::Host(HostError::missing_state(format!( + "missing connection end for connection {}", + fxt.msg.conn_id_on_a.clone() + ))); conn_open_ack_validate(&fxt, Expect::Failure(Some(expected_err))); } #[test] fn conn_open_ack_invalid_consensus_height() { let fxt = conn_open_ack_fixture(Ctx::DefaultWithConnection); - let expected_err = - ContextError::ConnectionError(ConnectionError::InsufficientConsensusHeight { - target_height: fxt.msg.consensus_height_of_a_on_b, - current_height: Height::new(0, 10).unwrap(), - }); + let expected_err = HandlerError::Connection(ConnectionError::InsufficientConsensusHeight { + target_height: fxt.msg.consensus_height_of_a_on_b, + current_height: Height::new(0, 10).unwrap(), + }); conn_open_ack_validate(&fxt, Expect::Failure(Some(expected_err))); } #[test] fn conn_open_ack_connection_mismatch() { let fxt = conn_open_ack_fixture(Ctx::NewWithConnectionEndOpen); - let expected_err = ContextError::ConnectionError(ConnectionError::MismatchedConnectionStates { + let expected_err = HandlerError::Connection(ConnectionError::MismatchedConnectionStates { expected: State::Init.to_string(), actual: State::Open.to_string(), }); diff --git a/tests-integration/tests/core/router.rs b/tests-integration/tests/core/router.rs index 303f5f469..825352428 100644 --- a/tests-integration/tests/core/router.rs +++ b/tests-integration/tests/core/router.rs @@ -4,7 +4,6 @@ use ibc::apps::transfer::handler::send_transfer; use ibc::apps::transfer::types::error::TokenTransferError; use ibc::apps::transfer::types::msgs::transfer::MsgTransfer; use ibc::apps::transfer::types::{BaseCoin, U256}; -use ibc::core::channel::types::error::ChannelError; use ibc::core::channel::types::msgs::{ ChannelMsg, MsgAcknowledgement, MsgChannelCloseConfirm, MsgChannelCloseInit, MsgChannelOpenAck, MsgChannelOpenInit, MsgChannelOpenTry, MsgRecvPacket, MsgTimeoutOnClose, PacketMsg, @@ -14,7 +13,7 @@ use ibc::core::client::types::msgs::{ClientMsg, MsgCreateClient, MsgUpdateClient use ibc::core::client::types::Height; use ibc::core::connection::types::msgs::ConnectionMsg; use ibc::core::entrypoint::dispatch; -use ibc::core::handler::types::error::ContextError; +use ibc::core::handler::types::error::HandlerError; use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::ConnectionId; @@ -22,6 +21,7 @@ use ibc::core::host::types::path::CommitmentPath; use ibc::core::host::ValidationContext; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Timestamp; +use ibc_core_host_types::error::HostError; use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::applications::transfer::{ extract_transfer_packet, MsgTransferConfig, PacketDataConfig, @@ -407,10 +407,10 @@ fn routing_module_and_keepers() { let res = match test.msg.clone() { TestMsg::Ics26(msg) => dispatch(&mut ctx.ibc_store, &mut router, msg), TestMsg::Ics20(msg) => send_transfer(&mut ctx.ibc_store, &mut DummyTransferModule, msg) - .map_err(|e: TokenTransferError| ChannelError::AppModule { - description: e.to_string(), + .map_err(|e: TokenTransferError| HostError::Other { + description: format!("token transfer application error: {e}"), }) - .map_err(ContextError::from), + .map_err(HandlerError::from), }; assert_eq!( From a4e409a92796a62b8576e7b107a4f36ec5c2e35a Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Tue, 17 Sep 2024 12:20:18 -0500 Subject: [PATCH 07/18] Consolidate `PacketError` and `ChannelError` (#1343) * Merge PacketError variants into ChannelError * cargo nightly fmt * Consolidate ChanelError verification variants * Convert ics04 try_from impls to use DecodingError * Add changelog entry * Incorporate some PR feedback * Remove ChannelError::MissingProof and MissingProofHeight error variants --- ...9-merge-packet-error-into-channel-error.md | 2 + .../src/handler/acknowledgement.rs | 11 +- .../src/handler/chan_close_confirm.rs | 2 +- .../src/handler/chan_open_ack.rs | 2 +- .../src/handler/chan_open_confirm.rs | 2 +- .../src/handler/chan_open_try.rs | 2 +- .../ics04-channel/src/handler/recv_packet.rs | 14 +-- .../ics04-channel/src/handler/send_packet.rs | 10 +- ibc-core/ics04-channel/src/handler/timeout.rs | 20 ++- .../src/handler/timeout_on_close.rs | 20 ++- .../types/src/acknowledgement.rs | 10 +- ibc-core/ics04-channel/types/src/channel.rs | 56 +++++---- ibc-core/ics04-channel/types/src/error.rs | 116 +++++------------- .../types/src/msgs/acknowledgement.rs | 3 +- .../types/src/msgs/chan_close_confirm.rs | 20 +-- .../types/src/msgs/chan_open_confirm.rs | 14 +-- .../types/src/msgs/chan_open_try.rs | 28 ++--- .../types/src/msgs/recv_packet.rs | 3 +- .../ics04-channel/types/src/msgs/timeout.rs | 19 ++- .../types/src/msgs/timeout_on_close.rs | 29 ++--- ibc-core/ics04-channel/types/src/packet.rs | 25 ++-- .../types/src/timeout/timestamp.rs | 10 +- ibc-core/ics25-handler/types/src/error.rs | 5 +- ibc-core/ics26-routing/src/module.rs | 10 +- ibc-query/src/error.rs | 8 +- .../fixtures/core/channel/acknowledgement.rs | 4 +- .../src/fixtures/core/channel/recv_packet.rs | 4 +- .../src/fixtures/core/channel/timeout.rs | 4 +- .../ibc/applications/nft_transfer/module.rs | 10 +- .../ibc/applications/transfer/module.rs | 10 +- ibc-testkit/src/testapp/ibc/core/types.rs | 18 +-- 31 files changed, 209 insertions(+), 282 deletions(-) create mode 100644 .changelog/unreleased/breaking-changes/1339-merge-packet-error-into-channel-error.md diff --git a/.changelog/unreleased/breaking-changes/1339-merge-packet-error-into-channel-error.md b/.changelog/unreleased/breaking-changes/1339-merge-packet-error-into-channel-error.md new file mode 100644 index 000000000..ad33f298c --- /dev/null +++ b/.changelog/unreleased/breaking-changes/1339-merge-packet-error-into-channel-error.md @@ -0,0 +1,2 @@ +- [ibc-core-channel] Merge `PacketError` type into `ChannelError` + ([#1339](https://github.com/cosmos/ibc-rs/pull/1343)) diff --git a/ibc-core/ics04-channel/src/handler/acknowledgement.rs b/ibc-core/ics04-channel/src/handler/acknowledgement.rs index 4c7b1c30e..c0d216ae0 100644 --- a/ibc-core/ics04-channel/src/handler/acknowledgement.rs +++ b/ibc-core/ics04-channel/src/handler/acknowledgement.rs @@ -1,6 +1,6 @@ use ibc_core_channel_types::channel::{Counterparty, Order, State as ChannelState}; use ibc_core_channel_types::commitment::{compute_ack_commitment, compute_packet_commitment}; -use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::events::AcknowledgePacket; use ibc_core_channel_types::msgs::MsgAcknowledgement; use ibc_core_client::context::prelude::*; @@ -27,7 +27,7 @@ where module .on_acknowledgement_packet_validate(&msg.packet, &msg.acknowledgement, &msg.signer) - .map_err(HandlerError::Packet) + .map_err(HandlerError::Channel) } pub fn acknowledgement_packet_execute( @@ -146,8 +146,7 @@ where ); if commitment_on_a != expected_commitment_on_a { - return Err(PacketError::MismatchedPacketCommitments { - sequence: packet.seq_on_a, + return Err(ChannelError::MismatchedPacketCommitments { actual: commitment_on_a, expected: expected_commitment_on_a, } @@ -158,7 +157,7 @@ where let seq_ack_path_on_a = SeqAckPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); let next_seq_ack = ctx_a.get_next_sequence_ack(&seq_ack_path_on_a)?; if packet.seq_on_a != next_seq_ack { - return Err(PacketError::MismatchedPacketSequences { + return Err(ChannelError::MismatchedPacketSequences { actual: packet.seq_on_a, expected: next_seq_ack, } @@ -202,7 +201,7 @@ where Path::Ack(ack_path_on_b), ack_commitment.into_vec(), ) - .map_err(ChannelError::FailedProofVerification)?; + .map_err(ChannelError::FailedVerification)?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs index e9cc78d5c..687a15539 100644 --- a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs @@ -156,7 +156,7 @@ where Path::ChannelEnd(chan_end_path_on_a), expected_chan_end_on_a.encode_vec(), ) - .map_err(ChannelError::FailedProofVerification)?; + .map_err(ChannelError::FailedVerification)?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs index 64aff01d6..ebd972497 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs @@ -153,7 +153,7 @@ where Path::ChannelEnd(chan_end_path_on_b), expected_chan_end_on_b.encode_vec(), ) - .map_err(ChannelError::FailedProofVerification)?; + .map_err(ChannelError::FailedVerification)?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs index e3ade9e35..2038b5a0d 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs @@ -156,7 +156,7 @@ where Path::ChannelEnd(chan_end_path_on_a), expected_chan_end_on_a.encode_vec(), ) - .map_err(ChannelError::FailedProofVerification)?; + .map_err(ChannelError::FailedVerification)?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_open_try.rs b/ibc-core/ics04-channel/src/handler/chan_open_try.rs index 09ca21604..3f7f944f7 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_try.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_try.rs @@ -178,7 +178,7 @@ where Path::ChannelEnd(chan_end_path_on_a), expected_chan_end_on_a.encode_vec(), ) - .map_err(ChannelError::FailedProofVerification)?; + .map_err(ChannelError::FailedVerification)?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/recv_packet.rs b/ibc-core/ics04-channel/src/handler/recv_packet.rs index faa0ffe02..f4906d6eb 100644 --- a/ibc-core/ics04-channel/src/handler/recv_packet.rs +++ b/ibc-core/ics04-channel/src/handler/recv_packet.rs @@ -1,6 +1,6 @@ use ibc_core_channel_types::channel::{Counterparty, Order, State as ChannelState}; use ibc_core_channel_types::commitment::{compute_ack_commitment, compute_packet_commitment}; -use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::events::{ReceivePacket, WriteAcknowledgement}; use ibc_core_channel_types::msgs::MsgRecvPacket; use ibc_core_channel_types::packet::Receipt; @@ -162,7 +162,7 @@ where let latest_height = ctx_b.host_height()?; if msg.packet.timeout_height_on_b.has_expired(latest_height) { - return Err(PacketError::InsufficientPacketHeight { + return Err(ChannelError::InsufficientPacketHeight { chain_height: latest_height, timeout_height: msg.packet.timeout_height_on_b, } @@ -175,7 +175,7 @@ where .timeout_timestamp_on_b .has_expired(&latest_timestamp) { - return Err(PacketError::InsufficientPacketTimestamp.into()); + return Err(ChannelError::InsufficientPacketTimestamp.into()); } // Verify proofs @@ -221,7 +221,7 @@ where Path::Commitment(commitment_path_on_a), expected_commitment_on_a.into_vec(), ) - .map_err(ChannelError::FailedProofVerification)?; + .map_err(ChannelError::FailedVerification)?; } match chan_end_on_b.ordering { @@ -230,7 +230,7 @@ where SeqRecvPath::new(&msg.packet.port_id_on_b, &msg.packet.chan_id_on_b); let next_seq_recv = ctx_b.get_next_sequence_recv(&seq_recv_path_on_b)?; if msg.packet.seq_on_a > next_seq_recv { - return Err(PacketError::MismatchedPacketSequences { + return Err(ChannelError::MismatchedPacketSequences { actual: msg.packet.seq_on_a, expected: next_seq_recv, } @@ -254,7 +254,7 @@ where validate_write_acknowledgement(ctx_b, msg)?; } Order::None => { - return Err(HandlerError::Channel(ChannelError::InvalidOrderType { + return Err(HandlerError::Channel(ChannelError::InvalidState { expected: "Channel ordering to not be None".to_string(), actual: chan_end_on_b.ordering.to_string(), })) @@ -271,7 +271,7 @@ where let packet = msg.packet.clone(); let ack_path_on_b = AckPath::new(&packet.port_id_on_b, &packet.chan_id_on_b, packet.seq_on_a); if ctx_b.get_packet_acknowledgement(&ack_path_on_b).is_ok() { - return Err(PacketError::DuplicateAcknowledgment(msg.packet.seq_on_a).into()); + return Err(ChannelError::DuplicateAcknowledgment(msg.packet.seq_on_a).into()); } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/send_packet.rs b/ibc-core/ics04-channel/src/handler/send_packet.rs index c15b03d21..cd567ffdf 100644 --- a/ibc-core/ics04-channel/src/handler/send_packet.rs +++ b/ibc-core/ics04-channel/src/handler/send_packet.rs @@ -1,6 +1,6 @@ use ibc_core_channel_types::channel::Counterparty; use ibc_core_channel_types::commitment::compute_packet_commitment; -use ibc_core_channel_types::error::PacketError; +use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::events::SendPacket; use ibc_core_channel_types::packet::Packet; use ibc_core_client::context::prelude::*; @@ -30,7 +30,7 @@ pub fn send_packet_validate( packet: &Packet, ) -> Result<(), HandlerError> { if !packet.timeout_height_on_b.is_set() && !packet.timeout_timestamp_on_b.is_set() { - return Err(HandlerError::Packet(PacketError::MissingTimeout)); + return Err(HandlerError::Channel(ChannelError::MissingTimeout)); } let chan_end_path_on_a = ChannelEndPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); @@ -64,7 +64,7 @@ pub fn send_packet_validate( let latest_height_on_a = client_state_of_b_on_a.latest_height(); if packet.timeout_height_on_b.has_expired(latest_height_on_a) { - return Err(PacketError::InsufficientPacketHeight { + return Err(ChannelError::InsufficientPacketHeight { chain_height: latest_height_on_a, timeout_height: packet.timeout_height_on_b, } @@ -81,14 +81,14 @@ pub fn send_packet_validate( let latest_timestamp = consensus_state_of_b_on_a.timestamp(); let packet_timestamp = packet.timeout_timestamp_on_b; if packet_timestamp.has_expired(&latest_timestamp) { - return Err(PacketError::InsufficientPacketTimestamp.into()); + return Err(ChannelError::InsufficientPacketTimestamp.into()); } let seq_send_path_on_a = SeqSendPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); let next_seq_send_on_a = ctx_a.get_next_sequence_send(&seq_send_path_on_a)?; if packet.seq_on_a != next_seq_send_on_a { - return Err(PacketError::MismatchedPacketSequences { + return Err(ChannelError::MismatchedPacketSequences { actual: packet.seq_on_a, expected: next_seq_send_on_a, } diff --git a/ibc-core/ics04-channel/src/handler/timeout.rs b/ibc-core/ics04-channel/src/handler/timeout.rs index 9e587256d..7e2d4d113 100644 --- a/ibc-core/ics04-channel/src/handler/timeout.rs +++ b/ibc-core/ics04-channel/src/handler/timeout.rs @@ -1,6 +1,6 @@ use ibc_core_channel_types::channel::{Counterparty, Order, State}; use ibc_core_channel_types::commitment::compute_packet_commitment; -use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::events::{ChannelClosed, TimeoutPacket}; use ibc_core_channel_types::msgs::{MsgTimeout, MsgTimeoutOnClose}; use ibc_core_client::context::prelude::*; @@ -41,7 +41,7 @@ where module .on_timeout_packet_validate(&packet, &signer) - .map_err(HandlerError::Packet) + .map_err(HandlerError::Channel) } pub fn timeout_packet_execute( @@ -170,8 +170,7 @@ where ); if commitment_on_a != expected_commitment_on_a { - return Err(PacketError::MismatchedPacketCommitments { - sequence: msg.packet.seq_on_a, + return Err(ChannelError::MismatchedPacketCommitments { expected: expected_commitment_on_a, actual: commitment_on_a, } @@ -201,7 +200,7 @@ where let timestamp_of_b = consensus_state_of_b_on_a.timestamp(); if !msg.packet.timed_out(×tamp_of_b, msg.proof_height_on_b) { - return Err(PacketError::PacketTimeoutNotReached { + return Err(ChannelError::PacketTimeoutNotReached { timeout_height: msg.packet.timeout_height_on_b, chain_height: msg.proof_height_on_b, timeout_timestamp: msg.packet.timeout_timestamp_on_b, @@ -215,7 +214,7 @@ where let next_seq_recv_verification_result = match chan_end_on_a.ordering { Order::Ordered => { if msg.packet.seq_on_a < msg.next_seq_recv_on_b { - return Err(PacketError::MismatchedPacketSequences { + return Err(ChannelError::MismatchedPacketSequences { actual: msg.packet.seq_on_a, expected: msg.next_seq_recv_on_b, } @@ -247,17 +246,14 @@ where ) } Order::None => { - return Err(HandlerError::Channel(ChannelError::InvalidOrderType { - expected: "Channel ordering cannot be None".to_string(), + return Err(HandlerError::Channel(ChannelError::InvalidState { + expected: "Channel ordering to not be None".to_string(), actual: chan_end_on_a.ordering.to_string(), })) } }; - next_seq_recv_verification_result.map_err(|e| ChannelError::FailedPacketVerification { - sequence: msg.next_seq_recv_on_b, - client_error: e, - })?; + next_seq_recv_verification_result.map_err(ChannelError::FailedVerification)?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/timeout_on_close.rs b/ibc-core/ics04-channel/src/handler/timeout_on_close.rs index e6bd30724..079048c60 100644 --- a/ibc-core/ics04-channel/src/handler/timeout_on_close.rs +++ b/ibc-core/ics04-channel/src/handler/timeout_on_close.rs @@ -1,6 +1,6 @@ use ibc_core_channel_types::channel::{ChannelEnd, Counterparty, Order, State}; use ibc_core_channel_types::commitment::compute_packet_commitment; -use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::msgs::MsgTimeoutOnClose; use ibc_core_client::context::prelude::*; use ibc_core_connection::delay::verify_conn_delay_passed; @@ -51,8 +51,7 @@ where &packet.timeout_timestamp_on_b, ); if commitment_on_a != expected_commitment_on_a { - return Err(PacketError::MismatchedPacketCommitments { - sequence: packet.seq_on_a, + return Err(ChannelError::MismatchedPacketCommitments { expected: expected_commitment_on_a, actual: commitment_on_a, } @@ -86,7 +85,7 @@ where let chan_id_on_b = chan_end_on_a .counterparty() .channel_id() - .ok_or(PacketError::Channel(ChannelError::MissingCounterparty))?; + .ok_or(ChannelError::MissingCounterparty)?; let conn_id_on_b = conn_end_on_a .counterparty() .connection_id() @@ -116,14 +115,14 @@ where Path::ChannelEnd(chan_end_path_on_b), expected_chan_end_on_b.encode_vec(), ) - .map_err(ChannelError::FailedProofVerification)?; + .map_err(ChannelError::FailedVerification)?; verify_conn_delay_passed(ctx_a, msg.proof_height_on_b, &conn_end_on_a)?; let next_seq_recv_verification_result = match chan_end_on_a.ordering { Order::Ordered => { if packet.seq_on_a < msg.next_seq_recv_on_b { - return Err(PacketError::MismatchedPacketSequences { + return Err(ChannelError::MismatchedPacketSequences { actual: packet.seq_on_a, expected: msg.next_seq_recv_on_b, } @@ -155,17 +154,14 @@ where ) } Order::None => { - return Err(HandlerError::Channel(ChannelError::InvalidOrderType { - expected: "Channel ordering cannot be None".to_string(), + return Err(HandlerError::Channel(ChannelError::InvalidState { + expected: "Channel ordering to not be None".to_string(), actual: chan_end_on_a.ordering.to_string(), })) } }; - next_seq_recv_verification_result.map_err(|e| ChannelError::FailedPacketVerification { - sequence: msg.next_seq_recv_on_b, - client_error: e, - })?; + next_seq_recv_verification_result.map_err(ChannelError::FailedVerification)?; }; Ok(()) diff --git a/ibc-core/ics04-channel/types/src/acknowledgement.rs b/ibc-core/ics04-channel/types/src/acknowledgement.rs index c061f2be5..82ce5dcde 100644 --- a/ibc-core/ics04-channel/types/src/acknowledgement.rs +++ b/ibc-core/ics04-channel/types/src/acknowledgement.rs @@ -6,7 +6,7 @@ use derive_more::Into; use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; -use super::error::PacketError; +use crate::error::ChannelError; /// A generic Acknowledgement type that modules may interpret as they like. /// @@ -42,13 +42,13 @@ impl AsRef<[u8]> for Acknowledgement { } impl TryFrom> for Acknowledgement { - type Error = PacketError; + type Error = DecodingError; fn try_from(bytes: Vec) -> Result { if bytes.is_empty() { Err(DecodingError::MissingRawData { description: "acknowledgment not set".to_string(), - })? + }) } else { Ok(Self(bytes)) } @@ -80,11 +80,11 @@ pub struct StatusValue(String); impl StatusValue { /// Constructs a new instance of `StatusValue` if the given value is not empty. - pub fn new(value: impl ToString) -> Result { + pub fn new(value: impl ToString) -> Result { let value = value.to_string(); if value.is_empty() { - return Err(PacketError::EmptyAcknowledgmentStatus); + return Err(ChannelError::MissingAcknowledgmentStatus); } Ok(Self(value)) diff --git a/ibc-core/ics04-channel/types/src/channel.rs b/ibc-core/ics04-channel/types/src/channel.rs index 846696561..677233b26 100644 --- a/ibc-core/ics04-channel/types/src/channel.rs +++ b/ibc-core/ics04-channel/types/src/channel.rs @@ -3,6 +3,7 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc_primitives::prelude::*; use ibc_primitives::utils::PrettySlice; @@ -50,11 +51,13 @@ impl IdentifiedChannelEnd { impl Protobuf for IdentifiedChannelEnd {} impl TryFrom for IdentifiedChannelEnd { - type Error = ChannelError; + type Error = DecodingError; fn try_from(value: RawIdentifiedChannel) -> Result { if value.upgrade_sequence != 0 { - return Err(ChannelError::UnsupportedChannelUpgradeSequence); + return Err(DecodingError::invalid_raw_data( + "channel upgrade sequence expected to be 0", + )); } let raw_channel_end = RawChannel { @@ -131,18 +134,23 @@ impl Display for ChannelEnd { impl Protobuf for ChannelEnd {} impl TryFrom for ChannelEnd { - type Error = ChannelError; + type Error = DecodingError; fn try_from(value: RawChannel) -> Result { - let chan_state: State = State::from_i32(value.state)?; - - let chan_ordering = Order::from_i32(value.ordering)?; + let chan_state: State = State::from_i32(value.state) + .map_err(|e| DecodingError::invalid_raw_data(format!("invalid channel state: {e}")))?; + let chan_ordering = Order::from_i32(value.ordering).map_err(|e| { + DecodingError::invalid_raw_data(format!("invalid channel ordering: {e}")) + })?; // Assemble the 'remote' attribute of the Channel, which represents the Counterparty. let remote = value .counterparty - .ok_or(ChannelError::MissingCounterparty)? - .try_into()?; + .ok_or(DecodingError::missing_raw_data("missing counterparty"))? + .try_into() + .map_err(|e| { + DecodingError::invalid_raw_data(format!("failed to convert raw counterparty: {e}")) + })?; // Parse each item in connection_hops into a ConnectionId. let connection_hops = value @@ -153,7 +161,12 @@ impl TryFrom for ChannelEnd { let version = value.version.into(); - ChannelEnd::new(chan_state, chan_ordering, remote, connection_hops, version) + let channel = ChannelEnd::new(chan_state, chan_ordering, remote, connection_hops, version) + .map_err(|e| { + DecodingError::invalid_raw_data(format!("failed to create new channel: {e}")) + })?; + + Ok(channel) } } @@ -251,14 +264,14 @@ impl ChannelEnd { pub fn validate_basic(&self) -> Result<(), ChannelError> { if self.state == State::Uninitialized { return Err(ChannelError::InvalidState { - expected: "Channel state cannot be Uninitialized".to_string(), + expected: "Channel state to not be Uninitialized".to_string(), actual: self.state.to_string(), }); } if self.ordering == Order::None { - return Err(ChannelError::InvalidOrderType { - expected: "Channel ordering cannot be None".to_string(), + return Err(ChannelError::InvalidState { + expected: "Channel ordering to not be None".to_string(), actual: self.ordering.to_string(), }); } @@ -281,7 +294,7 @@ impl ChannelEnd { pub fn verify_not_closed(&self) -> Result<(), ChannelError> { if self.state.eq(&State::Closed) { return Err(ChannelError::InvalidState { - expected: "Channel state cannot be Closed".to_string(), + expected: "Channel state to not be Closed".to_string(), actual: self.state.to_string(), }); } @@ -304,7 +317,7 @@ impl ChannelEnd { /// Checks if the counterparty of this channel end matches with an expected counterparty. pub fn verify_counterparty_matches(&self, expected: &Counterparty) -> Result<(), ChannelError> { if !self.counterparty().eq(expected) { - return Err(ChannelError::InvalidCounterparty { + return Err(ChannelError::MismatchedCounterparty { expected: expected.clone(), actual: self.counterparty().clone(), }); @@ -378,10 +391,7 @@ impl Counterparty { /// that the counterparty channel id has not been set. pub(crate) fn verify_empty_channel_id(&self) -> Result<(), ChannelError> { if self.channel_id().is_some() { - return Err(ChannelError::InvalidChannelId { - expected: "Counterparty channel id must be empty".to_string(), - actual: format!("{:?}", self.channel_id), - }); + return Err(ChannelError::UnexpectedChannelId); } Ok(()) } @@ -480,8 +490,8 @@ impl Order { 0 => Ok(Self::None), 1 => Ok(Self::Unordered), 2 => Ok(Self::Ordered), - _ => Err(ChannelError::InvalidOrderType { - expected: "Must be one of 0, 1, 2".to_string(), + _ => Err(ChannelError::InvalidState { + expected: "to be one of 0, 1, 2".to_string(), actual: nr.to_string(), }), } @@ -496,8 +506,8 @@ impl FromStr for Order { "uninitialized" => Ok(Self::None), "unordered" => Ok(Self::Unordered), "ordered" => Ok(Self::Ordered), - _ => Err(ChannelError::InvalidOrderType { - expected: "Must be one of 'uninitialized', 'unordered', 'ordered'".to_string(), + _ => Err(ChannelError::InvalidState { + expected: "to be one of 'uninitialized', 'unordered', 'ordered'".to_string(), actual: s.to_string(), }), } @@ -550,7 +560,7 @@ impl State { 3 => Ok(Self::Open), 4 => Ok(Self::Closed), _ => Err(ChannelError::InvalidState { - expected: "Must be one of: 0, 1, 2, 3, 4".to_string(), + expected: "to be one of: 0, 1, 2, 3, 4".to_string(), actual: s.to_string(), }), } diff --git a/ibc-core/ics04-channel/types/src/error.rs b/ibc-core/ics04-channel/types/src/error.rs index 722c5bf26..ca8a28a4a 100644 --- a/ibc-core/ics04-channel/types/src/error.rs +++ b/ibc-core/ics04-channel/types/src/error.rs @@ -4,7 +4,7 @@ use displaydoc::Display; use ibc_core_client_types::error::ClientError; use ibc_core_client_types::Height; use ibc_core_host_types::error::{DecodingError, IdentifierError}; -use ibc_core_host_types::identifiers::{ChannelId, PortId, Sequence}; +use ibc_core_host_types::identifiers::Sequence; use ibc_primitives::prelude::*; use ibc_primitives::{Timestamp, TimestampError}; @@ -14,53 +14,15 @@ use crate::commitment::PacketCommitment; use crate::timeout::TimeoutTimestamp; use crate::Version; +/// Errors that arise from the ICS04 Channel module #[derive(Debug, Display)] pub enum ChannelError { /// decoding error: `{0}` Decoding(DecodingError), - /// invalid channel id: expected `{expected}`, actual `{actual}` - InvalidChannelId { expected: String, actual: String }, - /// invalid channel state: expected `{expected}`, actual `{actual}` - InvalidState { expected: String, actual: String }, - /// invalid channel order type: expected `{expected}`, actual `{actual}` - InvalidOrderType { expected: String, actual: String }, - /// invalid connection hops length: expected `{expected}`, actual `{actual}` - InvalidConnectionHopsLength { expected: u64, actual: u64 }, - /// invalid counterparty: expected `{expected}`, actual `{actual}` - InvalidCounterparty { - expected: Counterparty, - actual: Counterparty, - }, - /// missing proof - MissingProof, - /// missing proof height - MissingProofHeight, - /// missing counterparty - MissingCounterparty, - /// unsupported channel upgrade sequence - UnsupportedChannelUpgradeSequence, - /// unsupported version: expected `{expected}`, actual `{actual}` - UnsupportedVersion { expected: Version, actual: Version }, - /// non-existent channel end: (`{port_id}`, `{channel_id}`) - NonexistentChannel { - port_id: PortId, - channel_id: ChannelId, - }, - /// failed packet verification for packet with sequence `{sequence}`: `{client_error}` - FailedPacketVerification { - sequence: Sequence, - client_error: ClientError, - }, - /// failed proof verification: `{0}` - FailedProofVerification(ClientError), -} - -#[derive(Debug, Display)] -pub enum PacketError { - /// channel error: `{0}` - Channel(ChannelError), - /// decoding error: `{0}` - Decoding(DecodingError), + /// packet acknowledgment for sequence `{0}` already exists + DuplicateAcknowledgment(Sequence), + /// failed verification: `{0}` + FailedVerification(ClientError), /// insufficient packet timeout height: should have `{timeout_height}` > `{chain_height}` InsufficientPacketHeight { chain_height: Height, @@ -68,29 +30,33 @@ pub enum PacketError { }, /// insufficient packet timestamp: should be greater than chain block timestamp InsufficientPacketTimestamp, + /// invalid channel state: expected `{expected}`, actual `{actual}` + InvalidState { expected: String, actual: String }, + /// invalid connection hops length: expected `{expected}`, actual `{actual}` + InvalidConnectionHopsLength { expected: u64, actual: u64 }, + /// invalid timeout timestamp: `{0}` + InvalidTimeoutTimestamp(TimestampError), + /// missing acknowledgment status + MissingAcknowledgmentStatus, + /// missing counterparty + MissingCounterparty, + /// missing timeout + MissingTimeout, + /// mismatched counterparty: expected `{expected}`, actual `{actual}` + MismatchedCounterparty { + expected: Counterparty, + actual: Counterparty, + }, /// mismatched packet sequences: expected `{expected}`, actual `{actual}` MismatchedPacketSequences { expected: Sequence, actual: Sequence, }, - /// mismatched commitments for packet `{sequence}`: expected `{expected:?}`, actual `{actual:?}` + /// mismatched packet commitments: expected `{expected:?}`, actual `{actual:?}` MismatchedPacketCommitments { - sequence: Sequence, expected: PacketCommitment, actual: PacketCommitment, }, - /// missing timeout - MissingTimeout, - /// invalid timeout height: `{0}` - InvalidTimeoutHeight(ClientError), - /// invalid timeout timestamp: `{0}` - InvalidTimeoutTimestamp(TimestampError), - /// empty acknowledgment status not allowed - EmptyAcknowledgmentStatus, - /// packet acknowledgment for sequence `{0}` already exists - DuplicateAcknowledgment(Sequence), - /// packet sequence cannot be 0 - ZeroPacketSequence, /// packet timeout height `{timeout_height}` > chain height `{chain_height} and timeout timestamp `{timeout_timestamp}` > chain timestamp `{chain_timestamp}` PacketTimeoutNotReached { timeout_height: TimeoutHeight, @@ -98,6 +64,10 @@ pub enum PacketError { timeout_timestamp: TimeoutTimestamp, chain_timestamp: Timestamp, }, + /// unexpected channel ID: expected to be empty + UnexpectedChannelId, + /// unsupported version: expected `{expected}`, actual `{actual}` + UnsupportedVersion { expected: Version, actual: Version }, } impl From for ChannelError { @@ -106,49 +76,25 @@ impl From for ChannelError { } } -impl From for PacketError { - fn from(e: IdentifierError) -> Self { - Self::Decoding(DecodingError::Identifier(e)) - } -} - impl From for ChannelError { fn from(e: DecodingError) -> Self { Self::Decoding(e) } } -impl From for PacketError { - fn from(e: DecodingError) -> Self { - Self::Decoding(e) - } -} - -impl From for PacketError { +impl From for ChannelError { fn from(e: TimestampError) -> Self { Self::InvalidTimeoutTimestamp(e) } } -#[cfg(feature = "std")] -impl std::error::Error for PacketError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match &self { - Self::Channel(e) => Some(e), - Self::Decoding(e) => Some(e), - _ => None, - } - } -} - #[cfg(feature = "std")] impl std::error::Error for ChannelError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { Self::Decoding(e) => Some(e), - Self::FailedPacketVerification { - client_error: e, .. - } => Some(e), + Self::FailedVerification(e) => Some(e), + Self::InvalidTimeoutTimestamp(e) => Some(e), _ => None, } } diff --git a/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs b/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs index b9f7d119e..47ceea8ac 100644 --- a/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs +++ b/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs @@ -7,7 +7,6 @@ use ibc_proto::ibc::core::channel::v1::MsgAcknowledgement as RawMsgAcknowledgeme use ibc_proto::Protobuf; use crate::acknowledgement::Acknowledgement; -use crate::error::PacketError; use crate::packet::Packet; pub const ACKNOWLEDGEMENT_TYPE_URL: &str = "/ibc.core.channel.v1.MsgAcknowledgement"; @@ -34,7 +33,7 @@ pub struct MsgAcknowledgement { impl Protobuf for MsgAcknowledgement {} impl TryFrom for MsgAcknowledgement { - type Error = PacketError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgAcknowledgement) -> Result { Ok(MsgAcknowledgement { diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs b/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs index 5074f552a..22fe3a3f7 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs @@ -1,13 +1,12 @@ use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ChannelId, PortId}; use ibc_primitives::prelude::*; use ibc_primitives::Signer; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseConfirm as RawMsgChannelCloseConfirm; use ibc_proto::Protobuf; -use crate::error::ChannelError; - pub const CHAN_CLOSE_CONFIRM_TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelCloseConfirm"; /// @@ -32,24 +31,27 @@ pub struct MsgChannelCloseConfirm { impl Protobuf for MsgChannelCloseConfirm {} impl TryFrom for MsgChannelCloseConfirm { - type Error = ChannelError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgChannelCloseConfirm) -> Result { if raw_msg.counterparty_upgrade_sequence != 0 { - return Err(ChannelError::UnsupportedChannelUpgradeSequence); + return Err(DecodingError::invalid_raw_data( + "counterparty upgrade sequence must be 0", + )); } Ok(MsgChannelCloseConfirm { port_id_on_b: raw_msg.port_id.parse()?, chan_id_on_b: raw_msg.channel_id.parse()?, - proof_chan_end_on_a: raw_msg - .proof_init - .try_into() - .map_err(|_| ChannelError::MissingProof)?, + proof_chan_end_on_a: raw_msg.proof_init.try_into().map_err(|e| { + DecodingError::missing_raw_data(format!( + "failed to decode commitment proof bytes: {e}" + )) + })?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ChannelError::MissingProofHeight)?, + .ok_or(DecodingError::missing_raw_data("missing proof height"))?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs index 9b6de510a..e9bf8c6ae 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs @@ -1,13 +1,12 @@ use ibc_core_client_types::Height; use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ChannelId, PortId}; use ibc_primitives::prelude::*; use ibc_primitives::Signer; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenConfirm as RawMsgChannelOpenConfirm; use ibc_proto::Protobuf; -use crate::error::ChannelError; - pub const CHAN_OPEN_CONFIRM_TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenConfirm"; /// @@ -32,20 +31,19 @@ pub struct MsgChannelOpenConfirm { impl Protobuf for MsgChannelOpenConfirm {} impl TryFrom for MsgChannelOpenConfirm { - type Error = ChannelError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgChannelOpenConfirm) -> Result { Ok(MsgChannelOpenConfirm { port_id_on_b: raw_msg.port_id.parse()?, chan_id_on_b: raw_msg.channel_id.parse()?, - proof_chan_end_on_a: raw_msg - .proof_ack - .try_into() - .map_err(|_| ChannelError::MissingProof)?, + proof_chan_end_on_a: raw_msg.proof_ack.try_into().map_err(|e| { + DecodingError::invalid_raw_data(format!("invalid commitment proof bytes: {e}")) + })?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ChannelError::MissingProofHeight)?, + .ok_or(DecodingError::invalid_raw_data("invalid proof height"))?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs index 77e5afd89..3bf9f6e24 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs @@ -51,21 +51,21 @@ impl MsgChannelOpenTry { impl Protobuf for MsgChannelOpenTry {} impl TryFrom for MsgChannelOpenTry { - type Error = ChannelError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgChannelOpenTry) -> Result { let chan_end_on_b: ChannelEnd = raw_msg .channel - .ok_or(DecodingError::MissingRawData { - description: "channel end not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data("channel end not set"))? .try_into()?; - chan_end_on_b.verify_state_matches(&State::TryOpen)?; + chan_end_on_b + .verify_state_matches(&State::TryOpen) + .map_err(|e| DecodingError::invalid_raw_data(format!("invalid channel state: {e}")))?; #[allow(deprecated)] if !raw_msg.previous_channel_id.is_empty() { - return Err(DecodingError::InvalidRawData { description: "previous channel id must be empty. It has been deprecated as crossing hellos are no longer supported".to_string() })?; + return Err(DecodingError::invalid_raw_data("previous channel id must be empty. It has been deprecated as crossing hellos are no longer supported"))?; } #[allow(deprecated)] @@ -74,19 +74,17 @@ impl TryFrom for MsgChannelOpenTry { ordering: chan_end_on_b.ordering, connection_hops_on_b: chan_end_on_b.connection_hops, port_id_on_a: chan_end_on_b.remote.port_id, - chan_id_on_a: chan_end_on_b - .remote - .channel_id - .ok_or(ChannelError::MissingCounterparty)?, + chan_id_on_a: chan_end_on_b.remote.channel_id.ok_or( + DecodingError::missing_raw_data("missing counterparty channel ID"), + )?, version_supported_on_a: raw_msg.counterparty_version.into(), - proof_chan_end_on_a: raw_msg - .proof_init - .try_into() - .map_err(|_| ChannelError::MissingProof)?, + proof_chan_end_on_a: raw_msg.proof_init.try_into().map_err(|e| { + DecodingError::invalid_raw_data(format!("invalid commitment proof bytes: {e}")) + })?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(ChannelError::MissingProofHeight)?, + .ok_or(DecodingError::invalid_raw_data("invalid proof height"))?, signer: raw_msg.signer.into(), version_proposal: chan_end_on_b.version, }; diff --git a/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs b/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs index 030449b72..11e85e310 100644 --- a/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs +++ b/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs @@ -6,7 +6,6 @@ use ibc_primitives::Signer; use ibc_proto::ibc::core::channel::v1::MsgRecvPacket as RawMsgRecvPacket; use ibc_proto::Protobuf; -use crate::error::PacketError; use crate::packet::Packet; pub const RECV_PACKET_TYPE_URL: &str = "/ibc.core.channel.v1.MsgRecvPacket"; @@ -34,7 +33,7 @@ pub struct MsgRecvPacket { impl Protobuf for MsgRecvPacket {} impl TryFrom for MsgRecvPacket { - type Error = PacketError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgRecvPacket) -> Result { Ok(MsgRecvPacket { diff --git a/ibc-core/ics04-channel/types/src/msgs/timeout.rs b/ibc-core/ics04-channel/types/src/msgs/timeout.rs index aaa24bd05..540a11325 100644 --- a/ibc-core/ics04-channel/types/src/msgs/timeout.rs +++ b/ibc-core/ics04-channel/types/src/msgs/timeout.rs @@ -7,7 +7,6 @@ use ibc_primitives::Signer; use ibc_proto::ibc::core::channel::v1::MsgTimeout as RawMsgTimeout; use ibc_proto::Protobuf; -use crate::error::PacketError; use crate::packet::Packet; pub const TIMEOUT_TYPE_URL: &str = "/ibc.core.channel.v1.MsgTimeout"; @@ -33,31 +32,27 @@ pub struct MsgTimeout { impl Protobuf for MsgTimeout {} impl TryFrom for MsgTimeout { - type Error = PacketError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgTimeout) -> Result { if raw_msg.next_sequence_recv == 0 { - return Err(PacketError::ZeroPacketSequence); + return Err(DecodingError::invalid_raw_data( + "packet sequence cannot be 0", + )); } Ok(MsgTimeout { packet: raw_msg .packet - .ok_or(DecodingError::MissingRawData { - description: "packet data not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data("packet data not set"))? .try_into()?, next_seq_recv_on_b: Sequence::from(raw_msg.next_sequence_recv), proof_unreceived_on_b: raw_msg.proof_unreceived.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode proof: {e}"), - } + DecodingError::invalid_raw_data(format!("failed to decode proof: {e}")) })?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::MissingRawData { - description: "proof height not set".to_string(), - })?, + .ok_or(DecodingError::missing_raw_data("proof height not set"))?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs b/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs index fd1142a7c..c4277cfe4 100644 --- a/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs +++ b/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs @@ -7,7 +7,6 @@ use ibc_primitives::Signer; use ibc_proto::ibc::core::channel::v1::MsgTimeoutOnClose as RawMsgTimeoutOnClose; use ibc_proto::Protobuf; -use crate::error::{ChannelError, PacketError}; use crate::packet::Packet; pub const TIMEOUT_ON_CLOSE_TYPE_URL: &str = "/ibc.core.channel.v1.MsgTimeoutOnClose"; @@ -33,43 +32,39 @@ pub struct MsgTimeoutOnClose { impl Protobuf for MsgTimeoutOnClose {} impl TryFrom for MsgTimeoutOnClose { - type Error = PacketError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgTimeoutOnClose) -> Result { if raw_msg.next_sequence_recv == 0 { - return Err(PacketError::ZeroPacketSequence); + return Err(DecodingError::invalid_raw_data( + "packet sequence cannot be 0", + )); } if raw_msg.counterparty_upgrade_sequence != 0 { - return Err(PacketError::Channel( - ChannelError::UnsupportedChannelUpgradeSequence, + return Err(DecodingError::invalid_raw_data( + "unsupported channel upgrade sequence", )); } Ok(MsgTimeoutOnClose { packet: raw_msg .packet - .ok_or(DecodingError::MissingRawData { - description: "packet data not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data("packet data not set"))? .try_into()?, next_seq_recv_on_b: Sequence::from(raw_msg.next_sequence_recv), proof_unreceived_on_b: raw_msg.proof_unreceived.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode proof: {e}"), - } + DecodingError::invalid_raw_data(format!("failed to decode proof: {e}")) })?, proof_close_on_b: raw_msg.proof_close.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode proof: {e}"), - } + DecodingError::invalid_raw_data(format!("failed to decode proof: {e}")) })?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::InvalidRawData { - description: "failed to decode proof height".to_string(), - })?, + .ok_or(DecodingError::invalid_raw_data( + "failed to decode proof height", + ))?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/packet.rs b/ibc-core/ics04-channel/types/src/packet.rs index 4d364fff6..e5f2e8779 100644 --- a/ibc-core/ics04-channel/types/src/packet.rs +++ b/ibc-core/ics04-channel/types/src/packet.rs @@ -7,7 +7,6 @@ use ibc_primitives::Timestamp; use ibc_proto::ibc::core::channel::v1::{Packet as RawPacket, PacketState as RawPacketState}; use super::timeout::TimeoutHeight; -use crate::error::PacketError; use crate::timeout::TimeoutTimestamp; /// Enumeration of proof carrying ICS4 message, helper for relayer. @@ -180,17 +179,17 @@ impl core::fmt::Display for Packet { } impl TryFrom for Packet { - type Error = PacketError; + type Error = DecodingError; fn try_from(raw_pkt: RawPacket) -> Result { if Sequence::from(raw_pkt.sequence).is_zero() { - return Err(PacketError::ZeroPacketSequence); + return Err(DecodingError::invalid_raw_data( + "packet sequence cannot be 0", + )); } if raw_pkt.data.is_empty() { - return Err(DecodingError::MissingRawData { - description: "packet data is not set".to_string(), - })?; + return Err(DecodingError::missing_raw_data("packet data is not set"))?; } // Note: ibc-go currently (July 2022) incorrectly treats the timeout @@ -207,7 +206,9 @@ impl TryFrom for Packet { // Packet timeout height and packet timeout timestamp cannot both be unset. if !packet_timeout_height.is_set() && !timeout_timestamp_on_b.is_set() { - return Err(PacketError::MissingTimeout); + return Err(DecodingError::missing_raw_data( + "missing one of packet timeout height or timeout timestamp", + )); } Ok(Packet { @@ -292,17 +293,17 @@ impl core::fmt::Display for PacketState { } impl TryFrom for PacketState { - type Error = PacketError; + type Error = DecodingError; fn try_from(raw_pkt: RawPacketState) -> Result { if Sequence::from(raw_pkt.sequence).is_zero() { - return Err(PacketError::ZeroPacketSequence); + return Err(DecodingError::invalid_raw_data( + "packet sequence cannot be 0", + )); } if raw_pkt.data.is_empty() { - return Err(DecodingError::MissingRawData { - description: "packet data not set".to_string(), - })?; + return Err(DecodingError::missing_raw_data("packet data not set"))?; } Ok(PacketState { diff --git a/ibc-core/ics04-channel/types/src/timeout/timestamp.rs b/ibc-core/ics04-channel/types/src/timeout/timestamp.rs index 86ef4328a..8cd45b712 100644 --- a/ibc-core/ics04-channel/types/src/timeout/timestamp.rs +++ b/ibc-core/ics04-channel/types/src/timeout/timestamp.rs @@ -5,7 +5,7 @@ use core::time::Duration; use ibc_primitives::prelude::*; use ibc_primitives::Timestamp; -use crate::error::PacketError; +use crate::error::ChannelError; /// Indicates a timestamp on the destination chain after which the packet will /// no longer be processed, and will instead count as having timed-out. @@ -101,7 +101,7 @@ impl Display for TimeoutTimestamp { } impl Add for TimeoutTimestamp { - type Output = Result; + type Output = Result; fn add(self, rhs: Duration) -> Self::Output { match self { @@ -109,13 +109,13 @@ impl Add for TimeoutTimestamp { let new_timestamp = timestamp.add(rhs)?; Ok(TimeoutTimestamp::At(new_timestamp)) } - TimeoutTimestamp::Never => Err(PacketError::MissingTimeout), + TimeoutTimestamp::Never => Err(ChannelError::MissingTimeout), } } } impl Sub for TimeoutTimestamp { - type Output = Result; + type Output = Result; fn sub(self, rhs: Duration) -> Self::Output { match self { @@ -123,7 +123,7 @@ impl Sub for TimeoutTimestamp { let new_timestamp = timestamp.sub(rhs)?; Ok(TimeoutTimestamp::At(new_timestamp)) } - TimeoutTimestamp::Never => Err(PacketError::MissingTimeout), + TimeoutTimestamp::Never => Err(ChannelError::MissingTimeout), } } } diff --git a/ibc-core/ics25-handler/types/src/error.rs b/ibc-core/ics25-handler/types/src/error.rs index bc93d11f4..a2823b357 100644 --- a/ibc-core/ics25-handler/types/src/error.rs +++ b/ibc-core/ics25-handler/types/src/error.rs @@ -2,7 +2,7 @@ use derive_more::From; use displaydoc::Display; -use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_channel_types::error::ChannelError; use ibc_core_client_types::error::ClientError; use ibc_core_connection_types::error::ConnectionError; use ibc_core_host_types::error::HostError; @@ -18,8 +18,6 @@ pub enum HandlerError { Connection(ConnectionError), /// ICS04 Channel error: {0} Channel(ChannelError), - /// ICS04 Packet error: {0} - Packet(PacketError), /// ICS26 Routing error: {0} Router(RouterError), /// ICS25 Host error: {0} @@ -45,7 +43,6 @@ impl std::error::Error for HandlerError { Self::Client(e) => Some(e), Self::Connection(e) => Some(e), Self::Channel(e) => Some(e), - Self::Packet(e) => Some(e), Self::Router(e) => Some(e), Self::Host(e) => Some(e), } diff --git a/ibc-core/ics26-routing/src/module.rs b/ibc-core/ics26-routing/src/module.rs index 26b296713..a0877b98d 100644 --- a/ibc-core/ics26-routing/src/module.rs +++ b/ibc-core/ics26-routing/src/module.rs @@ -3,7 +3,7 @@ use core::fmt::Debug; use ibc_core_channel_types::acknowledgement::Acknowledgement; use ibc_core_channel_types::channel::{Counterparty, Order}; -use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::packet::Packet; use ibc_core_channel_types::Version; use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId}; @@ -134,14 +134,14 @@ pub trait Module: Debug { _packet: &Packet, _acknowledgement: &Acknowledgement, _relayer: &Signer, - ) -> Result<(), PacketError>; + ) -> Result<(), ChannelError>; fn on_acknowledgement_packet_execute( &mut self, _packet: &Packet, _acknowledgement: &Acknowledgement, _relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>); + ) -> (ModuleExtras, Result<(), ChannelError>); /// Note: `MsgTimeout` and `MsgTimeoutOnClose` use the same callback @@ -149,7 +149,7 @@ pub trait Module: Debug { &self, packet: &Packet, relayer: &Signer, - ) -> Result<(), PacketError>; + ) -> Result<(), ChannelError>; /// Note: `MsgTimeout` and `MsgTimeoutOnClose` use the same callback @@ -157,5 +157,5 @@ pub trait Module: Debug { &mut self, packet: &Packet, relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>); + ) -> (ModuleExtras, Result<(), ChannelError>); } diff --git a/ibc-query/src/error.rs b/ibc-query/src/error.rs index 2d18a8547..6b20a3691 100644 --- a/ibc-query/src/error.rs +++ b/ibc-query/src/error.rs @@ -1,7 +1,7 @@ use alloc::string::{String, ToString}; use displaydoc::Display; -use ibc::core::channel::types::error::{ChannelError, PacketError}; +use ibc::core::channel::types::error::ChannelError; use ibc::core::client::types::error::ClientError; use ibc::core::connection::types::error::ConnectionError; use ibc::core::handler::types::error::HandlerError; @@ -68,12 +68,6 @@ impl From for QueryError { } } -impl From for QueryError { - fn from(e: PacketError) -> Self { - Self::Handler(HandlerError::Packet(e)) - } -} - impl From for QueryError { fn from(e: DecodingError) -> Self { Self::Decoding(e) diff --git a/ibc-testkit/src/fixtures/core/channel/acknowledgement.rs b/ibc-testkit/src/fixtures/core/channel/acknowledgement.rs index ac09a89e0..8d22324c2 100644 --- a/ibc-testkit/src/fixtures/core/channel/acknowledgement.rs +++ b/ibc-testkit/src/fixtures/core/channel/acknowledgement.rs @@ -27,8 +27,8 @@ pub fn dummy_raw_msg_ack_with_packet(packet: RawPacket, height: u64) -> RawMsgAc #[cfg(test)] mod test { - use ibc::core::channel::types::error::PacketError; use ibc::core::channel::types::msgs::MsgAcknowledgement; + use ibc::core::host::types::error::DecodingError; use ibc::primitives::prelude::*; use super::*; @@ -85,7 +85,7 @@ mod test { ]; for test in tests { - let res_msg: Result = test.raw.clone().try_into(); + let res_msg: Result = test.raw.clone().try_into(); assert_eq!( res_msg.is_ok(), diff --git a/ibc-testkit/src/fixtures/core/channel/recv_packet.rs b/ibc-testkit/src/fixtures/core/channel/recv_packet.rs index 57403a69e..2a34925b5 100644 --- a/ibc-testkit/src/fixtures/core/channel/recv_packet.rs +++ b/ibc-testkit/src/fixtures/core/channel/recv_packet.rs @@ -46,7 +46,7 @@ pub fn dummy_raw_msg_recv_packet(height: u64) -> RawMsgRecvPacket { #[cfg(test)] mod test { - use ibc::core::channel::types::error::PacketError; + use ibc::core::host::types::error::DecodingError; use ibc::primitives::prelude::*; use super::*; @@ -94,7 +94,7 @@ mod test { ]; for test in tests { - let res_msg: Result = test.raw.clone().try_into(); + let res_msg: Result = test.raw.clone().try_into(); assert_eq!( res_msg.is_ok(), diff --git a/ibc-testkit/src/fixtures/core/channel/timeout.rs b/ibc-testkit/src/fixtures/core/channel/timeout.rs index 97719aafd..175c6605e 100644 --- a/ibc-testkit/src/fixtures/core/channel/timeout.rs +++ b/ibc-testkit/src/fixtures/core/channel/timeout.rs @@ -25,8 +25,8 @@ pub fn dummy_raw_msg_timeout( #[cfg(test)] mod test { - use ibc::core::channel::types::error::PacketError; use ibc::core::channel::types::msgs::MsgTimeout; + use ibc::core::host::types::error::DecodingError; use ibc::primitives::prelude::*; use super::*; @@ -86,7 +86,7 @@ mod test { ]; for test in tests { - let res_msg: Result = test.raw.clone().try_into(); + let res_msg: Result = test.raw.clone().try_into(); assert_eq!( res_msg.is_ok(), diff --git a/ibc-testkit/src/testapp/ibc/applications/nft_transfer/module.rs b/ibc-testkit/src/testapp/ibc/applications/nft_transfer/module.rs index 06652a1dd..df6a158a6 100644 --- a/ibc-testkit/src/testapp/ibc/applications/nft_transfer/module.rs +++ b/ibc-testkit/src/testapp/ibc/applications/nft_transfer/module.rs @@ -1,6 +1,6 @@ use ibc::core::channel::types::acknowledgement::Acknowledgement; use ibc::core::channel::types::channel::{Counterparty, Order}; -use ibc::core::channel::types::error::{ChannelError, PacketError}; +use ibc::core::channel::types::error::ChannelError; use ibc::core::channel::types::packet::Packet; use ibc::core::channel::types::Version; use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; @@ -75,7 +75,7 @@ impl Module for DummyNftTransferModule { &self, _packet: &Packet, _relayer: &Signer, - ) -> Result<(), PacketError> { + ) -> Result<(), ChannelError> { Ok(()) } @@ -83,7 +83,7 @@ impl Module for DummyNftTransferModule { &mut self, _packet: &Packet, _relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>) { + ) -> (ModuleExtras, Result<(), ChannelError>) { (ModuleExtras::empty(), Ok(())) } @@ -92,7 +92,7 @@ impl Module for DummyNftTransferModule { _packet: &Packet, _acknowledgement: &Acknowledgement, _relayer: &Signer, - ) -> Result<(), PacketError> { + ) -> Result<(), ChannelError> { Ok(()) } @@ -101,7 +101,7 @@ impl Module for DummyNftTransferModule { _packet: &Packet, _acknowledgement: &Acknowledgement, _relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>) { + ) -> (ModuleExtras, Result<(), ChannelError>) { (ModuleExtras::empty(), Ok(())) } } diff --git a/ibc-testkit/src/testapp/ibc/applications/transfer/module.rs b/ibc-testkit/src/testapp/ibc/applications/transfer/module.rs index 2246c893b..289feb654 100644 --- a/ibc-testkit/src/testapp/ibc/applications/transfer/module.rs +++ b/ibc-testkit/src/testapp/ibc/applications/transfer/module.rs @@ -1,6 +1,6 @@ use ibc::core::channel::types::acknowledgement::Acknowledgement; use ibc::core::channel::types::channel::{Counterparty, Order}; -use ibc::core::channel::types::error::{ChannelError, PacketError}; +use ibc::core::channel::types::error::ChannelError; use ibc::core::channel::types::packet::Packet; use ibc::core::channel::types::Version; use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; @@ -75,7 +75,7 @@ impl Module for DummyTransferModule { &self, _packet: &Packet, _relayer: &Signer, - ) -> Result<(), PacketError> { + ) -> Result<(), ChannelError> { Ok(()) } @@ -83,7 +83,7 @@ impl Module for DummyTransferModule { &mut self, _packet: &Packet, _relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>) { + ) -> (ModuleExtras, Result<(), ChannelError>) { (ModuleExtras::empty(), Ok(())) } @@ -92,7 +92,7 @@ impl Module for DummyTransferModule { _packet: &Packet, _acknowledgement: &Acknowledgement, _relayer: &Signer, - ) -> Result<(), PacketError> { + ) -> Result<(), ChannelError> { Ok(()) } @@ -101,7 +101,7 @@ impl Module for DummyTransferModule { _packet: &Packet, _acknowledgement: &Acknowledgement, _relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>) { + ) -> (ModuleExtras, Result<(), ChannelError>) { (ModuleExtras::empty(), Ok(())) } } diff --git a/ibc-testkit/src/testapp/ibc/core/types.rs b/ibc-testkit/src/testapp/ibc/core/types.rs index 4bd314c60..9389d642c 100644 --- a/ibc-testkit/src/testapp/ibc/core/types.rs +++ b/ibc-testkit/src/testapp/ibc/core/types.rs @@ -205,7 +205,7 @@ where mod tests { use ibc::core::channel::types::acknowledgement::Acknowledgement; use ibc::core::channel::types::channel::{Counterparty, Order}; - use ibc::core::channel::types::error::{ChannelError, PacketError}; + use ibc::core::channel::types::error::ChannelError; use ibc::core::channel::types::packet::Packet; use ibc::core::channel::types::Version; use ibc::core::host::types::identifiers::{ChannelId, PortId}; @@ -292,7 +292,7 @@ mod tests { &self, _packet: &Packet, _relayer: &Signer, - ) -> Result<(), PacketError> { + ) -> Result<(), ChannelError> { Ok(()) } @@ -300,7 +300,7 @@ mod tests { &mut self, _packet: &Packet, _relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>) { + ) -> (ModuleExtras, Result<(), ChannelError>) { (ModuleExtras::empty(), Ok(())) } @@ -309,7 +309,7 @@ mod tests { _packet: &Packet, _acknowledgement: &Acknowledgement, _relayer: &Signer, - ) -> Result<(), PacketError> { + ) -> Result<(), ChannelError> { Ok(()) } @@ -318,7 +318,7 @@ mod tests { _packet: &Packet, _acknowledgement: &Acknowledgement, _relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>) { + ) -> (ModuleExtras, Result<(), ChannelError>) { (ModuleExtras::empty(), Ok(())) } } @@ -390,7 +390,7 @@ mod tests { &self, _packet: &Packet, _relayer: &Signer, - ) -> Result<(), PacketError> { + ) -> Result<(), ChannelError> { Ok(()) } @@ -398,7 +398,7 @@ mod tests { &mut self, _packet: &Packet, _relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>) { + ) -> (ModuleExtras, Result<(), ChannelError>) { (ModuleExtras::empty(), Ok(())) } @@ -407,7 +407,7 @@ mod tests { _packet: &Packet, _acknowledgement: &Acknowledgement, _relayer: &Signer, - ) -> Result<(), PacketError> { + ) -> Result<(), ChannelError> { Ok(()) } @@ -416,7 +416,7 @@ mod tests { _packet: &Packet, _acknowledgement: &Acknowledgement, _relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>) { + ) -> (ModuleExtras, Result<(), ChannelError>) { (ModuleExtras::empty(), Ok(())) } } From 4aecaece9bda3c0f4a3b6a8379d73bd7eddc2cc4 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 18 Sep 2024 08:30:33 -0500 Subject: [PATCH 08/18] Add `HostError` contexts to module-level error types (#1345) * Add ConnectionError::Host variant and clean up some other variants * Migrate some ics03 handlers to return HostErrors * Revert "Migrate some ics03 handlers to return HostErrors" This reverts commit f48a1a687c62a2a4aef655eb942d9095f34cc9a3. * Add HostError variant to ChannelError * Remove HandlerError::Host variant * Map client handler HostErrors to ClientError::Host * Revert "Map client handler HostErrors to ClientError::Host" This reverts commit 247be8acf05e8778bdb888281c9ce2c3d1d9909a. * Change ics02-client handlers to return ClientError * Change ics03-connection handlers to return ConnectionError * Change ics04-channel handlers to return ChannelError * Make necessary changes in ics25 dispatch * imp: misc improvements and fixes * imp: use derive_more::From for ChannelError * fix: rename InvalidClientState under ConnectionError * nit: remove redundant import --------- Co-authored-by: Farhad Shabani --- ibc-apps/ics20-transfer/src/module.rs | 13 +- ibc-apps/ics20-transfer/types/src/error.rs | 29 +--- ibc-apps/ics721-nft-transfer/src/module.rs | 14 +- .../ics721-nft-transfer/types/src/error.rs | 17 +- .../ics02-client/src/handler/create_client.rs | 9 +- .../src/handler/recover_client.rs | 8 +- .../ics02-client/src/handler/update_client.rs | 8 +- .../src/handler/upgrade_client.rs | 17 +- ibc-core/ics03-connection/src/delay.rs | 23 ++- .../src/handler/conn_open_ack.rs | 62 ++++--- .../src/handler/conn_open_confirm.rs | 27 ++-- .../src/handler/conn_open_init.rs | 6 +- .../src/handler/conn_open_try.rs | 62 ++++--- ibc-core/ics03-connection/src/handler/mod.rs | 12 +- .../ics03-connection/types/src/connection.rs | 2 +- ibc-core/ics03-connection/types/src/error.rs | 51 +++--- .../ics03-connection/types/src/version.rs | 10 +- .../src/handler/acknowledgement.rs | 33 ++-- .../src/handler/chan_close_confirm.rs | 25 ++- .../src/handler/chan_close_init.rs | 9 +- .../src/handler/chan_open_ack.rs | 23 ++- .../src/handler/chan_open_confirm.rs | 25 ++- .../src/handler/chan_open_init.rs | 8 +- .../src/handler/chan_open_try.rs | 23 ++- .../ics04-channel/src/handler/recv_packet.rs | 39 ++--- .../ics04-channel/src/handler/send_packet.rs | 17 +- ibc-core/ics04-channel/src/handler/timeout.rs | 26 ++- .../src/handler/timeout_on_close.rs | 31 ++-- ibc-core/ics04-channel/types/src/error.rs | 31 ++-- ibc-core/ics25-handler/src/entrypoint.rs | 153 +++++++++--------- ibc-core/ics25-handler/types/src/error.rs | 16 -- ibc-query/src/error.rs | 5 +- .../tests/core/ics02_client/upgrade_client.rs | 7 +- .../core/ics03_connection/conn_open_ack.rs | 9 +- tests-integration/tests/core/router.rs | 5 +- 35 files changed, 362 insertions(+), 493 deletions(-) diff --git a/ibc-apps/ics20-transfer/src/module.rs b/ibc-apps/ics20-transfer/src/module.rs index 2c24dc6fe..3ca271c43 100644 --- a/ibc-apps/ics20-transfer/src/module.rs +++ b/ibc-apps/ics20-transfer/src/module.rs @@ -6,7 +6,6 @@ use ibc_core::channel::types::acknowledgement::{Acknowledgement, Acknowledgement use ibc_core::channel::types::channel::{Counterparty, Order}; use ibc_core::channel::types::packet::Packet; use ibc_core::channel::types::Version; -use ibc_core::handler::types::error::HandlerError; use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc_core::primitives::prelude::*; @@ -42,9 +41,7 @@ pub fn on_chan_open_init_validate( } if !version.is_empty() { - version - .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(HandlerError::from)?; + version.verify_is_expected(Version::new(VERSION.to_string()))?; } Ok(()) @@ -78,9 +75,7 @@ pub fn on_chan_open_try_validate( }); } - counterparty_version - .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(HandlerError::from)?; + counterparty_version.verify_is_expected(Version::new(VERSION.to_string()))?; Ok(()) } @@ -103,9 +98,7 @@ pub fn on_chan_open_ack_validate( _channel_id: &ChannelId, counterparty_version: &Version, ) -> Result<(), TokenTransferError> { - counterparty_version - .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(HandlerError::from)?; + counterparty_version.verify_is_expected(Version::new(VERSION.to_string()))?; Ok(()) } diff --git a/ibc-apps/ics20-transfer/types/src/error.rs b/ibc-apps/ics20-transfer/types/src/error.rs index 00e81614b..113953dd5 100644 --- a/ibc-apps/ics20-transfer/types/src/error.rs +++ b/ibc-apps/ics20-transfer/types/src/error.rs @@ -2,17 +2,19 @@ use displaydoc::Display; use ibc_core::channel::types::acknowledgement::StatusValue; use ibc_core::channel::types::channel::Order; -use ibc_core::handler::types::error::HandlerError; +use ibc_core::channel::types::error::ChannelError; use ibc_core::host::types::error::{DecodingError, HostError}; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; -#[derive(Display, Debug)] +#[derive(Display, Debug, derive_more::From)] pub enum TokenTransferError { /// host error: `{0}` - Handler(HandlerError), + Host(HostError), /// decoding error: `{0}` Decoding(DecodingError), + /// channel error: `{0}` + Channel(ChannelError), /// missing destination channel `{channel_id}` on port `{port_id}` MissingDestinationChannel { port_id: PortId, @@ -36,31 +38,14 @@ pub enum TokenTransferError { impl std::error::Error for TokenTransferError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::Handler(e) => Some(e), + Self::Host(e) => Some(e), Self::Decoding(e) => Some(e), + Self::Channel(e) => Some(e), _ => None, } } } -impl From for TokenTransferError { - fn from(e: HandlerError) -> Self { - Self::Handler(e) - } -} - -impl From for TokenTransferError { - fn from(e: HostError) -> Self { - Self::Handler(HandlerError::Host(e)) - } -} - -impl From for TokenTransferError { - fn from(e: DecodingError) -> Self { - Self::Decoding(e) - } -} - impl From for StatusValue { fn from(e: TokenTransferError) -> Self { StatusValue::new(e.to_string()).expect("error message must not be empty") diff --git a/ibc-apps/ics721-nft-transfer/src/module.rs b/ibc-apps/ics721-nft-transfer/src/module.rs index a1f479b51..a7a54a447 100644 --- a/ibc-apps/ics721-nft-transfer/src/module.rs +++ b/ibc-apps/ics721-nft-transfer/src/module.rs @@ -3,7 +3,6 @@ use ibc_core::channel::types::acknowledgement::{Acknowledgement, Acknowledgement use ibc_core::channel::types::channel::{Counterparty, Order}; use ibc_core::channel::types::packet::Packet; use ibc_core::channel::types::Version; -use ibc_core::handler::types::error::HandlerError; use ibc_core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc_core::primitives::prelude::*; use ibc_core::primitives::Signer; @@ -42,9 +41,7 @@ pub fn on_chan_open_init_validate( } if !version.is_empty() { - version - .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(HandlerError::from)?; + version.verify_is_expected(Version::new(VERSION.to_string()))?; } Ok(()) @@ -78,9 +75,7 @@ pub fn on_chan_open_try_validate( }); } - counterparty_version - .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(HandlerError::from)?; + counterparty_version.verify_is_expected(Version::new(VERSION.to_string()))?; Ok(()) } @@ -103,10 +98,7 @@ pub fn on_chan_open_ack_validate( _channel_id: &ChannelId, counterparty_version: &Version, ) -> Result<(), NftTransferError> { - counterparty_version - .verify_is_expected(Version::new(VERSION.to_string())) - .map_err(HandlerError::from)?; - + counterparty_version.verify_is_expected(Version::new(VERSION.to_string()))?; Ok(()) } diff --git a/ibc-apps/ics721-nft-transfer/types/src/error.rs b/ibc-apps/ics721-nft-transfer/types/src/error.rs index bda017a9b..40035e4ff 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/error.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/error.rs @@ -3,15 +3,17 @@ use derive_more::From; use displaydoc::Display; use ibc_core::channel::types::acknowledgement::StatusValue; use ibc_core::channel::types::channel::Order; -use ibc_core::handler::types::error::HandlerError; +use ibc_core::channel::types::error::ChannelError; use ibc_core::host::types::error::{DecodingError, HostError}; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; #[derive(Display, Debug, From)] pub enum NftTransferError { - /// handler error: `{0}` - Handler(HandlerError), + /// host error: `{0}` + Host(HostError), + /// channel error: `{0}` + Channel(ChannelError), /// decoding error: `{0}` Decoding(DecodingError), /// missing destination channel `{channel_id}` on port `{port_id}` @@ -41,19 +43,14 @@ pub enum NftTransferError { impl std::error::Error for NftTransferError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::Handler(e) => Some(e), + Self::Channel(e) => Some(e), + Self::Host(e) => Some(e), Self::Decoding(e) => Some(e), _ => None, } } } -impl From for NftTransferError { - fn from(e: HostError) -> Self { - Self::Handler(HandlerError::Host(e)) - } -} - impl From for StatusValue { fn from(err: NftTransferError) -> Self { StatusValue::new(err.to_string()).expect("error message must not be empty") diff --git a/ibc-core/ics02-client/src/handler/create_client.rs b/ibc-core/ics02-client/src/handler/create_client.rs index 8ea87b2f1..fa79a9eac 100644 --- a/ibc-core/ics02-client/src/handler/create_client.rs +++ b/ibc-core/ics02-client/src/handler/create_client.rs @@ -5,13 +5,12 @@ use ibc_core_client_types::error::ClientError; use ibc_core_client_types::events::CreateClient; use ibc_core_client_types::msgs::MsgCreateClient; use ibc_core_client_types::Status; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::{ClientStateMut, ClientStateRef, ExecutionContext, ValidationContext}; use ibc_primitives::prelude::*; use ibc_primitives::proto::Any; -pub fn validate(ctx: &Ctx, msg: MsgCreateClient) -> Result<(), HandlerError> +pub fn validate(ctx: &Ctx, msg: MsgCreateClient) -> Result<(), ClientError> where Ctx: ValidationContext, as TryFrom>::Error: Into, @@ -36,7 +35,7 @@ where let status = client_state.status(client_val_ctx, &client_id)?; if status.is_frozen() { - return Err(ClientError::UnexpectedStatus(Status::Frozen).into()); + return Err(ClientError::UnexpectedStatus(Status::Frozen)); }; let host_timestamp = ctx.host_timestamp()?; @@ -44,13 +43,13 @@ where client_state.verify_consensus_state(consensus_state, &host_timestamp)?; if client_val_ctx.client_state(&client_id).is_ok() { - return Err(ClientError::DuplicateClientState(client_id).into()); + return Err(ClientError::DuplicateClientState(client_id)); }; Ok(()) } -pub fn execute(ctx: &mut Ctx, msg: MsgCreateClient) -> Result<(), HandlerError> +pub fn execute(ctx: &mut Ctx, msg: MsgCreateClient) -> Result<(), ClientError> where Ctx: ExecutionContext, as TryFrom>::Error: Into, diff --git a/ibc-core/ics02-client/src/handler/recover_client.rs b/ibc-core/ics02-client/src/handler/recover_client.rs index c3e2826b2..f08cefd98 100644 --- a/ibc-core/ics02-client/src/handler/recover_client.rs +++ b/ibc-core/ics02-client/src/handler/recover_client.rs @@ -3,7 +3,6 @@ use ibc_core_client_context::prelude::*; use ibc_core_client_types::error::ClientError; use ibc_core_client_types::msgs::MsgRecoverClient; -use ibc_core_handler_types::error::HandlerError; use ibc_core_host::types::path::ClientConsensusStatePath; use ibc_core_host::{ExecutionContext, ValidationContext}; @@ -11,7 +10,7 @@ use ibc_core_host::{ExecutionContext, ValidationContext}; /// includes validating that the parameters of the subject and substitute clients match, /// as well as validating that the substitute client *is* active and that the subject /// client is *not* active. -pub fn validate(ctx: &Ctx, msg: MsgRecoverClient) -> Result<(), HandlerError> +pub fn validate(ctx: &Ctx, msg: MsgRecoverClient) -> Result<(), ClientError> where Ctx: ValidationContext, { @@ -33,8 +32,7 @@ where return Err(ClientError::NotAllowedClientRecoveryHeights { subject_height, substitute_height, - } - .into()); + }); } substitute_client_state @@ -62,7 +60,7 @@ where /// - copying the substitute client's consensus state as the subject's consensus state /// - setting the subject client's processed height and processed time values to match the substitute client's /// - setting the subject client's latest height, trusting period, and chain ID values to match the substitute client's -pub fn execute(ctx: &mut Ctx, msg: MsgRecoverClient) -> Result<(), HandlerError> +pub fn execute(ctx: &mut Ctx, msg: MsgRecoverClient) -> Result<(), ClientError> where Ctx: ExecutionContext, { diff --git a/ibc-core/ics02-client/src/handler/update_client.rs b/ibc-core/ics02-client/src/handler/update_client.rs index b40d94a68..569141490 100644 --- a/ibc-core/ics02-client/src/handler/update_client.rs +++ b/ibc-core/ics02-client/src/handler/update_client.rs @@ -5,14 +5,13 @@ use ibc_core_client_types::error::ClientError; use ibc_core_client_types::events::{ClientMisbehaviour, UpdateClient}; use ibc_core_client_types::msgs::MsgUpdateOrMisbehaviour; use ibc_core_client_types::UpdateKind; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::error::HostError; use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_primitives::prelude::*; use ibc_primitives::ToVec; -pub fn validate(ctx: &Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), HandlerError> +pub fn validate(ctx: &Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ClientError> where Ctx: ValidationContext, { @@ -36,7 +35,7 @@ where Ok(()) } -pub fn execute(ctx: &mut Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), HandlerError> +pub fn execute(ctx: &mut Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ClientError> where Ctx: ExecutionContext, { @@ -67,8 +66,7 @@ where if !matches!(update_kind, UpdateKind::UpdateClient) { return Err(ClientError::FailedMisbehaviourHandling { description: "misbehaviour submitted, but none found".to_string(), - } - .into()); + }); } let header = client_message; diff --git a/ibc-core/ics02-client/src/handler/upgrade_client.rs b/ibc-core/ics02-client/src/handler/upgrade_client.rs index 3fe5f8b95..ae119faeb 100644 --- a/ibc-core/ics02-client/src/handler/upgrade_client.rs +++ b/ibc-core/ics02-client/src/handler/upgrade_client.rs @@ -1,16 +1,15 @@ //! Protocol logic specific to processing ICS2 messages of type `MsgUpgradeAnyClient`. //! use ibc_core_client_context::prelude::*; +use ibc_core_client_types::error::ClientError; use ibc_core_client_types::events::UpgradeClient; use ibc_core_client_types::msgs::MsgUpgradeClient; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; -use ibc_core_host::types::error::HostError; use ibc_core_host::types::path::ClientConsensusStatePath; use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_primitives::prelude::*; -pub fn validate(ctx: &Ctx, msg: MsgUpgradeClient) -> Result<(), HandlerError> +pub fn validate(ctx: &Ctx, msg: MsgUpgradeClient) -> Result<(), ClientError> where Ctx: ValidationContext, { @@ -36,15 +35,7 @@ where old_client_state.latest_height().revision_number(), old_client_state.latest_height().revision_height(), ); - let old_consensus_state = client_val_ctx - .consensus_state(&old_client_cons_state_path) - .map_err(|_| { - HostError::missing_state(format!( - "missing consensus state for client {} at height {}", - client_id, - old_client_state.latest_height() - )) - })?; + let old_consensus_state = client_val_ctx.consensus_state(&old_client_cons_state_path)?; // Validate the upgraded client state and consensus state and verify proofs against the root old_client_state.verify_upgrade_client( @@ -58,7 +49,7 @@ where Ok(()) } -pub fn execute(ctx: &mut Ctx, msg: MsgUpgradeClient) -> Result<(), HandlerError> +pub fn execute(ctx: &mut Ctx, msg: MsgUpgradeClient) -> Result<(), ClientError> where Ctx: ExecutionContext, { diff --git a/ibc-core/ics03-connection/src/delay.rs b/ibc-core/ics03-connection/src/delay.rs index b2c51158a..e254dc4d7 100644 --- a/ibc-core/ics03-connection/src/delay.rs +++ b/ibc-core/ics03-connection/src/delay.rs @@ -2,14 +2,13 @@ use ibc_core_client::context::ClientValidationContext; use ibc_core_client::types::Height; use ibc_core_connection_types::error::ConnectionError; use ibc_core_connection_types::ConnectionEnd; -use ibc_core_handler_types::error::HandlerError; use ibc_core_host::ValidationContext; pub fn verify_conn_delay_passed( ctx: &Ctx, packet_proof_height: Height, connection_end: &ConnectionEnd, -) -> Result<(), HandlerError> +) -> Result<(), ConnectionError> where Ctx: ValidationContext, { @@ -31,23 +30,19 @@ where let earliest_valid_time = (last_client_update.0 + conn_delay_time_period) .map_err(ConnectionError::OverflowedTimestamp)?; if current_host_time < earliest_valid_time { - return Err(HandlerError::Connection( - ConnectionError::InsufficientTimeElapsed { - current_host_time, - earliest_valid_time, - }, - )); + return Err(ConnectionError::InsufficientTimeElapsed { + current_host_time, + earliest_valid_time, + }); } // Verify that the current host chain height is later than the last client update height let earliest_valid_height = last_client_update.1.add(conn_delay_height_period); if current_host_height < earliest_valid_height { - return Err(HandlerError::Connection( - ConnectionError::InsufficientBlocksElapsed { - current_host_height, - earliest_valid_height, - }, - )); + return Err(ConnectionError::InsufficientBlocksElapsed { + current_host_height, + earliest_valid_height, + }); }; Ok(()) diff --git a/ibc-core/ics03-connection/src/handler/conn_open_ack.rs b/ibc-core/ics03-connection/src/handler/conn_open_ack.rs index 470100833..a91a16c76 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_ack.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_ack.rs @@ -6,7 +6,6 @@ use ibc_core_connection_types::error::ConnectionError; use ibc_core_connection_types::events::OpenAck; use ibc_core_connection_types::msgs::MsgConnectionOpenAck; use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::ClientId; use ibc_core_host::types::path::{ClientConsensusStatePath, ClientStatePath, ConnectionPath, Path}; @@ -17,7 +16,7 @@ use ibc_primitives::ToVec; use crate::handler::{pack_host_consensus_state, unpack_host_client_state}; -pub fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenAck) -> Result<(), HandlerError> +pub fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenAck) -> Result<(), ConnectionError> where Ctx: ValidationContext, >::Error: Into, @@ -30,7 +29,7 @@ fn validate_impl( ctx_a: &Ctx, msg: &MsgConnectionOpenAck, vars: &LocalVars, -) -> Result<(), HandlerError> +) -> Result<(), ConnectionError> where Ctx: ValidationContext, >::Error: Into, @@ -43,8 +42,7 @@ where return Err(ConnectionError::InsufficientConsensusHeight { target_height: msg.consensus_height_of_a_on_b, current_height: host_height, - } - .into()); + }); } let client_val_ctx_a = ctx_a.get_client_validation_context(); @@ -96,26 +94,22 @@ where vars.conn_end_on_a.delay_period(), )?; - client_state_of_b_on_a - .verify_membership( - prefix_on_b, - &msg.proof_conn_end_on_b, - consensus_state_of_b_on_a.root(), - Path::Connection(ConnectionPath::new(&msg.conn_id_on_b)), - expected_conn_end_on_b.encode_vec(), - ) - .map_err(ConnectionError::FailedToVerifyConnectionState)?; - } - - client_state_of_b_on_a - .verify_membership( + client_state_of_b_on_a.verify_membership( prefix_on_b, - &msg.proof_client_state_of_a_on_b, + &msg.proof_conn_end_on_b, consensus_state_of_b_on_a.root(), - Path::ClientState(ClientStatePath::new(vars.client_id_on_b().clone())), - msg.client_state_of_a_on_b.to_vec(), - ) - .map_err(ConnectionError::FailedToVerifyClientState)?; + Path::Connection(ConnectionPath::new(&msg.conn_id_on_b)), + expected_conn_end_on_b.encode_vec(), + )?; + } + + client_state_of_b_on_a.verify_membership( + prefix_on_b, + &msg.proof_client_state_of_a_on_b, + consensus_state_of_b_on_a.root(), + Path::ClientState(ClientStatePath::new(vars.client_id_on_b().clone())), + msg.client_state_of_a_on_b.to_vec(), + )?; let expected_consensus_state_of_a_on_b = ctx_a.host_consensus_state(&msg.consensus_height_of_a_on_b)?; @@ -129,21 +123,19 @@ where msg.consensus_height_of_a_on_b.revision_height(), ); - client_state_of_b_on_a - .verify_membership( - prefix_on_b, - &msg.proof_consensus_state_of_a_on_b, - consensus_state_of_b_on_a.root(), - Path::ClientConsensusState(client_cons_state_path_on_b), - stored_consensus_state_of_a_on_b.to_vec(), - ) - .map_err(ConnectionError::FailedToVerifyConsensusState)?; + client_state_of_b_on_a.verify_membership( + prefix_on_b, + &msg.proof_consensus_state_of_a_on_b, + consensus_state_of_b_on_a.root(), + Path::ClientConsensusState(client_cons_state_path_on_b), + stored_consensus_state_of_a_on_b.to_vec(), + )?; } Ok(()) } -pub fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenAck) -> Result<(), HandlerError> +pub fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenAck) -> Result<(), ConnectionError> where Ctx: ExecutionContext, { @@ -155,7 +147,7 @@ fn execute_impl( ctx_a: &mut Ctx, msg: MsgConnectionOpenAck, vars: LocalVars, -) -> Result<(), HandlerError> +) -> Result<(), ConnectionError> where Ctx: ExecutionContext, { @@ -193,7 +185,7 @@ struct LocalVars { } impl LocalVars { - fn new(ctx_a: &Ctx, msg: &MsgConnectionOpenAck) -> Result + fn new(ctx_a: &Ctx, msg: &MsgConnectionOpenAck) -> Result where Ctx: ValidationContext, { diff --git a/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs b/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs index 414b01006..ba934493d 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs @@ -5,7 +5,6 @@ use ibc_core_connection_types::error::ConnectionError; use ibc_core_connection_types::events::OpenConfirm; use ibc_core_connection_types::msgs::MsgConnectionOpenConfirm; use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::{ClientId, ConnectionId}; use ibc_core_host::types::path::{ClientConsensusStatePath, ConnectionPath, Path}; @@ -13,7 +12,7 @@ use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_primitives::prelude::*; use ibc_primitives::proto::Protobuf; -pub fn validate(ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm) -> Result<(), HandlerError> +pub fn validate(ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm) -> Result<(), ConnectionError> where Ctx: ValidationContext, { @@ -25,7 +24,7 @@ fn validate_impl( ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm, vars: &LocalVars, -) -> Result<(), HandlerError> +) -> Result<(), ConnectionError> where Ctx: ValidationContext, { @@ -74,21 +73,19 @@ where conn_end_on_b.delay_period(), )?; - client_state_of_a_on_b - .verify_membership( - prefix_on_a, - &msg.proof_conn_end_on_a, - consensus_state_of_a_on_b.root(), - Path::Connection(ConnectionPath::new(conn_id_on_a)), - expected_conn_end_on_a.encode_vec(), - ) - .map_err(ConnectionError::FailedToVerifyConnectionState)?; + client_state_of_a_on_b.verify_membership( + prefix_on_a, + &msg.proof_conn_end_on_a, + consensus_state_of_a_on_b.root(), + Path::Connection(ConnectionPath::new(conn_id_on_a)), + expected_conn_end_on_a.encode_vec(), + )?; } Ok(()) } -pub fn execute(ctx_b: &mut Ctx, msg: &MsgConnectionOpenConfirm) -> Result<(), HandlerError> +pub fn execute(ctx_b: &mut Ctx, msg: &MsgConnectionOpenConfirm) -> Result<(), ConnectionError> where Ctx: ExecutionContext, { @@ -100,7 +97,7 @@ fn execute_impl( ctx_b: &mut Ctx, msg: &MsgConnectionOpenConfirm, vars: LocalVars, -) -> Result<(), HandlerError> +) -> Result<(), ConnectionError> where Ctx: ExecutionContext, { @@ -137,7 +134,7 @@ struct LocalVars { } impl LocalVars { - fn new(ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm) -> Result + fn new(ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm) -> Result where Ctx: ValidationContext, { diff --git a/ibc-core/ics03-connection/src/handler/conn_open_init.rs b/ibc-core/ics03-connection/src/handler/conn_open_init.rs index 9a42ec556..267603a7f 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_init.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_init.rs @@ -1,16 +1,16 @@ //! Protocol logic specific to ICS3 messages of type `MsgConnectionOpenInit`. use ibc_core_client::context::prelude::*; +use ibc_core_connection_types::error::ConnectionError; use ibc_core_connection_types::events::OpenInit; use ibc_core_connection_types::msgs::MsgConnectionOpenInit; use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::ConnectionId; use ibc_core_host::types::path::{ClientConnectionPath, ConnectionPath}; use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_primitives::prelude::*; -pub fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenInit) -> Result<(), HandlerError> +pub fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenInit) -> Result<(), ConnectionError> where Ctx: ValidationContext, { @@ -32,7 +32,7 @@ where Ok(()) } -pub fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenInit) -> Result<(), HandlerError> +pub fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenInit) -> Result<(), ConnectionError> where Ctx: ExecutionContext, { diff --git a/ibc-core/ics03-connection/src/handler/conn_open_try.rs b/ibc-core/ics03-connection/src/handler/conn_open_try.rs index 93a963643..2b47e488d 100644 --- a/ibc-core/ics03-connection/src/handler/conn_open_try.rs +++ b/ibc-core/ics03-connection/src/handler/conn_open_try.rs @@ -5,7 +5,6 @@ use ibc_core_connection_types::error::ConnectionError; use ibc_core_connection_types::events::OpenTry; use ibc_core_connection_types::msgs::MsgConnectionOpenTry; use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::{ClientId, ConnectionId}; use ibc_core_host::types::path::{ @@ -18,7 +17,7 @@ use ibc_primitives::ToVec; use crate::handler::{pack_host_consensus_state, unpack_host_client_state}; -pub fn validate(ctx_b: &Ctx, msg: MsgConnectionOpenTry) -> Result<(), HandlerError> +pub fn validate(ctx_b: &Ctx, msg: MsgConnectionOpenTry) -> Result<(), ConnectionError> where Ctx: ValidationContext, >::Error: Into, @@ -31,7 +30,7 @@ fn validate_impl( ctx_b: &Ctx, msg: &MsgConnectionOpenTry, vars: &LocalVars, -) -> Result<(), HandlerError> +) -> Result<(), ConnectionError> where Ctx: ValidationContext, >::Error: Into, @@ -54,8 +53,7 @@ where return Err(ConnectionError::InsufficientConsensusHeight { target_height: msg.consensus_height_of_b_on_a, current_height: host_height, - } - .into()); + }); } let client_id_on_a = msg.counterparty.client_id(); @@ -92,26 +90,22 @@ where msg.delay_period, )?; - client_state_of_a_on_b - .verify_membership( - prefix_on_a, - &msg.proof_conn_end_on_a, - consensus_state_of_a_on_b.root(), - Path::Connection(ConnectionPath::new(&vars.conn_id_on_a)), - expected_conn_end_on_a.encode_vec(), - ) - .map_err(ConnectionError::FailedToVerifyConnectionState)?; - } - - client_state_of_a_on_b - .verify_membership( + client_state_of_a_on_b.verify_membership( prefix_on_a, - &msg.proof_client_state_of_b_on_a, + &msg.proof_conn_end_on_a, consensus_state_of_a_on_b.root(), - Path::ClientState(ClientStatePath::new(client_id_on_a.clone())), - msg.client_state_of_b_on_a.to_vec(), - ) - .map_err(ConnectionError::FailedToVerifyClientState)?; + Path::Connection(ConnectionPath::new(&vars.conn_id_on_a)), + expected_conn_end_on_a.encode_vec(), + )?; + } + + client_state_of_a_on_b.verify_membership( + prefix_on_a, + &msg.proof_client_state_of_b_on_a, + consensus_state_of_a_on_b.root(), + Path::ClientState(ClientStatePath::new(client_id_on_a.clone())), + msg.client_state_of_b_on_a.to_vec(), + )?; let expected_consensus_state_of_b_on_a = ctx_b.host_consensus_state(&msg.consensus_height_of_b_on_a)?; @@ -125,21 +119,19 @@ where msg.consensus_height_of_b_on_a.revision_height(), ); - client_state_of_a_on_b - .verify_membership( - prefix_on_a, - &msg.proof_consensus_state_of_b_on_a, - consensus_state_of_a_on_b.root(), - Path::ClientConsensusState(client_cons_state_path_on_a), - stored_consensus_state_of_b_on_a.to_vec(), - ) - .map_err(ConnectionError::FailedToVerifyConsensusState)?; + client_state_of_a_on_b.verify_membership( + prefix_on_a, + &msg.proof_consensus_state_of_b_on_a, + consensus_state_of_a_on_b.root(), + Path::ClientConsensusState(client_cons_state_path_on_a), + stored_consensus_state_of_b_on_a.to_vec(), + )?; } Ok(()) } -pub fn execute(ctx_b: &mut Ctx, msg: MsgConnectionOpenTry) -> Result<(), HandlerError> +pub fn execute(ctx_b: &mut Ctx, msg: MsgConnectionOpenTry) -> Result<(), ConnectionError> where Ctx: ExecutionContext, { @@ -151,7 +143,7 @@ fn execute_impl( ctx_b: &mut Ctx, msg: MsgConnectionOpenTry, vars: LocalVars, -) -> Result<(), HandlerError> +) -> Result<(), ConnectionError> where Ctx: ExecutionContext, { @@ -188,7 +180,7 @@ struct LocalVars { } impl LocalVars { - fn new(ctx_b: &Ctx, msg: &MsgConnectionOpenTry) -> Result + fn new(ctx_b: &Ctx, msg: &MsgConnectionOpenTry) -> Result where Ctx: ValidationContext, { diff --git a/ibc-core/ics03-connection/src/handler/mod.rs b/ibc-core/ics03-connection/src/handler/mod.rs index 8026db244..791d1c778 100644 --- a/ibc-core/ics03-connection/src/handler/mod.rs +++ b/ibc-core/ics03-connection/src/handler/mod.rs @@ -1,5 +1,5 @@ use ibc_core_client::types::error::ClientError; -use ibc_core_handler_types::error::HandlerError; +use ibc_core_connection_types::error::ConnectionError; #[cfg(feature = "wasm-client")] use ibc_core_host::types::error::DecodingError; use ibc_core_host::types::identifiers::ClientId; @@ -18,7 +18,7 @@ pub mod conn_open_try; pub(crate) fn unpack_host_client_state( value: Any, host_client_id_at_counterparty: &ClientId, -) -> Result +) -> Result where CS: TryFrom, >::Error: Into, @@ -26,15 +26,9 @@ where #[cfg(feature = "wasm-client")] if host_client_id_at_counterparty.is_wasm_client_id() { use ibc_client_wasm_types::client_state::ClientState as WasmClientState; - use ibc_core_connection_types::error::ConnectionError; - use ibc_primitives::prelude::ToString; use prost::Message; - let wasm_client_state = WasmClientState::try_from(value).map_err(|e| { - HandlerError::Connection(ConnectionError::InvalidClientState { - description: e.to_string(), - }) - })?; + let wasm_client_state = WasmClientState::try_from(value)?; let any_client_state = ::decode(wasm_client_state.data.as_slice()) .map_err(|e| ConnectionError::Decoding(DecodingError::Prost(e)))?; diff --git a/ibc-core/ics03-connection/types/src/connection.rs b/ibc-core/ics03-connection/types/src/connection.rs index 2ce46ff52..fe4446de5 100644 --- a/ibc-core/ics03-connection/types/src/connection.rs +++ b/ibc-core/ics03-connection/types/src/connection.rs @@ -259,7 +259,7 @@ impl ConnectionEnd { // + Init: contains the set of compatible versions, // + TryOpen/Open: contains the single version chosen by the handshake protocol. if state != State::Init && versions.len() != 1 { - return Err(ConnectionError::InvalidStateForConnectionEndInit); + return Err(ConnectionError::InvalidState { description: "invalid state for initializing new ConnectionEnd; expected `Init` connection state and a single version".to_string() }); } Ok(Self { diff --git a/ibc-core/ics03-connection/types/src/error.rs b/ibc-core/ics03-connection/types/src/error.rs index 96febd06f..ca6362488 100644 --- a/ibc-core/ics03-connection/types/src/error.rs +++ b/ibc-core/ics03-connection/types/src/error.rs @@ -3,39 +3,30 @@ use displaydoc::Display; use ibc_core_client_types::error::ClientError; use ibc_core_client_types::Height; -use ibc_core_host_types::error::{DecodingError, IdentifierError}; -use ibc_core_host_types::identifiers::ConnectionId; +use ibc_core_host_types::error::{DecodingError, HostError, IdentifierError}; use ibc_primitives::prelude::*; use ibc_primitives::{Timestamp, TimestampError}; -use crate::version::Version; - #[derive(Debug, Display)] pub enum ConnectionError { + /// client error: `{0}` + Client(ClientError), /// decoding error: `{0}` Decoding(DecodingError), - /// invalid state for initializing new ConnectionEnd; expected `Init` connection state and a single version - InvalidStateForConnectionEndInit, + /// host error: `{0}` + Host(HostError), /// invalid counterparty InvalidCounterparty, - /// invalid client state: `{description}` - InvalidClientState { description: String }, + /// invalid connection state: `{description}` + InvalidState { description: String }, /// mismatched connection states: expected `{expected}`, actual `{actual}` MismatchedConnectionStates { expected: String, actual: String }, - /// empty supported features - EmptyFeatures, - /// unsupported version \"`{0}`\" - UnsupportedVersion(Version), - /// unsupported feature \"`{0}`\" - UnsupportedFeature(String), + /// missing supported features + MissingFeatures, /// missing common version MissingCommonVersion, - /// missing common features - MissingCommonFeatures, /// missing counterparty MissingCounterparty, - /// missing connection `{0}` - MissingConnection(ConnectionId), /// insufficient consensus height `{current_height}` for host chain; needs to meet counterparty's height `{target_height}` InsufficientConsensusHeight { target_height: Height, @@ -51,12 +42,6 @@ pub enum ConnectionError { current_host_time: Timestamp, earliest_valid_time: Timestamp, }, - /// failed to verify connection state: `{0}` - FailedToVerifyConnectionState(ClientError), - /// failed to verify consensus state: `{0}` - FailedToVerifyConsensusState(ClientError), - /// failed to verify client state: `{0}` - FailedToVerifyClientState(ClientError), /// overflowed timestamp: `{0}` OverflowedTimestamp(TimestampError), } @@ -73,13 +58,25 @@ impl From for ConnectionError { } } +impl From for ConnectionError { + fn from(e: ClientError) -> Self { + Self::Client(e) + } +} + +impl From for ConnectionError { + fn from(e: HostError) -> Self { + Self::Host(e) + } +} + #[cfg(feature = "std")] impl std::error::Error for ConnectionError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { - Self::FailedToVerifyConnectionState(e) - | Self::FailedToVerifyConsensusState(e) - | Self::FailedToVerifyClientState(e) => Some(e), + Self::Host(e) => Some(e), + Self::Client(e) => Some(e), + Self::Decoding(e) => Some(e), _ => None, } } diff --git a/ibc-core/ics03-connection/types/src/version.rs b/ibc-core/ics03-connection/types/src/version.rs index 5a2061edf..3f2412876 100644 --- a/ibc-core/ics03-connection/types/src/version.rs +++ b/ibc-core/ics03-connection/types/src/version.rs @@ -43,7 +43,7 @@ impl Version { let maybe_supported_version = find_supported_version(self, supported_versions)?; if self.features.is_empty() { - return Err(ConnectionError::EmptyFeatures); + return Err(ConnectionError::MissingFeatures); } for feature in self.features.iter() { @@ -55,7 +55,7 @@ impl Version { /// Checks whether the given feature is supported in this version pub fn verify_feature_supported(&self, feature: String) -> Result<(), ConnectionError> { if !self.features.contains(&feature) { - return Err(ConnectionError::UnsupportedFeature(feature)); + return Err(ConnectionError::MissingFeatures); } Ok(()) } @@ -82,7 +82,7 @@ impl TryFrom for Version { } for feature in value.features.iter() { if feature.trim().is_empty() { - return Err(ConnectionError::EmptyFeatures); + return Err(ConnectionError::MissingFeatures); } } Ok(Version { @@ -156,7 +156,7 @@ fn find_supported_version( supported_versions .iter() .find(|sv| sv.identifier == version.identifier) - .ok_or(ConnectionError::UnsupportedVersion(version.clone())) + .ok_or(ConnectionError::MissingCommonVersion) .cloned() } @@ -175,7 +175,7 @@ fn get_feature_set_intersection( .collect(); if feature_set_intersection.is_empty() { - return Err(ConnectionError::MissingCommonFeatures); + return Err(ConnectionError::MissingFeatures); } Ok(feature_set_intersection) diff --git a/ibc-core/ics04-channel/src/handler/acknowledgement.rs b/ibc-core/ics04-channel/src/handler/acknowledgement.rs index c0d216ae0..8d4ee4e1c 100644 --- a/ibc-core/ics04-channel/src/handler/acknowledgement.rs +++ b/ibc-core/ics04-channel/src/handler/acknowledgement.rs @@ -6,7 +6,6 @@ use ibc_core_channel_types::msgs::MsgAcknowledgement; use ibc_core_client::context::prelude::*; use ibc_core_connection::delay::verify_conn_delay_passed; use ibc_core_connection::types::State as ConnectionState; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ AckPath, ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, SeqAckPath, @@ -19,22 +18,20 @@ pub fn acknowledgement_packet_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgAcknowledgement, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ValCtx: ValidationContext, { validate(ctx_a, &msg)?; - module - .on_acknowledgement_packet_validate(&msg.packet, &msg.acknowledgement, &msg.signer) - .map_err(HandlerError::Channel) + module.on_acknowledgement_packet_validate(&msg.packet, &msg.acknowledgement, &msg.signer) } pub fn acknowledgement_packet_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgAcknowledgement, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ExecCtx: ExecutionContext, { @@ -103,7 +100,7 @@ where Ok(()) } -fn validate(ctx_a: &Ctx, msg: &MsgAcknowledgement) -> Result<(), HandlerError> +fn validate(ctx_a: &Ctx, msg: &MsgAcknowledgement) -> Result<(), ChannelError> where Ctx: ValidationContext, { @@ -149,8 +146,7 @@ where return Err(ChannelError::MismatchedPacketCommitments { actual: commitment_on_a, expected: expected_commitment_on_a, - } - .into()); + }); } if let Order::Ordered = chan_end_on_a.ordering { @@ -160,8 +156,7 @@ where return Err(ChannelError::MismatchedPacketSequences { actual: packet.seq_on_a, expected: next_seq_ack, - } - .into()); + }); } } @@ -193,15 +188,13 @@ where verify_conn_delay_passed(ctx_a, msg.proof_height_on_b, &conn_end_on_a)?; // Verify the proof for the packet against the chain store. - client_state_of_b_on_a - .verify_membership( - conn_end_on_a.counterparty().prefix(), - &msg.proof_acked_on_b, - consensus_state_of_b_on_a.root(), - Path::Ack(ack_path_on_b), - ack_commitment.into_vec(), - ) - .map_err(ChannelError::FailedVerification)?; + client_state_of_b_on_a.verify_membership( + conn_end_on_a.counterparty().prefix(), + &msg.proof_acked_on_b, + consensus_state_of_b_on_a.root(), + Path::Ack(ack_path_on_b), + ack_commitment.into_vec(), + )?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs index 687a15539..56db78a68 100644 --- a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs @@ -7,7 +7,6 @@ use ibc_core_channel_types::msgs::MsgChannelCloseConfirm; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; use ibc_core_connection_types::error::ConnectionError; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; use ibc_core_host::{ExecutionContext, ValidationContext}; @@ -19,7 +18,7 @@ pub fn chan_close_confirm_validate( ctx_b: &ValCtx, module: &dyn Module, msg: MsgChannelCloseConfirm, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ValCtx: ValidationContext, { @@ -34,7 +33,7 @@ pub fn chan_close_confirm_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelCloseConfirm, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ExecCtx: ExecutionContext, { @@ -62,7 +61,7 @@ where .counterparty() .channel_id .clone() - .ok_or(HandlerError::Channel(ChannelError::MissingCounterparty))?; + .ok_or(ChannelError::MissingCounterparty)?; let conn_id_on_b = chan_end_on_b.connection_hops[0].clone(); IbcEvent::CloseConfirmChannel(CloseConfirm::new( @@ -88,7 +87,7 @@ where Ok(()) } -fn validate(ctx_b: &Ctx, msg: &MsgChannelCloseConfirm) -> Result<(), HandlerError> +fn validate(ctx_b: &Ctx, msg: &MsgChannelCloseConfirm) -> Result<(), ChannelError> where Ctx: ValidationContext, { @@ -148,15 +147,13 @@ where // Verify the proof for the channel state against the expected channel end. // A counterparty channel id of None in not possible, and is checked by validate_basic in msg. - client_state_of_a_on_b - .verify_membership( - prefix_on_a, - &msg.proof_chan_end_on_a, - consensus_state_of_a_on_b.root(), - Path::ChannelEnd(chan_end_path_on_a), - expected_chan_end_on_a.encode_vec(), - ) - .map_err(ChannelError::FailedVerification)?; + client_state_of_a_on_b.verify_membership( + prefix_on_a, + &msg.proof_chan_end_on_a, + consensus_state_of_a_on_b.root(), + Path::ChannelEnd(chan_end_path_on_a), + expected_chan_end_on_a.encode_vec(), + )?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_close_init.rs b/ibc-core/ics04-channel/src/handler/chan_close_init.rs index 0f0cd557d..6a0a6e189 100644 --- a/ibc-core/ics04-channel/src/handler/chan_close_init.rs +++ b/ibc-core/ics04-channel/src/handler/chan_close_init.rs @@ -5,7 +5,6 @@ use ibc_core_channel_types::events::CloseInit; use ibc_core_channel_types::msgs::MsgChannelCloseInit; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::ChannelEndPath; use ibc_core_host::{ExecutionContext, ValidationContext}; @@ -16,7 +15,7 @@ pub fn chan_close_init_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgChannelCloseInit, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ValCtx: ValidationContext, { @@ -31,7 +30,7 @@ pub fn chan_close_init_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelCloseInit, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ExecCtx: ExecutionContext, { @@ -60,7 +59,7 @@ where .counterparty() .channel_id .clone() - .ok_or(HandlerError::Channel(ChannelError::MissingCounterparty))?; + .ok_or(ChannelError::MissingCounterparty)?; let conn_id_on_a = chan_end_on_a.connection_hops[0].clone(); IbcEvent::CloseInitChannel(CloseInit::new( @@ -86,7 +85,7 @@ where Ok(()) } -fn validate(ctx_a: &Ctx, msg: &MsgChannelCloseInit) -> Result<(), HandlerError> +fn validate(ctx_a: &Ctx, msg: &MsgChannelCloseInit) -> Result<(), ChannelError> where Ctx: ValidationContext, { diff --git a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs index ebd972497..5e07b8298 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs @@ -6,7 +6,6 @@ use ibc_core_channel_types::msgs::MsgChannelOpenAck; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; use ibc_core_connection_types::error::ConnectionError; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; use ibc_core_host::{ExecutionContext, ValidationContext}; @@ -18,7 +17,7 @@ pub fn chan_open_ack_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgChannelOpenAck, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ValCtx: ValidationContext, { @@ -33,7 +32,7 @@ pub fn chan_open_ack_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenAck, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ExecCtx: ExecutionContext, { @@ -87,7 +86,7 @@ where Ok(()) } -fn validate(ctx_a: &Ctx, msg: &MsgChannelOpenAck) -> Result<(), HandlerError> +fn validate(ctx_a: &Ctx, msg: &MsgChannelOpenAck) -> Result<(), ChannelError> where Ctx: ValidationContext, { @@ -145,15 +144,13 @@ where // Verify the proof for the channel state against the expected channel end. // A counterparty channel id of None in not possible, and is checked by validate_basic in msg. - client_state_of_b_on_a - .verify_membership( - prefix_on_b, - &msg.proof_chan_end_on_b, - consensus_state_of_b_on_a.root(), - Path::ChannelEnd(chan_end_path_on_b), - expected_chan_end_on_b.encode_vec(), - ) - .map_err(ChannelError::FailedVerification)?; + client_state_of_b_on_a.verify_membership( + prefix_on_b, + &msg.proof_chan_end_on_b, + consensus_state_of_b_on_a.root(), + Path::ChannelEnd(chan_end_path_on_b), + expected_chan_end_on_b.encode_vec(), + )?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs index 2038b5a0d..df3fa51db 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs @@ -7,7 +7,6 @@ use ibc_core_channel_types::msgs::MsgChannelOpenConfirm; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; use ibc_core_connection_types::error::ConnectionError; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; use ibc_core_host::{ExecutionContext, ValidationContext}; @@ -19,7 +18,7 @@ pub fn chan_open_confirm_validate( ctx_b: &ValCtx, module: &dyn Module, msg: MsgChannelOpenConfirm, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ValCtx: ValidationContext, { @@ -34,7 +33,7 @@ pub fn chan_open_confirm_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenConfirm, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ExecCtx: ExecutionContext, { @@ -63,7 +62,7 @@ where .counterparty() .channel_id .clone() - .ok_or(HandlerError::Channel(ChannelError::MissingCounterparty))?; + .ok_or(ChannelError::MissingCounterparty)?; let core_event = IbcEvent::OpenConfirmChannel(OpenConfirm::new( msg.port_id_on_b.clone(), @@ -87,7 +86,7 @@ where Ok(()) } -fn validate(ctx_b: &Ctx, msg: &MsgChannelOpenConfirm) -> Result<(), HandlerError> +fn validate(ctx_b: &Ctx, msg: &MsgChannelOpenConfirm) -> Result<(), ChannelError> where Ctx: ValidationContext, { @@ -148,15 +147,13 @@ where // Verify the proof for the channel state against the expected channel end. // A counterparty channel id of None in not possible, and is checked in msg. - client_state_of_a_on_b - .verify_membership( - prefix_on_a, - &msg.proof_chan_end_on_a, - consensus_state_of_a_on_b.root(), - Path::ChannelEnd(chan_end_path_on_a), - expected_chan_end_on_a.encode_vec(), - ) - .map_err(ChannelError::FailedVerification)?; + client_state_of_a_on_b.verify_membership( + prefix_on_a, + &msg.proof_chan_end_on_a, + consensus_state_of_a_on_b.root(), + Path::ChannelEnd(chan_end_path_on_a), + expected_chan_end_on_a.encode_vec(), + )?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/chan_open_init.rs b/ibc-core/ics04-channel/src/handler/chan_open_init.rs index b952e7d1a..fe931efa0 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_init.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_init.rs @@ -1,10 +1,10 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelOpenInit`. use ibc_core_channel_types::channel::{ChannelEnd, Counterparty, State}; +use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::events::OpenInit; use ibc_core_channel_types::msgs::MsgChannelOpenInit; use ibc_core_client::context::prelude::*; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::ChannelId; use ibc_core_host::types::path::{ChannelEndPath, SeqAckPath, SeqRecvPath, SeqSendPath}; @@ -16,7 +16,7 @@ pub fn chan_open_init_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgChannelOpenInit, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ValCtx: ValidationContext, { @@ -39,7 +39,7 @@ pub fn chan_open_init_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenInit, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ExecCtx: ExecutionContext, { @@ -107,7 +107,7 @@ where Ok(()) } -fn validate(ctx_a: &Ctx, msg: &MsgChannelOpenInit) -> Result<(), HandlerError> +fn validate(ctx_a: &Ctx, msg: &MsgChannelOpenInit) -> Result<(), ChannelError> where Ctx: ValidationContext, { diff --git a/ibc-core/ics04-channel/src/handler/chan_open_try.rs b/ibc-core/ics04-channel/src/handler/chan_open_try.rs index 3f7f944f7..d01e646c6 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_try.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_try.rs @@ -7,7 +7,6 @@ use ibc_core_channel_types::msgs::MsgChannelOpenTry; use ibc_core_client::context::prelude::*; use ibc_core_connection::types::State as ConnectionState; use ibc_core_connection_types::error::ConnectionError; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::ChannelId; use ibc_core_host::types::path::{ @@ -22,7 +21,7 @@ pub fn chan_open_try_validate( ctx_b: &ValCtx, module: &dyn Module, msg: MsgChannelOpenTry, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ValCtx: ValidationContext, { @@ -46,7 +45,7 @@ pub fn chan_open_try_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenTry, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ExecCtx: ExecutionContext, { @@ -116,7 +115,7 @@ where Ok(()) } -fn validate(ctx_b: &Ctx, msg: &MsgChannelOpenTry) -> Result<(), HandlerError> +fn validate(ctx_b: &Ctx, msg: &MsgChannelOpenTry) -> Result<(), ChannelError> where Ctx: ValidationContext, { @@ -170,15 +169,13 @@ where // Verify the proof for the channel state against the expected channel end. // A counterparty channel id of None in not possible, and is checked by validate_basic in msg. - client_state_of_a_on_b - .verify_membership( - prefix_on_a, - &msg.proof_chan_end_on_a, - consensus_state_of_a_on_b.root(), - Path::ChannelEnd(chan_end_path_on_a), - expected_chan_end_on_a.encode_vec(), - ) - .map_err(ChannelError::FailedVerification)?; + client_state_of_a_on_b.verify_membership( + prefix_on_a, + &msg.proof_chan_end_on_a, + consensus_state_of_a_on_b.root(), + Path::ChannelEnd(chan_end_path_on_a), + expected_chan_end_on_a.encode_vec(), + )?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/recv_packet.rs b/ibc-core/ics04-channel/src/handler/recv_packet.rs index f4906d6eb..c12b01885 100644 --- a/ibc-core/ics04-channel/src/handler/recv_packet.rs +++ b/ibc-core/ics04-channel/src/handler/recv_packet.rs @@ -7,7 +7,6 @@ use ibc_core_channel_types::packet::Receipt; use ibc_core_client::context::prelude::*; use ibc_core_connection::delay::verify_conn_delay_passed; use ibc_core_connection::types::State as ConnectionState; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ AckPath, ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, ReceiptPath, @@ -17,7 +16,7 @@ use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_core_router::module::Module; use ibc_primitives::prelude::*; -pub fn recv_packet_validate(ctx_b: &ValCtx, msg: MsgRecvPacket) -> Result<(), HandlerError> +pub fn recv_packet_validate(ctx_b: &ValCtx, msg: MsgRecvPacket) -> Result<(), ChannelError> where ValCtx: ValidationContext, { @@ -32,7 +31,7 @@ pub fn recv_packet_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgRecvPacket, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ExecCtx: ExecutionContext, { @@ -136,7 +135,7 @@ where Ok(()) } -fn validate(ctx_b: &Ctx, msg: &MsgRecvPacket) -> Result<(), HandlerError> +fn validate(ctx_b: &Ctx, msg: &MsgRecvPacket) -> Result<(), ChannelError> where Ctx: ValidationContext, { @@ -165,8 +164,7 @@ where return Err(ChannelError::InsufficientPacketHeight { chain_height: latest_height, timeout_height: msg.packet.timeout_height_on_b, - } - .into()); + }); } let latest_timestamp = ctx_b.host_timestamp()?; @@ -175,7 +173,7 @@ where .timeout_timestamp_on_b .has_expired(&latest_timestamp) { - return Err(ChannelError::InsufficientPacketTimestamp.into()); + return Err(ChannelError::InsufficientPacketTimestamp); } // Verify proofs @@ -213,15 +211,13 @@ where verify_conn_delay_passed(ctx_b, msg.proof_height_on_a, &conn_end_on_b)?; // Verify the proof for the packet against the chain store. - client_state_of_a_on_b - .verify_membership( - conn_end_on_b.counterparty().prefix(), - &msg.proof_commitment_on_a, - consensus_state_of_a_on_b.root(), - Path::Commitment(commitment_path_on_a), - expected_commitment_on_a.into_vec(), - ) - .map_err(ChannelError::FailedVerification)?; + client_state_of_a_on_b.verify_membership( + conn_end_on_b.counterparty().prefix(), + &msg.proof_commitment_on_a, + consensus_state_of_a_on_b.root(), + Path::Commitment(commitment_path_on_a), + expected_commitment_on_a.into_vec(), + )?; } match chan_end_on_b.ordering { @@ -233,8 +229,7 @@ where return Err(ChannelError::MismatchedPacketSequences { actual: msg.packet.seq_on_a, expected: next_seq_recv, - } - .into()); + }); } if msg.packet.seq_on_a == next_seq_recv { @@ -254,24 +249,24 @@ where validate_write_acknowledgement(ctx_b, msg)?; } Order::None => { - return Err(HandlerError::Channel(ChannelError::InvalidState { + return Err(ChannelError::InvalidState { expected: "Channel ordering to not be None".to_string(), actual: chan_end_on_b.ordering.to_string(), - })) + }) } } Ok(()) } -fn validate_write_acknowledgement(ctx_b: &Ctx, msg: &MsgRecvPacket) -> Result<(), HandlerError> +fn validate_write_acknowledgement(ctx_b: &Ctx, msg: &MsgRecvPacket) -> Result<(), ChannelError> where Ctx: ValidationContext, { let packet = msg.packet.clone(); let ack_path_on_b = AckPath::new(&packet.port_id_on_b, &packet.chan_id_on_b, packet.seq_on_a); if ctx_b.get_packet_acknowledgement(&ack_path_on_b).is_ok() { - return Err(ChannelError::DuplicateAcknowledgment(msg.packet.seq_on_a).into()); + return Err(ChannelError::DuplicateAcknowledgment(msg.packet.seq_on_a)); } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/send_packet.rs b/ibc-core/ics04-channel/src/handler/send_packet.rs index cd567ffdf..e4d9a4ba1 100644 --- a/ibc-core/ics04-channel/src/handler/send_packet.rs +++ b/ibc-core/ics04-channel/src/handler/send_packet.rs @@ -4,7 +4,6 @@ use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::events::SendPacket; use ibc_core_channel_types::packet::Packet; use ibc_core_client::context::prelude::*; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, SeqSendPath, @@ -19,7 +18,7 @@ use crate::context::{SendPacketExecutionContext, SendPacketValidationContext}; pub fn send_packet( ctx_a: &mut impl SendPacketExecutionContext, packet: Packet, -) -> Result<(), HandlerError> { +) -> Result<(), ChannelError> { send_packet_validate(ctx_a, &packet)?; send_packet_execute(ctx_a, packet) } @@ -28,9 +27,9 @@ pub fn send_packet( pub fn send_packet_validate( ctx_a: &impl SendPacketValidationContext, packet: &Packet, -) -> Result<(), HandlerError> { +) -> Result<(), ChannelError> { if !packet.timeout_height_on_b.is_set() && !packet.timeout_timestamp_on_b.is_set() { - return Err(HandlerError::Channel(ChannelError::MissingTimeout)); + return Err(ChannelError::MissingTimeout); } let chan_end_path_on_a = ChannelEndPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); @@ -67,8 +66,7 @@ pub fn send_packet_validate( return Err(ChannelError::InsufficientPacketHeight { chain_height: latest_height_on_a, timeout_height: packet.timeout_height_on_b, - } - .into()); + }); } let client_cons_state_path_on_a = ClientConsensusStatePath::new( @@ -81,7 +79,7 @@ pub fn send_packet_validate( let latest_timestamp = consensus_state_of_b_on_a.timestamp(); let packet_timestamp = packet.timeout_timestamp_on_b; if packet_timestamp.has_expired(&latest_timestamp) { - return Err(ChannelError::InsufficientPacketTimestamp.into()); + return Err(ChannelError::InsufficientPacketTimestamp); } let seq_send_path_on_a = SeqSendPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); @@ -91,8 +89,7 @@ pub fn send_packet_validate( return Err(ChannelError::MismatchedPacketSequences { actual: packet.seq_on_a, expected: next_seq_send_on_a, - } - .into()); + }); } Ok(()) @@ -104,7 +101,7 @@ pub fn send_packet_validate( pub fn send_packet_execute( ctx_a: &mut impl SendPacketExecutionContext, packet: Packet, -) -> Result<(), HandlerError> { +) -> Result<(), ChannelError> { { let seq_send_path_on_a = SeqSendPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); let next_seq_send_on_a = ctx_a.get_next_sequence_send(&seq_send_path_on_a)?; diff --git a/ibc-core/ics04-channel/src/handler/timeout.rs b/ibc-core/ics04-channel/src/handler/timeout.rs index 7e2d4d113..176fc3fa9 100644 --- a/ibc-core/ics04-channel/src/handler/timeout.rs +++ b/ibc-core/ics04-channel/src/handler/timeout.rs @@ -5,7 +5,6 @@ use ibc_core_channel_types::events::{ChannelClosed, TimeoutPacket}; use ibc_core_channel_types::msgs::{MsgTimeout, MsgTimeoutOnClose}; use ibc_core_client::context::prelude::*; use ibc_core_connection::delay::verify_conn_delay_passed; -use ibc_core_handler_types::error::HandlerError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, ReceiptPath, SeqRecvPath, @@ -25,7 +24,7 @@ pub fn timeout_packet_validate( ctx_a: &ValCtx, module: &dyn Module, timeout_msg_type: TimeoutMsgType, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ValCtx: ValidationContext, { @@ -39,16 +38,14 @@ where TimeoutMsgType::TimeoutOnClose(msg) => (msg.packet, msg.signer), }; - module - .on_timeout_packet_validate(&packet, &signer) - .map_err(HandlerError::Channel) + module.on_timeout_packet_validate(&packet, &signer) } pub fn timeout_packet_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, timeout_msg_type: TimeoutMsgType, -) -> Result<(), HandlerError> +) -> Result<(), ChannelError> where ExecCtx: ExecutionContext, { @@ -126,7 +123,7 @@ where Ok(()) } -fn validate(ctx_a: &Ctx, msg: &MsgTimeout) -> Result<(), HandlerError> +fn validate(ctx_a: &Ctx, msg: &MsgTimeout) -> Result<(), ChannelError> where Ctx: ValidationContext, { @@ -173,8 +170,7 @@ where return Err(ChannelError::MismatchedPacketCommitments { expected: expected_commitment_on_a, actual: commitment_on_a, - } - .into()); + }); } // Verify proofs @@ -205,8 +201,7 @@ where chain_height: msg.proof_height_on_b, timeout_timestamp: msg.packet.timeout_timestamp_on_b, chain_timestamp: timestamp_of_b, - } - .into()); + }); } verify_conn_delay_passed(ctx_a, msg.proof_height_on_b, &conn_end_on_a)?; @@ -217,8 +212,7 @@ where return Err(ChannelError::MismatchedPacketSequences { actual: msg.packet.seq_on_a, expected: msg.next_seq_recv_on_b, - } - .into()); + }); } let seq_recv_path_on_b = SeqRecvPath::new(&msg.packet.port_id_on_b, &msg.packet.chan_id_on_b); @@ -246,14 +240,14 @@ where ) } Order::None => { - return Err(HandlerError::Channel(ChannelError::InvalidState { + return Err(ChannelError::InvalidState { expected: "Channel ordering to not be None".to_string(), actual: chan_end_on_a.ordering.to_string(), - })) + }) } }; - next_seq_recv_verification_result.map_err(ChannelError::FailedVerification)?; + next_seq_recv_verification_result?; } Ok(()) diff --git a/ibc-core/ics04-channel/src/handler/timeout_on_close.rs b/ibc-core/ics04-channel/src/handler/timeout_on_close.rs index 079048c60..16cda09ae 100644 --- a/ibc-core/ics04-channel/src/handler/timeout_on_close.rs +++ b/ibc-core/ics04-channel/src/handler/timeout_on_close.rs @@ -5,7 +5,6 @@ use ibc_core_channel_types::msgs::MsgTimeoutOnClose; use ibc_core_client::context::prelude::*; use ibc_core_connection::delay::verify_conn_delay_passed; use ibc_core_connection::types::error::ConnectionError; -use ibc_core_handler_types::error::HandlerError; use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, ReceiptPath, SeqRecvPath, }; @@ -13,7 +12,7 @@ use ibc_core_host::ValidationContext; use ibc_primitives::prelude::*; use ibc_primitives::proto::Protobuf; -pub fn validate(ctx_a: &Ctx, msg: &MsgTimeoutOnClose) -> Result<(), HandlerError> +pub fn validate(ctx_a: &Ctx, msg: &MsgTimeoutOnClose) -> Result<(), ChannelError> where Ctx: ValidationContext, { @@ -54,8 +53,7 @@ where return Err(ChannelError::MismatchedPacketCommitments { expected: expected_commitment_on_a, actual: commitment_on_a, - } - .into()); + }); } let conn_id_on_a = chan_end_on_a.connection_hops()[0].clone(); @@ -107,15 +105,13 @@ where // Verify the proof for the channel state against the expected channel end. // A counterparty channel id of None in not possible, and is checked by validate_basic in msg. - client_state_of_b_on_a - .verify_membership( - prefix_on_b, - &msg.proof_close_on_b, - consensus_state_of_b_on_a.root(), - Path::ChannelEnd(chan_end_path_on_b), - expected_chan_end_on_b.encode_vec(), - ) - .map_err(ChannelError::FailedVerification)?; + client_state_of_b_on_a.verify_membership( + prefix_on_b, + &msg.proof_close_on_b, + consensus_state_of_b_on_a.root(), + Path::ChannelEnd(chan_end_path_on_b), + expected_chan_end_on_b.encode_vec(), + )?; verify_conn_delay_passed(ctx_a, msg.proof_height_on_b, &conn_end_on_a)?; @@ -125,8 +121,7 @@ where return Err(ChannelError::MismatchedPacketSequences { actual: packet.seq_on_a, expected: msg.next_seq_recv_on_b, - } - .into()); + }); } let seq_recv_path_on_b = SeqRecvPath::new(&packet.port_id_on_b, &packet.chan_id_on_b); @@ -154,14 +149,14 @@ where ) } Order::None => { - return Err(HandlerError::Channel(ChannelError::InvalidState { + return Err(ChannelError::InvalidState { expected: "Channel ordering to not be None".to_string(), actual: chan_end_on_a.ordering.to_string(), - })) + }) } }; - next_seq_recv_verification_result.map_err(ChannelError::FailedVerification)?; + next_seq_recv_verification_result?; }; Ok(()) diff --git a/ibc-core/ics04-channel/types/src/error.rs b/ibc-core/ics04-channel/types/src/error.rs index ca8a28a4a..24d58a9ec 100644 --- a/ibc-core/ics04-channel/types/src/error.rs +++ b/ibc-core/ics04-channel/types/src/error.rs @@ -3,7 +3,8 @@ use displaydoc::Display; use ibc_core_client_types::error::ClientError; use ibc_core_client_types::Height; -use ibc_core_host_types::error::{DecodingError, IdentifierError}; +use ibc_core_connection_types::error::ConnectionError; +use ibc_core_host_types::error::{DecodingError, HostError, IdentifierError}; use ibc_core_host_types::identifiers::Sequence; use ibc_primitives::prelude::*; use ibc_primitives::{Timestamp, TimestampError}; @@ -15,14 +16,18 @@ use crate::timeout::TimeoutTimestamp; use crate::Version; /// Errors that arise from the ICS04 Channel module -#[derive(Debug, Display)] +#[derive(Debug, Display, derive_more::From)] pub enum ChannelError { /// decoding error: `{0}` Decoding(DecodingError), + /// host error: `{0}` + Host(HostError), + /// client error: `{0}` + Client(ClientError), + /// connection error: `{0}` + Connection(ConnectionError), /// packet acknowledgment for sequence `{0}` already exists DuplicateAcknowledgment(Sequence), - /// failed verification: `{0}` - FailedVerification(ClientError), /// insufficient packet timeout height: should have `{timeout_height}` > `{chain_height}` InsufficientPacketHeight { chain_height: Height, @@ -68,6 +73,8 @@ pub enum ChannelError { UnexpectedChannelId, /// unsupported version: expected `{expected}`, actual `{actual}` UnsupportedVersion { expected: Version, actual: Version }, + /// application specific error: `{description}` + AppSpecific { description: String }, } impl From for ChannelError { @@ -76,24 +83,14 @@ impl From for ChannelError { } } -impl From for ChannelError { - fn from(e: DecodingError) -> Self { - Self::Decoding(e) - } -} - -impl From for ChannelError { - fn from(e: TimestampError) -> Self { - Self::InvalidTimeoutTimestamp(e) - } -} - #[cfg(feature = "std")] impl std::error::Error for ChannelError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { Self::Decoding(e) => Some(e), - Self::FailedVerification(e) => Some(e), + Self::Client(e) => Some(e), + Self::Connection(e) => Some(e), + Self::Host(e) => Some(e), Self::InvalidTimeoutTimestamp(e) => Some(e), _ => None, } diff --git a/ibc-core/ics25-handler/src/entrypoint.rs b/ibc-core/ics25-handler/src/entrypoint.rs index f3aa2323a..7a276398c 100644 --- a/ibc-core/ics25-handler/src/entrypoint.rs +++ b/ibc-core/ics25-handler/src/entrypoint.rs @@ -6,6 +6,7 @@ use ibc_core_channel::handler::{ chan_open_try_execute, chan_open_try_validate, recv_packet_execute, recv_packet_validate, timeout_packet_execute, timeout_packet_validate, TimeoutMsgType, }; +use ibc_core_channel::types::error::ChannelError; use ibc_core_channel::types::msgs::{ channel_msg_to_port_id, packet_msg_to_port_id, ChannelMsg, PacketMsg, }; @@ -58,14 +59,16 @@ where { match msg { MsgEnvelope::Client(msg) => match msg { - ClientMsg::CreateClient(msg) => create_client::validate(ctx, msg), - ClientMsg::UpdateClient(msg) => { - update_client::validate(ctx, MsgUpdateOrMisbehaviour::UpdateClient(msg)) - } - ClientMsg::Misbehaviour(msg) => { - update_client::validate(ctx, MsgUpdateOrMisbehaviour::Misbehaviour(msg)) - } - ClientMsg::UpgradeClient(msg) => upgrade_client::validate(ctx, msg), + ClientMsg::CreateClient(msg) => Ok(create_client::validate(ctx, msg)?), + ClientMsg::UpdateClient(msg) => Ok(update_client::validate( + ctx, + MsgUpdateOrMisbehaviour::UpdateClient(msg), + )?), + ClientMsg::Misbehaviour(msg) => Ok(update_client::validate( + ctx, + MsgUpdateOrMisbehaviour::Misbehaviour(msg), + )?), + ClientMsg::UpgradeClient(msg) => Ok(upgrade_client::validate(ctx, msg)?), ClientMsg::RecoverClient(_msg) => { // Recover client messages are not dispatched by ibc-rs as they can only be // authorized via a passing governance proposal @@ -73,53 +76,51 @@ where } }, MsgEnvelope::Connection(msg) => match msg { - ConnectionMsg::OpenInit(msg) => conn_open_init::validate(ctx, msg), - ConnectionMsg::OpenTry(msg) => conn_open_try::validate(ctx, msg), - ConnectionMsg::OpenAck(msg) => conn_open_ack::validate(ctx, msg), - ConnectionMsg::OpenConfirm(msg) => conn_open_confirm::validate(ctx, &msg), + ConnectionMsg::OpenInit(msg) => Ok(conn_open_init::validate(ctx, msg)?), + ConnectionMsg::OpenTry(msg) => Ok(conn_open_try::validate(ctx, msg)?), + ConnectionMsg::OpenAck(msg) => Ok(conn_open_ack::validate(ctx, msg)?), + ConnectionMsg::OpenConfirm(msg) => Ok(conn_open_confirm::validate(ctx, &msg)?), }, MsgEnvelope::Channel(msg) => { let port_id = channel_msg_to_port_id(&msg); - let module_id = router - .lookup_module(port_id) - .ok_or(HostError::missing_state(format!( - "failed to look up port {}", - port_id.clone() - )))?; + let module_id = router.lookup_module(port_id).ok_or(ChannelError::Host( + HostError::missing_state(format!("failed to look up port {}", port_id.clone())), + ))?; let module = router .get_route(&module_id) .ok_or(RouterError::MissingModule)?; match msg { - ChannelMsg::OpenInit(msg) => chan_open_init_validate(ctx, module, msg), - ChannelMsg::OpenTry(msg) => chan_open_try_validate(ctx, module, msg), - ChannelMsg::OpenAck(msg) => chan_open_ack_validate(ctx, module, msg), - ChannelMsg::OpenConfirm(msg) => chan_open_confirm_validate(ctx, module, msg), - ChannelMsg::CloseInit(msg) => chan_close_init_validate(ctx, module, msg), - ChannelMsg::CloseConfirm(msg) => chan_close_confirm_validate(ctx, module, msg), + ChannelMsg::OpenInit(msg) => Ok(chan_open_init_validate(ctx, module, msg)?), + ChannelMsg::OpenTry(msg) => Ok(chan_open_try_validate(ctx, module, msg)?), + ChannelMsg::OpenAck(msg) => Ok(chan_open_ack_validate(ctx, module, msg)?), + ChannelMsg::OpenConfirm(msg) => Ok(chan_open_confirm_validate(ctx, module, msg)?), + ChannelMsg::CloseInit(msg) => Ok(chan_close_init_validate(ctx, module, msg)?), + ChannelMsg::CloseConfirm(msg) => Ok(chan_close_confirm_validate(ctx, module, msg)?), } } MsgEnvelope::Packet(msg) => { let port_id = packet_msg_to_port_id(&msg); - let module_id = router - .lookup_module(port_id) - .ok_or(HostError::missing_state(format!( - "failed to look up port {}", - port_id.clone() - )))?; + let module_id = router.lookup_module(port_id).ok_or(ChannelError::Host( + HostError::missing_state(format!("failed to look up port {}", port_id.clone())), + ))?; let module = router .get_route(&module_id) .ok_or(RouterError::MissingModule)?; match msg { - PacketMsg::Recv(msg) => recv_packet_validate(ctx, msg), - PacketMsg::Ack(msg) => acknowledgement_packet_validate(ctx, module, msg), - PacketMsg::Timeout(msg) => { - timeout_packet_validate(ctx, module, TimeoutMsgType::Timeout(msg)) - } - PacketMsg::TimeoutOnClose(msg) => { - timeout_packet_validate(ctx, module, TimeoutMsgType::TimeoutOnClose(msg)) - } + PacketMsg::Recv(msg) => Ok(recv_packet_validate(ctx, msg)?), + PacketMsg::Ack(msg) => Ok(acknowledgement_packet_validate(ctx, module, msg)?), + PacketMsg::Timeout(msg) => Ok(timeout_packet_validate( + ctx, + module, + TimeoutMsgType::Timeout(msg), + )?), + PacketMsg::TimeoutOnClose(msg) => Ok(timeout_packet_validate( + ctx, + module, + TimeoutMsgType::TimeoutOnClose(msg), + )?), } } } @@ -137,14 +138,16 @@ where { match msg { MsgEnvelope::Client(msg) => match msg { - ClientMsg::CreateClient(msg) => create_client::execute(ctx, msg), - ClientMsg::UpdateClient(msg) => { - update_client::execute(ctx, MsgUpdateOrMisbehaviour::UpdateClient(msg)) - } - ClientMsg::Misbehaviour(msg) => { - update_client::execute(ctx, MsgUpdateOrMisbehaviour::Misbehaviour(msg)) - } - ClientMsg::UpgradeClient(msg) => upgrade_client::execute(ctx, msg), + ClientMsg::CreateClient(msg) => Ok(create_client::execute(ctx, msg)?), + ClientMsg::UpdateClient(msg) => Ok(update_client::execute( + ctx, + MsgUpdateOrMisbehaviour::UpdateClient(msg), + )?), + ClientMsg::Misbehaviour(msg) => Ok(update_client::execute( + ctx, + MsgUpdateOrMisbehaviour::Misbehaviour(msg), + )?), + ClientMsg::UpgradeClient(msg) => Ok(upgrade_client::execute(ctx, msg)?), ClientMsg::RecoverClient(_msg) => { // Recover client messages are not dispatched by ibc-rs as they can only be // authorized via a passing governance proposal @@ -152,53 +155,51 @@ where } }, MsgEnvelope::Connection(msg) => match msg { - ConnectionMsg::OpenInit(msg) => conn_open_init::execute(ctx, msg), - ConnectionMsg::OpenTry(msg) => conn_open_try::execute(ctx, msg), - ConnectionMsg::OpenAck(msg) => conn_open_ack::execute(ctx, msg), - ConnectionMsg::OpenConfirm(msg) => conn_open_confirm::execute(ctx, &msg), + ConnectionMsg::OpenInit(msg) => Ok(conn_open_init::execute(ctx, msg)?), + ConnectionMsg::OpenTry(msg) => Ok(conn_open_try::execute(ctx, msg)?), + ConnectionMsg::OpenAck(msg) => Ok(conn_open_ack::execute(ctx, msg)?), + ConnectionMsg::OpenConfirm(msg) => Ok(conn_open_confirm::execute(ctx, &msg)?), }, MsgEnvelope::Channel(msg) => { let port_id = channel_msg_to_port_id(&msg); - let module_id = router - .lookup_module(port_id) - .ok_or(HostError::missing_state(format!( - "failed to look up port {}", - port_id.clone() - )))?; + let module_id = router.lookup_module(port_id).ok_or(ChannelError::Host( + HostError::missing_state(format!("failed to look up port {}", port_id.clone())), + ))?; let module = router .get_route_mut(&module_id) .ok_or(RouterError::MissingModule)?; match msg { - ChannelMsg::OpenInit(msg) => chan_open_init_execute(ctx, module, msg), - ChannelMsg::OpenTry(msg) => chan_open_try_execute(ctx, module, msg), - ChannelMsg::OpenAck(msg) => chan_open_ack_execute(ctx, module, msg), - ChannelMsg::OpenConfirm(msg) => chan_open_confirm_execute(ctx, module, msg), - ChannelMsg::CloseInit(msg) => chan_close_init_execute(ctx, module, msg), - ChannelMsg::CloseConfirm(msg) => chan_close_confirm_execute(ctx, module, msg), + ChannelMsg::OpenInit(msg) => Ok(chan_open_init_execute(ctx, module, msg)?), + ChannelMsg::OpenTry(msg) => Ok(chan_open_try_execute(ctx, module, msg)?), + ChannelMsg::OpenAck(msg) => Ok(chan_open_ack_execute(ctx, module, msg)?), + ChannelMsg::OpenConfirm(msg) => Ok(chan_open_confirm_execute(ctx, module, msg)?), + ChannelMsg::CloseInit(msg) => Ok(chan_close_init_execute(ctx, module, msg)?), + ChannelMsg::CloseConfirm(msg) => Ok(chan_close_confirm_execute(ctx, module, msg)?), } } MsgEnvelope::Packet(msg) => { let port_id = packet_msg_to_port_id(&msg); - let module_id = router - .lookup_module(port_id) - .ok_or(HostError::missing_state(format!( - "failed to look up port {}", - port_id.clone() - )))?; + let module_id = router.lookup_module(port_id).ok_or(ChannelError::Host( + HostError::missing_state(format!("failed to look up port {}", port_id.clone())), + ))?; let module = router .get_route_mut(&module_id) .ok_or(RouterError::MissingModule)?; match msg { - PacketMsg::Recv(msg) => recv_packet_execute(ctx, module, msg), - PacketMsg::Ack(msg) => acknowledgement_packet_execute(ctx, module, msg), - PacketMsg::Timeout(msg) => { - timeout_packet_execute(ctx, module, TimeoutMsgType::Timeout(msg)) - } - PacketMsg::TimeoutOnClose(msg) => { - timeout_packet_execute(ctx, module, TimeoutMsgType::TimeoutOnClose(msg)) - } + PacketMsg::Recv(msg) => Ok(recv_packet_execute(ctx, module, msg)?), + PacketMsg::Ack(msg) => Ok(acknowledgement_packet_execute(ctx, module, msg)?), + PacketMsg::Timeout(msg) => Ok(timeout_packet_execute( + ctx, + module, + TimeoutMsgType::Timeout(msg), + )?), + PacketMsg::TimeoutOnClose(msg) => Ok(timeout_packet_execute( + ctx, + module, + TimeoutMsgType::TimeoutOnClose(msg), + )?), } } } diff --git a/ibc-core/ics25-handler/types/src/error.rs b/ibc-core/ics25-handler/types/src/error.rs index a2823b357..fce14adc9 100644 --- a/ibc-core/ics25-handler/types/src/error.rs +++ b/ibc-core/ics25-handler/types/src/error.rs @@ -5,7 +5,6 @@ use displaydoc::Display; use ibc_core_channel_types::error::ChannelError; use ibc_core_client_types::error::ClientError; use ibc_core_connection_types::error::ConnectionError; -use ibc_core_host_types::error::HostError; use ibc_core_router_types::error::RouterError; use ibc_primitives::prelude::*; @@ -20,20 +19,6 @@ pub enum HandlerError { Channel(ChannelError), /// ICS26 Routing error: {0} Router(RouterError), - /// ICS25 Host error: {0} - Host(HostError), -} - -// TODO(seanchen1991): Figure out how to remove this -impl From for ClientError { - fn from(e: HandlerError) -> Self { - match e { - HandlerError::Client(e) => e, - _ => ClientError::Other { - description: e.to_string(), - }, - } - } } #[cfg(feature = "std")] @@ -44,7 +29,6 @@ impl std::error::Error for HandlerError { Self::Connection(e) => Some(e), Self::Channel(e) => Some(e), Self::Router(e) => Some(e), - Self::Host(e) => Some(e), } } } diff --git a/ibc-query/src/error.rs b/ibc-query/src/error.rs index 6b20a3691..4c064be97 100644 --- a/ibc-query/src/error.rs +++ b/ibc-query/src/error.rs @@ -15,6 +15,8 @@ use tonic::Status; pub enum QueryError { /// handler error: `{0}` Handler(HandlerError), + /// host error: `{0}` + Host(HostError), /// decoding error: `{0}` Decoding(DecodingError), /// missing proof: `{0}` @@ -37,6 +39,7 @@ impl From for Status { fn from(e: QueryError) -> Self { match e { QueryError::Handler(ctx_err) => Self::internal(ctx_err.to_string()), + QueryError::Host(host_err) => Self::internal(host_err.to_string()), QueryError::Decoding(de) => Self::internal(de.to_string()), QueryError::MissingProof(description) => Self::not_found(description), QueryError::MissingField(description) => Self::invalid_argument(description), @@ -82,6 +85,6 @@ impl From for QueryError { impl From for QueryError { fn from(e: HostError) -> Self { - Self::Handler(HandlerError::Host(e)) + Self::Host(e) } } diff --git a/tests-integration/tests/core/ics02_client/upgrade_client.rs b/tests-integration/tests/core/ics02_client/upgrade_client.rs index fb2e0f22b..e2713f4d6 100644 --- a/tests-integration/tests/core/ics02_client/upgrade_client.rs +++ b/tests-integration/tests/core/ics02_client/upgrade_client.rs @@ -143,10 +143,11 @@ fn msg_upgrade_client_healthy() { #[test] fn upgrade_client_fail_nonexisting_client() { let fxt = msg_upgrade_client_fixture(Ctx::Default, Msg::Default); - let expected_err = HandlerError::Host(HostError::missing_state(format!( - "missing client state for client {0}", + let expected_err: HandlerError = ClientError::Host(HostError::missing_state(format!( + "missing client state for client {}", fxt.msg.client_id.clone() - ))); + ))) + .into(); upgrade_client_validate(&fxt, Expect::Failure(Some(expected_err))); } diff --git a/tests-integration/tests/core/ics03_connection/conn_open_ack.rs b/tests-integration/tests/core/ics03_connection/conn_open_ack.rs index bf5064ad5..7bab98ef4 100644 --- a/tests-integration/tests/core/ics03_connection/conn_open_ack.rs +++ b/tests-integration/tests/core/ics03_connection/conn_open_ack.rs @@ -127,7 +127,9 @@ fn conn_open_ack_validate(fxt: &Fixture, expect: Expect) { let cons_state_height = fxt.msg.consensus_height_of_a_on_b; match res.unwrap_err() { - HandlerError::Host(HostError::MissingState { ref description }) => { + HandlerError::Connection(ConnectionError::Host(HostError::MissingState { + ref description, + })) => { assert!(description.contains(right_connection_id.to_string().as_str())) } HandlerError::Connection(ConnectionError::InsufficientConsensusHeight { @@ -188,10 +190,11 @@ fn conn_open_ack_healthy() { #[test] fn conn_open_ack_no_connection() { let fxt = conn_open_ack_fixture(Ctx::New); - let expected_err = HandlerError::Host(HostError::missing_state(format!( + let expected_err: HandlerError = ConnectionError::Host(HostError::missing_state(format!( "missing connection end for connection {}", fxt.msg.conn_id_on_a.clone() - ))); + ))) + .into(); conn_open_ack_validate(&fxt, Expect::Failure(Some(expected_err))); } diff --git a/tests-integration/tests/core/router.rs b/tests-integration/tests/core/router.rs index 825352428..5db8045ae 100644 --- a/tests-integration/tests/core/router.rs +++ b/tests-integration/tests/core/router.rs @@ -1,9 +1,9 @@ use core::ops::Add; use ibc::apps::transfer::handler::send_transfer; -use ibc::apps::transfer::types::error::TokenTransferError; use ibc::apps::transfer::types::msgs::transfer::MsgTransfer; use ibc::apps::transfer::types::{BaseCoin, U256}; +use ibc::core::channel::types::error::ChannelError; use ibc::core::channel::types::msgs::{ ChannelMsg, MsgAcknowledgement, MsgChannelCloseConfirm, MsgChannelCloseInit, MsgChannelOpenAck, MsgChannelOpenInit, MsgChannelOpenTry, MsgRecvPacket, MsgTimeoutOnClose, PacketMsg, @@ -21,7 +21,6 @@ use ibc::core::host::types::path::CommitmentPath; use ibc::core::host::ValidationContext; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Timestamp; -use ibc_core_host_types::error::HostError; use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::applications::transfer::{ extract_transfer_packet, MsgTransferConfig, PacketDataConfig, @@ -407,7 +406,7 @@ fn routing_module_and_keepers() { let res = match test.msg.clone() { TestMsg::Ics26(msg) => dispatch(&mut ctx.ibc_store, &mut router, msg), TestMsg::Ics20(msg) => send_transfer(&mut ctx.ibc_store, &mut DummyTransferModule, msg) - .map_err(|e: TokenTransferError| HostError::Other { + .map_err(|e| ChannelError::AppSpecific { description: format!("token transfer application error: {e}"), }) .map_err(HandlerError::from), From 5bdd3777f02c3d74d7150ca2a16385a6fa76fe22 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 20 Sep 2024 14:06:26 -0500 Subject: [PATCH 09/18] Clean up generic String variants in error types (#1347) * Clean up most instances of ClientError::Other * Rename CommitmentError variants * Clean up some DecodingError calls * Incorporate some PR feedback * Incorporate more PR feedback * A bunch of DecodingError associated type changes * Eliminate a bunch of redundant map_err calls * cargo fmt * Fix ics23 spec tests * Fix a typo * Clean up some error messages * Consolidate MismatchedTypeUrl and MismatchedEventKind variants * Miscellaneous clean up * cargo fmt * Remove unused CommitmentError variants * Clean up errors to match ADR description * More clean up * Add changelog entry * fix: remove now unused HeightError * Clean up TimestampError --------- Co-authored-by: Farhad Shabani --- ...46-remove-generic-string-error-variants.md | 2 + ibc-apps/ics20-transfer/src/module.rs | 4 +- ibc-apps/ics20-transfer/types/src/amount.rs | 4 +- ibc-apps/ics20-transfer/types/src/coin.rs | 2 +- ibc-apps/ics20-transfer/types/src/denom.rs | 4 +- ibc-apps/ics20-transfer/types/src/error.rs | 10 +- .../ics20-transfer/types/src/msgs/transfer.rs | 6 +- ibc-apps/ics721-nft-transfer/src/module.rs | 4 +- .../ics721-nft-transfer/types/src/class.rs | 4 +- .../ics721-nft-transfer/types/src/error.rs | 14 +- .../types/src/msgs/transfer.rs | 7 +- .../ics721-nft-transfer/types/src/packet.rs | 2 +- .../ics07-tendermint/src/client_state.rs | 7 +- .../src/client_state/common.rs | 8 +- .../src/client_state/execution.rs | 7 +- .../src/client_state/misbehaviour.rs | 14 +- .../src/client_state/update_client.rs | 14 +- .../src/client_state/validation.rs | 2 +- .../ics07-tendermint/src/consensus_state.rs | 7 +- .../types/src/client_state.rs | 88 ++++----- .../types/src/consensus_state.rs | 30 ++- .../ics07-tendermint/types/src/error.rs | 32 +-- .../ics07-tendermint/types/src/header.rs | 47 ++--- .../types/src/misbehaviour.rs | 22 +-- .../types/src/trust_threshold.rs | 12 +- .../ics08-wasm/types/src/client_state.rs | 13 +- .../ics08-wasm/types/src/consensus_state.rs | 11 +- .../ics02-client/src/handler/create_client.rs | 2 +- .../src/handler/recover_client.rs | 2 +- .../ics02-client/src/handler/update_client.rs | 4 +- ibc-core/ics02-client/types/src/error.rs | 91 ++++----- ibc-core/ics02-client/types/src/events.rs | 184 +++++++++--------- ibc-core/ics02-client/types/src/height.rs | 102 +++------- .../types/src/msgs/create_client.rs | 16 +- .../types/src/msgs/misbehaviour.rs | 6 +- .../types/src/msgs/upgrade_client.rs | 23 +-- ibc-core/ics02-client/types/src/status.rs | 11 +- ibc-core/ics03-connection/src/delay.rs | 3 +- .../ics03-connection/types/src/connection.rs | 44 ++--- ibc-core/ics03-connection/types/src/error.rs | 19 +- .../types/src/msgs/conn_open_ack.rs | 45 ++--- .../types/src/msgs/conn_open_confirm.rs | 16 +- .../types/src/msgs/conn_open_init.rs | 20 +- .../types/src/msgs/conn_open_try.rs | 57 ++---- .../ics03-connection/types/src/version.rs | 8 +- .../src/handler/acknowledgement.rs | 4 +- .../ics04-channel/src/handler/recv_packet.rs | 4 +- .../ics04-channel/src/handler/send_packet.rs | 4 +- ibc-core/ics04-channel/src/handler/timeout.rs | 6 +- .../src/handler/timeout_on_close.rs | 4 +- .../types/src/acknowledgement.rs | 4 +- ibc-core/ics04-channel/types/src/channel.rs | 29 +-- ibc-core/ics04-channel/types/src/error.rs | 40 ++-- .../ics04-channel/types/src/events/mod.rs | 12 +- .../types/src/events/packet_attributes.rs | 13 +- .../types/src/msgs/acknowledgement.rs | 18 +- .../types/src/msgs/chan_close_confirm.rs | 10 +- .../types/src/msgs/chan_close_init.rs | 5 +- .../types/src/msgs/chan_open_ack.rs | 13 +- .../types/src/msgs/chan_open_confirm.rs | 8 +- .../types/src/msgs/chan_open_init.rs | 23 ++- .../types/src/msgs/chan_open_try.rs | 19 +- .../types/src/msgs/recv_packet.rs | 14 +- .../ics04-channel/types/src/msgs/timeout.rs | 10 +- .../types/src/msgs/timeout_on_close.rs | 18 +- .../ics23-commitment/types/src/commitment.rs | 15 +- ibc-core/ics23-commitment/types/src/error.rs | 43 ++-- ibc-core/ics23-commitment/types/src/merkle.rs | 13 +- ibc-core/ics23-commitment/types/src/specs.rs | 83 ++++---- .../cosmos/src/upgrade_proposal/plan.rs | 31 ++- .../cosmos/src/upgrade_proposal/proposal.rs | 23 +-- .../cosmos/src/validate_self_client.rs | 16 +- ibc-core/ics24-host/types/src/error.rs | 43 ++-- .../types/src/identifiers/chain_id.rs | 3 +- .../types/src/identifiers/sequence.rs | 3 +- ibc-core/ics24-host/types/src/validate.rs | 5 +- ibc-core/ics25-handler/types/src/events.rs | 4 +- ibc-primitives/src/types/timestamp.rs | 31 ++- ibc-query/src/core/client/types/request.rs | 8 +- ibc-query/src/error.rs | 6 - .../src/fixtures/clients/tendermint.rs | 3 +- .../testapp/ibc/clients/mock/client_state.rs | 24 +-- .../ibc/clients/mock/consensus_state.rs | 17 +- .../src/testapp/ibc/clients/mock/header.rs | 14 +- .../testapp/ibc/clients/mock/misbehaviour.rs | 21 +- ibc-testkit/src/testapp/ibc/clients/mod.rs | 31 ++- .../src/testapp/ibc/core/client_ctx.rs | 6 +- ibc-testkit/src/testapp/ibc/core/core_ctx.rs | 88 +++------ .../tests/core/ics02_client/create_client.rs | 6 +- 89 files changed, 788 insertions(+), 1037 deletions(-) create mode 100644 .changelog/unreleased/breaking-changes/1346-remove-generic-string-error-variants.md diff --git a/.changelog/unreleased/breaking-changes/1346-remove-generic-string-error-variants.md b/.changelog/unreleased/breaking-changes/1346-remove-generic-string-error-variants.md new file mode 100644 index 000000000..453d87f01 --- /dev/null +++ b/.changelog/unreleased/breaking-changes/1346-remove-generic-string-error-variants.md @@ -0,0 +1,2 @@ +- [ibc-core] Remove `ClientError::Other` variant + ([\#1346](https://github.com/cosmos/ibc-rs/issues/1346)) diff --git a/ibc-apps/ics20-transfer/src/module.rs b/ibc-apps/ics20-transfer/src/module.rs index 3ca271c43..6092a638f 100644 --- a/ibc-apps/ics20-transfer/src/module.rs +++ b/ibc-apps/ics20-transfer/src/module.rs @@ -133,7 +133,7 @@ pub fn on_chan_close_init_validate( _port_id: &PortId, _channel_id: &ChannelId, ) -> Result<(), TokenTransferError> { - Err(TokenTransferError::UnsupportedClosedChannel) + Err(TokenTransferError::InvalidClosedChannel) } pub fn on_chan_close_init_execute( @@ -141,7 +141,7 @@ pub fn on_chan_close_init_execute( _port_id: &PortId, _channel_id: &ChannelId, ) -> Result { - Err(TokenTransferError::UnsupportedClosedChannel) + Err(TokenTransferError::InvalidClosedChannel) } pub fn on_chan_close_confirm_validate( diff --git a/ibc-apps/ics20-transfer/types/src/amount.rs b/ibc-apps/ics20-transfer/types/src/amount.rs index a4efd39bd..8f1b2c81f 100644 --- a/ibc-apps/ics20-transfer/types/src/amount.rs +++ b/ibc-apps/ics20-transfer/types/src/amount.rs @@ -106,9 +106,7 @@ impl FromStr for Amount { fn from_str(s: &str) -> Result { let amount = U256::from_dec_str(s).map_err(|e| { - DecodingError::invalid_raw_data(format!( - "invalid amount that could not be parsed as a U256: {e}" - )) + DecodingError::invalid_raw_data(format!("amount could not be parsed as a U256: {e}")) })?; Ok(Self(amount)) diff --git a/ibc-apps/ics20-transfer/types/src/coin.rs b/ibc-apps/ics20-transfer/types/src/coin.rs index 6ebabc0f7..db95bcc9f 100644 --- a/ibc-apps/ics20-transfer/types/src/coin.rs +++ b/ibc-apps/ics20-transfer/types/src/coin.rs @@ -77,7 +77,7 @@ where .all(|x| x.is_alphanumeric() || VALID_DENOM_CHARACTERS.contains(x)) }) .ok_or(DecodingError::invalid_raw_data(format!( - "invalid coin: {coin_str}" + "coin str: {coin_str}" )))?; Ok(Coin { diff --git a/ibc-apps/ics20-transfer/types/src/denom.rs b/ibc-apps/ics20-transfer/types/src/denom.rs index 0a951ca79..02ffc71c9 100644 --- a/ibc-apps/ics20-transfer/types/src/denom.rs +++ b/ibc-apps/ics20-transfer/types/src/denom.rs @@ -218,9 +218,7 @@ impl FromStr for TracePath { remaining_parts .is_none() .then_some(trace_path) - .ok_or(DecodingError::invalid_raw_data(format!( - "invalid trace path: {s}" - ))) + .ok_or(DecodingError::invalid_raw_data(format!("trace path: {s}"))) } } diff --git a/ibc-apps/ics20-transfer/types/src/error.rs b/ibc-apps/ics20-transfer/types/src/error.rs index 113953dd5..3c2058598 100644 --- a/ibc-apps/ics20-transfer/types/src/error.rs +++ b/ibc-apps/ics20-transfer/types/src/error.rs @@ -9,11 +9,11 @@ use ibc_core::primitives::prelude::*; #[derive(Display, Debug, derive_more::From)] pub enum TokenTransferError { - /// host error: `{0}` + /// host error: {0} Host(HostError), - /// decoding error: `{0}` + /// decoding error: {0} Decoding(DecodingError), - /// channel error: `{0}` + /// channel error: {0} Channel(ChannelError), /// missing destination channel `{channel_id}` on port `{port_id}` MissingDestinationChannel { @@ -24,8 +24,8 @@ pub enum TokenTransferError { MismatchedChannelOrders { expected: Order, actual: Order }, /// mismatched port IDs: expected `{expected}`, actual `{actual}` MismatchedPortIds { expected: PortId, actual: PortId }, - /// channel cannot be closed - UnsupportedClosedChannel, + /// invalid channel state: cannot be closed + InvalidClosedChannel, /// failed to deserialize packet data FailedToDeserializePacketData, /// failed to deserialize acknowledgement diff --git a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs index 0bdaf0979..f8a72b7ff 100644 --- a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs @@ -55,7 +55,7 @@ impl TryFrom for MsgTransfer { // Packet timeout height and packet timeout timestamp cannot both be unset. if !timeout_height_on_b.is_set() && !timeout_timestamp_on_b.is_set() { return Err(DecodingError::missing_raw_data( - "missing timeout height or timeout timestamp", + "msg transfer timeout height or timeout timestamp", )); } @@ -65,7 +65,7 @@ impl TryFrom for MsgTransfer { packet_data: PacketData { token: raw_msg .token - .ok_or(DecodingError::missing_raw_data("missing token"))? + .ok_or(DecodingError::missing_raw_data("msg transfer token"))? .try_into()?, sender: raw_msg.sender.into(), receiver: raw_msg.receiver.into(), @@ -100,7 +100,7 @@ impl TryFrom for MsgTransfer { fn try_from(raw: Any) -> Result { match raw.type_url.as_str() { TYPE_URL => Ok(MsgTransfer::decode_vec(&raw.value)?), - _ => Err(DecodingError::MismatchedTypeUrls { + _ => Err(DecodingError::MismatchedResourceName { expected: TYPE_URL.to_string(), actual: raw.type_url, })?, diff --git a/ibc-apps/ics721-nft-transfer/src/module.rs b/ibc-apps/ics721-nft-transfer/src/module.rs index a7a54a447..53b45e7c3 100644 --- a/ibc-apps/ics721-nft-transfer/src/module.rs +++ b/ibc-apps/ics721-nft-transfer/src/module.rs @@ -132,7 +132,7 @@ pub fn on_chan_close_init_validate( _port_id: &PortId, _channel_id: &ChannelId, ) -> Result<(), NftTransferError> { - Err(NftTransferError::UnsupportedClosedChannel) + Err(NftTransferError::InvalidClosedChannel) } pub fn on_chan_close_init_execute( @@ -140,7 +140,7 @@ pub fn on_chan_close_init_execute( _port_id: &PortId, _channel_id: &ChannelId, ) -> Result { - Err(NftTransferError::UnsupportedClosedChannel) + Err(NftTransferError::InvalidClosedChannel) } pub fn on_chan_close_confirm_validate( diff --git a/ibc-apps/ics721-nft-transfer/types/src/class.rs b/ibc-apps/ics721-nft-transfer/types/src/class.rs index 17c0d9c98..d554be89b 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/class.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/class.rs @@ -247,9 +247,7 @@ impl FromStr for ClassUri { fn from_str(class_uri: &str) -> Result { match Uri::from_str(class_uri) { Ok(uri) => Ok(Self(uri)), - Err(err) => Err(DecodingError::invalid_raw_data(format!( - "invalid class URI: {err}" - ))), + Err(err) => Err(DecodingError::invalid_raw_data(format!("class URI: {err}"))), } } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/error.rs b/ibc-apps/ics721-nft-transfer/types/src/error.rs index 40035e4ff..9335f4c2f 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/error.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/error.rs @@ -10,19 +10,19 @@ use ibc_core::primitives::prelude::*; #[derive(Display, Debug, From)] pub enum NftTransferError { - /// host error: `{0}` + /// host error: {0} Host(HostError), - /// channel error: `{0}` + /// channel error: {0} Channel(ChannelError), - /// decoding error: `{0}` + /// decoding error: {0} Decoding(DecodingError), /// missing destination channel `{channel_id}` on port `{port_id}` MissingDestinationChannel { port_id: PortId, channel_id: ChannelId, }, - /// empty token ID - EmptyTokenId, + /// missing token ID + MissingTokenId, /// mismatched number of token IDs: expected `{expected}`, actual `{actual}` MismatchedNumberOfTokenIds { expected: usize, actual: usize }, /// mismatched channel orders: expected `{expected}`, actual `{actual}` @@ -35,8 +35,8 @@ pub enum NftTransferError { FailedToDeserializeAck, /// failed to parse account ID FailedToParseAccount, - /// channel cannot be closed - UnsupportedClosedChannel, + /// invalid channel state: cannot be closed + InvalidClosedChannel, } #[cfg(feature = "std")] diff --git a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs index ae9a31bc4..92e83527c 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs @@ -8,7 +8,6 @@ use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::applications::nft_transfer::v1::MsgTransfer as RawMsgTransfer; use ibc_proto::Protobuf; -use crate::error::NftTransferError; use crate::packet::PacketData; pub(crate) const TYPE_URL: &str = "/ibc.applications.nft_transfer.v1.MsgTransfer"; @@ -115,12 +114,12 @@ impl From for RawMsgTransfer { impl Protobuf for MsgTransfer {} impl TryFrom for MsgTransfer { - type Error = NftTransferError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { match raw.type_url.as_str() { - TYPE_URL => Ok(MsgTransfer::decode_vec(&raw.value).map_err(DecodingError::Protobuf)?), - _ => Err(DecodingError::MismatchedTypeUrls { + TYPE_URL => Ok(MsgTransfer::decode_vec(&raw.value)?), + _ => Err(DecodingError::MismatchedResourceName { expected: TYPE_URL.to_string(), actual: raw.type_url, })?, diff --git a/ibc-apps/ics721-nft-transfer/types/src/packet.rs b/ibc-apps/ics721-nft-transfer/types/src/packet.rs index 5d9871768..afa773bfc 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/packet.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/packet.rs @@ -92,7 +92,7 @@ impl PacketData { /// Performs the basic validation of the packet data fields. pub fn validate_basic(&self) -> Result<(), NftTransferError> { if self.token_ids.0.is_empty() { - return Err(NftTransferError::EmptyTokenId); + return Err(NftTransferError::MissingTokenId); } let num = self.token_ids.0.len(); let num_uri = self diff --git a/ibc-clients/ics07-tendermint/src/client_state.rs b/ibc-clients/ics07-tendermint/src/client_state.rs index ecfbba885..6319e309c 100644 --- a/ibc-clients/ics07-tendermint/src/client_state.rs +++ b/ibc-clients/ics07-tendermint/src/client_state.rs @@ -8,10 +8,9 @@ //! Rust). As such, this module also includes some trait implementations that //! serve to pass through traits implemented on the wrapped `ClientState` type. -use ibc_client_tendermint_types::error::TendermintClientError; use ibc_client_tendermint_types::proto::v1::ClientState as RawTmClientState; use ibc_client_tendermint_types::ClientState as ClientStateType; -use ibc_core_client::types::error::ClientError; +use ibc_core_host::types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_primitives::proto::{Any, Protobuf}; @@ -44,7 +43,7 @@ impl ClientState { impl Protobuf for ClientState {} impl TryFrom for ClientState { - type Error = TendermintClientError; + type Error = DecodingError; fn try_from(raw: RawTmClientState) -> Result { Ok(Self(ClientStateType::try_from(raw)?)) @@ -60,7 +59,7 @@ impl From for RawTmClientState { impl Protobuf for ClientState {} impl TryFrom for ClientState { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { Ok(Self(ClientStateType::try_from(raw)?)) diff --git a/ibc-clients/ics07-tendermint/src/client_state/common.rs b/ibc-clients/ics07-tendermint/src/client_state/common.rs index ca0a82eec..4623df3ac 100644 --- a/ibc-clients/ics07-tendermint/src/client_state/common.rs +++ b/ibc-clients/ics07-tendermint/src/client_state/common.rs @@ -159,11 +159,11 @@ pub fn verify_consensus_state( let tm_consensus_state = TmConsensusState::try_from(consensus_state)?; if tm_consensus_state.root().is_empty() { - Err(CommitmentError::EmptyCommitmentRoot)?; + Err(CommitmentError::MissingCommitmentRoot)?; }; if consensus_state_status(&tm_consensus_state, host_timestamp, trusting_period)?.is_expired() { - return Err(ClientError::UnexpectedStatus(Status::Expired)); + return Err(ClientError::InvalidStatus(Status::Expired)); } Ok(()) @@ -206,7 +206,7 @@ pub fn validate_proof_height( let latest_height = client_state.latest_height; if latest_height < proof_height { - return Err(ClientError::InvalidProofHeight { + return Err(ClientError::InsufficientProofHeight { actual: latest_height, expected: proof_height, }); @@ -294,7 +294,7 @@ pub fn verify_membership( value: Vec, ) -> Result<(), ClientError> { if prefix.is_empty() { - Err(CommitmentError::EmptyCommitmentPrefix)?; + Err(CommitmentError::MissingCommitmentPrefix)?; } let merkle_path = MerklePath::new(vec![prefix.as_bytes().to_vec().into(), path]); diff --git a/ibc-clients/ics07-tendermint/src/client_state/execution.rs b/ibc-clients/ics07-tendermint/src/client_state/execution.rs index 084d0441c..d4aafbf1b 100644 --- a/ibc-clients/ics07-tendermint/src/client_state/execution.rs +++ b/ibc-clients/ics07-tendermint/src/client_state/execution.rs @@ -8,6 +8,7 @@ use ibc_core_host::types::identifiers::ClientId; use ibc_core_host::types::path::{ClientConsensusStatePath, ClientStatePath}; use ibc_primitives::prelude::*; use ibc_primitives::proto::Any; +use ibc_primitives::TimestampError; use super::ClientState; @@ -341,11 +342,7 @@ where let tm_consensus_state_timestamp = tm_consensus_state.timestamp(); let tm_consensus_state_expiry = (tm_consensus_state_timestamp + client_state.trusting_period) - .map_err(|_| ClientError::Other { - description: String::from( - "Timestamp overflow error occurred while attempting to parse TmConsensusState", - ), - })?; + .map_err(|_| TimestampError::OverflowedTimestamp)?; if tm_consensus_state_expiry > host_timestamp { break; diff --git a/ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs b/ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs index 29e672c6b..0d8ce51ce 100644 --- a/ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs +++ b/ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs @@ -4,6 +4,7 @@ use ibc_client_tendermint_types::{ }; use ibc_core_client::context::{Convertible, ExtClientValidationContext}; use ibc_core_client::types::error::ClientError; +use ibc_core_host::types::error::IdentifierError; use ibc_core_host::types::identifiers::{ChainId, ClientId}; use ibc_core_host::types::path::ClientConsensusStatePath; use ibc_primitives::prelude::*; @@ -116,12 +117,13 @@ where // main header verification, delegated to the tendermint-light-client crate. let untrusted_state = header.as_untrusted_block_state(); - let tm_chain_id = &chain_id - .as_str() - .try_into() - .map_err(|e| ClientError::Other { - description: format!("failed to parse chain id: {e}"), - })?; + let tm_chain_id = + &chain_id + .as_str() + .try_into() + .map_err(|e| IdentifierError::FailedToParse { + description: format!("chain ID `{chain_id}`: {e:?}"), + })?; let trusted_state = header.as_trusted_block_state(tm_chain_id, trusted_time, trusted_next_validator_hash)?; diff --git a/ibc-clients/ics07-tendermint/src/client_state/update_client.rs b/ibc-clients/ics07-tendermint/src/client_state/update_client.rs index 40ec52751..d0f706b30 100644 --- a/ibc-clients/ics07-tendermint/src/client_state/update_client.rs +++ b/ibc-clients/ics07-tendermint/src/client_state/update_client.rs @@ -3,6 +3,7 @@ use ibc_client_tendermint_types::{ConsensusState as ConsensusStateType, Header a use ibc_core_client::context::{Convertible, ExtClientValidationContext}; use ibc_core_client::types::error::ClientError; use ibc_core_client::types::Height; +use ibc_core_host::types::error::IdentifierError; use ibc_core_host::types::identifiers::{ChainId, ClientId}; use ibc_core_host::types::path::ClientConsensusStatePath; use ibc_primitives::prelude::*; @@ -52,18 +53,17 @@ where )?; TrustedBlockState { - chain_id: &chain_id - .as_str() - .try_into() - .map_err(|e| ClientError::Other { - description: format!("failed to parse chain id: {}", e), - })?, + chain_id: &chain_id.as_str().try_into().map_err(|e| { + IdentifierError::FailedToParse { + description: format!("chain ID `{chain_id}`: {e:?}"), + } + })?, header_time: trusted_consensus_state.timestamp(), height: header .trusted_height .revision_height() .try_into() - .map_err(|_| ClientError::FailedHeaderVerification { + .map_err(|_| ClientError::FailedToVerifyHeader { description: TendermintClientError::InvalidHeaderHeight( header.trusted_height.revision_height(), ) diff --git a/ibc-clients/ics07-tendermint/src/client_state/validation.rs b/ibc-clients/ics07-tendermint/src/client_state/validation.rs index 4cd1a9cc8..ccb08b5af 100644 --- a/ibc-clients/ics07-tendermint/src/client_state/validation.rs +++ b/ibc-clients/ics07-tendermint/src/client_state/validation.rs @@ -278,5 +278,5 @@ where && subject_proof_specs == &substitute_proof_specs && subject_upgrade_path == &substitute_upgrade_path) .then_some(()) - .ok_or(ClientError::MismatchedClientRecoveryStates) + .ok_or(ClientError::FailedToVerifyClientRecoveryStates) } diff --git a/ibc-clients/ics07-tendermint/src/consensus_state.rs b/ibc-clients/ics07-tendermint/src/consensus_state.rs index 6d0ed7f63..52f0173ce 100644 --- a/ibc-clients/ics07-tendermint/src/consensus_state.rs +++ b/ibc-clients/ics07-tendermint/src/consensus_state.rs @@ -6,12 +6,11 @@ //! implementations that serve to pass through traits implemented on the wrapped //! `ConsensusState` type. -use ibc_client_tendermint_types::error::TendermintClientError; use ibc_client_tendermint_types::proto::v1::ConsensusState as RawTmConsensusState; use ibc_client_tendermint_types::ConsensusState as ConsensusStateType; use ibc_core_client::context::consensus_state::ConsensusState as ConsensusStateTrait; -use ibc_core_client::types::error::ClientError; use ibc_core_commitment_types::commitment::CommitmentRoot; +use ibc_core_host::types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_primitives::proto::{Any, Protobuf}; use ibc_primitives::Timestamp; @@ -52,7 +51,7 @@ impl From for ConsensusStateType { impl Protobuf for ConsensusState {} impl TryFrom for ConsensusState { - type Error = TendermintClientError; + type Error = DecodingError; fn try_from(raw: RawTmConsensusState) -> Result { Ok(Self(ConsensusStateType::try_from(raw)?)) @@ -68,7 +67,7 @@ impl From for RawTmConsensusState { impl Protobuf for ConsensusState {} impl TryFrom for ConsensusState { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { Ok(Self(ConsensusStateType::try_from(raw)?)) diff --git a/ibc-clients/ics07-tendermint/types/src/client_state.rs b/ibc-clients/ics07-tendermint/types/src/client_state.rs index 91ab3d944..ad92b99f0 100644 --- a/ibc-clients/ics07-tendermint/types/src/client_state.rs +++ b/ibc-clients/ics07-tendermint/types/src/client_state.rs @@ -4,7 +4,6 @@ use core::cmp::max; use core::str::FromStr; use core::time::Duration; -use ibc_core_client_types::error::ClientError; use ibc_core_client_types::proto::v1::Height as RawHeight; use ibc_core_client_types::Height; use ibc_core_commitment_types::specs::ProofSpecs; @@ -187,7 +186,7 @@ impl ClientState { // `upgrade_path` itself may be empty, but if not then each key must be non-empty for key in self.upgrade_path.iter() { if key.trim().is_empty() { - return Err(TendermintClientError::EmptyUpgradePathKey); + return Err(TendermintClientError::MissingUpgradePathKey); } } @@ -203,11 +202,7 @@ impl ClientState { /// Tendermint-specific light client verification. pub fn as_light_client_options(&self) -> Result { Ok(Options { - trust_threshold: self.trust_level.try_into().map_err(|e: ClientError| { - TendermintClientError::InvalidTrustThreshold { - description: e.to_string(), - } - })?, + trust_threshold: self.trust_level.try_into()?, trusting_period: self.trusting_period, clock_drift: self.max_clock_drift, }) @@ -235,70 +230,64 @@ impl ClientState { impl Protobuf for ClientState {} impl TryFrom for ClientState { - type Error = TendermintClientError; + type Error = DecodingError; fn try_from(raw: RawTmClientState) -> Result { let chain_id = ChainId::from_str(raw.chain_id.as_str())?; let trust_level = { - let trust_level = raw.trust_level.ok_or(DecodingError::MissingRawData { - description: "trust level not set".to_string(), - })?; - trust_level - .try_into() - .map_err(|e| DecodingError::InvalidRawData { - description: format!("failed to decoding trust threshold: {e}"), - })? + let trust_level = raw.trust_level.ok_or(DecodingError::missing_raw_data( + "tm client state trust level", + ))?; + trust_level.try_into()? }; let trusting_period = raw .trusting_period - .ok_or(DecodingError::MissingRawData { - description: "trusting period not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data( + "tm client state trusting period", + ))? .try_into() - .map_err(|_| DecodingError::InvalidRawData { - description: "failed to decode trusting period".to_string(), + .map_err(|d| { + DecodingError::invalid_raw_data(format!("tm client state trusting period: {d:?}")) })?; let unbonding_period = raw .unbonding_period - .ok_or(DecodingError::MissingRawData { - description: "unbonding period not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data( + "tm client state unbonding period", + ))? .try_into() - .map_err(|_| DecodingError::InvalidRawData { - description: "failed to decode unbonding period".to_string(), + .map_err(|d| { + DecodingError::invalid_raw_data(format!("tm client state unbonding period: {d:?}")) })?; let max_clock_drift = raw .max_clock_drift - .ok_or(DecodingError::MissingRawData { - description: "max clock drift not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data( + "tm client state max clock drift", + ))? .try_into() - .map_err(|_| DecodingError::InvalidRawData { - description: "failed to decode max clock drift".to_string(), + .map_err(|d| { + DecodingError::invalid_raw_data(format!("tm client state max clock drift: {d:?}")) })?; let latest_height = raw .latest_height - .ok_or(DecodingError::MissingRawData { - description: "latest height not set".to_string(), - })? - .try_into() - .map_err(|e| DecodingError::InvalidRawData { - description: format!("failed to decode latest height: {e}"), - })?; + .ok_or(DecodingError::missing_raw_data( + "tm client state latest height", + ))? + .try_into()?; + + let proof_specs = raw.proof_specs.try_into()?; // NOTE: In `RawClientState`, a `frozen_height` of `0` means "not // frozen". See: // https://github.com/cosmos/ibc-go/blob/8422d0c4c35ef970539466c5bdec1cd27369bab3/modules/light-clients/07-tendermint/types/client_state.go#L74 - let frozen_height = - Height::try_from(raw.frozen_height.ok_or(DecodingError::MissingRawData { - description: "frozen height not set".to_string(), - })?) - .ok(); + let frozen_height = Height::try_from(raw.frozen_height.ok_or( + DecodingError::missing_raw_data("tm client state frozen height"), + )?) + .ok(); // We use set this deprecated field just so that we can properly convert // it back in its raw form @@ -315,7 +304,7 @@ impl TryFrom for ClientState { unbonding_period, max_clock_drift, latest_height, - raw.proof_specs.try_into()?, + proof_specs, raw.upgrade_path, frozen_height, allow_update, @@ -355,20 +344,17 @@ impl From for RawTmClientState { impl Protobuf for ClientState {} impl TryFrom for ClientState { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { fn decode_client_state(value: &[u8]) -> Result { - let client_state = - Protobuf::::decode(value).map_err(DecodingError::Protobuf)?; + let client_state = Protobuf::::decode(value)?; Ok(client_state) } match raw.type_url.as_str() { - TENDERMINT_CLIENT_STATE_TYPE_URL => { - decode_client_state(&raw.value).map_err(ClientError::Decoding) - } - _ => Err(DecodingError::MismatchedTypeUrls { + TENDERMINT_CLIENT_STATE_TYPE_URL => decode_client_state(&raw.value), + _ => Err(DecodingError::MismatchedResourceName { expected: TENDERMINT_CLIENT_STATE_TYPE_URL.to_string(), actual: raw.type_url, })?, diff --git a/ibc-clients/ics07-tendermint/types/src/consensus_state.rs b/ibc-clients/ics07-tendermint/types/src/consensus_state.rs index 723da3497..3bd630a8a 100644 --- a/ibc-clients/ics07-tendermint/types/src/consensus_state.rs +++ b/ibc-clients/ics07-tendermint/types/src/consensus_state.rs @@ -1,6 +1,5 @@ //! Defines Tendermint's `ConsensusState` type -use ibc_core_client_types::error::ClientError; use ibc_core_commitment_types::commitment::CommitmentRoot; use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; @@ -52,27 +51,24 @@ impl TryFrom for ConsensusState { fn try_from(raw: RawConsensusState) -> Result { let proto_root = raw .root - .ok_or(DecodingError::MissingRawData { - description: "no commitment root set".into(), - })? + .ok_or(DecodingError::missing_raw_data( + "consensus state commitment root", + ))? .hash; - let ibc_proto::google::protobuf::Timestamp { seconds, nanos } = - raw.timestamp.ok_or(DecodingError::MissingRawData { - description: "no timestamp set".into(), - })?; + let ibc_proto::google::protobuf::Timestamp { seconds, nanos } = raw + .timestamp + .ok_or(DecodingError::missing_raw_data("consensus state timestamp"))?; // FIXME: shunts like this are necessary due to // https://github.com/informalsystems/tendermint-rs/issues/1053 let proto_timestamp = tpb::Timestamp { seconds, nanos }; let timestamp = proto_timestamp .try_into() - .map_err(|e| DecodingError::InvalidRawData { - description: format!("invalid timestamp: {e}"), - })?; + .map_err(|e| DecodingError::invalid_raw_data(format!("timestamp: {e}")))?; let next_validators_hash = Hash::from_bytes(Algorithm::Sha256, &raw.next_validators_hash) - .map_err(|e| DecodingError::InvalidHash { - description: e.to_string(), + .map_err(|e| { + DecodingError::invalid_raw_data(format!("next validators hash: {e}")) })?; Ok(Self { @@ -103,7 +99,7 @@ impl From for RawConsensusState { impl Protobuf for ConsensusState {} impl TryFrom for ConsensusState { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { fn decode_consensus_state(value: &[u8]) -> Result { @@ -112,10 +108,8 @@ impl TryFrom for ConsensusState { } match raw.type_url.as_str() { - TENDERMINT_CONSENSUS_STATE_TYPE_URL => { - decode_consensus_state(&raw.value).map_err(ClientError::Decoding) - } - _ => Err(DecodingError::MismatchedTypeUrls { + TENDERMINT_CONSENSUS_STATE_TYPE_URL => decode_consensus_state(&raw.value), + _ => Err(DecodingError::MismatchedResourceName { expected: TENDERMINT_CONSENSUS_STATE_TYPE_URL.to_string(), actual: raw.type_url, })?, diff --git a/ibc-clients/ics07-tendermint/types/src/error.rs b/ibc-clients/ics07-tendermint/types/src/error.rs index eb4c2c67d..588e39f18 100644 --- a/ibc-clients/ics07-tendermint/types/src/error.rs +++ b/ibc-clients/ics07-tendermint/types/src/error.rs @@ -17,17 +17,17 @@ use tendermint_light_client_verifier::Verdict; /// The main error type for the Tendermint light client #[derive(Debug, Display)] pub enum TendermintClientError { - /// decoding error: `{0}` + /// decoding error: {0} Decoding(DecodingError), - /// invalid client state trust threshold: `{description}` + /// invalid client state trust threshold: {description} InvalidTrustThreshold { description: String }, - /// invalid clock drift; must be greater than 0 + /// invalid max clock drift; must be greater than 0 InvalidMaxClockDrift, - /// invalid client proof specs: `{0}` + /// invalid client proof specs `{0}` InvalidProofSpec(CommitmentError), - /// invalid header timestamp: `{0}` - InvalidHeaderTimestamp(TimestampError), - /// invalid header height: `{0}` + /// invalid timestamp `{0}` + InvalidTimestamp(TimestampError), + /// invalid header height `{0}` InvalidHeaderHeight(u64), /// mismatched revision heights: expected `{expected}`, actual `{actual}` MismatchedRevisionHeights { expected: u64, actual: u64 }, @@ -35,11 +35,11 @@ pub enum TendermintClientError { MismatchedHeaderChainIds { expected: String, actual: String }, /// mismatched validator hashes: expected `{expected}`, actual `{actual}` MismatchedValidatorHashes { expected: Hash, actual: Hash }, - /// empty client state upgrade-path key - EmptyUpgradePathKey, - /// failed to verify header: `{0}` + /// missing client state upgrade-path key + MissingUpgradePathKey, + /// failed to verify header: {0} FailedToVerifyHeader(Box), - /// insufficient validator overlap: `{0}` + /// insufficient validator overlap `{0}` InsufficientValidatorOverlap(VotingPowerTally), /// insufficient trusting period `{trusting_period:?}`; should be > consensus state timestamp `{duration_since_consensus_state:?}` InsufficientTrustingPeriod { @@ -55,13 +55,13 @@ impl std::error::Error for TendermintClientError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self { Self::Decoding(e) => Some(e), + Self::InvalidTimestamp(e) => Some(e), + Self::InvalidProofSpec(e) => Some(e), _ => None, } } } -// TODO(seanchen1991): Should this impl be deprecated in favor of a -// From for TendermintClientError impl? impl From for ClientError { fn from(e: TendermintClientError) -> Self { Self::ClientSpecific { @@ -88,6 +88,12 @@ impl From for TendermintClientError { } } +impl From for TendermintClientError { + fn from(e: TimestampError) -> Self { + Self::InvalidTimestamp(e) + } +} + pub trait IntoResult { fn into_result(self) -> Result; } diff --git a/ibc-clients/ics07-tendermint/types/src/header.rs b/ibc-clients/ics07-tendermint/types/src/header.rs index aaadfde07..a7abc0dff 100644 --- a/ibc-clients/ics07-tendermint/types/src/header.rs +++ b/ibc-clients/ics07-tendermint/types/src/header.rs @@ -53,7 +53,7 @@ impl Header { .header .time .try_into() - .map_err(TendermintClientError::InvalidHeaderTimestamp) + .map_err(TendermintClientError::InvalidTimestamp) } pub fn height(&self) -> Height { @@ -120,10 +120,9 @@ impl Header { if &self.trusted_next_validator_set.hash_with::() == trusted_next_validator_hash { Ok(()) } else { - Err(ClientError::FailedHeaderVerification { - description: - "header trusted next validator set hash does not match hash stored on chain" - .to_string(), + Err(ClientError::FailedToVerifyHeader { + description: "trusted next validator set hash does not match hash stored on chain" + .to_string(), }) } } @@ -165,42 +164,32 @@ impl Header { impl Protobuf for Header {} impl TryFrom for Header { - type Error = TendermintClientError; + type Error = DecodingError; fn try_from(raw: RawHeader) -> Result { let header = Self { signed_header: raw .signed_header - .ok_or(DecodingError::MissingRawData { - description: "signed header not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data("signed header"))? .try_into() - .map_err(|e| DecodingError::InvalidRawData { - description: format!("failed to decode signed header: {e:?}"), - })?, + .map_err(|e| DecodingError::invalid_raw_data(format!("signed header: {e:?}")))?, validator_set: raw .validator_set - .ok_or(DecodingError::MissingRawData { - description: "validator set not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data("validator set"))? .try_into() - .map_err(|e| DecodingError::InvalidRawData { - description: format!("failed to decode validator set: {e:?}"), - })?, + .map_err(|e| DecodingError::invalid_raw_data(format!("validator set: {e:?}")))?, trusted_height: raw .trusted_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::MissingRawData { - description: "trusted height not set".to_string(), - })?, + .ok_or(DecodingError::missing_raw_data("trusted height"))?, trusted_next_validator_set: raw .trusted_validators - .ok_or(DecodingError::MissingRawData { - description: "trusted next validator set not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data( + "trusted next validator set", + ))? .try_into() - .map_err(|e| DecodingError::InvalidRawData { - description: format!("failed to decode trusted next validator set: {e:?}"), + .map_err(|e| { + DecodingError::invalid_raw_data(format!("trusted next validator set: {e:?}")) })?, }; @@ -211,7 +200,7 @@ impl TryFrom for Header { impl Protobuf for Header {} impl TryFrom for Header { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { fn decode_header(value: &[u8]) -> Result { @@ -219,8 +208,8 @@ impl TryFrom for Header { Ok(header) } match raw.type_url.as_str() { - TENDERMINT_HEADER_TYPE_URL => decode_header(&raw.value).map_err(ClientError::Decoding), - _ => Err(DecodingError::MismatchedTypeUrls { + TENDERMINT_HEADER_TYPE_URL => decode_header(&raw.value), + _ => Err(DecodingError::MismatchedResourceName { expected: TENDERMINT_HEADER_TYPE_URL.to_string(), actual: raw.type_url, })?, diff --git a/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs b/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs index 17de928e7..ebb900326 100644 --- a/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs +++ b/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs @@ -1,6 +1,5 @@ //! Defines the misbehaviour type for the tendermint light client -use ibc_core_client_types::error::ClientError; use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; @@ -75,23 +74,20 @@ impl Misbehaviour { impl Protobuf for Misbehaviour {} impl TryFrom for Misbehaviour { - type Error = TendermintClientError; + type Error = DecodingError; + #[allow(deprecated)] fn try_from(raw: RawMisbehaviour) -> Result { let client_id = raw.client_id.parse()?; let header1: Header = raw .header_1 - .ok_or_else(|| DecodingError::MissingRawData { - description: "missing header1 in raw misbehaviour".into(), - })? + .ok_or_else(|| DecodingError::missing_raw_data("misbehaviour header1"))? .try_into()?; let header2: Header = raw .header_2 - .ok_or_else(|| DecodingError::MissingRawData { - description: "missing header2 in raw misbehaviour".into(), - })? + .ok_or_else(|| DecodingError::missing_raw_data("misbehaviour header2"))? .try_into()?; Ok(Self::new(client_id, header1, header2)) @@ -112,18 +108,16 @@ impl From for RawMisbehaviour { impl Protobuf for Misbehaviour {} impl TryFrom for Misbehaviour { - type Error = ClientError; + type Error = DecodingError; - fn try_from(raw: Any) -> Result { + fn try_from(raw: Any) -> Result { fn decode_misbehaviour(value: &[u8]) -> Result { let misbehaviour = Protobuf::::decode(value)?; Ok(misbehaviour) } match raw.type_url.as_str() { - TENDERMINT_MISBEHAVIOUR_TYPE_URL => { - decode_misbehaviour(&raw.value).map_err(ClientError::Decoding) - } - _ => Err(DecodingError::MismatchedTypeUrls { + TENDERMINT_MISBEHAVIOUR_TYPE_URL => decode_misbehaviour(&raw.value), + _ => Err(DecodingError::MismatchedResourceName { expected: TENDERMINT_MISBEHAVIOUR_TYPE_URL.to_string(), actual: raw.type_url, })?, diff --git a/ibc-clients/ics07-tendermint/types/src/trust_threshold.rs b/ibc-clients/ics07-tendermint/types/src/trust_threshold.rs index 401390b5e..bad001302 100644 --- a/ibc-clients/ics07-tendermint/types/src/trust_threshold.rs +++ b/ibc-clients/ics07-tendermint/types/src/trust_threshold.rs @@ -5,6 +5,7 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use ibc_core_client_types::error::ClientError; +use ibc_core_host_types::error::DecodingError; use ibc_proto::ibc::lightclients::tendermint::v1::Fraction; use ibc_proto::Protobuf; use tendermint::trust_threshold::TrustThresholdFraction; @@ -103,13 +104,11 @@ impl From for TrustThreshold { /// Conversion from IBC domain type into /// Tendermint domain type. impl TryFrom for TrustThresholdFraction { - type Error = ClientError; + type Error = DecodingError; fn try_from(t: TrustThreshold) -> Result { - Self::new(t.numerator, t.denominator).map_err(|_| ClientError::InvalidTrustThreshold { - numerator: t.numerator, - denominator: t.denominator, - }) + Self::new(t.numerator, t.denominator) + .map_err(|_| DecodingError::invalid_raw_data("trust threshold")) } } @@ -125,10 +124,11 @@ impl From for Fraction { } impl TryFrom for TrustThreshold { - type Error = ClientError; + type Error = DecodingError; fn try_from(value: Fraction) -> Result { Self::new(value.numerator, value.denominator) + .map_err(|_| DecodingError::invalid_raw_data("trust threshold")) } } diff --git a/ibc-clients/ics08-wasm/types/src/client_state.rs b/ibc-clients/ics08-wasm/types/src/client_state.rs index b7506267a..c2e2ebea5 100644 --- a/ibc-clients/ics08-wasm/types/src/client_state.rs +++ b/ibc-clients/ics08-wasm/types/src/client_state.rs @@ -43,13 +43,10 @@ impl TryFrom for ClientState { fn try_from(raw: RawClientState) -> Result { let latest_height = raw .latest_height - .ok_or(DecodingError::MissingRawData { - description: "latest height not set".to_string(), - })? - .try_into() - .map_err(|e| DecodingError::InvalidRawData { - description: format!("failed to decode latest height: {e}"), - })?; + .ok_or(DecodingError::missing_raw_data( + "client state latest height", + ))? + .try_into()?; Ok(Self { data: raw.data, checksum: raw.checksum, @@ -80,7 +77,7 @@ impl TryFrom for ClientState { match any.type_url.as_str() { WASM_CLIENT_STATE_TYPE_URL => decode_client_state(&any.value), - _ => Err(DecodingError::MismatchedTypeUrls { + _ => Err(DecodingError::MismatchedResourceName { expected: WASM_CLIENT_STATE_TYPE_URL.to_string(), actual: any.type_url, })?, diff --git a/ibc-clients/ics08-wasm/types/src/consensus_state.rs b/ibc-clients/ics08-wasm/types/src/consensus_state.rs index a1346cb32..a6f129469 100644 --- a/ibc-clients/ics08-wasm/types/src/consensus_state.rs +++ b/ibc-clients/ics08-wasm/types/src/consensus_state.rs @@ -1,6 +1,5 @@ //! Defines the consensus state type for the ICS-08 Wasm light client. -use ibc_core_client::types::error::ClientError; use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_primitives::proto::{Any, Protobuf}; @@ -36,7 +35,7 @@ impl From for RawConsensusState { } impl TryFrom for ConsensusState { - type Error = ClientError; + type Error = DecodingError; fn try_from(value: RawConsensusState) -> Result { Ok(Self { data: value.data }) @@ -55,7 +54,7 @@ impl From for Any { } impl TryFrom for ConsensusState { - type Error = ClientError; + type Error = DecodingError; fn try_from(any: Any) -> Result { fn decode_consensus_state(value: &[u8]) -> Result { @@ -63,10 +62,8 @@ impl TryFrom for ConsensusState { Ok(consensus_state) } match any.type_url.as_str() { - WASM_CONSENSUS_STATE_TYPE_URL => { - decode_consensus_state(&any.value).map_err(ClientError::Decoding) - } - _ => Err(DecodingError::MismatchedTypeUrls { + WASM_CONSENSUS_STATE_TYPE_URL => decode_consensus_state(&any.value), + _ => Err(DecodingError::MismatchedResourceName { expected: WASM_CONSENSUS_STATE_TYPE_URL.to_string(), actual: any.type_url.to_string(), })?, diff --git a/ibc-core/ics02-client/src/handler/create_client.rs b/ibc-core/ics02-client/src/handler/create_client.rs index fa79a9eac..511f45f2c 100644 --- a/ibc-core/ics02-client/src/handler/create_client.rs +++ b/ibc-core/ics02-client/src/handler/create_client.rs @@ -35,7 +35,7 @@ where let status = client_state.status(client_val_ctx, &client_id)?; if status.is_frozen() { - return Err(ClientError::UnexpectedStatus(Status::Frozen)); + return Err(ClientError::InvalidStatus(Status::Frozen)); }; let host_timestamp = ctx.host_timestamp()?; diff --git a/ibc-core/ics02-client/src/handler/recover_client.rs b/ibc-core/ics02-client/src/handler/recover_client.rs index f08cefd98..a239ed8fc 100644 --- a/ibc-core/ics02-client/src/handler/recover_client.rs +++ b/ibc-core/ics02-client/src/handler/recover_client.rs @@ -29,7 +29,7 @@ where let substitute_height = substitute_client_state.latest_height(); if subject_height >= substitute_height { - return Err(ClientError::NotAllowedClientRecoveryHeights { + return Err(ClientError::InvalidClientRecoveryHeights { subject_height, substitute_height, }); diff --git a/ibc-core/ics02-client/src/handler/update_client.rs b/ibc-core/ics02-client/src/handler/update_client.rs index 569141490..51a30c3b1 100644 --- a/ibc-core/ics02-client/src/handler/update_client.rs +++ b/ibc-core/ics02-client/src/handler/update_client.rs @@ -64,7 +64,7 @@ where ctx.emit_ibc_event(event)?; } else { if !matches!(update_kind, UpdateKind::UpdateClient) { - return Err(ClientError::FailedMisbehaviourHandling { + return Err(ClientError::FailedToHandleMisbehaviour { description: "misbehaviour submitted, but none found".to_string(), }); } @@ -77,7 +77,7 @@ where { let event = { let consensus_height = consensus_heights.first().ok_or( - HostError::missing_state("missing updated height in client update state"), + HostError::missing_state("updated height in client update state"), )?; IbcEvent::UpdateClient(UpdateClient::new( diff --git a/ibc-core/ics02-client/types/src/error.rs b/ibc-core/ics02-client/types/src/error.rs index 0b15ac36c..bdd4b509f 100644 --- a/ibc-core/ics02-client/types/src/error.rs +++ b/ibc-core/ics02-client/types/src/error.rs @@ -2,10 +2,10 @@ use displaydoc::Display; use ibc_core_commitment_types::error::CommitmentError; -use ibc_core_host_types::error::{DecodingError, HostError}; +use ibc_core_host_types::error::{DecodingError, HostError, IdentifierError}; use ibc_core_host_types::identifiers::ClientId; use ibc_primitives::prelude::*; -use ibc_primitives::Timestamp; +use ibc_primitives::{Timestamp, TimestampError}; use crate::height::Height; use crate::Status; @@ -13,69 +13,49 @@ use crate::Status; /// Encodes all the possible client errors #[derive(Debug, Display)] pub enum ClientError { - /// host error : `{0}` + /// host error : {0} Host(HostError), - /// upgrade client error: `{0}` + /// upgrade client error: {0} Upgrade(UpgradeClientError), - /// decoding error: `{0}` + /// decoding error: {0} Decoding(DecodingError), - /// invalid trust threshold: `{numerator}`/`{denominator}` + /// timestamp error: {0} + Timestamp(TimestampError), + /// invalid trust threshold `{numerator}`/`{denominator}` InvalidTrustThreshold { numerator: u64, denominator: u64 }, - /// invalid client state type: `{0}` + /// invalid client state type `{0}` InvalidClientStateType(String), /// invalid update client message InvalidUpdateClientMessage, /// invalid height; cannot be zero or negative InvalidHeight, - /// invalid proof height; expected `{actual}` >= `{expected}` - InvalidProofHeight { actual: Height, expected: Height }, - /// invalid consensus state timestamp: `{0}` + /// invalid status `{0}` + InvalidStatus(Status), + /// invalid consensus state timestamp `{0}` InvalidConsensusStateTimestamp(Timestamp), - /// invalid attribute key: `{0}` - InvalidAttributeKey(String), - /// invalid attribute value: `{0}` - InvalidAttributeValue(String), - /// invalid status: `{0}` - InvalidStatus(String), - /// invalid header type: `{0}` + /// invalid header type `{0}` InvalidHeaderType(String), - /// missing local consensus state at `{0}` - MissingLocalConsensusState(Height), - /// missing attribute key - MissingAttributeKey, - /// missing attribute value - MissingAttributeValue, - /// unexpected status found: `{0}` - UnexpectedStatus(Status), - /// client state already exists: `{0}` - DuplicateClientState(ClientId), - /// mismatched client recovery states - MismatchedClientRecoveryStates, - /// client recovery heights not allowed: expected substitute client height `{substitute_height}` > subject client height `{subject_height}` - NotAllowedClientRecoveryHeights { + /// invalid client recovery heights: expected substitute client height `{substitute_height}` > subject client height `{subject_height}` + InvalidClientRecoveryHeights { subject_height: Height, substitute_height: Height, }, - /// failed ICS23 verification: `{0}` + /// insufficient proof height; expected `{actual}` >= `{expected}` + InsufficientProofHeight { expected: Height, actual: Height }, + /// missing local consensus state at `{0}` + MissingLocalConsensusState(Height), + /// duplicate client state `{0}` + DuplicateClientState(ClientId), + /// failed to verify client recovery states + FailedToVerifyClientRecoveryStates, + /// failed ICS23 verification: {0} FailedICS23Verification(CommitmentError), - /// failed header verification: `{description}` - FailedHeaderVerification { description: String }, - /// failed misbehaviour handling: `{description}` - FailedMisbehaviourHandling { description: String }, - - // TODO(seanchen1991): Incorporate this error into its own variants - /// client-specific error: `{description}` + /// failed to verify header: {description} + FailedToVerifyHeader { description: String }, + /// failed to handle misbehaviour: {description} + FailedToHandleMisbehaviour { description: String }, + /// client-specific error: {description} ClientSpecific { description: String }, - /// other error: `{description}` - Other { description: String }, -} - -impl From<&'static str> for ClientError { - fn from(s: &'static str) -> Self { - Self::Other { - description: s.to_string(), - } - } } impl From for ClientError { @@ -96,6 +76,18 @@ impl From for ClientError { } } +impl From for ClientError { + fn from(e: IdentifierError) -> Self { + Self::Decoding(DecodingError::Identifier(e)) + } +} + +impl From for ClientError { + fn from(e: TimestampError) -> Self { + Self::Timestamp(e) + } +} + #[cfg(feature = "std")] impl std::error::Error for ClientError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { @@ -104,6 +96,7 @@ impl std::error::Error for ClientError { Self::Decoding(e) => Some(e), Self::Upgrade(e) => Some(e), Self::Host(e) => Some(e), + Self::Timestamp(e) => Some(e), _ => None, } } diff --git a/ibc-core/ics02-client/types/src/events.rs b/ibc-core/ics02-client/types/src/events.rs index c6c36dc3c..744776b88 100644 --- a/ibc-core/ics02-client/types/src/events.rs +++ b/ibc-core/ics02-client/types/src/events.rs @@ -8,8 +8,8 @@ use subtle_encoding::hex; use tendermint::abci; use self::str::FromStr; -use crate::error::ClientError; use crate::height::Height; + /// Client event types pub const CREATE_CLIENT_EVENT: &str = "create_client"; pub const UPDATE_CLIENT_EVENT: &str = "update_client"; @@ -60,14 +60,13 @@ impl TryFrom for ClientIdAttribute { fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != CLIENT_ID_ATTRIBUTE_KEY { - return Err(DecodingError::InvalidRawData { - description: format!("invalid attribute key {}", key_str), + return Err(DecodingError::MismatchedResourceName { + expected: CLIENT_ID_ATTRIBUTE_KEY.to_string(), + actual: key_str.to_string(), }); } } else { - return Err(DecodingError::MissingRawData { - description: "missing attribute key".to_string(), - }); + return Err(DecodingError::missing_raw_data("attribute key")); } value @@ -76,9 +75,7 @@ impl TryFrom for ClientIdAttribute { let client_id = ClientId::from_str(value)?; Ok(ClientIdAttribute { client_id }) }) - .map_err(|e| DecodingError::MissingRawData { - description: format!("missing attribute value: {e}"), - })? + .map_err(|e| DecodingError::missing_raw_data(format!("attribute value: {e}")))? } } @@ -112,14 +109,13 @@ impl TryFrom for ClientTypeAttribute { fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != CLIENT_TYPE_ATTRIBUTE_KEY { - return Err(DecodingError::InvalidRawData { - description: format!("invalid attribute key {}", key_str), - }); + return Err(DecodingError::MismatchedResourceName { + expected: CLIENT_TYPE_ATTRIBUTE_KEY.to_string(), + actual: key_str.to_string(), + })?; } } else { - return Err(DecodingError::MissingRawData { - description: "missing attribute key".to_string(), - }); + return Err(DecodingError::missing_raw_data("client type attribute key")); } value @@ -128,8 +124,8 @@ impl TryFrom for ClientTypeAttribute { let client_type = ClientType::from_str(value)?; Ok(ClientTypeAttribute { client_type }) }) - .map_err(|e| DecodingError::MissingRawData { - description: format!("missing attribute value: {e}"), + .map_err(|e| { + DecodingError::missing_raw_data(format!("client type attribute value: {e}")) })? } } @@ -164,27 +160,25 @@ impl TryFrom for ConsensusHeightAttribute { fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != CONSENSUS_HEIGHT_ATTRIBUTE_KEY { - return Err(DecodingError::InvalidRawData { - description: format!("invalid attribute key {}", key_str), - }); + return Err(DecodingError::MismatchedResourceName { + expected: CONSENSUS_HEIGHT_ATTRIBUTE_KEY.to_string(), + actual: key_str.to_string(), + })?; } } else { - return Err(DecodingError::MissingRawData { - description: "missing attribute key".to_string(), - }); + return Err(DecodingError::missing_raw_data( + "consensus height attribute key", + )); } value .value_str() .map(|value| { - let consensus_height = - Height::from_str(value).map_err(|e| DecodingError::InvalidRawData { - description: format!("invalid attribute value: {e}"), - })?; + let consensus_height = Height::from_str(value)?; Ok(ConsensusHeightAttribute { consensus_height }) }) - .map_err(|e| DecodingError::MissingRawData { - description: format!("missing attribute value: {e}"), + .map_err(|e| { + DecodingError::missing_raw_data(format!("consensus height attribute value: {e}")) })? } } @@ -219,15 +213,20 @@ impl From for abci::EventAttribute { } impl TryFrom for ConsensusHeightsAttribute { - type Error = ClientError; + type Error = DecodingError; fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != CONSENSUS_HEIGHTS_ATTRIBUTE_KEY { - return Err(ClientError::InvalidAttributeKey(key_str.to_string())); + return Err(DecodingError::MismatchedResourceName { + expected: CONSENSUS_HEIGHTS_ATTRIBUTE_KEY.to_string(), + actual: key_str.to_string(), + })?; } } else { - return Err(ClientError::MissingAttributeKey); + return Err(DecodingError::missing_raw_data( + "consensus heights attribute key", + )); } value @@ -235,15 +234,15 @@ impl TryFrom for ConsensusHeightsAttribute { .map(|value| { let consensus_heights: Vec = value .split(',') - .map(|height_str| { - Height::from_str(height_str) - .map_err(|_| ClientError::InvalidAttributeValue(height_str.to_string())) - }) - .collect::, ClientError>>()?; + .map(Height::from_str) + .collect::, DecodingError>>( + )?; Ok(ConsensusHeightsAttribute { consensus_heights }) }) - .map_err(|_| ClientError::MissingAttributeValue)? + .map_err(|e| { + DecodingError::invalid_raw_data(format!("consensus heights attribute value: {e}")) + })? } } @@ -272,32 +271,36 @@ impl From for abci::EventAttribute { ( HEADER_ATTRIBUTE_KEY, str::from_utf8(&hex::encode(attr.header)) - .expect("Never fails because hexadecimal is valid UTF-8"), + .expect("never fails because hexadecimal is valid UTF-8"), ) .into() } } impl TryFrom for HeaderAttribute { - type Error = ClientError; + type Error = DecodingError; fn try_from(value: abci::EventAttribute) -> Result { if let Ok(key_str) = value.key_str() { if key_str != HEADER_ATTRIBUTE_KEY { - return Err(ClientError::InvalidAttributeKey(key_str.to_string())); + return Err(DecodingError::MismatchedResourceName { + expected: HEADER_ATTRIBUTE_KEY.to_string(), + actual: key_str.to_string(), + })?; } } else { - return Err(ClientError::MissingAttributeKey); + return Err(DecodingError::missing_raw_data("header attribute key")); } value .value_str() .map(|value| { - let header = hex::decode(value) - .map_err(|_| ClientError::InvalidAttributeValue(value.to_string()))?; + let header = hex::decode(value).map_err(|e| { + DecodingError::invalid_raw_data(format!("header attribute value: {e}")) + })?; Ok(HeaderAttribute { header }) }) - .map_err(|_| ClientError::MissingAttributeValue)? + .map_err(|e| DecodingError::invalid_raw_data(format!("header attribute value: {e}")))? } } @@ -366,9 +369,10 @@ impl TryFrom for CreateClient { fn try_from(value: abci::Event) -> Result { if value.kind != CREATE_CLIENT_EVENT { - return Err(DecodingError::InvalidRawData { - description: format!("invalid event kind: expected `{}`", CREATE_CLIENT_EVENT), - }); + return Err(DecodingError::MismatchedResourceName { + expected: CREATE_CLIENT_EVENT.to_string(), + actual: value.kind, + })?; } value @@ -382,19 +386,13 @@ impl TryFrom for CreateClient { Option, ), attribute| { - let key = attribute - .key_str() - .map_err(|_| DecodingError::MissingRawData { - description: "missing attribute key".to_string(), - })?; + let key = attribute.key_str().map_err(|e| { + DecodingError::missing_raw_data(format!("create client attribute key: {e}")) + })?; match key { CLIENT_ID_ATTRIBUTE_KEY => Ok(( - Some(attribute.clone().try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("{e}"), - } - })?), + Some(attribute.clone().try_into()?), client_type, consensus_height, )), @@ -416,16 +414,13 @@ impl TryFrom for CreateClient { Option, Option, )| { - let client_id = client_id.ok_or(DecodingError::MissingRawData { - description: "missing attribute key".to_string(), - })?; - let client_type = client_type.ok_or(DecodingError::MissingRawData { - description: "missing attribute key".to_string(), - })?; - let consensus_height = - consensus_height.ok_or(DecodingError::MissingRawData { - description: "missing attribute key".to_string(), - })?; + let client_id = + client_id.ok_or(DecodingError::missing_raw_data("client ID attribute"))?; + let client_type = client_type + .ok_or(DecodingError::missing_raw_data("client type attribute"))?; + let consensus_height = consensus_height.ok_or( + DecodingError::missing_raw_data("consensus height attribute"), + )?; Ok(CreateClient::new( client_id.client_id, @@ -522,13 +517,14 @@ impl From for abci::Event { } } impl TryFrom for UpdateClient { - type Error = ClientError; + type Error = DecodingError; fn try_from(value: abci::Event) -> Result { if value.kind != UPDATE_CLIENT_EVENT { - return Err(ClientError::Other { - description: "Error in parsing UpdateClient event".to_string(), - }); + return Err(DecodingError::MismatchedResourceName { + expected: UPDATE_CLIENT_EVENT.to_string(), + actual: value.kind.to_string(), + })?; } type UpdateClientAttributes = ( @@ -545,9 +541,9 @@ impl TryFrom for UpdateClient { .try_fold( (None, None, None, None, None), |acc: UpdateClientAttributes, attribute| { - let key = attribute - .key_str() - .map_err(|_| ClientError::MissingAttributeKey)?; + let key = attribute.key_str().map_err(|e| { + DecodingError::invalid_raw_data(format!("attribute key: {e}")) + })?; match key { CLIENT_ID_ATTRIBUTE_KEY => Ok(( @@ -591,17 +587,25 @@ impl TryFrom for UpdateClient { ) .and_then( |(client_id, client_type, consensus_height, consensus_heights, header)| { - let client_id = client_id.ok_or(ClientError::MissingAttributeKey)?.client_id; + let client_id = client_id + .ok_or(DecodingError::missing_raw_data("client ID"))? + .client_id; let client_type = client_type - .ok_or(ClientError::MissingAttributeKey)? + .ok_or(DecodingError::missing_raw_data("client type attribute"))? .client_type; let consensus_height = consensus_height - .ok_or(ClientError::MissingAttributeKey)? + .ok_or(DecodingError::missing_raw_data( + "consensus height attribute", + ))? .consensus_height; let consensus_heights = consensus_heights - .ok_or(ClientError::MissingAttributeKey)? + .ok_or(DecodingError::missing_raw_data( + "consensus heights attribute", + ))? .consensus_heights; - let header = header.ok_or(ClientError::MissingAttributeKey)?.header; + let header = header + .ok_or(DecodingError::missing_raw_data("header attribute"))? + .header; Ok(UpdateClient::new( client_id, @@ -729,7 +733,6 @@ impl From for abci::Event { mod tests { use core::any::Any; - use ibc_core_host_types::error::IdentifierError; use rstest::*; use super::*; @@ -759,10 +762,10 @@ mod tests { abci::EventAttribute::from(("consensus_height", "1-10")), ], }, - Err(IdentifierError::FailedToParse { - value: "CreateClient".to_string(), - description: "failed to parse event".to_string() - }.into()) + Err(DecodingError::MismatchedResourceName { + expected: "CreateClient".to_string(), + actual: "some_other_event".to_string(), + }) )] #[case( abci::Event { @@ -772,7 +775,7 @@ mod tests { abci::EventAttribute::from(("consensus_height", "1-10")), ], }, - Err(DecodingError::MissingRawData { description: "missing attribute key".to_string() }), + Err(DecodingError::missing_raw_data("attribute key")), )] fn test_create_client_try_from( #[case] event: abci::Event, @@ -820,8 +823,9 @@ mod tests { abci::EventAttribute::from(("header", "1234")), ], }, - Err(ClientError::Other { - description: "Error in parsing UpdateClient event".to_string(), + Err(DecodingError::MismatchedResourceName { + expected: UPDATE_CLIENT_EVENT.to_string(), + actual: "some_other_event".to_owned(), }), )] #[case( @@ -834,11 +838,11 @@ mod tests { abci::EventAttribute::from(("header", "1234")), ], }, - Err(ClientError::MissingAttributeKey), + Err(DecodingError::missing_raw_data("attribute key")), )] fn test_update_client_try_from( #[case] event: abci::Event, - #[case] expected: Result, + #[case] expected: Result, ) { let result = UpdateClient::try_from(event); if expected.is_err() { diff --git a/ibc-core/ics02-client/types/src/height.rs b/ibc-core/ics02-client/types/src/height.rs index 92da357ee..612351863 100644 --- a/ibc-core/ics02-client/types/src/height.rs +++ b/ibc-core/ics02-client/types/src/height.rs @@ -1,10 +1,8 @@ //! Defines the core `Height` type used throughout the library use core::cmp::Ordering; -use core::num::ParseIntError; use core::str::FromStr; -use displaydoc::Display; use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_proto::ibc::core::client::v1::Height as RawHeight; @@ -121,7 +119,7 @@ impl TryFrom for Height { fn try_from(raw_height: RawHeight) -> Result { Height::new(raw_height.revision_number, raw_height.revision_height) - .map_err(DecodingError::invalid_raw_data) + .map_err(|_| DecodingError::invalid_raw_data("height of 0 not allowed")) } } @@ -150,58 +148,19 @@ impl core::fmt::Display for Height { } } -/// Encodes all errors related to chain heights -#[derive(Debug, Display, PartialEq, Eq)] -pub enum HeightError { - /// cannot convert into a `Height` type from string `{height}` - HeightConversion { - height: String, - error: ParseIntError, - }, - /// attempted to parse an invalid zero height - ZeroHeight, - /// the height(`{raw_height}`) is not a valid format, this format must be used: \[revision_number\]-\[revision_height\] - InvalidFormat { raw_height: String }, -} - -#[cfg(feature = "std")] -impl std::error::Error for HeightError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match &self { - HeightError::HeightConversion { error: e, .. } => Some(e), - HeightError::ZeroHeight | HeightError::InvalidFormat { .. } => None, - } - } -} - impl TryFrom<&str> for Height { - type Error = HeightError; + type Error = DecodingError; fn try_from(value: &str) -> Result { - let (rev_number_str, rev_height_str) = - value - .split_once('-') - .ok_or_else(|| HeightError::InvalidFormat { - raw_height: value.to_owned(), - })?; - - let revision_number = - rev_number_str - .parse::() - .map_err(|e| HeightError::HeightConversion { - height: value.to_owned(), - error: e, - })?; - - let revision_height = - rev_height_str - .parse::() - .map_err(|e| HeightError::HeightConversion { - height: value.to_owned(), - error: e, - })?; - - Height::new(revision_number, revision_height).map_err(|_| HeightError::ZeroHeight) + let (rev_number_str, rev_height_str) = value.split_once('-').ok_or_else(|| { + DecodingError::invalid_raw_data(format!("height `{value}` not properly formatted")) + })?; + + let revision_number = rev_number_str.parse::()?; + let revision_height = rev_height_str.parse::()?; + + Height::new(revision_number, revision_height) + .map_err(|_| DecodingError::invalid_raw_data("height of 0 not allowed")) } } @@ -212,7 +171,7 @@ impl From for String { } impl FromStr for Height { - type Err = HeightError; + type Err = DecodingError; fn from_str(s: &str) -> Result { Height::try_from(s) @@ -222,41 +181,34 @@ impl FromStr for Height { #[test] fn test_valid_height() { assert_eq!( - "1-1".parse::(), - Ok(Height { + "1-1".parse::().unwrap(), + Height { revision_number: 1, revision_height: 1 - }) + } ); assert_eq!( - "1-10".parse::(), - Ok(Height { + "1-10".parse::().unwrap(), + Height { revision_number: 1, revision_height: 10 - }) + } ); } #[test] fn test_invalid_height() { - assert_eq!( - HeightError::ZeroHeight, - "0-0".parse::().unwrap_err() - ); + assert!("0-0".parse::().is_err()); assert!("0-".parse::().is_err()); assert!("-0".parse::().is_err()); assert!("-".parse::().is_err()); assert!("1-1-1".parse::().is_err()); - assert_eq!( - "1".parse::(), - Err(HeightError::InvalidFormat { - raw_height: "1".to_owned() - }) - ); - assert_eq!( - "".parse::(), - Err(HeightError::InvalidFormat { - raw_height: "".to_owned() - }) - ); + + let decoding_err = "1".parse::().unwrap_err(); + let decoding_err = decoding_err.to_string(); + assert!(decoding_err.contains("height `1` not properly formatted")); + + let decoding_err = "".parse::().unwrap_err(); + let decoding_err = decoding_err.to_string(); + assert!(decoding_err.contains("height `` not properly formatted")); } diff --git a/ibc-core/ics02-client/types/src/msgs/create_client.rs b/ibc-core/ics02-client/types/src/msgs/create_client.rs index 72a035c9e..1891a143e 100644 --- a/ibc-core/ics02-client/types/src/msgs/create_client.rs +++ b/ibc-core/ics02-client/types/src/msgs/create_client.rs @@ -7,8 +7,6 @@ use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::client::v1::MsgCreateClient as RawMsgCreateClient; use ibc_proto::Protobuf; -use crate::error::ClientError; - pub const CREATE_CLIENT_TYPE_URL: &str = "/ibc.core.client.v1.MsgCreateClient"; /// A type of message that triggers the creation of a new on-chain (IBC) client. @@ -37,16 +35,16 @@ impl MsgCreateClient { impl Protobuf for MsgCreateClient {} impl TryFrom for MsgCreateClient { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: RawMsgCreateClient) -> Result { - let raw_client_state = raw.client_state.ok_or(DecodingError::MissingRawData { - description: "no raw client state set".to_string(), - })?; + let raw_client_state = raw + .client_state + .ok_or(DecodingError::missing_raw_data("client state"))?; - let raw_consensus_state = raw.consensus_state.ok_or(DecodingError::MissingRawData { - description: "no raw consensus state set".to_string(), - })?; + let raw_consensus_state = raw + .consensus_state + .ok_or(DecodingError::missing_raw_data("consensus state"))?; Ok(MsgCreateClient::new( raw_client_state, diff --git a/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs b/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs index f923902ba..1e495393b 100644 --- a/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs +++ b/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs @@ -39,9 +39,9 @@ impl TryFrom for MsgSubmitMisbehaviour { type Error = DecodingError; fn try_from(raw: RawMsgSubmitMisbehaviour) -> Result { - let raw_misbehaviour = raw.misbehaviour.ok_or(DecodingError::MissingRawData { - description: "misbehaviour not set".to_string(), - })?; + let raw_misbehaviour = raw + .misbehaviour + .ok_or(DecodingError::missing_raw_data("msg submit misbehaviour"))?; Ok(MsgSubmitMisbehaviour { client_id: raw.client_id.parse()?, diff --git a/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs b/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs index f5ed52afb..d581f8e1b 100644 --- a/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs +++ b/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs @@ -57,28 +57,17 @@ impl TryFrom for MsgUpgradeClient { fn try_from(proto_msg: RawMsgUpgradeClient) -> Result { let raw_client_state = proto_msg .client_state - .ok_or(DecodingError::MissingRawData { - description: "client state not set".to_string(), - })?; + .ok_or(DecodingError::missing_raw_data("msg upgrade client state"))?; let raw_consensus_state = proto_msg .consensus_state - .ok_or(DecodingError::MissingRawData { - description: "consensus state not set".to_string(), - })?; + .ok_or(DecodingError::missing_raw_data( + "msg upgrade client consensus state", + ))?; - let c_bytes = - CommitmentProofBytes::try_from(proto_msg.proof_upgrade_client).map_err(|e| { - DecodingError::InvalidRawData { - description: format!("invalid upgrade client state proof: {e}"), - } - })?; - - let cs_bytes = CommitmentProofBytes::try_from(proto_msg.proof_upgrade_consensus_state) - .map_err(|e| DecodingError::InvalidRawData { - description: format!("invalid upgrade consensus state proof: {e}"), - })?; + let c_bytes = CommitmentProofBytes::try_from(proto_msg.proof_upgrade_client)?; + let cs_bytes = CommitmentProofBytes::try_from(proto_msg.proof_upgrade_consensus_state)?; Ok(MsgUpgradeClient { client_id: ClientId::from_str(&proto_msg.client_id)?, diff --git a/ibc-core/ics02-client/types/src/status.rs b/ibc-core/ics02-client/types/src/status.rs index 25f28d3cf..39e4f36f2 100644 --- a/ibc-core/ics02-client/types/src/status.rs +++ b/ibc-core/ics02-client/types/src/status.rs @@ -1,6 +1,7 @@ use core::fmt::{Debug, Display, Formatter}; use core::str::FromStr; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use crate::error::ClientError; @@ -50,7 +51,7 @@ impl Status { pub fn verify_is_active(&self) -> Result<(), ClientError> { match self { Self::Active => Ok(()), - &status => Err(ClientError::UnexpectedStatus(status)), + &status => Err(ClientError::InvalidStatus(status)), } } @@ -58,7 +59,7 @@ impl Status { pub fn verify_is_inactive(&self) -> Result<(), ClientError> { match self { Self::Frozen | Self::Expired => Ok(()), - &status => Err(ClientError::UnexpectedStatus(status)), + &status => Err(ClientError::InvalidStatus(status)), } } } @@ -70,7 +71,7 @@ impl Display for Status { } impl FromStr for Status { - type Err = ClientError; + type Err = DecodingError; fn from_str(s: &str) -> Result { match s { @@ -78,7 +79,9 @@ impl FromStr for Status { "FROZEN" => Ok(Status::Frozen), "EXPIRED" => Ok(Status::Expired), "UNAUTHORIZED" => Ok(Status::Unauthorized), - _ => Err(ClientError::InvalidStatus(s.to_string())), + _ => Err(DecodingError::invalid_raw_data(format!( + "invalid status {s}", + ))), } } } diff --git a/ibc-core/ics03-connection/src/delay.rs b/ibc-core/ics03-connection/src/delay.rs index e254dc4d7..b0f427b22 100644 --- a/ibc-core/ics03-connection/src/delay.rs +++ b/ibc-core/ics03-connection/src/delay.rs @@ -27,8 +27,7 @@ where let conn_delay_height_period = ctx.block_delay(&conn_delay_time_period); // Verify that the current host chain time is later than the last client update time - let earliest_valid_time = (last_client_update.0 + conn_delay_time_period) - .map_err(ConnectionError::OverflowedTimestamp)?; + let earliest_valid_time = (last_client_update.0 + conn_delay_time_period)?; if current_host_time < earliest_valid_time { return Err(ConnectionError::InsufficientTimeElapsed { current_host_time, diff --git a/ibc-core/ics03-connection/types/src/connection.rs b/ibc-core/ics03-connection/types/src/connection.rs index fe4446de5..f518f86a5 100644 --- a/ibc-core/ics03-connection/types/src/connection.rs +++ b/ibc-core/ics03-connection/types/src/connection.rs @@ -56,7 +56,7 @@ impl IdentifiedConnectionEnd { impl Protobuf for IdentifiedConnectionEnd {} impl TryFrom for IdentifiedConnectionEnd { - type Error = ConnectionError; + type Error = DecodingError; fn try_from(value: RawIdentifiedConnection) -> Result { let raw_connection_end = RawConnectionEnd { @@ -195,21 +195,17 @@ mod sealed { impl Protobuf for ConnectionEnd {} impl TryFrom for ConnectionEnd { - type Error = ConnectionError; + type Error = DecodingError; fn try_from(value: RawConnectionEnd) -> Result { let state = value.state.try_into()?; if value.client_id.is_empty() { - return Err(DecodingError::MissingRawData { - description: "connection end is empty".to_string(), - })?; + return Err(DecodingError::missing_raw_data("connection end client ID"))?; } if value.versions.is_empty() { - return Err(DecodingError::MissingRawData { - description: "empty connection versions".to_string(), - })?; + return Err(DecodingError::missing_raw_data("connection end versions"))?; } Self::new( @@ -217,9 +213,7 @@ impl TryFrom for ConnectionEnd { value.client_id.parse()?, value .counterparty - .ok_or(DecodingError::MissingRawData { - description: "missing counterparty".to_string(), - })? + .ok_or(DecodingError::missing_raw_data("counterparty"))? .try_into()?, value .versions @@ -228,6 +222,7 @@ impl TryFrom for ConnectionEnd { .collect::, _>>()?, Duration::from_nanos(value.delay_period), ) + .map_err(|_| DecodingError::invalid_raw_data("connection end")) } } @@ -259,7 +254,7 @@ impl ConnectionEnd { // + Init: contains the set of compatible versions, // + TryOpen/Open: contains the single version chosen by the handshake protocol. if state != State::Init && versions.len() != 1 { - return Err(ConnectionError::InvalidState { description: "invalid state for initializing new ConnectionEnd; expected `Init` connection state and a single version".to_string() }); + return Err(ConnectionError::InvalidState { description: "failed to initialize new ConnectionEnd; expected `Init` connection state and a single version".to_string() }); } Ok(Self { @@ -370,7 +365,7 @@ impl Protobuf for Counterparty {} // Converts from the wire format RawCounterparty. Typically used from the relayer side // during queries for response validation and to extract the Counterparty structure. impl TryFrom for Counterparty { - type Error = ConnectionError; + type Error = DecodingError; fn try_from(raw_counterparty: RawCounterparty) -> Result { let connection_id: Option = if raw_counterparty.connection_id.is_empty() { @@ -383,9 +378,7 @@ impl TryFrom for Counterparty { connection_id, raw_counterparty .prefix - .ok_or(DecodingError::MissingRawData { - description: "counterparty prefix not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data("counterparty prefix"))? .key_prefix .into(), )) @@ -432,15 +425,6 @@ impl Counterparty { pub fn prefix(&self) -> &CommitmentPrefix { &self.prefix } - - /// Called upon initiating a connection handshake on the host chain to verify - /// that the counterparty connection id has not been set. - pub(crate) fn verify_empty_connection_id(&self) -> Result<(), ConnectionError> { - if self.connection_id().is_some() { - return Err(ConnectionError::InvalidCounterparty); - } - Ok(()) - } } #[cfg_attr( @@ -517,17 +501,17 @@ impl Display for State { } impl TryFrom for State { - type Error = ConnectionError; + type Error = DecodingError; + fn try_from(value: i32) -> Result { match value { 0 => Ok(Self::Uninitialized), 1 => Ok(Self::Init), 2 => Ok(Self::TryOpen), 3 => Ok(Self::Open), - _ => Err(ConnectionError::MismatchedConnectionStates { - expected: "0, 1, 2, or 3".to_string(), - actual: value.to_string(), - }), + _ => Err(DecodingError::invalid_raw_data(format!( + "connection state expected to be 0, 1, 2, or 3, actual {value}", + ))), } } } diff --git a/ibc-core/ics03-connection/types/src/error.rs b/ibc-core/ics03-connection/types/src/error.rs index ca6362488..fa4ad6297 100644 --- a/ibc-core/ics03-connection/types/src/error.rs +++ b/ibc-core/ics03-connection/types/src/error.rs @@ -9,15 +9,17 @@ use ibc_primitives::{Timestamp, TimestampError}; #[derive(Debug, Display)] pub enum ConnectionError { - /// client error: `{0}` + /// client error: {0} Client(ClientError), - /// decoding error: `{0}` + /// decoding error: {0} Decoding(DecodingError), - /// host error: `{0}` + /// host error: {0} Host(HostError), + /// timestamp error: {0} + Timestamp(TimestampError), /// invalid counterparty InvalidCounterparty, - /// invalid connection state: `{description}` + /// invalid connection state: {description} InvalidState { description: String }, /// mismatched connection states: expected `{expected}`, actual `{actual}` MismatchedConnectionStates { expected: String, actual: String }, @@ -42,8 +44,6 @@ pub enum ConnectionError { current_host_time: Timestamp, earliest_valid_time: Timestamp, }, - /// overflowed timestamp: `{0}` - OverflowedTimestamp(TimestampError), } impl From for ConnectionError { @@ -58,6 +58,12 @@ impl From for ConnectionError { } } +impl From for ConnectionError { + fn from(e: TimestampError) -> Self { + Self::Timestamp(e) + } +} + impl From for ConnectionError { fn from(e: ClientError) -> Self { Self::Client(e) @@ -77,6 +83,7 @@ impl std::error::Error for ConnectionError { Self::Host(e) => Some(e), Self::Client(e) => Some(e), Self::Decoding(e) => Some(e), + Self::Timestamp(e) => Some(e), _ => None, } } diff --git a/ibc-core/ics03-connection/types/src/msgs/conn_open_ack.rs b/ibc-core/ics03-connection/types/src/msgs/conn_open_ack.rs index 39cd8e712..9379c25e3 100644 --- a/ibc-core/ics03-connection/types/src/msgs/conn_open_ack.rs +++ b/ibc-core/ics03-connection/types/src/msgs/conn_open_ack.rs @@ -8,7 +8,6 @@ use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenAck as RawMsgConnectionOpenAck; use ibc_proto::Protobuf; -use crate::error::ConnectionError; use crate::version::Version; pub const CONN_OPEN_ACK_TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenAck"; @@ -48,57 +47,35 @@ pub struct MsgConnectionOpenAck { impl Protobuf for MsgConnectionOpenAck {} impl TryFrom for MsgConnectionOpenAck { - type Error = ConnectionError; + type Error = DecodingError; fn try_from(msg: RawMsgConnectionOpenAck) -> Result { Ok(Self { conn_id_on_a: msg.connection_id.parse()?, conn_id_on_b: msg.counterparty_connection_id.parse()?, - client_state_of_a_on_b: msg.client_state.ok_or(DecodingError::MissingRawData { - description: "client state not set".to_string(), - })?, + client_state_of_a_on_b: msg + .client_state + .ok_or(DecodingError::missing_raw_data("client state"))?, version: msg .version - .ok_or(DecodingError::MissingRawData { - description: "connection version not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data("connection version"))? .try_into()?, - proof_conn_end_on_b: msg.proof_try.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode connection end proof: {e}"), - } - })?, - proof_client_state_of_a_on_b: msg.proof_client.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode client state proof: {e}"), - } - })?, - proof_consensus_state_of_a_on_b: msg.proof_consensus.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode consensus state proof: {e}"), - } - })?, + proof_conn_end_on_b: msg.proof_try.try_into()?, + proof_client_state_of_a_on_b: msg.proof_client.try_into()?, + proof_consensus_state_of_a_on_b: msg.proof_consensus.try_into()?, proofs_height_on_b: msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::MissingRawData { - description: "proof height not set".to_string(), - })?, + .ok_or(DecodingError::missing_raw_data("proof height"))?, consensus_height_of_a_on_b: msg .consensus_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::MissingRawData { - description: "consensus height not set".to_string(), - })?, + .ok_or(DecodingError::missing_raw_data("consensus height"))?, signer: msg.signer.into(), proof_consensus_state_of_a: if msg.host_consensus_state_proof.is_empty() { None } else { - Some(msg.host_consensus_state_proof.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode host consensus state proof: {e}"), - } - })?) + Some(msg.host_consensus_state_proof.try_into()?) }, }) } diff --git a/ibc-core/ics03-connection/types/src/msgs/conn_open_confirm.rs b/ibc-core/ics03-connection/types/src/msgs/conn_open_confirm.rs index 982e8f15c..24a58b87e 100644 --- a/ibc-core/ics03-connection/types/src/msgs/conn_open_confirm.rs +++ b/ibc-core/ics03-connection/types/src/msgs/conn_open_confirm.rs @@ -7,8 +7,6 @@ use ibc_primitives::Signer; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; use ibc_proto::Protobuf; -use crate::error::ConnectionError; - pub const CONN_OPEN_CONFIRM_TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenConfirm"; /// Per our convention, this message is sent to chain B. @@ -32,22 +30,18 @@ pub struct MsgConnectionOpenConfirm { impl Protobuf for MsgConnectionOpenConfirm {} impl TryFrom for MsgConnectionOpenConfirm { - type Error = ConnectionError; + type Error = DecodingError; fn try_from(msg: RawMsgConnectionOpenConfirm) -> Result { Ok(Self { conn_id_on_b: msg.connection_id.parse()?, - proof_conn_end_on_a: msg.proof_ack.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode connection end proof: {e}"), - } - })?, + proof_conn_end_on_a: msg.proof_ack.try_into()?, proof_height_on_a: msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::InvalidRawData { - description: "failed to decode proof height".to_string(), - })?, + .ok_or(DecodingError::invalid_raw_data( + "msg conn open confirm proof height", + ))?, signer: msg.signer.into(), }) } diff --git a/ibc-core/ics03-connection/types/src/msgs/conn_open_init.rs b/ibc-core/ics03-connection/types/src/msgs/conn_open_init.rs index 672f419da..57790a387 100644 --- a/ibc-core/ics03-connection/types/src/msgs/conn_open_init.rs +++ b/ibc-core/ics03-connection/types/src/msgs/conn_open_init.rs @@ -8,7 +8,6 @@ use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenInit as RawMsgConnect use ibc_proto::Protobuf; use crate::connection::Counterparty; -use crate::error::ConnectionError; use crate::version::Version; pub const CONN_OPEN_INIT_TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenInit"; @@ -51,7 +50,10 @@ mod borsh_impls { self.delay_period.as_nanos().try_into().map_err(|_| { io::Error::new( io::ErrorKind::Other, - format!("Duration too long: {} nanos", self.delay_period.as_nanos()), + format!( + "Duration too long: `{}` nanos", + self.delay_period.as_nanos() + ), ) })?; @@ -85,17 +87,21 @@ mod borsh_impls { impl Protobuf for MsgConnectionOpenInit {} impl TryFrom for MsgConnectionOpenInit { - type Error = ConnectionError; + type Error = DecodingError; fn try_from(msg: RawMsgConnectionOpenInit) -> Result { let counterparty: Counterparty = msg .counterparty - .ok_or(DecodingError::MissingRawData { - description: "counterparty not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data( + "msg conn open init counterparty", + ))? .try_into()?; - counterparty.verify_empty_connection_id()?; + if let Some(cid) = counterparty.connection_id() { + return Err(DecodingError::invalid_raw_data(format!( + "expected msg conn open init connection ID to be empty, actual `{cid}`", + ))); + } Ok(Self { client_id_on_a: msg.client_id.parse()?, diff --git a/ibc-core/ics03-connection/types/src/msgs/conn_open_try.rs b/ibc-core/ics03-connection/types/src/msgs/conn_open_try.rs index 5714784c4..ea5f22f03 100644 --- a/ibc-core/ics03-connection/types/src/msgs/conn_open_try.rs +++ b/ibc-core/ics03-connection/types/src/msgs/conn_open_try.rs @@ -11,7 +11,6 @@ use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnecti use ibc_proto::Protobuf; use crate::connection::Counterparty; -use crate::error::ConnectionError; use crate::version::Version; pub const CONN_OPEN_TRY_TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenTry"; @@ -145,7 +144,7 @@ mod borsh_impls { impl Protobuf for MsgConnectionOpenTry {} impl TryFrom for MsgConnectionOpenTry { - type Error = ConnectionError; + type Error = DecodingError; fn try_from(msg: RawMsgConnectionOpenTry) -> Result { let counterparty_versions = msg @@ -155,9 +154,9 @@ impl TryFrom for MsgConnectionOpenTry { .collect::, _>>()?; if counterparty_versions.is_empty() { - return Err(DecodingError::MissingRawData { - description: "connection versions not set".to_string(), - })?; + return Err(DecodingError::missing_raw_data( + "msg conn open try connection versions", + )); } // We set the deprecated `previous_connection_id` field so that we can @@ -166,53 +165,37 @@ impl TryFrom for MsgConnectionOpenTry { Ok(Self { previous_connection_id: msg.previous_connection_id, client_id_on_b: msg.client_id.parse()?, - client_state_of_b_on_a: msg.client_state.ok_or(DecodingError::MissingRawData { - description: "client state not set".to_string(), - })?, + client_state_of_b_on_a: msg.client_state.ok_or(DecodingError::missing_raw_data( + "msg conn open try client state", + ))?, counterparty: msg .counterparty - .ok_or(DecodingError::MissingRawData { - description: "counterparty not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data( + "msg conn open try counterparty", + ))? .try_into()?, versions_on_a: counterparty_versions, - proof_conn_end_on_a: msg.proof_init.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode connection end proof: {e}"), - } - })?, - proof_client_state_of_b_on_a: msg.proof_client.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode client state proof: {e}"), - } - })?, - proof_consensus_state_of_b_on_a: msg.proof_consensus.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode consensus state proof: {e}"), - } - })?, + proof_conn_end_on_a: msg.proof_init.try_into()?, + proof_client_state_of_b_on_a: msg.proof_client.try_into()?, + proof_consensus_state_of_b_on_a: msg.proof_consensus.try_into()?, proofs_height_on_a: msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::InvalidRawData { - description: "failed to decode proof height".to_string(), - })?, + .ok_or(DecodingError::invalid_raw_data( + "msg conn open try proof height", + ))?, consensus_height_of_b_on_a: msg .consensus_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::InvalidRawData { - description: "failed to decode consensus height".to_string(), - })?, + .ok_or(DecodingError::invalid_raw_data( + "msg conn open try consensus height", + ))?, delay_period: Duration::from_nanos(msg.delay_period), signer: msg.signer.into(), proof_consensus_state_of_b: if msg.host_consensus_state_proof.is_empty() { None } else { - Some(msg.host_consensus_state_proof.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode consensus state proof: {e}"), - } - })?) + Some(msg.host_consensus_state_proof.try_into()?) }, }) } diff --git a/ibc-core/ics03-connection/types/src/version.rs b/ibc-core/ics03-connection/types/src/version.rs index 3f2412876..89f577cc0 100644 --- a/ibc-core/ics03-connection/types/src/version.rs +++ b/ibc-core/ics03-connection/types/src/version.rs @@ -72,17 +72,15 @@ impl Version { impl Protobuf for Version {} impl TryFrom for Version { - type Error = ConnectionError; + type Error = DecodingError; fn try_from(value: RawVersion) -> Result { if value.identifier.trim().is_empty() { - return Err(DecodingError::MissingRawData { - description: "version is empty".to_string(), - })?; + return Err(DecodingError::missing_raw_data("version identifier")); } for feature in value.features.iter() { if feature.trim().is_empty() { - return Err(ConnectionError::MissingFeatures); + return Err(DecodingError::missing_raw_data("version features")); } } Ok(Version { diff --git a/ibc-core/ics04-channel/src/handler/acknowledgement.rs b/ibc-core/ics04-channel/src/handler/acknowledgement.rs index 8d4ee4e1c..fddea0d82 100644 --- a/ibc-core/ics04-channel/src/handler/acknowledgement.rs +++ b/ibc-core/ics04-channel/src/handler/acknowledgement.rs @@ -143,7 +143,7 @@ where ); if commitment_on_a != expected_commitment_on_a { - return Err(ChannelError::MismatchedPacketCommitments { + return Err(ChannelError::MismatchedPacketCommitment { actual: commitment_on_a, expected: expected_commitment_on_a, }); @@ -153,7 +153,7 @@ where let seq_ack_path_on_a = SeqAckPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); let next_seq_ack = ctx_a.get_next_sequence_ack(&seq_ack_path_on_a)?; if packet.seq_on_a != next_seq_ack { - return Err(ChannelError::MismatchedPacketSequences { + return Err(ChannelError::MismatchedPacketSequence { actual: packet.seq_on_a, expected: next_seq_ack, }); diff --git a/ibc-core/ics04-channel/src/handler/recv_packet.rs b/ibc-core/ics04-channel/src/handler/recv_packet.rs index c12b01885..60bf30199 100644 --- a/ibc-core/ics04-channel/src/handler/recv_packet.rs +++ b/ibc-core/ics04-channel/src/handler/recv_packet.rs @@ -173,7 +173,7 @@ where .timeout_timestamp_on_b .has_expired(&latest_timestamp) { - return Err(ChannelError::InsufficientPacketTimestamp); + return Err(ChannelError::ExpiredPacketTimestamp); } // Verify proofs @@ -226,7 +226,7 @@ where SeqRecvPath::new(&msg.packet.port_id_on_b, &msg.packet.chan_id_on_b); let next_seq_recv = ctx_b.get_next_sequence_recv(&seq_recv_path_on_b)?; if msg.packet.seq_on_a > next_seq_recv { - return Err(ChannelError::MismatchedPacketSequences { + return Err(ChannelError::MismatchedPacketSequence { actual: msg.packet.seq_on_a, expected: next_seq_recv, }); diff --git a/ibc-core/ics04-channel/src/handler/send_packet.rs b/ibc-core/ics04-channel/src/handler/send_packet.rs index e4d9a4ba1..1206d0460 100644 --- a/ibc-core/ics04-channel/src/handler/send_packet.rs +++ b/ibc-core/ics04-channel/src/handler/send_packet.rs @@ -79,14 +79,14 @@ pub fn send_packet_validate( let latest_timestamp = consensus_state_of_b_on_a.timestamp(); let packet_timestamp = packet.timeout_timestamp_on_b; if packet_timestamp.has_expired(&latest_timestamp) { - return Err(ChannelError::InsufficientPacketTimestamp); + return Err(ChannelError::ExpiredPacketTimestamp); } let seq_send_path_on_a = SeqSendPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); let next_seq_send_on_a = ctx_a.get_next_sequence_send(&seq_send_path_on_a)?; if packet.seq_on_a != next_seq_send_on_a { - return Err(ChannelError::MismatchedPacketSequences { + return Err(ChannelError::MismatchedPacketSequence { actual: packet.seq_on_a, expected: next_seq_send_on_a, }); diff --git a/ibc-core/ics04-channel/src/handler/timeout.rs b/ibc-core/ics04-channel/src/handler/timeout.rs index 176fc3fa9..33604b958 100644 --- a/ibc-core/ics04-channel/src/handler/timeout.rs +++ b/ibc-core/ics04-channel/src/handler/timeout.rs @@ -167,7 +167,7 @@ where ); if commitment_on_a != expected_commitment_on_a { - return Err(ChannelError::MismatchedPacketCommitments { + return Err(ChannelError::MismatchedPacketCommitment { expected: expected_commitment_on_a, actual: commitment_on_a, }); @@ -196,7 +196,7 @@ where let timestamp_of_b = consensus_state_of_b_on_a.timestamp(); if !msg.packet.timed_out(×tamp_of_b, msg.proof_height_on_b) { - return Err(ChannelError::PacketTimeoutNotReached { + return Err(ChannelError::InsufficientPacketTimeout { timeout_height: msg.packet.timeout_height_on_b, chain_height: msg.proof_height_on_b, timeout_timestamp: msg.packet.timeout_timestamp_on_b, @@ -209,7 +209,7 @@ where let next_seq_recv_verification_result = match chan_end_on_a.ordering { Order::Ordered => { if msg.packet.seq_on_a < msg.next_seq_recv_on_b { - return Err(ChannelError::MismatchedPacketSequences { + return Err(ChannelError::MismatchedPacketSequence { actual: msg.packet.seq_on_a, expected: msg.next_seq_recv_on_b, }); diff --git a/ibc-core/ics04-channel/src/handler/timeout_on_close.rs b/ibc-core/ics04-channel/src/handler/timeout_on_close.rs index 16cda09ae..00d880577 100644 --- a/ibc-core/ics04-channel/src/handler/timeout_on_close.rs +++ b/ibc-core/ics04-channel/src/handler/timeout_on_close.rs @@ -50,7 +50,7 @@ where &packet.timeout_timestamp_on_b, ); if commitment_on_a != expected_commitment_on_a { - return Err(ChannelError::MismatchedPacketCommitments { + return Err(ChannelError::MismatchedPacketCommitment { expected: expected_commitment_on_a, actual: commitment_on_a, }); @@ -118,7 +118,7 @@ where let next_seq_recv_verification_result = match chan_end_on_a.ordering { Order::Ordered => { if packet.seq_on_a < msg.next_seq_recv_on_b { - return Err(ChannelError::MismatchedPacketSequences { + return Err(ChannelError::MismatchedPacketSequence { actual: packet.seq_on_a, expected: msg.next_seq_recv_on_b, }); diff --git a/ibc-core/ics04-channel/types/src/acknowledgement.rs b/ibc-core/ics04-channel/types/src/acknowledgement.rs index 82ce5dcde..efbbe28ce 100644 --- a/ibc-core/ics04-channel/types/src/acknowledgement.rs +++ b/ibc-core/ics04-channel/types/src/acknowledgement.rs @@ -46,9 +46,7 @@ impl TryFrom> for Acknowledgement { fn try_from(bytes: Vec) -> Result { if bytes.is_empty() { - Err(DecodingError::MissingRawData { - description: "acknowledgment not set".to_string(), - }) + Err(DecodingError::missing_raw_data("acknowledgment")) } else { Ok(Self(bytes)) } diff --git a/ibc-core/ics04-channel/types/src/channel.rs b/ibc-core/ics04-channel/types/src/channel.rs index 677233b26..38140cb35 100644 --- a/ibc-core/ics04-channel/types/src/channel.rs +++ b/ibc-core/ics04-channel/types/src/channel.rs @@ -138,19 +138,15 @@ impl TryFrom for ChannelEnd { fn try_from(value: RawChannel) -> Result { let chan_state: State = State::from_i32(value.state) - .map_err(|e| DecodingError::invalid_raw_data(format!("invalid channel state: {e}")))?; + .map_err(|e| DecodingError::invalid_raw_data(format!("channel state: {e}")))?; - let chan_ordering = Order::from_i32(value.ordering).map_err(|e| { - DecodingError::invalid_raw_data(format!("invalid channel ordering: {e}")) - })?; + let chan_ordering = Order::from_i32(value.ordering) + .map_err(|e| DecodingError::invalid_raw_data(format!("channel ordering: {e}")))?; // Assemble the 'remote' attribute of the Channel, which represents the Counterparty. let remote = value .counterparty - .ok_or(DecodingError::missing_raw_data("missing counterparty"))? - .try_into() - .map_err(|e| { - DecodingError::invalid_raw_data(format!("failed to convert raw counterparty: {e}")) - })?; + .ok_or(DecodingError::missing_raw_data("channel counterparty"))? + .try_into()?; // Parse each item in connection_hops into a ConnectionId. let connection_hops = value @@ -162,9 +158,7 @@ impl TryFrom for ChannelEnd { let version = value.version.into(); let channel = ChannelEnd::new(chan_state, chan_ordering, remote, connection_hops, version) - .map_err(|e| { - DecodingError::invalid_raw_data(format!("failed to create new channel: {e}")) - })?; + .map_err(|e| DecodingError::invalid_raw_data(format!("channel end: {e}")))?; Ok(channel) } @@ -386,15 +380,6 @@ impl Counterparty { pub fn channel_id(&self) -> Option<&ChannelId> { self.channel_id.as_ref() } - - /// Called upon initiating a channel handshake on the host chain to verify - /// that the counterparty channel id has not been set. - pub(crate) fn verify_empty_channel_id(&self) -> Result<(), ChannelError> { - if self.channel_id().is_some() { - return Err(ChannelError::UnexpectedChannelId); - } - Ok(()) - } } impl Display for Counterparty { @@ -417,7 +402,7 @@ impl Display for Counterparty { impl Protobuf for Counterparty {} impl TryFrom for Counterparty { - type Error = ChannelError; + type Error = DecodingError; fn try_from(raw_counterparty: RawCounterparty) -> Result { let channel_id: Option = if raw_counterparty.channel_id.is_empty() { diff --git a/ibc-core/ics04-channel/types/src/error.rs b/ibc-core/ics04-channel/types/src/error.rs index 24d58a9ec..911aed095 100644 --- a/ibc-core/ics04-channel/types/src/error.rs +++ b/ibc-core/ics04-channel/types/src/error.rs @@ -18,14 +18,16 @@ use crate::Version; /// Errors that arise from the ICS04 Channel module #[derive(Debug, Display, derive_more::From)] pub enum ChannelError { - /// decoding error: `{0}` + /// decoding error: {0} Decoding(DecodingError), - /// host error: `{0}` + /// host error: {0} Host(HostError), - /// client error: `{0}` + /// client error: {0} Client(ClientError), - /// connection error: `{0}` + /// connection error: {0} Connection(ConnectionError), + /// timestamp error: {0} + Timestamp(TimestampError), /// packet acknowledgment for sequence `{0}` already exists DuplicateAcknowledgment(Sequence), /// insufficient packet timeout height: should have `{timeout_height}` > `{chain_height}` @@ -33,14 +35,19 @@ pub enum ChannelError { chain_height: Height, timeout_height: TimeoutHeight, }, - /// insufficient packet timestamp: should be greater than chain block timestamp - InsufficientPacketTimestamp, + /// expired packet timestamp: should be greater than chain block timestamp + ExpiredPacketTimestamp, + /// packet timeout height `{timeout_height}` > chain height `{chain_height} and timeout timestamp `{timeout_timestamp}` > chain timestamp `{chain_timestamp}` + InsufficientPacketTimeout { + timeout_height: TimeoutHeight, + chain_height: Height, + timeout_timestamp: TimeoutTimestamp, + chain_timestamp: Timestamp, + }, /// invalid channel state: expected `{expected}`, actual `{actual}` InvalidState { expected: String, actual: String }, /// invalid connection hops length: expected `{expected}`, actual `{actual}` InvalidConnectionHopsLength { expected: u64, actual: u64 }, - /// invalid timeout timestamp: `{0}` - InvalidTimeoutTimestamp(TimestampError), /// missing acknowledgment status MissingAcknowledgmentStatus, /// missing counterparty @@ -52,25 +59,16 @@ pub enum ChannelError { expected: Counterparty, actual: Counterparty, }, - /// mismatched packet sequences: expected `{expected}`, actual `{actual}` - MismatchedPacketSequences { + /// mismatched packet sequence: expected `{expected}`, actual `{actual}` + MismatchedPacketSequence { expected: Sequence, actual: Sequence, }, /// mismatched packet commitments: expected `{expected:?}`, actual `{actual:?}` - MismatchedPacketCommitments { + MismatchedPacketCommitment { expected: PacketCommitment, actual: PacketCommitment, }, - /// packet timeout height `{timeout_height}` > chain height `{chain_height} and timeout timestamp `{timeout_timestamp}` > chain timestamp `{chain_timestamp}` - PacketTimeoutNotReached { - timeout_height: TimeoutHeight, - chain_height: Height, - timeout_timestamp: TimeoutTimestamp, - chain_timestamp: Timestamp, - }, - /// unexpected channel ID: expected to be empty - UnexpectedChannelId, /// unsupported version: expected `{expected}`, actual `{actual}` UnsupportedVersion { expected: Version, actual: Version }, /// application specific error: `{description}` @@ -91,7 +89,7 @@ impl std::error::Error for ChannelError { Self::Client(e) => Some(e), Self::Connection(e) => Some(e), Self::Host(e) => Some(e), - Self::InvalidTimeoutTimestamp(e) => Some(e), + Self::Timestamp(e) => Some(e), _ => None, } } diff --git a/ibc-core/ics04-channel/types/src/events/mod.rs b/ibc-core/ics04-channel/types/src/events/mod.rs index 798210a82..4b65a94c6 100644 --- a/ibc-core/ics04-channel/types/src/events/mod.rs +++ b/ibc-core/ics04-channel/types/src/events/mod.rs @@ -3,6 +3,7 @@ mod channel_attributes; mod packet_attributes; +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId, Sequence}; use ibc_primitives::prelude::*; use tendermint::abci; @@ -21,7 +22,6 @@ use super::acknowledgement::Acknowledgement; use super::channel::Order; use super::timeout::TimeoutHeight; use super::Version; -use crate::error::ChannelError; use crate::packet::Packet; use crate::timeout::TimeoutTimestamp; @@ -671,7 +671,7 @@ impl SendPacket { } impl TryFrom for abci::Event { - type Error = ChannelError; + type Error = DecodingError; fn try_from(v: SendPacket) -> Result { let mut attributes = Vec::with_capacity(11); @@ -782,7 +782,7 @@ impl ReceivePacket { } impl TryFrom for abci::Event { - type Error = ChannelError; + type Error = DecodingError; fn try_from(v: ReceivePacket) -> Result { let mut attributes = Vec::with_capacity(11); @@ -897,7 +897,7 @@ impl WriteAcknowledgement { } impl TryFrom for abci::Event { - type Error = ChannelError; + type Error = DecodingError; fn try_from(v: WriteAcknowledgement) -> Result { let mut attributes = Vec::with_capacity(11); @@ -1002,7 +1002,7 @@ impl AcknowledgePacket { } impl TryFrom for abci::Event { - type Error = ChannelError; + type Error = DecodingError; fn try_from(v: AcknowledgePacket) -> Result { Ok(abci::Event { @@ -1099,7 +1099,7 @@ impl TimeoutPacket { } impl TryFrom for abci::Event { - type Error = ChannelError; + type Error = DecodingError; fn try_from(v: TimeoutPacket) -> Result { Ok(abci::Event { diff --git a/ibc-core/ics04-channel/types/src/events/packet_attributes.rs b/ibc-core/ics04-channel/types/src/events/packet_attributes.rs index 35fb84a7f..c7a2c4179 100644 --- a/ibc-core/ics04-channel/types/src/events/packet_attributes.rs +++ b/ibc-core/ics04-channel/types/src/events/packet_attributes.rs @@ -12,7 +12,6 @@ use tendermint::abci; use crate::acknowledgement::Acknowledgement; use crate::channel::Order; -use crate::error::ChannelError; use crate::timeout::{TimeoutHeight, TimeoutTimestamp}; const PKT_SEQ_ATTRIBUTE_KEY: &str = "packet_sequence"; @@ -48,15 +47,11 @@ pub struct PacketDataAttribute { } impl TryFrom for Vec { - type Error = ChannelError; + type Error = DecodingError; fn try_from(attr: PacketDataAttribute) -> Result { let tags = vec![ - ( - PKT_DATA_ATTRIBUTE_KEY, - str::from_utf8(&attr.packet_data).map_err(DecodingError::StrUtf8)?, - ) - .into(), + (PKT_DATA_ATTRIBUTE_KEY, str::from_utf8(&attr.packet_data)?).into(), ( PKT_DATA_HEX_ATTRIBUTE_KEY, str::from_utf8(&hex::encode(attr.packet_data)) @@ -313,7 +308,7 @@ pub struct AcknowledgementAttribute { } impl TryFrom for Vec { - type Error = ChannelError; + type Error = DecodingError; fn try_from(attr: AcknowledgementAttribute) -> Result { let tags = vec![ @@ -323,7 +318,7 @@ impl TryFrom for Vec { // is valid UTF-8, even though the standard doesn't require // it. It has been deprecated in ibc-go. It will be removed // in the future. - str::from_utf8(attr.acknowledgement.as_bytes()).map_err(DecodingError::StrUtf8)?, + str::from_utf8(attr.acknowledgement.as_bytes())?, ) .into(), ( diff --git a/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs b/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs index 47ceea8ac..10839e91d 100644 --- a/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs +++ b/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs @@ -39,22 +39,18 @@ impl TryFrom for MsgAcknowledgement { Ok(MsgAcknowledgement { packet: raw_msg .packet - .ok_or(DecodingError::MissingRawData { - description: "packet data not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data( + "msg acknowledgement packet data", + ))? .try_into()?, acknowledgement: raw_msg.acknowledgement.try_into()?, - proof_acked_on_b: raw_msg.proof_acked.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode proof: {e}"), - } - })?, + proof_acked_on_b: raw_msg.proof_acked.try_into()?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::InvalidRawData { - description: "failed to decode proof height".to_string(), - })?, + .ok_or(DecodingError::invalid_raw_data( + "msg acknowledgement proof height", + ))?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs b/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs index 22fe3a3f7..f3cbf1171 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs @@ -43,15 +43,13 @@ impl TryFrom for MsgChannelCloseConfirm { Ok(MsgChannelCloseConfirm { port_id_on_b: raw_msg.port_id.parse()?, chan_id_on_b: raw_msg.channel_id.parse()?, - proof_chan_end_on_a: raw_msg.proof_init.try_into().map_err(|e| { - DecodingError::missing_raw_data(format!( - "failed to decode commitment proof bytes: {e}" - )) - })?, + proof_chan_end_on_a: raw_msg.proof_init.try_into()?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::missing_raw_data("missing proof height"))?, + .ok_or(DecodingError::invalid_raw_data( + "msg channel close confirm proof height", + ))?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_close_init.rs b/ibc-core/ics04-channel/types/src/msgs/chan_close_init.rs index 2663b4186..3d852e5fa 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_close_init.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_close_init.rs @@ -1,11 +1,10 @@ +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::identifiers::{ChannelId, PortId}; use ibc_primitives::prelude::*; use ibc_primitives::Signer; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseInit as RawMsgChannelCloseInit; use ibc_proto::Protobuf; -use crate::error::ChannelError; - pub const CHAN_CLOSE_INIT_TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelCloseInit"; /// @@ -27,7 +26,7 @@ pub struct MsgChannelCloseInit { impl Protobuf for MsgChannelCloseInit {} impl TryFrom for MsgChannelCloseInit { - type Error = ChannelError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgChannelCloseInit) -> Result { Ok(MsgChannelCloseInit { diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs index cb13fe9cb..4d1151ff6 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs @@ -7,7 +7,6 @@ use ibc_primitives::Signer; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenAck as RawMsgChannelOpenAck; use ibc_proto::Protobuf; -use crate::error::ChannelError; use crate::Version; pub const CHAN_OPEN_ACK_TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenAck"; @@ -34,7 +33,7 @@ pub struct MsgChannelOpenAck { impl Protobuf for MsgChannelOpenAck {} impl TryFrom for MsgChannelOpenAck { - type Error = ChannelError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgChannelOpenAck) -> Result { Ok(MsgChannelOpenAck { @@ -42,17 +41,11 @@ impl TryFrom for MsgChannelOpenAck { chan_id_on_a: raw_msg.channel_id.parse()?, chan_id_on_b: raw_msg.counterparty_channel_id.parse()?, version_on_b: raw_msg.counterparty_version.into(), - proof_chan_end_on_b: raw_msg.proof_try.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode proof: {e}"), - } - })?, + proof_chan_end_on_b: raw_msg.proof_try.try_into()?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::MissingRawData { - description: "proof height not set".to_string(), - })?, + .ok_or(DecodingError::missing_raw_data("proof height"))?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs index e9bf8c6ae..d28fe2a6e 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs @@ -37,13 +37,13 @@ impl TryFrom for MsgChannelOpenConfirm { Ok(MsgChannelOpenConfirm { port_id_on_b: raw_msg.port_id.parse()?, chan_id_on_b: raw_msg.channel_id.parse()?, - proof_chan_end_on_a: raw_msg.proof_ack.try_into().map_err(|e| { - DecodingError::invalid_raw_data(format!("invalid commitment proof bytes: {e}")) - })?, + proof_chan_end_on_a: raw_msg.proof_ack.try_into()?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::invalid_raw_data("invalid proof height"))?, + .ok_or(DecodingError::invalid_raw_data( + "msg channel open confirm proof height", + ))?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs index c264ddabe..2299802d4 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs @@ -43,17 +43,28 @@ impl MsgChannelOpenInit { impl Protobuf for MsgChannelOpenInit {} impl TryFrom for MsgChannelOpenInit { - type Error = ChannelError; + type Error = DecodingError; fn try_from(raw_msg: RawMsgChannelOpenInit) -> Result { let chan_end_on_a: ChannelEnd = raw_msg .channel - .ok_or(DecodingError::MissingRawData { - description: "channel end not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data("channel end"))? .try_into()?; - chan_end_on_a.verify_state_matches(&State::Init)?; - chan_end_on_a.counterparty().verify_empty_channel_id()?; + + chan_end_on_a + .verify_state_matches(&State::Init) + .map_err(|_| { + DecodingError::invalid_raw_data(format!( + "expected channel end to be in `Init` state but it is in `{}` instead", + chan_end_on_a.state + )) + })?; + + if let Some(cid) = chan_end_on_a.counterparty().channel_id() { + return Err(DecodingError::invalid_raw_data(format!( + "expected counterparty channel ID to be empty, actual `{cid}`", + ))); + } Ok(MsgChannelOpenInit { port_id_on_a: raw_msg.port_id.parse()?, diff --git a/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs b/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs index 3bf9f6e24..042f2c07a 100644 --- a/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs +++ b/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs @@ -61,11 +61,16 @@ impl TryFrom for MsgChannelOpenTry { chan_end_on_b .verify_state_matches(&State::TryOpen) - .map_err(|e| DecodingError::invalid_raw_data(format!("invalid channel state: {e}")))?; + .map_err(|_| { + DecodingError::invalid_raw_data(format!( + "channel state expected to be in `TryOpen` state, actual `{}`", + chan_end_on_b.state() + )) + })?; #[allow(deprecated)] if !raw_msg.previous_channel_id.is_empty() { - return Err(DecodingError::invalid_raw_data("previous channel id must be empty. It has been deprecated as crossing hellos are no longer supported"))?; + return Err(DecodingError::invalid_raw_data("previous channel id must be empty; it has been deprecated as crossing hellos are no longer supported"))?; } #[allow(deprecated)] @@ -75,16 +80,16 @@ impl TryFrom for MsgChannelOpenTry { connection_hops_on_b: chan_end_on_b.connection_hops, port_id_on_a: chan_end_on_b.remote.port_id, chan_id_on_a: chan_end_on_b.remote.channel_id.ok_or( - DecodingError::missing_raw_data("missing counterparty channel ID"), + DecodingError::missing_raw_data("msg channel open try counterparty channel ID"), )?, version_supported_on_a: raw_msg.counterparty_version.into(), - proof_chan_end_on_a: raw_msg.proof_init.try_into().map_err(|e| { - DecodingError::invalid_raw_data(format!("invalid commitment proof bytes: {e}")) - })?, + proof_chan_end_on_a: raw_msg.proof_init.try_into()?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::invalid_raw_data("invalid proof height"))?, + .ok_or(DecodingError::invalid_raw_data( + "msg channel open try proof height", + ))?, signer: raw_msg.signer.into(), version_proposal: chan_end_on_b.version, }; diff --git a/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs b/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs index 11e85e310..c2b14ab41 100644 --- a/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs +++ b/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs @@ -39,21 +39,13 @@ impl TryFrom for MsgRecvPacket { Ok(MsgRecvPacket { packet: raw_msg .packet - .ok_or(DecodingError::MissingRawData { - description: "packet data not set".to_string(), - })? + .ok_or(DecodingError::missing_raw_data("msg recv packet data"))? .try_into()?, - proof_commitment_on_a: raw_msg.proof_commitment.try_into().map_err(|e| { - DecodingError::InvalidRawData { - description: format!("failed to decode proof: {e}"), - } - })?, + proof_commitment_on_a: raw_msg.proof_commitment.try_into()?, proof_height_on_a: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::InvalidRawData { - description: "failed to decode proof height".to_string(), - })?, + .ok_or(DecodingError::invalid_raw_data("msg recv proof height"))?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/timeout.rs b/ibc-core/ics04-channel/types/src/msgs/timeout.rs index 540a11325..5fc255896 100644 --- a/ibc-core/ics04-channel/types/src/msgs/timeout.rs +++ b/ibc-core/ics04-channel/types/src/msgs/timeout.rs @@ -37,22 +37,20 @@ impl TryFrom for MsgTimeout { fn try_from(raw_msg: RawMsgTimeout) -> Result { if raw_msg.next_sequence_recv == 0 { return Err(DecodingError::invalid_raw_data( - "packet sequence cannot be 0", + "msg timeout packet sequence cannot be 0", )); } Ok(MsgTimeout { packet: raw_msg .packet - .ok_or(DecodingError::missing_raw_data("packet data not set"))? + .ok_or(DecodingError::missing_raw_data("msg timeout packet data"))? .try_into()?, next_seq_recv_on_b: Sequence::from(raw_msg.next_sequence_recv), - proof_unreceived_on_b: raw_msg.proof_unreceived.try_into().map_err(|e| { - DecodingError::invalid_raw_data(format!("failed to decode proof: {e}")) - })?, + proof_unreceived_on_b: raw_msg.proof_unreceived.try_into()?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::missing_raw_data("proof height not set"))?, + .ok_or(DecodingError::missing_raw_data("msg timeout proof height"))?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs b/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs index c4277cfe4..34394b856 100644 --- a/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs +++ b/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs @@ -42,29 +42,21 @@ impl TryFrom for MsgTimeoutOnClose { } if raw_msg.counterparty_upgrade_sequence != 0 { - return Err(DecodingError::invalid_raw_data( - "unsupported channel upgrade sequence", - )); + return Err(DecodingError::invalid_raw_data("channel upgrade sequence")); } Ok(MsgTimeoutOnClose { packet: raw_msg .packet - .ok_or(DecodingError::missing_raw_data("packet data not set"))? + .ok_or(DecodingError::missing_raw_data("msg timeout packet data"))? .try_into()?, next_seq_recv_on_b: Sequence::from(raw_msg.next_sequence_recv), - proof_unreceived_on_b: raw_msg.proof_unreceived.try_into().map_err(|e| { - DecodingError::invalid_raw_data(format!("failed to decode proof: {e}")) - })?, - proof_close_on_b: raw_msg.proof_close.try_into().map_err(|e| { - DecodingError::invalid_raw_data(format!("failed to decode proof: {e}")) - })?, + proof_unreceived_on_b: raw_msg.proof_unreceived.try_into()?, + proof_close_on_b: raw_msg.proof_close.try_into()?, proof_height_on_b: raw_msg .proof_height .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or(DecodingError::invalid_raw_data( - "failed to decode proof height", - ))?, + .ok_or(DecodingError::invalid_raw_data("msg timeout proof height"))?, signer: raw_msg.signer.into(), }) } diff --git a/ibc-core/ics23-commitment/types/src/commitment.rs b/ibc-core/ics23-commitment/types/src/commitment.rs index 004c09152..af1f30153 100644 --- a/ibc-core/ics23-commitment/types/src/commitment.rs +++ b/ibc-core/ics23-commitment/types/src/commitment.rs @@ -10,7 +10,6 @@ use ibc_proto::Protobuf; use subtle_encoding::{Encoding, Hex}; use super::merkle::MerkleProof; -use crate::error::CommitmentError; /// Encodes a commitment root; most often a Merkle tree root hash. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -91,13 +90,11 @@ impl fmt::Debug for CommitmentProofBytes { } impl TryFrom> for CommitmentProofBytes { - type Error = CommitmentError; + type Error = DecodingError; fn try_from(bytes: Vec) -> Result { if bytes.is_empty() { - Err(DecodingError::MissingRawData { - description: "empty commitment proof bytes".to_string(), - })? + Err(DecodingError::missing_raw_data("commitment proof bytes"))? } else { Ok(Self { bytes }) } @@ -105,7 +102,7 @@ impl TryFrom> for CommitmentProofBytes { } impl TryFrom for CommitmentProofBytes { - type Error = CommitmentError; + type Error = DecodingError; fn try_from(proof: RawMerkleProof) -> Result { proof.to_vec().try_into() @@ -113,7 +110,7 @@ impl TryFrom for CommitmentProofBytes { } impl TryFrom for CommitmentProofBytes { - type Error = CommitmentError; + type Error = DecodingError; fn try_from(value: MerkleProof) -> Result { Self::try_from(RawMerkleProof::from(value)) @@ -121,10 +118,10 @@ impl TryFrom for CommitmentProofBytes { } impl<'a> TryFrom<&'a CommitmentProofBytes> for MerkleProof { - type Error = CommitmentError; + type Error = DecodingError; fn try_from(value: &'a CommitmentProofBytes) -> Result { - Ok(Protobuf::::decode(value.as_ref()).map_err(DecodingError::Protobuf)?) + Ok(Protobuf::::decode(value.as_ref())?) } } diff --git a/ibc-core/ics23-commitment/types/src/error.rs b/ibc-core/ics23-commitment/types/src/error.rs index c367a0817..3554767eb 100644 --- a/ibc-core/ics23-commitment/types/src/error.rs +++ b/ibc-core/ics23-commitment/types/src/error.rs @@ -6,32 +6,26 @@ use ibc_primitives::prelude::*; #[derive(Debug, Display)] pub enum CommitmentError { - /// decoding error: `{0}` + /// decoding error: {0} Decoding(DecodingError), - /// empty commitment prefix - EmptyCommitmentPrefix, - /// empty commitment root - EmptyCommitmentRoot, - /// empty merkle proof - EmptyMerkleProof, - /// empty merkle root - EmptyMerkleRoot, - /// empty verified value - EmptyVerifiedValue, - /// empty proof specs - EmptyProofSpecs, + /// missing commitment root + MissingCommitmentRoot, + /// missing commitment prefix + MissingCommitmentPrefix, + /// missing merkle proof + MissingMerkleProof, + /// missing merkle root + MissingMerkleRoot, + /// missing verified value + MissingVerifiedValue, + /// missing proof specs + MissingProofSpecs, /// mismatched number of proofs: expected `{expected}`, actual `{actual}` MismatchedNumberOfProofs { expected: usize, actual: usize }, - /// invalid range: [`{min}`, `{max}`] + /// invalid range [`{min}`, `{max}`] InvalidRange { min: i32, max: i32 }, /// invalid merkle proof InvalidMerkleProof, - /// invalid child size: `{0}` - InvalidChildSize(i32), - /// invalid hash operation: `{0}` - InvalidHashOp(i32), - /// invalid length operation: `{0}` - InvalidLengthOp(i32), /// failed to verify membership FailedToVerifyMembership, } @@ -43,4 +37,11 @@ impl From for CommitmentError { } #[cfg(feature = "std")] -impl std::error::Error for CommitmentError {} +impl std::error::Error for CommitmentError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match &self { + Self::Decoding(e) => Some(e), + _ => None, + } + } +} diff --git a/ibc-core/ics23-commitment/types/src/merkle.rs b/ibc-core/ics23-commitment/types/src/merkle.rs index 69aad45e5..d2bcea088 100644 --- a/ibc-core/ics23-commitment/types/src/merkle.rs +++ b/ibc-core/ics23-commitment/types/src/merkle.rs @@ -1,5 +1,6 @@ //! Merkle proof utilities +use ibc_core_host_types::error::DecodingError; use ibc_core_host_types::path::PathBytes; use ibc_primitives::prelude::*; use ibc_primitives::proto::Protobuf; @@ -70,7 +71,7 @@ pub struct MerkleProof { impl Protobuf for MerkleProof {} impl TryFrom for MerkleProof { - type Error = CommitmentError; + type Error = DecodingError; fn try_from(proof: RawMerkleProof) -> Result { Ok(Self { @@ -98,10 +99,10 @@ impl MerkleProof { ) -> Result<(), CommitmentError> { // validate arguments if self.proofs.is_empty() { - return Err(CommitmentError::EmptyMerkleProof); + return Err(CommitmentError::MissingMerkleProof); } if root.hash.is_empty() { - return Err(CommitmentError::EmptyMerkleRoot); + return Err(CommitmentError::MissingMerkleRoot); } let num = self.proofs.len(); let ics23_specs = Vec::::from(specs.clone()); @@ -118,7 +119,7 @@ impl MerkleProof { }); } if value.is_empty() { - return Err(CommitmentError::EmptyVerifiedValue); + return Err(CommitmentError::MissingVerifiedValue); } let mut subroot = value.clone(); @@ -164,10 +165,10 @@ impl MerkleProof { ) -> Result<(), CommitmentError> { // validate arguments if self.proofs.is_empty() { - return Err(CommitmentError::EmptyMerkleProof); + return Err(CommitmentError::MissingMerkleProof); } if root.hash.is_empty() { - return Err(CommitmentError::EmptyMerkleRoot); + return Err(CommitmentError::MissingMerkleRoot); } let num = self.proofs.len(); let ics23_specs = Vec::::from(specs.clone()); diff --git a/ibc-core/ics23-commitment/types/src/specs.rs b/ibc-core/ics23-commitment/types/src/specs.rs index d163c6bf8..5d0f0f473 100644 --- a/ibc-core/ics23-commitment/types/src/specs.rs +++ b/ibc-core/ics23-commitment/types/src/specs.rs @@ -1,5 +1,6 @@ //! Defines proof specs, which encode the structure of proofs +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_proto::ics23::{InnerSpec as RawInnerSpec, LeafOp as RawLeafOp, ProofSpec as RawProofSpec}; use ics23::{HashOp, LengthOp}; @@ -30,7 +31,7 @@ impl ProofSpecs { pub fn validate(&self) -> Result<(), CommitmentError> { if self.is_empty() { - return Err(CommitmentError::EmptyProofSpecs); + return Err(CommitmentError::MissingProofSpecs); } for proof_spec in &self.0 { // A non-positive `min_depth` or `max_depth` indicates no limit on the respective bound. @@ -54,11 +55,12 @@ impl ProofSpecs { } impl TryFrom> for ProofSpecs { - type Error = CommitmentError; - fn try_from(ics23_specs: Vec) -> Result { + type Error = DecodingError; + + fn try_from(ics23_specs: Vec) -> Result { // no proof specs provided if ics23_specs.is_empty() { - return Err(CommitmentError::EmptyProofSpecs); + return Err(DecodingError::missing_raw_data("proof specs")); } ics23_specs @@ -80,8 +82,9 @@ impl From for Vec { struct ProofSpec(RawProofSpec); impl TryFrom for ProofSpec { - type Error = CommitmentError; - fn try_from(spec: RawProofSpec) -> Result { + type Error = DecodingError; + + fn try_from(spec: RawProofSpec) -> Result { // A non-positive `min_depth` or `max_depth` indicates no limit on the respective bound. // For simplicity, negative values for `min_depth` and `max_depth` are not allowed // and only `0` is used to indicate no limit. When `min_depth` and `max_depth` are both positive, @@ -90,10 +93,10 @@ impl TryFrom for ProofSpec { || spec.min_depth < 0 || (0 < spec.min_depth && 0 < spec.max_depth && spec.max_depth < spec.min_depth) { - return Err(CommitmentError::InvalidRange { - min: spec.min_depth, - max: spec.max_depth, - }); + return Err(DecodingError::invalid_raw_data(format!( + "proof spec range [`{}`, `{}`]", + spec.min_depth, spec.max_depth + ))); } let leaf_spec = spec @@ -128,17 +131,17 @@ impl From for RawProofSpec { struct LeafOp(RawLeafOp); impl TryFrom for LeafOp { - type Error = CommitmentError; + type Error = DecodingError; fn try_from(leaf_op: RawLeafOp) -> Result { let _ = HashOp::try_from(leaf_op.hash) - .map_err(|_| CommitmentError::InvalidHashOp(leaf_op.hash))?; + .map_err(|_| DecodingError::invalid_raw_data("leaf op hash"))?; let _ = HashOp::try_from(leaf_op.prehash_key) - .map_err(|_| CommitmentError::InvalidHashOp(leaf_op.prehash_key))?; + .map_err(|_| DecodingError::invalid_raw_data("leaf op prehash key"))?; let _ = HashOp::try_from(leaf_op.prehash_value) - .map_err(|_| CommitmentError::InvalidHashOp(leaf_op.prehash_value))?; + .map_err(|_| DecodingError::invalid_raw_data("leaf op prehash value"))?; let _ = LengthOp::try_from(leaf_op.length) - .map_err(|_| CommitmentError::InvalidLengthOp(leaf_op.length))?; + .map_err(|_| DecodingError::invalid_raw_data("leaf op length"))?; Ok(Self(leaf_op)) } @@ -155,11 +158,11 @@ impl From for RawLeafOp { struct InnerSpec(RawInnerSpec); impl TryFrom for InnerSpec { - type Error = CommitmentError; + type Error = DecodingError; - fn try_from(inner_spec: RawInnerSpec) -> Result { + fn try_from(inner_spec: RawInnerSpec) -> Result { if inner_spec.child_size <= 0 { - return Err(CommitmentError::InvalidChildSize(inner_spec.child_size)); + return Err(DecodingError::invalid_raw_data("inner spec child size")); } // Negative prefix lengths are not allowed and the maximum prefix length must @@ -168,10 +171,10 @@ impl TryFrom for InnerSpec { || inner_spec.max_prefix_length < 0 || inner_spec.max_prefix_length < inner_spec.min_prefix_length { - return Err(CommitmentError::InvalidRange { - min: inner_spec.min_prefix_length, - max: inner_spec.max_prefix_length, - }); + return Err(DecodingError::invalid_raw_data(format!( + "inner spec range: [`{}`, `{}`]", + inner_spec.min_prefix_length, inner_spec.max_prefix_length + ))); } Ok(Self(RawInnerSpec { @@ -202,15 +205,15 @@ mod tests { #[case(0, 0)] #[case(2, 2)] #[case(5, 6)] - #[should_panic(expected = "InvalidRange")] + #[should_panic(expected = "InvalidRawData")] #[case(-3,3)] - #[should_panic(expected = "InvalidRange")] + #[should_panic(expected = "InvalidRawData")] #[case(2,-6)] - #[should_panic(expected = "InvalidRange")] + #[should_panic(expected = "InvalidRawData")] #[case(-2,-6)] - #[should_panic(expected = "InvalidRange")] + #[should_panic(expected = "InvalidRawData")] #[case(-6,-2)] - #[should_panic(expected = "InvalidRange")] + #[should_panic(expected = "InvalidRawData")] #[case(5, 3)] fn test_proof_specs_try_from(#[case] min_depth: i32, #[case] max_depth: i32) { let raw_proof_spec = RawProofSpec { @@ -227,15 +230,15 @@ mod tests { #[case(0, 0)] #[case(1, 2)] #[case(2, 2)] - #[should_panic(expected = "InvalidRange")] + #[should_panic(expected = "InvalidRawData")] #[case(2, 1)] - #[should_panic(expected = "InvalidRange")] + #[should_panic(expected = "InvalidRawData")] #[case(-2,1)] - #[should_panic(expected = "InvalidRange")] + #[should_panic(expected = "InvalidRawData")] #[case(2,-1)] - #[should_panic(expected = "InvalidRange")] + #[should_panic(expected = "InvalidRawData")] #[case(-2,-1)] - #[should_panic(expected = "InvalidRange")] + #[should_panic(expected = "InvalidRawData")] #[case(-1,-2)] fn test_inner_specs_try_from(#[case] min_prefix_length: i32, #[case] max_prefix_length: i32) { let raw_inner_spec = RawInnerSpec { @@ -252,21 +255,21 @@ mod tests { #[rstest] #[case(0, 0, 0, 0)] #[case(9, 9, 9, 8)] - #[should_panic(expected = "InvalidHashOp")] + #[should_panic(expected = "leaf op hash")] #[case(-1, 4, 4, 4)] - #[should_panic(expected = "InvalidHashOp")] + #[should_panic(expected = "leaf op hash")] #[case(10, 4, 4, 4)] - #[should_panic(expected = "InvalidHashOp")] + #[should_panic(expected = "leaf op prehash key")] #[case(4, -1, 4, 4)] - #[should_panic(expected = "InvalidHashOp")] + #[should_panic(expected = "leaf op prehash key")] #[case(4, 10, 4, 4)] - #[should_panic(expected = "InvalidHashOp")] + #[should_panic(expected = "leaf op prehash value")] #[case(4, 4, -1, 4)] - #[should_panic(expected = "InvalidHashOp")] + #[should_panic(expected = "leaf op prehash value")] #[case(4, 4, 10, 4)] - #[should_panic(expected = "InvalidLengthOp")] + #[should_panic(expected = "leaf op length")] #[case(4, 4, 4, -1)] - #[should_panic(expected = "InvalidLengthOp")] + #[should_panic(expected = "leaf op length")] #[case(4, 4, 4, 9)] fn test_leaf_op_try_from( #[case] hash: i32, diff --git a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs index ccba17567..c973cfe2b 100644 --- a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs +++ b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs @@ -1,7 +1,6 @@ //! Definition of domain `Plan` type. -use ibc_core_client_types::error::UpgradeClientError; -use ibc_core_host_types::error::{DecodingError, IdentifierError}; +use ibc_core_host_types::error::DecodingError; use ibc_primitives::prelude::*; use ibc_proto::cosmos::upgrade::v1beta1::Plan as RawPlan; use ibc_proto::google::protobuf::Any; @@ -33,30 +32,26 @@ impl TryFrom for Plan { fn try_from(raw: RawPlan) -> Result { if raw.name.is_empty() { - return Err(DecodingError::InvalidRawData { - description: "upgrade plan name cannot be empty".to_string(), - }); + return Err(DecodingError::missing_raw_data("upgrade plan name")); } #[allow(deprecated)] if raw.time.is_some() { - return Err(DecodingError::InvalidRawData { - description: "upgrade plan time must be empty".to_string(), - }); + return Err(DecodingError::invalid_raw_data( + "upgrade plan time must be empty", + )); } #[allow(deprecated)] if raw.upgraded_client_state.is_some() { - return Err(DecodingError::InvalidRawData { - description: "upgrade plan `upgraded_client_state` field must be empty".to_string(), - }); + return Err(DecodingError::invalid_raw_data( + "upgrade plan `upgraded_client_state` field must be empty", + )); } Ok(Self { name: raw.name, - height: u64::try_from(raw.height).map_err(|_| { - DecodingError::Identifier(IdentifierError::OverflowedRevisionNumber) - })?, + height: u64::try_from(raw.height)?, info: raw.info, }) } @@ -78,14 +73,12 @@ impl From for RawPlan { impl Protobuf for Plan {} impl TryFrom for Plan { - type Error = UpgradeClientError; + type Error = DecodingError; fn try_from(any: Any) -> Result { match any.type_url.as_str() { - TYPE_URL => { - Ok(Protobuf::::decode_vec(&any.value).map_err(DecodingError::Protobuf)?) - } - _ => Err(DecodingError::MismatchedTypeUrls { + TYPE_URL => Ok(Protobuf::::decode_vec(&any.value)?), + _ => Err(DecodingError::MismatchedResourceName { expected: TYPE_URL.to_string(), actual: any.type_url, })?, diff --git a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs index 9de0a272a..a98441ce7 100644 --- a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs +++ b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/proposal.rs @@ -32,31 +32,24 @@ impl TryFrom for UpgradeProposal { fn try_from(raw: RawUpgradeProposal) -> Result { if raw.title.is_empty() { - return Err(DecodingError::InvalidRawData { - description: "invalid upgrade proposal: missing title field".to_string(), - }); + return Err(DecodingError::missing_raw_data("upgrade proposal title")); } if raw.description.is_empty() { - return Err(DecodingError::InvalidRawData { - description: "invalid upgrade proposal: missing description field".to_string(), - }); + return Err(DecodingError::missing_raw_data( + "upgrade proposal description", + )); } let plan = if let Some(plan) = raw.plan { plan.try_into()? } else { - return Err(DecodingError::InvalidRawData { - description: "invalid upgrade proposal: missing plan field".to_string(), - }); + return Err(DecodingError::missing_raw_data("upgrade proposal plan")); }; - let upgraded_client_state = - raw.upgraded_client_state - .ok_or_else(|| DecodingError::InvalidRawData { - description: "invalid upgrade proposal: missing upgraded client state" - .to_string(), - })?; + let upgraded_client_state = raw.upgraded_client_state.ok_or_else(|| { + DecodingError::missing_raw_data("upgrade proposal upgraded client state") + })?; Ok(Self { title: raw.title, diff --git a/ibc-core/ics24-host/cosmos/src/validate_self_client.rs b/ibc-core/ics24-host/cosmos/src/validate_self_client.rs index d6c84e365..96b13306c 100644 --- a/ibc-core/ics24-host/cosmos/src/validate_self_client.rs +++ b/ibc-core/ics24-host/cosmos/src/validate_self_client.rs @@ -22,7 +22,7 @@ pub trait ValidateSelfClientContext { .validate() .map_err(|e| { HostError::invalid_state(format!( - "invalid counterparty client state that could not be validated: {e}" + "counterparty client state could not be validated: {e}" )) })?; @@ -34,7 +34,7 @@ pub trait ValidateSelfClientContext { if self_chain_id != &client_state_of_host_on_counterparty.chain_id { return Err(HostError::invalid_state(format!( - "invalid chain ID: expected {}, actual {}", + "chain ID: expected `{}`, actual `{}`", self_chain_id, client_state_of_host_on_counterparty.chain_id ))); } @@ -44,7 +44,7 @@ pub trait ValidateSelfClientContext { if self_revision_number != latest_height.revision_number() { return Err(HostError::invalid_state(format!( - "mismatched client revision numbers; expected {}, actual {}", + "mismatched client revision numbers; expected `{}`, actual `{}`", self_revision_number, latest_height.revision_number() ))); @@ -52,7 +52,7 @@ pub trait ValidateSelfClientContext { if latest_height >= self.host_current_height() { return Err(HostError::invalid_state(format!( - "client latest height {} should be less than chain height {}", + "client latest height `{}` should be less than chain height `{}`", latest_height, self.host_current_height() ))); @@ -60,7 +60,7 @@ pub trait ValidateSelfClientContext { if self.proof_specs() != &client_state_of_host_on_counterparty.proof_specs { return Err(HostError::invalid_state(format!( - "invalid client proof specs; expected {:?}, actual {:?}", + "client proof specs; expected `{:?}`, actual `{:?}`", self.proof_specs(), client_state_of_host_on_counterparty.proof_specs ))); @@ -78,7 +78,7 @@ pub trait ValidateSelfClientContext { if self.unbonding_period() != client_state_of_host_on_counterparty.unbonding_period { return Err(HostError::invalid_state(format!( - "invalid unbonding period; expected {:?}, actual {:?}", + "unbonding period; expected `{:?}`, actual `{:?}`", self.unbonding_period(), client_state_of_host_on_counterparty.unbonding_period, ))); @@ -88,7 +88,7 @@ pub trait ValidateSelfClientContext { < client_state_of_host_on_counterparty.trusting_period { return Err(HostError::invalid_state(format!( - "invalid counterparty client state: unbonding period must be greater than trusting period; unbonding period ({:?}) < trusting period ({:?})", + "counterparty client state: unbonding period must be greater than trusting period; unbonding period ({:?}) < trusting period ({:?})", client_state_of_host_on_counterparty.unbonding_period, client_state_of_host_on_counterparty.trusting_period ))); @@ -98,7 +98,7 @@ pub trait ValidateSelfClientContext { && self.upgrade_path() != client_state_of_host_on_counterparty.upgrade_path { return Err(HostError::invalid_state(format!( - "invalid upgrade path; expected {:?}, actual {:?}", + "upgrade path; expected `{:?}`, actual `{:?}`", self.upgrade_path(), client_state_of_host_on_counterparty.upgrade_path ))); diff --git a/ibc-core/ics24-host/types/src/error.rs b/ibc-core/ics24-host/types/src/error.rs index 7fd47c2cc..580fcc90b 100644 --- a/ibc-core/ics24-host/types/src/error.rs +++ b/ibc-core/ics24-host/types/src/error.rs @@ -1,6 +1,7 @@ //! Foundational error types that are applicable across multiple ibc-rs workspaces. use alloc::string::{FromUtf8Error, String}; +use core::num::{ParseIntError, TryFromIntError}; use core::str::Utf8Error; use base64::DecodeError as Base64Error; @@ -58,10 +59,10 @@ pub enum IdentifierError { InvalidLength { actual: String, min: u64, max: u64 }, /// id `{0}` can only contain alphanumeric characters or `.`, `_`, `+`, `-`, `#`, - `[`, `]`, `<`, `>` InvalidCharacter(String), - /// invalid prefix: `{0}` + /// invalid prefix `{0}` InvalidPrefix(String), - /// failed to parse `{value}`: `{description}` - FailedToParse { value: String, description: String }, + /// failed to parse: `{description}` + FailedToParse { description: String }, /// overflowed revision number OverflowedRevisionNumber, } @@ -70,29 +71,31 @@ pub enum IdentifierError { /// and/or converting raw types into domain types. #[derive(Debug, Display)] pub enum DecodingError { - /// identifier error: `{0}` + /// identifier error: {0} Identifier(IdentifierError), - /// base64 decoding error: `{0}` + /// base64 decoding error: {0} Base64(Base64Error), - /// utf-8 String decoding error: `{0}` + /// utf-8 String decoding error: {0} StringUtf8(FromUtf8Error), - /// utf-8 str decoding error: `{0}` + /// utf-8 str decoding error: {0} StrUtf8(Utf8Error), - /// protobuf decoding error: `{0}` + /// integer parsing error: {0} + ParseInt(ParseIntError), + /// integer TryFrom error: {0} + TryFromInt(TryFromIntError), + /// protobuf decoding error: {0} Protobuf(ProtoError), - /// prost decoding error: `{0}` + /// prost decoding error: {0} Prost(ProstError), - /// invalid hash bytes: `{description}` - InvalidHash { description: String }, /// invalid JSON data: `{description}` InvalidJson { description: String }, /// invalid raw data: `{description}` InvalidRawData { description: String }, /// missing raw data: `{description}` MissingRawData { description: String }, - /// mismatched type URLs: expected `{expected}`, actual `{actual}` - MismatchedTypeUrls { expected: String, actual: String }, - /// unknown type URL: `{0}` + /// mismatched resource name: expected `{expected}`, actual `{actual}` + MismatchedResourceName { expected: String, actual: String }, + /// unknown type URL `{0}` UnknownTypeUrl(String), } @@ -140,6 +143,18 @@ impl From for DecodingError { } } +impl From for DecodingError { + fn from(e: ParseIntError) -> Self { + Self::ParseInt(e) + } +} + +impl From for DecodingError { + fn from(e: TryFromIntError) -> Self { + Self::TryFromInt(e) + } +} + #[cfg(feature = "std")] impl std::error::Error for IdentifierError {} diff --git a/ibc-core/ics24-host/types/src/identifiers/chain_id.rs b/ibc-core/ics24-host/types/src/identifiers/chain_id.rs index eeae43a6a..c96ccc36f 100644 --- a/ibc-core/ics24-host/types/src/identifiers/chain_id.rs +++ b/ibc-core/ics24-host/types/src/identifiers/chain_id.rs @@ -313,8 +313,7 @@ fn parse_chain_id_string(chain_id_str: &str) -> Result<(&str, u64), IdentifierEr .map(|revision_number| (chain_name, revision_number)) }) .ok_or(IdentifierError::FailedToParse { - value: chain_id_str.to_string(), - description: "invalid revision number".to_string(), + description: format!("revision number for chain ID `{chain_id_str}`"), }) } diff --git a/ibc-core/ics24-host/types/src/identifiers/sequence.rs b/ibc-core/ics24-host/types/src/identifiers/sequence.rs index 146a978d7..0ab91f24c 100644 --- a/ibc-core/ics24-host/types/src/identifiers/sequence.rs +++ b/ibc-core/ics24-host/types/src/identifiers/sequence.rs @@ -26,8 +26,7 @@ impl core::str::FromStr for Sequence { fn from_str(s: &str) -> Result { Ok(Self::from(s.parse::().map_err(|e| { IdentifierError::FailedToParse { - value: s.to_string(), - description: e.to_string(), + description: format!("sequence `{s}`: {e}"), } })?)) } diff --git a/ibc-core/ics24-host/types/src/validate.rs b/ibc-core/ics24-host/types/src/validate.rs index 3c1557d6a..614cfd8a4 100644 --- a/ibc-core/ics24-host/types/src/validate.rs +++ b/ibc-core/ics24-host/types/src/validate.rs @@ -75,9 +75,8 @@ pub fn validate_named_u64_index(id: &str, name: &str) -> Result<(), Error> { return Err(Error::InvalidPrefix(id.into())); } - _ = number_s.parse::().map_err(|_| Error::FailedToParse { - value: id.into(), - description: "invalid prefix".to_string(), + _ = number_s.parse::().map_err(|e| Error::FailedToParse { + description: format!("named index `{id}`: {e}"), })?; Ok(()) diff --git a/ibc-core/ics25-handler/types/src/events.rs b/ibc-core/ics25-handler/types/src/events.rs index 28480c375..77ebe79e1 100644 --- a/ibc-core/ics25-handler/types/src/events.rs +++ b/ibc-core/ics25-handler/types/src/events.rs @@ -1,9 +1,9 @@ //! Defines events emitted during handling of IBC messages -use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::events as ChannelEvents; use ibc_core_client_types::events::{self as ClientEvents}; use ibc_core_connection_types::events as ConnectionEvents; +use ibc_core_host_types::error::DecodingError; use ibc_core_router_types::event::ModuleEvent; use ibc_primitives::prelude::*; use tendermint::abci; @@ -55,7 +55,7 @@ pub enum IbcEvent { } impl TryFrom for abci::Event { - type Error = ChannelError; + type Error = DecodingError; fn try_from(event: IbcEvent) -> Result { Ok(match event { diff --git a/ibc-primitives/src/types/timestamp.rs b/ibc-primitives/src/types/timestamp.rs index 7551db5e7..032662d9c 100644 --- a/ibc-primitives/src/types/timestamp.rs +++ b/ibc-primitives/src/types/timestamp.rs @@ -13,7 +13,6 @@ use ibc_proto::Protobuf; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use tendermint::Time; -use time::error::ComponentRange; use time::macros::offset; use time::{OffsetDateTime, PrimitiveDateTime}; @@ -47,7 +46,7 @@ impl Timestamp { pub fn from_unix_timestamp(secs: u64, nanos: u32) -> Result { if nanos > 999_999_999 { - return Err(TimestampError::DateOutOfRange); + return Err(TimestampError::InvalidDate); } let total_nanos = secs as i128 * 1_000_000_000 + nanos as i128; @@ -66,7 +65,7 @@ impl Timestamp { 1970..=9999 => Ok(Self { time: PrimitiveDateTime::new(t.date(), t.time()), }), - _ => Err(TimestampError::DateOutOfRange), + _ => Err(TimestampError::InvalidDate), } } @@ -168,11 +167,11 @@ impl Add for Timestamp { type Output = Result; fn add(self, rhs: Duration) -> Self::Output { - let duration = rhs.try_into().map_err(|_| TimestampError::DateOutOfRange)?; + let duration = rhs.try_into().map_err(|_| TimestampError::InvalidDate)?; let t = self .time .checked_add(duration) - .ok_or(TimestampError::DateOutOfRange)?; + .ok_or(TimestampError::InvalidDate)?; Self::from_utc(t.assume_utc()) } } @@ -181,11 +180,11 @@ impl Sub for Timestamp { type Output = Result; fn sub(self, rhs: Duration) -> Self::Output { - let duration = rhs.try_into().map_err(|_| TimestampError::DateOutOfRange)?; + let duration = rhs.try_into().map_err(|_| TimestampError::InvalidDate)?; let t = self .time .checked_sub(duration) - .ok_or(TimestampError::DateOutOfRange)?; + .ok_or(TimestampError::InvalidDate)?; Self::from_utc(t.assume_utc()) } } @@ -269,16 +268,16 @@ impl scale_info::TypeInfo for Timestamp { #[derive(Debug, Display, derive_more::From)] pub enum TimestampError { - /// parsing u64 integer from string error: `{0}` + /// parse int error: {0} ParseInt(ParseIntError), - /// error converting integer to `Timestamp`: `{0}` + /// try from int error: {0} TryFromInt(TryFromIntError), - /// date out of range - DateOutOfRange, - /// Timestamp overflow when modifying with duration - TimestampOverflow, - /// Timestamp is not set - Conversion(ComponentRange), + /// failed to convert timestamp: {0} + Conversion(time::error::ComponentRange), + /// invalid date: out of range + InvalidDate, + /// overflowed timestamp + OverflowedTimestamp, } #[cfg(feature = "std")] @@ -287,7 +286,7 @@ impl std::error::Error for TimestampError { match &self { Self::ParseInt(e) => Some(e), Self::TryFromInt(e) => Some(e), - Self::Conversion(e) => Some(e), + // Self::Conversion(e) => Some(e), _ => None, } } diff --git a/ibc-query/src/core/client/types/request.rs b/ibc-query/src/core/client/types/request.rs index 8648c69bc..5c3a537e2 100644 --- a/ibc-query/src/core/client/types/request.rs +++ b/ibc-query/src/core/client/types/request.rs @@ -2,6 +2,7 @@ //! and from the corresponding gRPC proto types for the client module. use ibc::core::client::types::Height; +use ibc::core::host::types::error::DecodingError; use ibc::core::host::types::identifiers::ClientId; use ibc::primitives::prelude::*; use ibc_proto::ibc::core::client::v1::{ @@ -82,7 +83,12 @@ impl TryFrom for QueryConsensusStateRequest { client_id: request.client_id.parse()?, consensus_height: (!request.latest_height) .then(|| Height::new(request.revision_number, request.revision_height)) - .transpose()?, + .transpose() + .map_err(|e| { + DecodingError::invalid_raw_data(format!( + "consensus state request consensus height: {e}" + )) + })?, query_height: None, }) } diff --git a/ibc-query/src/error.rs b/ibc-query/src/error.rs index 4c064be97..2db8bce20 100644 --- a/ibc-query/src/error.rs +++ b/ibc-query/src/error.rs @@ -47,12 +47,6 @@ impl From for Status { } } -impl From for QueryError { - fn from(e: HandlerError) -> Self { - Self::Handler(e) - } -} - impl From for QueryError { fn from(e: ClientError) -> Self { Self::Handler(HandlerError::Client(e)) diff --git a/ibc-testkit/src/fixtures/clients/tendermint.rs b/ibc-testkit/src/fixtures/clients/tendermint.rs index 74c5a14d9..3653c39ef 100644 --- a/ibc-testkit/src/fixtures/clients/tendermint.rs +++ b/ibc-testkit/src/fixtures/clients/tendermint.rs @@ -13,6 +13,7 @@ use ibc::clients::tendermint::types::{ use ibc::core::client::types::proto::v1::Height as RawHeight; use ibc::core::client::types::Height; use ibc::core::commitment_types::specs::ProofSpecs; +use ibc::core::host::types::error::DecodingError; use ibc::core::host::types::identifiers::ChainId; use ibc::core::primitives::prelude::*; use tendermint::block::Header as TmHeader; @@ -21,7 +22,7 @@ use typed_builder::TypedBuilder; /// Returns a dummy tendermint `ClientState` by given `frozen_height`, for testing purposes only! pub fn dummy_tm_client_state_from_raw( frozen_height: RawHeight, -) -> Result { +) -> Result { ClientStateType::try_from(dummy_raw_tm_client_state(frozen_height)).map(TmClientState::from) } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs index ef6f4c0f0..500be2769 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs @@ -91,15 +91,13 @@ impl MockClientState { impl Protobuf for MockClientState {} impl TryFrom for MockClientState { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: RawMockClientState) -> Result { Ok(Self { header: raw .header - .ok_or(ClientError::Other { - description: "header is not present".into(), - })? + .ok_or(DecodingError::missing_raw_data("mock client state header"))? .try_into()?, trusting_period: Duration::from_nanos(raw.trusting_period), frozen: raw.frozen, @@ -124,7 +122,7 @@ impl From for RawMockClientState { impl Protobuf for MockClientState {} impl TryFrom for MockClientState { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { fn decode_client_state(value: &[u8]) -> Result { @@ -132,10 +130,8 @@ impl TryFrom for MockClientState { Ok(client_state) } match raw.type_url.as_str() { - MOCK_CLIENT_STATE_TYPE_URL => { - decode_client_state(&raw.value).map_err(ClientError::Decoding) - } - _ => Err(DecodingError::MismatchedTypeUrls { + MOCK_CLIENT_STATE_TYPE_URL => decode_client_state(&raw.value), + _ => Err(DecodingError::MismatchedResourceName { expected: MOCK_CLIENT_STATE_TYPE_URL.to_string(), actual: raw.type_url, })?, @@ -171,7 +167,7 @@ impl ClientStateCommon for MockClientState { if consensus_state_status(&mock_consensus_state, host_timestamp, self.trusting_period)? .is_expired() { - return Err(ClientError::UnexpectedStatus(Status::Expired)); + return Err(ClientError::InvalidStatus(Status::Expired)); } Ok(()) @@ -187,7 +183,7 @@ impl ClientStateCommon for MockClientState { fn validate_proof_height(&self, proof_height: Height) -> Result<(), ClientError> { if self.latest_height() < proof_height { - return Err(ClientError::InvalidProofHeight { + return Err(ClientError::InsufficientProofHeight { actual: self.latest_height(), expected: proof_height, }); @@ -308,9 +304,9 @@ where let now = ctx.host_timestamp()?; let elapsed_since_latest_consensus_state = now .duration_since(&latest_consensus_state.timestamp()) - .ok_or(ClientError::Other { - description: format!("latest consensus state is in the future. now: {now}, latest consensus state: {}", latest_consensus_state.timestamp()), - })?; + .ok_or(ClientError::InvalidConsensusStateTimestamp( + latest_consensus_state.timestamp(), + ))?; if self.expired(elapsed_since_latest_consensus_state) { return Ok(Status::Expired); diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs index 66d53d595..658a01c76 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs @@ -1,5 +1,4 @@ use ibc::core::client::context::consensus_state::ConsensusState; -use ibc::core::client::types::error::ClientError; use ibc::core::commitment_types::commitment::CommitmentRoot; use ibc::core::host::types::error::DecodingError; use ibc::core::primitives::prelude::*; @@ -39,12 +38,12 @@ impl MockConsensusState { impl Protobuf for MockConsensusState {} impl TryFrom for MockConsensusState { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: RawMockConsensusState) -> Result { - let raw_header = raw.header.ok_or(DecodingError::MissingRawData { - description: "no raw header set".to_string(), - })?; + let raw_header = raw.header.ok_or(DecodingError::missing_raw_data( + "mock consensus state header", + ))?; Ok(Self { header: raw_header.try_into()?, @@ -64,7 +63,7 @@ impl From for RawMockConsensusState { impl Protobuf for MockConsensusState {} impl TryFrom for MockConsensusState { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { fn decode_consensus_state(value: &[u8]) -> Result { @@ -72,10 +71,8 @@ impl TryFrom for MockConsensusState { Ok(mock_consensus_state) } match raw.type_url.as_str() { - MOCK_CONSENSUS_STATE_TYPE_URL => { - decode_consensus_state(&raw.value).map_err(ClientError::Decoding) - } - _ => Err(DecodingError::MismatchedTypeUrls { + MOCK_CONSENSUS_STATE_TYPE_URL => decode_consensus_state(&raw.value), + _ => Err(DecodingError::MismatchedResourceName { expected: MOCK_CONSENSUS_STATE_TYPE_URL.to_string(), actual: raw.type_url, })?, diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/header.rs b/ibc-testkit/src/testapp/ibc/clients/mock/header.rs index 9f46592e4..230dcedd5 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/header.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/header.rs @@ -1,7 +1,6 @@ use alloc::string::ToString; use core::fmt::{Display, Error as FmtError, Formatter}; -use ibc::core::client::types::error::ClientError; use ibc::core::client::types::Height; use ibc::core::host::types::error::DecodingError; use ibc::core::primitives::Timestamp; @@ -41,15 +40,13 @@ impl Display for MockHeader { impl Protobuf for MockHeader {} impl TryFrom for MockHeader { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: RawMockHeader) -> Result { Ok(Self { height: raw .height - .ok_or(ClientError::Other { - description: "missing height".into(), - })? + .ok_or(DecodingError::missing_raw_data("mock header height"))? .try_into()?, timestamp: Timestamp::from_nanoseconds(raw.timestamp), }) @@ -92,13 +89,12 @@ impl MockHeader { impl Protobuf for MockHeader {} impl TryFrom for MockHeader { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { match raw.type_url.as_str() { - MOCK_HEADER_TYPE_URL => Ok(Protobuf::::decode_vec(&raw.value) - .map_err(DecodingError::Protobuf)?), - _ => Err(DecodingError::MismatchedTypeUrls { + MOCK_HEADER_TYPE_URL => Ok(Protobuf::::decode_vec(&raw.value)?), + _ => Err(DecodingError::MismatchedResourceName { expected: MOCK_HEADER_TYPE_URL.to_string(), actual: raw.type_url, })?, diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs b/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs index d537e8209..2c23dd287 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs @@ -1,4 +1,3 @@ -use ibc::core::client::types::error::ClientError; use ibc::core::host::types::error::DecodingError; use ibc::core::host::types::identifiers::ClientId; use ibc::core::primitives::prelude::*; @@ -20,22 +19,18 @@ pub struct Misbehaviour { impl Protobuf for Misbehaviour {} impl TryFrom for Misbehaviour { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: RawMisbehaviour) -> Result { Ok(Self { client_id: ClientId::new("07-tendermint", 0).expect("no error"), header1: raw .header1 - .ok_or(DecodingError::MissingRawData { - description: "missing header1 in raw misbehaviour".into(), - })? + .ok_or(DecodingError::missing_raw_data("misbehaviour header1"))? .try_into()?, header2: raw .header2 - .ok_or(DecodingError::MissingRawData { - description: "missing header2 in raw misbehaviour".into(), - })? + .ok_or(DecodingError::missing_raw_data("misbehaviour header2"))? .try_into()?, }) } @@ -54,18 +49,16 @@ impl From for RawMisbehaviour { impl Protobuf for Misbehaviour {} impl TryFrom for Misbehaviour { - type Error = ClientError; + type Error = DecodingError; - fn try_from(raw: Any) -> Result { + fn try_from(raw: Any) -> Result { fn decode_misbehaviour(value: &[u8]) -> Result { let raw_misbehaviour = Protobuf::::decode(value)?; Ok(raw_misbehaviour) } match raw.type_url.as_str() { - MOCK_MISBEHAVIOUR_TYPE_URL => { - decode_misbehaviour(&raw.value).map_err(ClientError::Decoding) - } - _ => Err(DecodingError::MismatchedTypeUrls { + MOCK_MISBEHAVIOUR_TYPE_URL => decode_misbehaviour(&raw.value), + _ => Err(DecodingError::MismatchedResourceName { expected: MOCK_MISBEHAVIOUR_TYPE_URL.to_string(), actual: raw.type_url, })?, diff --git a/ibc-testkit/src/testapp/ibc/clients/mod.rs b/ibc-testkit/src/testapp/ibc/clients/mod.rs index 05fe539da..3a0b8389d 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mod.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mod.rs @@ -10,8 +10,8 @@ use ibc::clients::tendermint::types::{ ClientState as ClientStateType, ConsensusState as ConsensusStateType, TENDERMINT_CLIENT_STATE_TYPE_URL, TENDERMINT_CONSENSUS_STATE_TYPE_URL, }; -use ibc::core::client::types::error::ClientError; use ibc::core::client::types::Height; +use ibc::core::host::types::error::DecodingError; use ibc::core::primitives::prelude::*; use ibc::derive::{ClientState, ConsensusState}; use ibc::primitives::proto::{Any, Protobuf}; @@ -51,7 +51,7 @@ impl AnyClientState { impl Protobuf for AnyClientState {} impl TryFrom for AnyClientState { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { if raw.type_url == TENDERMINT_CLIENT_STATE_TYPE_URL { @@ -59,9 +59,7 @@ impl TryFrom for AnyClientState { } else if raw.type_url == MOCK_CLIENT_STATE_TYPE_URL { MockClientState::try_from(raw).map(Into::into) } else { - Err(ClientError::Other { - description: "failed to deserialize message".to_string(), - }) + Err(DecodingError::UnknownTypeUrl(raw.type_url)) } } } @@ -94,7 +92,7 @@ pub enum AnyConsensusState { } impl TryFrom for AnyConsensusState { - type Error = ClientError; + type Error = DecodingError; fn try_from(raw: Any) -> Result { if raw.type_url == TENDERMINT_CONSENSUS_STATE_TYPE_URL { @@ -102,9 +100,7 @@ impl TryFrom for AnyConsensusState { } else if raw.type_url == MOCK_CONSENSUS_STATE_TYPE_URL { MockConsensusState::try_from(raw).map(Into::into) } else { - Err(ClientError::Other { - description: "failed to deserialize message".to_string(), - }) + Err(DecodingError::UnknownTypeUrl(raw.type_url)) } } } @@ -119,28 +115,27 @@ impl From for Any { } impl TryFrom for ConsensusStateType { - type Error = ClientError; + type Error = DecodingError; fn try_from(value: AnyConsensusState) -> Result { match value { AnyConsensusState::Tendermint(cs) => Ok(cs.inner().clone()), - _ => Err(ClientError::Other { - description: "failed to convert AnyConsensusState to TmConsensusState".to_string(), - }), + _ => Err(DecodingError::invalid_raw_data( + "AnyConsensusState could not be converted to TmConsensusState", + )), } } } impl TryFrom for MockConsensusState { - type Error = ClientError; + type Error = DecodingError; fn try_from(value: AnyConsensusState) -> Result { match value { AnyConsensusState::Mock(cs) => Ok(cs), - _ => Err(ClientError::Other { - description: "failed to convert AnyConsensusState to MockConsensusState" - .to_string(), - }), + _ => Err(DecodingError::invalid_raw_data( + "AnyConsensusState could not be converted to MockConsensusState", + )), } } } diff --git a/ibc-testkit/src/testapp/ibc/core/client_ctx.rs b/ibc-testkit/src/testapp/ibc/core/client_ctx.rs index f2dbe930c..4640a6c23 100644 --- a/ibc-testkit/src/testapp/ibc/core/client_ctx.rs +++ b/ibc-testkit/src/testapp/ibc/core/client_ctx.rs @@ -106,7 +106,7 @@ where .get(StoreHeight::Pending, &path) .ok_or_else(|| { HostError::failed_to_retrieve(format!( - "missing consensus state for client {} at height {}", + "consensus state for client `{}` at height `{}`", client_id.clone(), *height )) @@ -143,7 +143,7 @@ where .get(StoreHeight::Pending, &path) .ok_or_else(|| { HostError::failed_to_retrieve(format!( - "missing consensus state for client {} at height {}", + "consensus state for client `{}` at height `{}`", client_id.clone(), *height )) @@ -185,7 +185,7 @@ where .consensus_state_store .get(StoreHeight::Pending, client_cons_state_path) .ok_or(HostError::failed_to_retrieve(format!( - "missing consensus state for client {} at height {}", + "consensus state for client `{}` at height `{}`", client_cons_state_path.client_id.clone(), height )))?; diff --git a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs index 05fbc0640..9e1837308 100644 --- a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs +++ b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs @@ -54,7 +54,7 @@ where fn client_counter(&self) -> Result { self.client_counter .get(StoreHeight::Pending, &NextClientSequencePath) - .ok_or(HostError::missing_state("missing client counter")) + .ok_or(HostError::missing_state("client counter")) } fn host_consensus_state(&self, height: &Height) -> Result { @@ -85,7 +85,7 @@ where .revision_number() { return Err(HostError::invalid_state(format!( - "client is not in the same revision as the chain; expected {}, actual {}", + "client is not in the same revision as the chain; expected `{}`, actual `{}`", self_revision_number, client_state_of_host_on_counterparty .latest_height() @@ -97,7 +97,7 @@ where if client_state_of_host_on_counterparty.latest_height() >= host_current_height { return Err(HostError::invalid_state( format!( - "invalid counterparty client state: client latest height {} should be less than chain height {}", + "counterparty client state: client latest height `{}` should be less than chain height `{}`", client_state_of_host_on_counterparty.latest_height(), host_current_height ), @@ -111,7 +111,7 @@ where self.connection_end_store .get(StoreHeight::Pending, &ConnectionPath::new(conn_id)) .ok_or(HostError::missing_state(format!( - "missing connection end for connection {}", + "connection end for connection `{}`", conn_id.clone() ))) } @@ -125,14 +125,14 @@ where fn connection_counter(&self) -> Result { self.conn_counter .get(StoreHeight::Pending, &NextConnectionSequencePath) - .ok_or(HostError::missing_state("missing connection counter")) + .ok_or(HostError::missing_state("connection counter")) } fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result { self.channel_end_store .get(StoreHeight::Pending, channel_end_path) .ok_or(HostError::missing_state(format!( - "missing channel {} in port {}", + "channel `{}` in port `{}`", channel_end_path.1.clone(), channel_end_path.0.clone() ))) @@ -141,25 +141,19 @@ where fn get_next_sequence_send(&self, seq_send_path: &SeqSendPath) -> Result { self.send_sequence_store .get(StoreHeight::Pending, seq_send_path) - .ok_or(HostError::failed_to_retrieve( - "failed to retrieve send packet sequence", - )) + .ok_or(HostError::failed_to_retrieve("send packet sequence")) } fn get_next_sequence_recv(&self, seq_recv_path: &SeqRecvPath) -> Result { self.recv_sequence_store .get(StoreHeight::Pending, seq_recv_path) - .ok_or(HostError::failed_to_retrieve( - "failed to retrieve recv packet sequence", - )) + .ok_or(HostError::failed_to_retrieve("recv packet sequence")) } fn get_next_sequence_ack(&self, seq_ack_path: &SeqAckPath) -> Result { self.ack_sequence_store .get(StoreHeight::Pending, seq_ack_path) - .ok_or(HostError::failed_to_retrieve( - "failed to retrieve ack packet sequence", - )) + .ok_or(HostError::failed_to_retrieve("ack packet sequence")) } fn get_packet_commitment( @@ -168,9 +162,7 @@ where ) -> Result { self.packet_commitment_store .get(StoreHeight::Pending, commitment_path) - .ok_or(HostError::failed_to_retrieve( - "failed to retrieve packet commitment", - )) + .ok_or(HostError::failed_to_retrieve("packet commitment")) } fn get_packet_receipt(&self, receipt_path: &ReceiptPath) -> Result { @@ -191,7 +183,7 @@ where self.packet_ack_store .get(StoreHeight::Pending, ack_path) .ok_or(HostError::failed_to_retrieve(format!( - "failed to retrieve packet acknowledgment {}", + "packet acknowledgment `{}`", ack_path.sequence ))) } @@ -202,9 +194,7 @@ where fn channel_counter(&self) -> Result { self.channel_counter .get(StoreHeight::Pending, &NextChannelSequencePath) - .ok_or(HostError::failed_to_retrieve( - "failed to retrieve channel counter", - )) + .ok_or(HostError::failed_to_retrieve("channel counter")) } /// Returns the maximum expected time per block @@ -271,7 +261,7 @@ where .get(StoreHeight::Pending, &client_state_path) .ok_or_else(|| { HostError::failed_to_retrieve(format!( - "failed to retrieve client state from path {}", + "client state from path `{}`", client_state_path.0.clone() )) })?; @@ -307,7 +297,7 @@ where .consensus_state_store .get(StoreHeight::Pending, &consensus_path) .ok_or(HostError::failed_to_retrieve(format!( - "missing consensus state for client {} at height {}", + "consensus state for client `{}` at height `{}`", consensus_path.client_id, height, )))?; Ok((height, client_state)) @@ -359,7 +349,7 @@ where .get(StoreHeight::Pending, &connection_path) .ok_or_else(|| { HostError::failed_to_retrieve(format!( - "missing connection {}", + "connection end `{}`", connection_path.0.clone() )) })?; @@ -401,7 +391,7 @@ where .get(StoreHeight::Pending, &channel_path) .ok_or_else(|| { HostError::failed_to_retrieve(format!( - "missing channel {} with port {}", + "channel `{}` with port `{}`", channel_path.1.clone(), channel_path.0.clone() )) @@ -594,13 +584,11 @@ where let current_sequence = self .client_counter .get(StoreHeight::Pending, &NextClientSequencePath) - .ok_or(HostError::failed_to_retrieve("missing client counter"))?; + .ok_or(HostError::failed_to_retrieve("client counter"))?; self.client_counter .set(NextClientSequencePath, current_sequence + 1) - .map_err(|e| { - HostError::failed_to_store(format!("failed to update client counter: {e:?}")) - })?; + .map_err(|e| HostError::failed_to_store(format!("client counter: {e:?}")))?; Ok(()) } @@ -613,9 +601,7 @@ where ) -> Result<(), HostError> { self.connection_end_store .set(connection_path.clone(), connection_end) - .map_err(|e| { - HostError::failed_to_store(format!("failed to set connection end: {e:?}")) - })?; + .map_err(|e| HostError::failed_to_store(format!("connection end: {e:?}")))?; Ok(()) } @@ -632,9 +618,7 @@ where conn_ids.push(conn_id); self.connection_ids_store .set(client_connection_path.clone(), conn_ids) - .map_err(|e| { - HostError::failed_to_store(format!("failed to store connection IDs: {e:?}")) - })?; + .map_err(|e| HostError::failed_to_store(format!("connection IDs: {e:?}")))?; Ok(()) } @@ -644,13 +628,11 @@ where let current_sequence = self .conn_counter .get(StoreHeight::Pending, &NextConnectionSequencePath) - .ok_or(HostError::failed_to_retrieve("missing connection counter"))?; + .ok_or(HostError::failed_to_retrieve("connection counter"))?; self.conn_counter .set(NextConnectionSequencePath, current_sequence + 1) - .map_err(|e| { - HostError::failed_to_store(format!("failed to update connection counter: {e:?}")) - })?; + .map_err(|e| HostError::failed_to_store(format!("connection counter: {e:?}")))?; Ok(()) } @@ -662,9 +644,7 @@ where ) -> Result<(), HostError> { self.packet_commitment_store .set(commitment_path.clone(), commitment) - .map_err(|e| { - HostError::failed_to_store(format!("failed to store packet commitment: {e:?}")) - })?; + .map_err(|e| HostError::failed_to_store(format!("packet commitment: {e:?}")))?; Ok(()) } @@ -683,9 +663,7 @@ where ) -> Result<(), HostError> { self.packet_receipt_store .set_path(receipt_path.clone()) - .map_err(|e| { - HostError::failed_to_store(format!("failed to store packet receipt: {e:?}")) - })?; + .map_err(|e| HostError::failed_to_store(format!("packet receipt: {e:?}")))?; Ok(()) } @@ -696,9 +674,7 @@ where ) -> Result<(), HostError> { self.packet_ack_store .set(ack_path.clone(), ack_commitment) - .map_err(|e| { - HostError::failed_to_store(format!("failed to store packet acknowledgment: {e:?}")) - })?; + .map_err(|e| HostError::failed_to_store(format!("packet acknowledgment: {e:?}")))?; Ok(()) } @@ -714,7 +690,7 @@ where ) -> Result<(), HostError> { self.channel_end_store .set(channel_end_path.clone(), channel_end) - .map_err(|e| HostError::failed_to_store(format!("failed to store channel: {e:?}")))?; + .map_err(|e| HostError::failed_to_store(format!("channel: {e:?}")))?; Ok(()) } @@ -725,9 +701,7 @@ where ) -> Result<(), HostError> { self.send_sequence_store .set(seq_send_path.clone(), seq) - .map_err(|e| { - HostError::failed_to_store(format!("failed to store send sequence: {e:?}")) - })?; + .map_err(|e| HostError::failed_to_store(format!("next send sequence: {e:?}")))?; Ok(()) } @@ -738,9 +712,7 @@ where ) -> Result<(), HostError> { self.recv_sequence_store .set(seq_recv_path.clone(), seq) - .map_err(|e| { - HostError::failed_to_store(format!("failed to store recv sequence: {e:?}")) - })?; + .map_err(|e| HostError::failed_to_store(format!("next recv sequence: {e:?}")))?; Ok(()) } @@ -761,11 +733,11 @@ where let current_sequence = self .channel_counter .get(StoreHeight::Pending, &NextChannelSequencePath) - .ok_or(HostError::failed_to_retrieve("missing counter"))?; + .ok_or(HostError::failed_to_retrieve("channel counter"))?; self.channel_counter .set(NextChannelSequencePath, current_sequence + 1) - .map_err(|e| HostError::failed_to_store(format!("failed to update counter: {e:?}")))?; + .map_err(|e| HostError::failed_to_store(format!("channel counter: {e:?}")))?; Ok(()) } diff --git a/tests-integration/tests/core/ics02_client/create_client.rs b/tests-integration/tests/core/ics02_client/create_client.rs index baa9188c0..852cdd273 100644 --- a/tests-integration/tests/core/ics02_client/create_client.rs +++ b/tests-integration/tests/core/ics02_client/create_client.rs @@ -180,7 +180,7 @@ fn test_create_expired_mock_client() { let fxt = create_client_fixture(Ctx::Default, Msg::ExpiredMockHeader); create_client_validate( &fxt, - Expect::Failure(Some(HandlerError::Client(ClientError::UnexpectedStatus( + Expect::Failure(Some(HandlerError::Client(ClientError::InvalidStatus( Status::Expired, )))), ); @@ -206,7 +206,7 @@ fn test_create_expired_tm_client() { let fxt = create_client_fixture(Ctx::Default, Msg::ExpiredTendermintHeader); create_client_validate( &fxt, - Expect::Failure(Some(HandlerError::Client(ClientError::UnexpectedStatus( + Expect::Failure(Some(HandlerError::Client(ClientError::InvalidStatus( Status::Expired, )))), ); @@ -218,7 +218,7 @@ fn test_create_frozen_tm_client() { let fxt = create_client_fixture(Ctx::Default, Msg::FrozenTendermintHeader); create_client_validate( &fxt, - Expect::Failure(Some(HandlerError::Client(ClientError::UnexpectedStatus( + Expect::Failure(Some(HandlerError::Client(ClientError::InvalidStatus( Status::Frozen, )))), ); From df738780c44c3fadf28cba42da30f08f58cab7b1 Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Fri, 20 Sep 2024 12:21:59 -0700 Subject: [PATCH 10/18] nitpicks --- .../unreleased/breaking-changes/1320-define-host-error-type.md | 2 +- ibc-primitives/src/types/timestamp.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changelog/unreleased/breaking-changes/1320-define-host-error-type.md b/.changelog/unreleased/breaking-changes/1320-define-host-error-type.md index ff8e02c75..35ebe5841 100644 --- a/.changelog/unreleased/breaking-changes/1320-define-host-error-type.md +++ b/.changelog/unreleased/breaking-changes/1320-define-host-error-type.md @@ -1,2 +1,2 @@ -- Defined a new `HostError` type in ics24 to draw distinction between protocol errors and host errors +- [ibc-core] Defined a new `HostError` type in ics24 to draw distinction between protocol errors and host errors ([\1320](https://github.com/cosmos/ibc-rs/issues/1320)) diff --git a/ibc-primitives/src/types/timestamp.rs b/ibc-primitives/src/types/timestamp.rs index 032662d9c..fe2b043dd 100644 --- a/ibc-primitives/src/types/timestamp.rs +++ b/ibc-primitives/src/types/timestamp.rs @@ -286,7 +286,7 @@ impl std::error::Error for TimestampError { match &self { Self::ParseInt(e) => Some(e), Self::TryFromInt(e) => Some(e), - // Self::Conversion(e) => Some(e), + Self::Conversion(e) => Some(e), _ => None, } } From 2c9467178d393f362aa119258806ef251b6d28c1 Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Fri, 20 Sep 2024 12:27:24 -0700 Subject: [PATCH 11/18] fix: remove ibc-core-connection-types dep under ICS-04 --- ci/cw-check/Cargo.lock | 1 - ci/no-std-check/Cargo.lock | 1 - ibc-core/ics04-channel/Cargo.toml | 1 - ibc-core/ics04-channel/src/handler/chan_close_confirm.rs | 2 +- ibc-core/ics04-channel/src/handler/chan_open_ack.rs | 2 +- ibc-core/ics04-channel/src/handler/chan_open_confirm.rs | 2 +- ibc-core/ics04-channel/src/handler/chan_open_try.rs | 2 +- 7 files changed, 4 insertions(+), 7 deletions(-) diff --git a/ci/cw-check/Cargo.lock b/ci/cw-check/Cargo.lock index a67985134..128dbb7e6 100644 --- a/ci/cw-check/Cargo.lock +++ b/ci/cw-check/Cargo.lock @@ -852,7 +852,6 @@ dependencies = [ "ibc-core-client", "ibc-core-commitment-types", "ibc-core-connection", - "ibc-core-connection-types", "ibc-core-handler-types", "ibc-core-host", "ibc-core-router", diff --git a/ci/no-std-check/Cargo.lock b/ci/no-std-check/Cargo.lock index be243bc1b..bbc64e565 100644 --- a/ci/no-std-check/Cargo.lock +++ b/ci/no-std-check/Cargo.lock @@ -1285,7 +1285,6 @@ dependencies = [ "ibc-core-client", "ibc-core-commitment-types", "ibc-core-connection", - "ibc-core-connection-types", "ibc-core-handler-types", "ibc-core-host", "ibc-core-router", diff --git a/ibc-core/ics04-channel/Cargo.toml b/ibc-core/ics04-channel/Cargo.toml index f9dd35235..1ad973cc1 100644 --- a/ibc-core/ics04-channel/Cargo.toml +++ b/ibc-core/ics04-channel/Cargo.toml @@ -20,7 +20,6 @@ all-features = true [dependencies] ibc-core-client = { workspace = true } ibc-core-connection = { workspace = true } -ibc-core-connection-types = { workspace = true } ibc-core-channel-types = { workspace = true } ibc-core-commitment-types = { workspace = true } ibc-core-host = { workspace = true } diff --git a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs index 56db78a68..798f628e1 100644 --- a/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs @@ -5,8 +5,8 @@ use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::events::CloseConfirm; use ibc_core_channel_types::msgs::MsgChannelCloseConfirm; use ibc_core_client::context::prelude::*; +use ibc_core_connection::types::error::ConnectionError; use ibc_core_connection::types::State as ConnectionState; -use ibc_core_connection_types::error::ConnectionError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; use ibc_core_host::{ExecutionContext, ValidationContext}; diff --git a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs index 5e07b8298..c6d81a9fe 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_ack.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_ack.rs @@ -4,8 +4,8 @@ use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::events::OpenAck; use ibc_core_channel_types::msgs::MsgChannelOpenAck; use ibc_core_client::context::prelude::*; +use ibc_core_connection::types::error::ConnectionError; use ibc_core_connection::types::State as ConnectionState; -use ibc_core_connection_types::error::ConnectionError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; use ibc_core_host::{ExecutionContext, ValidationContext}; diff --git a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs index df3fa51db..2f1fc56d3 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs @@ -5,8 +5,8 @@ use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::events::OpenConfirm; use ibc_core_channel_types::msgs::MsgChannelOpenConfirm; use ibc_core_client::context::prelude::*; +use ibc_core_connection::types::error::ConnectionError; use ibc_core_connection::types::State as ConnectionState; -use ibc_core_connection_types::error::ConnectionError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; use ibc_core_host::{ExecutionContext, ValidationContext}; diff --git a/ibc-core/ics04-channel/src/handler/chan_open_try.rs b/ibc-core/ics04-channel/src/handler/chan_open_try.rs index d01e646c6..c8e735700 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_try.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_try.rs @@ -5,8 +5,8 @@ use ibc_core_channel_types::error::ChannelError; use ibc_core_channel_types::events::OpenTry; use ibc_core_channel_types::msgs::MsgChannelOpenTry; use ibc_core_client::context::prelude::*; +use ibc_core_connection::types::error::ConnectionError; use ibc_core_connection::types::State as ConnectionState; -use ibc_core_connection_types::error::ConnectionError; use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; use ibc_core_host::types::identifiers::ChannelId; use ibc_core_host::types::path::{ From 3ca721d34084e330e8287ba8d44d189c2330dc73 Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Mon, 23 Sep 2024 12:28:03 -0700 Subject: [PATCH 12/18] fix: propogate errors in refund_packet_nft_execute --- ibc-apps/ics20-transfer/src/handler/mod.rs | 8 +++++--- ibc-apps/ics721-nft-transfer/src/handler/mod.rs | 6 ++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ibc-apps/ics20-transfer/src/handler/mod.rs b/ibc-apps/ics20-transfer/src/handler/mod.rs index 95ed5441c..5c232cb4b 100644 --- a/ibc-apps/ics20-transfer/src/handler/mod.rs +++ b/ibc-apps/ics20-transfer/src/handler/mod.rs @@ -57,13 +57,15 @@ pub fn refund_packet_token_validate( packet.chan_id_on_a.clone(), &data.token.denom, ) { - Ok(ctx_a.unescrow_coins_validate( + ctx_a.unescrow_coins_validate( &sender, &packet.port_id_on_a, &packet.chan_id_on_a, &data.token, - )?) + )?; } else { - Ok(ctx_a.mint_coins_validate(&sender, &data.token)?) + ctx_a.mint_coins_validate(&sender, &data.token)?; } + + Ok(()) } diff --git a/ibc-apps/ics721-nft-transfer/src/handler/mod.rs b/ibc-apps/ics721-nft-transfer/src/handler/mod.rs index 9acca019f..661533958 100644 --- a/ibc-apps/ics721-nft-transfer/src/handler/mod.rs +++ b/ibc-apps/ics721-nft-transfer/src/handler/mod.rs @@ -46,8 +46,7 @@ pub fn refund_packet_nft_execute( let token_uri = data.token_uris.as_ref().and_then(|uris| uris.get(i)); let token_data = data.token_data.as_ref().and_then(|data| data.get(i)); - let _ = - ctx_a.mint_nft_execute(&sender, &data.class_id, token_id, token_uri, token_data); + ctx_a.mint_nft_execute(&sender, &data.class_id, token_id, token_uri, token_data)?; } Ok(()) @@ -86,8 +85,7 @@ pub fn refund_packet_nft_validate( let token_uri = data.token_uris.as_ref().and_then(|uris| uris.get(i)); let token_data = data.token_data.as_ref().and_then(|data| data.get(i)); - let _ = - ctx_a.mint_nft_validate(&sender, &data.class_id, token_id, token_uri, token_data); + ctx_a.mint_nft_validate(&sender, &data.class_id, token_id, token_uri, token_data)?; } Ok(()) From 1ba66b9bd75cd03e9f92e7ccfe481aa69d13d526 Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Mon, 23 Sep 2024 12:34:44 -0700 Subject: [PATCH 13/18] fix: revert few errors in ICS-20 module callbacks --- ibc-apps/ics20-transfer/src/module.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/ibc-apps/ics20-transfer/src/module.rs b/ibc-apps/ics20-transfer/src/module.rs index 6092a638f..41d3016a4 100644 --- a/ibc-apps/ics20-transfer/src/module.rs +++ b/ibc-apps/ics20-transfer/src/module.rs @@ -6,7 +6,6 @@ use ibc_core::channel::types::acknowledgement::{Acknowledgement, Acknowledgement use ibc_core::channel::types::channel::{Counterparty, Order}; use ibc_core::channel::types::packet::Packet; use ibc_core::channel::types::Version; -use ibc_core::host::types::error::DecodingError; use ibc_core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc_core::primitives::prelude::*; use ibc_core::primitives::Signer; @@ -263,11 +262,8 @@ pub fn on_timeout_packet_validate( where Ctx: TokenTransferValidationContext, { - let data = serde_json::from_slice::(&packet.data).map_err(|e| { - DecodingError::InvalidJson { - description: format!("failed to deserialize packet data: {e}"), - } - })?; + let data = serde_json::from_slice::(&packet.data) + .map_err(|_| TokenTransferError::FailedToDeserializePacketData)?; refund_packet_token_validate(ctx, packet, &data)?; @@ -282,10 +278,7 @@ pub fn on_timeout_packet_execute( let Ok(data) = serde_json::from_slice::(&packet.data) else { return ( ModuleExtras::empty(), - Err(DecodingError::InvalidJson { - description: "failed to deserialize packet data".to_string(), - } - .into()), + Err(TokenTransferError::FailedToDeserializePacketData), ); }; From 91ac57be7636753280ce76df18f1ad2280bbf94d Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Mon, 23 Sep 2024 13:37:51 -0700 Subject: [PATCH 14/18] imp: use if let for type_url matches --- .../ics20-transfer/types/src/msgs/transfer.rs | 9 +++++---- .../types/src/msgs/transfer.rs | 9 +++++---- .../ics07-tendermint/types/src/client_state.rs | 14 +++++--------- .../ics07-tendermint/types/src/consensus_state.rs | 14 +++++--------- ibc-clients/ics07-tendermint/types/src/header.rs | 13 +++++-------- .../ics07-tendermint/types/src/misbehaviour.rs | 13 +++++-------- ibc-clients/ics08-wasm/types/src/client_state.rs | 14 +++++--------- .../ics08-wasm/types/src/consensus_state.rs | 15 ++++++--------- .../cosmos/src/upgrade_proposal/plan.rs | 9 +++++---- .../src/testapp/ibc/clients/mock/client_state.rs | 13 +++++-------- .../testapp/ibc/clients/mock/consensus_state.rs | 13 +++++-------- .../src/testapp/ibc/clients/mock/header.rs | 9 +++++---- .../src/testapp/ibc/clients/mock/misbehaviour.rs | 13 +++++-------- 13 files changed, 66 insertions(+), 92 deletions(-) diff --git a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs index f8a72b7ff..a337b2b51 100644 --- a/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs @@ -98,12 +98,13 @@ impl TryFrom for MsgTransfer { type Error = DecodingError; fn try_from(raw: Any) -> Result { - match raw.type_url.as_str() { - TYPE_URL => Ok(MsgTransfer::decode_vec(&raw.value)?), - _ => Err(DecodingError::MismatchedResourceName { + if let TYPE_URL = raw.type_url.as_str() { + MsgTransfer::decode_vec(&raw.value).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: TYPE_URL.to_string(), actual: raw.type_url, - })?, + }) } } } diff --git a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs index 92e83527c..97fa5b415 100644 --- a/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs +++ b/ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs @@ -117,12 +117,13 @@ impl TryFrom for MsgTransfer { type Error = DecodingError; fn try_from(raw: Any) -> Result { - match raw.type_url.as_str() { - TYPE_URL => Ok(MsgTransfer::decode_vec(&raw.value)?), - _ => Err(DecodingError::MismatchedResourceName { + if let TYPE_URL = raw.type_url.as_str() { + MsgTransfer::decode_vec(&raw.value).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: TYPE_URL.to_string(), actual: raw.type_url, - })?, + }) } } } diff --git a/ibc-clients/ics07-tendermint/types/src/client_state.rs b/ibc-clients/ics07-tendermint/types/src/client_state.rs index ad92b99f0..2ad610d9d 100644 --- a/ibc-clients/ics07-tendermint/types/src/client_state.rs +++ b/ibc-clients/ics07-tendermint/types/src/client_state.rs @@ -347,17 +347,13 @@ impl TryFrom for ClientState { type Error = DecodingError; fn try_from(raw: Any) -> Result { - fn decode_client_state(value: &[u8]) -> Result { - let client_state = Protobuf::::decode(value)?; - Ok(client_state) - } - - match raw.type_url.as_str() { - TENDERMINT_CLIENT_STATE_TYPE_URL => decode_client_state(&raw.value), - _ => Err(DecodingError::MismatchedResourceName { + if let TENDERMINT_CLIENT_STATE_TYPE_URL = raw.type_url.as_str() { + Protobuf::::decode(raw.value.as_ref()).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: TENDERMINT_CLIENT_STATE_TYPE_URL.to_string(), actual: raw.type_url, - })?, + }) } } } diff --git a/ibc-clients/ics07-tendermint/types/src/consensus_state.rs b/ibc-clients/ics07-tendermint/types/src/consensus_state.rs index 3bd630a8a..d38fda228 100644 --- a/ibc-clients/ics07-tendermint/types/src/consensus_state.rs +++ b/ibc-clients/ics07-tendermint/types/src/consensus_state.rs @@ -102,17 +102,13 @@ impl TryFrom for ConsensusState { type Error = DecodingError; fn try_from(raw: Any) -> Result { - fn decode_consensus_state(value: &[u8]) -> Result { - let client_state = Protobuf::::decode(value)?; - Ok(client_state) - } - - match raw.type_url.as_str() { - TENDERMINT_CONSENSUS_STATE_TYPE_URL => decode_consensus_state(&raw.value), - _ => Err(DecodingError::MismatchedResourceName { + if let TENDERMINT_CONSENSUS_STATE_TYPE_URL = raw.type_url.as_str() { + Protobuf::::decode(raw.value.as_ref()).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: TENDERMINT_CONSENSUS_STATE_TYPE_URL.to_string(), actual: raw.type_url, - })?, + })? } } } diff --git a/ibc-clients/ics07-tendermint/types/src/header.rs b/ibc-clients/ics07-tendermint/types/src/header.rs index a7abc0dff..376e16c78 100644 --- a/ibc-clients/ics07-tendermint/types/src/header.rs +++ b/ibc-clients/ics07-tendermint/types/src/header.rs @@ -203,16 +203,13 @@ impl TryFrom for Header { type Error = DecodingError; fn try_from(raw: Any) -> Result { - fn decode_header(value: &[u8]) -> Result { - let header = Protobuf::::decode(value)?; - Ok(header) - } - match raw.type_url.as_str() { - TENDERMINT_HEADER_TYPE_URL => decode_header(&raw.value), - _ => Err(DecodingError::MismatchedResourceName { + if let TENDERMINT_HEADER_TYPE_URL = raw.type_url.as_str() { + Protobuf::::decode(raw.value.as_ref()).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: TENDERMINT_HEADER_TYPE_URL.to_string(), actual: raw.type_url, - })?, + }) } } } diff --git a/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs b/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs index ebb900326..e4a87c5ae 100644 --- a/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs +++ b/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs @@ -111,16 +111,13 @@ impl TryFrom for Misbehaviour { type Error = DecodingError; fn try_from(raw: Any) -> Result { - fn decode_misbehaviour(value: &[u8]) -> Result { - let misbehaviour = Protobuf::::decode(value)?; - Ok(misbehaviour) - } - match raw.type_url.as_str() { - TENDERMINT_MISBEHAVIOUR_TYPE_URL => decode_misbehaviour(&raw.value), - _ => Err(DecodingError::MismatchedResourceName { + if let TENDERMINT_MISBEHAVIOUR_TYPE_URL = raw.type_url.as_str() { + Protobuf::::decode(raw.value.as_ref()).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: TENDERMINT_MISBEHAVIOUR_TYPE_URL.to_string(), actual: raw.type_url, - })?, + }) } } } diff --git a/ibc-clients/ics08-wasm/types/src/client_state.rs b/ibc-clients/ics08-wasm/types/src/client_state.rs index c2e2ebea5..64a778633 100644 --- a/ibc-clients/ics08-wasm/types/src/client_state.rs +++ b/ibc-clients/ics08-wasm/types/src/client_state.rs @@ -70,17 +70,13 @@ impl TryFrom for ClientState { type Error = DecodingError; fn try_from(any: Any) -> Result { - fn decode_client_state(value: &[u8]) -> Result { - let client_state = Protobuf::::decode(value)?; - Ok(client_state) - } - - match any.type_url.as_str() { - WASM_CLIENT_STATE_TYPE_URL => decode_client_state(&any.value), - _ => Err(DecodingError::MismatchedResourceName { + if let WASM_CLIENT_STATE_TYPE_URL = any.type_url.as_str() { + Protobuf::::decode(any.value.as_ref()).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: WASM_CLIENT_STATE_TYPE_URL.to_string(), actual: any.type_url, - })?, + }) } } } diff --git a/ibc-clients/ics08-wasm/types/src/consensus_state.rs b/ibc-clients/ics08-wasm/types/src/consensus_state.rs index a6f129469..e77f469c7 100644 --- a/ibc-clients/ics08-wasm/types/src/consensus_state.rs +++ b/ibc-clients/ics08-wasm/types/src/consensus_state.rs @@ -57,16 +57,13 @@ impl TryFrom for ConsensusState { type Error = DecodingError; fn try_from(any: Any) -> Result { - fn decode_consensus_state(value: &[u8]) -> Result { - let consensus_state = Protobuf::::decode(value)?; - Ok(consensus_state) - } - match any.type_url.as_str() { - WASM_CONSENSUS_STATE_TYPE_URL => decode_consensus_state(&any.value), - _ => Err(DecodingError::MismatchedResourceName { + if let WASM_CONSENSUS_STATE_TYPE_URL = any.type_url.as_str() { + Protobuf::::decode(any.value.as_ref()).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: WASM_CONSENSUS_STATE_TYPE_URL.to_string(), - actual: any.type_url.to_string(), - })?, + actual: any.type_url, + }) } } } diff --git a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs index c973cfe2b..6541ad049 100644 --- a/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs +++ b/ibc-core/ics24-host/cosmos/src/upgrade_proposal/plan.rs @@ -76,12 +76,13 @@ impl TryFrom for Plan { type Error = DecodingError; fn try_from(any: Any) -> Result { - match any.type_url.as_str() { - TYPE_URL => Ok(Protobuf::::decode_vec(&any.value)?), - _ => Err(DecodingError::MismatchedResourceName { + if let TYPE_URL = any.type_url.as_str() { + Protobuf::::decode_vec(&any.value).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: TYPE_URL.to_string(), actual: any.type_url, - })?, + }) } } } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs index 500be2769..a789743e1 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs @@ -125,16 +125,13 @@ impl TryFrom for MockClientState { type Error = DecodingError; fn try_from(raw: Any) -> Result { - fn decode_client_state(value: &[u8]) -> Result { - let client_state = Protobuf::::decode(value)?; - Ok(client_state) - } - match raw.type_url.as_str() { - MOCK_CLIENT_STATE_TYPE_URL => decode_client_state(&raw.value), - _ => Err(DecodingError::MismatchedResourceName { + if let MOCK_CLIENT_STATE_TYPE_URL = raw.type_url.as_str() { + Protobuf::::decode(raw.value.as_ref()).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: MOCK_CLIENT_STATE_TYPE_URL.to_string(), actual: raw.type_url, - })?, + }) } } } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs index 658a01c76..8149a5d62 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs @@ -66,16 +66,13 @@ impl TryFrom for MockConsensusState { type Error = DecodingError; fn try_from(raw: Any) -> Result { - fn decode_consensus_state(value: &[u8]) -> Result { - let mock_consensus_state = Protobuf::::decode(value)?; - Ok(mock_consensus_state) - } - match raw.type_url.as_str() { - MOCK_CONSENSUS_STATE_TYPE_URL => decode_consensus_state(&raw.value), - _ => Err(DecodingError::MismatchedResourceName { + if let MOCK_CONSENSUS_STATE_TYPE_URL = raw.type_url.as_str() { + Protobuf::::decode(raw.value.as_ref()).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: MOCK_CONSENSUS_STATE_TYPE_URL.to_string(), actual: raw.type_url, - })?, + }) } } } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/header.rs b/ibc-testkit/src/testapp/ibc/clients/mock/header.rs index 230dcedd5..42830d58b 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/header.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/header.rs @@ -92,12 +92,13 @@ impl TryFrom for MockHeader { type Error = DecodingError; fn try_from(raw: Any) -> Result { - match raw.type_url.as_str() { - MOCK_HEADER_TYPE_URL => Ok(Protobuf::::decode_vec(&raw.value)?), - _ => Err(DecodingError::MismatchedResourceName { + if let MOCK_HEADER_TYPE_URL = raw.type_url.as_str() { + Protobuf::::decode_vec(&raw.value).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: MOCK_HEADER_TYPE_URL.to_string(), actual: raw.type_url, - })?, + }) } } } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs b/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs index 2c23dd287..a3fde7a6d 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs @@ -52,16 +52,13 @@ impl TryFrom for Misbehaviour { type Error = DecodingError; fn try_from(raw: Any) -> Result { - fn decode_misbehaviour(value: &[u8]) -> Result { - let raw_misbehaviour = Protobuf::::decode(value)?; - Ok(raw_misbehaviour) - } - match raw.type_url.as_str() { - MOCK_MISBEHAVIOUR_TYPE_URL => decode_misbehaviour(&raw.value), - _ => Err(DecodingError::MismatchedResourceName { + if let MOCK_MISBEHAVIOUR_TYPE_URL = raw.type_url.as_str() { + Protobuf::::decode(raw.value.as_ref()).map_err(Into::into) + } else { + Err(DecodingError::MismatchedResourceName { expected: MOCK_MISBEHAVIOUR_TYPE_URL.to_string(), actual: raw.type_url, - })?, + }) } } } From 0642d4a6c9a5a4302971aced4fe581347e59893e Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Mon, 23 Sep 2024 14:14:08 -0700 Subject: [PATCH 15/18] nit: minor improvements --- ibc-apps/ics20-transfer/src/handler/mod.rs | 8 +- ibc-core/ics25-handler/src/entrypoint.rs | 124 ++++++++++----------- 2 files changed, 62 insertions(+), 70 deletions(-) diff --git a/ibc-apps/ics20-transfer/src/handler/mod.rs b/ibc-apps/ics20-transfer/src/handler/mod.rs index 5c232cb4b..f1cd65967 100644 --- a/ibc-apps/ics20-transfer/src/handler/mod.rs +++ b/ibc-apps/ics20-transfer/src/handler/mod.rs @@ -28,17 +28,19 @@ pub fn refund_packet_token_execute( packet.chan_id_on_a.clone(), &data.token.denom, ) { - Ok(ctx_a.unescrow_coins_execute( + ctx_a.unescrow_coins_execute( &sender, &packet.port_id_on_a, &packet.chan_id_on_a, &data.token, - )?) + )?; } // mint vouchers back to sender else { - Ok(ctx_a.mint_coins_execute(&sender, &data.token)?) + ctx_a.mint_coins_execute(&sender, &data.token)?; } + + Ok(()) } pub fn refund_packet_token_validate( diff --git a/ibc-core/ics25-handler/src/entrypoint.rs b/ibc-core/ics25-handler/src/entrypoint.rs index 7a276398c..3d8fafa2c 100644 --- a/ibc-core/ics25-handler/src/entrypoint.rs +++ b/ibc-core/ics25-handler/src/entrypoint.rs @@ -59,27 +59,24 @@ where { match msg { MsgEnvelope::Client(msg) => match msg { - ClientMsg::CreateClient(msg) => Ok(create_client::validate(ctx, msg)?), - ClientMsg::UpdateClient(msg) => Ok(update_client::validate( - ctx, - MsgUpdateOrMisbehaviour::UpdateClient(msg), - )?), - ClientMsg::Misbehaviour(msg) => Ok(update_client::validate( - ctx, - MsgUpdateOrMisbehaviour::Misbehaviour(msg), - )?), - ClientMsg::UpgradeClient(msg) => Ok(upgrade_client::validate(ctx, msg)?), + ClientMsg::CreateClient(msg) => create_client::validate(ctx, msg)?, + ClientMsg::UpdateClient(msg) => { + update_client::validate(ctx, MsgUpdateOrMisbehaviour::UpdateClient(msg))? + } + ClientMsg::Misbehaviour(msg) => { + update_client::validate(ctx, MsgUpdateOrMisbehaviour::Misbehaviour(msg))? + } + ClientMsg::UpgradeClient(msg) => upgrade_client::validate(ctx, msg)?, ClientMsg::RecoverClient(_msg) => { // Recover client messages are not dispatched by ibc-rs as they can only be // authorized via a passing governance proposal - Ok(()) } }, MsgEnvelope::Connection(msg) => match msg { - ConnectionMsg::OpenInit(msg) => Ok(conn_open_init::validate(ctx, msg)?), - ConnectionMsg::OpenTry(msg) => Ok(conn_open_try::validate(ctx, msg)?), - ConnectionMsg::OpenAck(msg) => Ok(conn_open_ack::validate(ctx, msg)?), - ConnectionMsg::OpenConfirm(msg) => Ok(conn_open_confirm::validate(ctx, &msg)?), + ConnectionMsg::OpenInit(msg) => conn_open_init::validate(ctx, msg)?, + ConnectionMsg::OpenTry(msg) => conn_open_try::validate(ctx, msg)?, + ConnectionMsg::OpenAck(msg) => conn_open_ack::validate(ctx, msg)?, + ConnectionMsg::OpenConfirm(msg) => conn_open_confirm::validate(ctx, &msg)?, }, MsgEnvelope::Channel(msg) => { let port_id = channel_msg_to_port_id(&msg); @@ -91,12 +88,12 @@ where .ok_or(RouterError::MissingModule)?; match msg { - ChannelMsg::OpenInit(msg) => Ok(chan_open_init_validate(ctx, module, msg)?), - ChannelMsg::OpenTry(msg) => Ok(chan_open_try_validate(ctx, module, msg)?), - ChannelMsg::OpenAck(msg) => Ok(chan_open_ack_validate(ctx, module, msg)?), - ChannelMsg::OpenConfirm(msg) => Ok(chan_open_confirm_validate(ctx, module, msg)?), - ChannelMsg::CloseInit(msg) => Ok(chan_close_init_validate(ctx, module, msg)?), - ChannelMsg::CloseConfirm(msg) => Ok(chan_close_confirm_validate(ctx, module, msg)?), + ChannelMsg::OpenInit(msg) => chan_open_init_validate(ctx, module, msg)?, + ChannelMsg::OpenTry(msg) => chan_open_try_validate(ctx, module, msg)?, + ChannelMsg::OpenAck(msg) => chan_open_ack_validate(ctx, module, msg)?, + ChannelMsg::OpenConfirm(msg) => chan_open_confirm_validate(ctx, module, msg)?, + ChannelMsg::CloseInit(msg) => chan_close_init_validate(ctx, module, msg)?, + ChannelMsg::CloseConfirm(msg) => chan_close_confirm_validate(ctx, module, msg)?, } } MsgEnvelope::Packet(msg) => { @@ -109,21 +106,19 @@ where .ok_or(RouterError::MissingModule)?; match msg { - PacketMsg::Recv(msg) => Ok(recv_packet_validate(ctx, msg)?), - PacketMsg::Ack(msg) => Ok(acknowledgement_packet_validate(ctx, module, msg)?), - PacketMsg::Timeout(msg) => Ok(timeout_packet_validate( - ctx, - module, - TimeoutMsgType::Timeout(msg), - )?), - PacketMsg::TimeoutOnClose(msg) => Ok(timeout_packet_validate( - ctx, - module, - TimeoutMsgType::TimeoutOnClose(msg), - )?), + PacketMsg::Recv(msg) => recv_packet_validate(ctx, msg)?, + PacketMsg::Ack(msg) => acknowledgement_packet_validate(ctx, module, msg)?, + PacketMsg::Timeout(msg) => { + timeout_packet_validate(ctx, module, TimeoutMsgType::Timeout(msg))? + } + PacketMsg::TimeoutOnClose(msg) => { + timeout_packet_validate(ctx, module, TimeoutMsgType::TimeoutOnClose(msg))? + } } } - } + }; + + Ok(()) } /// Entrypoint which only performs message execution @@ -138,27 +133,24 @@ where { match msg { MsgEnvelope::Client(msg) => match msg { - ClientMsg::CreateClient(msg) => Ok(create_client::execute(ctx, msg)?), - ClientMsg::UpdateClient(msg) => Ok(update_client::execute( - ctx, - MsgUpdateOrMisbehaviour::UpdateClient(msg), - )?), - ClientMsg::Misbehaviour(msg) => Ok(update_client::execute( - ctx, - MsgUpdateOrMisbehaviour::Misbehaviour(msg), - )?), - ClientMsg::UpgradeClient(msg) => Ok(upgrade_client::execute(ctx, msg)?), + ClientMsg::CreateClient(msg) => create_client::execute(ctx, msg)?, + ClientMsg::UpdateClient(msg) => { + update_client::execute(ctx, MsgUpdateOrMisbehaviour::UpdateClient(msg))? + } + ClientMsg::Misbehaviour(msg) => { + update_client::execute(ctx, MsgUpdateOrMisbehaviour::Misbehaviour(msg))? + } + ClientMsg::UpgradeClient(msg) => upgrade_client::execute(ctx, msg)?, ClientMsg::RecoverClient(_msg) => { // Recover client messages are not dispatched by ibc-rs as they can only be // authorized via a passing governance proposal - Ok(()) } }, MsgEnvelope::Connection(msg) => match msg { - ConnectionMsg::OpenInit(msg) => Ok(conn_open_init::execute(ctx, msg)?), - ConnectionMsg::OpenTry(msg) => Ok(conn_open_try::execute(ctx, msg)?), - ConnectionMsg::OpenAck(msg) => Ok(conn_open_ack::execute(ctx, msg)?), - ConnectionMsg::OpenConfirm(msg) => Ok(conn_open_confirm::execute(ctx, &msg)?), + ConnectionMsg::OpenInit(msg) => conn_open_init::execute(ctx, msg)?, + ConnectionMsg::OpenTry(msg) => conn_open_try::execute(ctx, msg)?, + ConnectionMsg::OpenAck(msg) => conn_open_ack::execute(ctx, msg)?, + ConnectionMsg::OpenConfirm(msg) => conn_open_confirm::execute(ctx, &msg)?, }, MsgEnvelope::Channel(msg) => { let port_id = channel_msg_to_port_id(&msg); @@ -170,12 +162,12 @@ where .ok_or(RouterError::MissingModule)?; match msg { - ChannelMsg::OpenInit(msg) => Ok(chan_open_init_execute(ctx, module, msg)?), - ChannelMsg::OpenTry(msg) => Ok(chan_open_try_execute(ctx, module, msg)?), - ChannelMsg::OpenAck(msg) => Ok(chan_open_ack_execute(ctx, module, msg)?), - ChannelMsg::OpenConfirm(msg) => Ok(chan_open_confirm_execute(ctx, module, msg)?), - ChannelMsg::CloseInit(msg) => Ok(chan_close_init_execute(ctx, module, msg)?), - ChannelMsg::CloseConfirm(msg) => Ok(chan_close_confirm_execute(ctx, module, msg)?), + ChannelMsg::OpenInit(msg) => chan_open_init_execute(ctx, module, msg)?, + ChannelMsg::OpenTry(msg) => chan_open_try_execute(ctx, module, msg)?, + ChannelMsg::OpenAck(msg) => chan_open_ack_execute(ctx, module, msg)?, + ChannelMsg::OpenConfirm(msg) => chan_open_confirm_execute(ctx, module, msg)?, + ChannelMsg::CloseInit(msg) => chan_close_init_execute(ctx, module, msg)?, + ChannelMsg::CloseConfirm(msg) => chan_close_confirm_execute(ctx, module, msg)?, } } MsgEnvelope::Packet(msg) => { @@ -188,19 +180,17 @@ where .ok_or(RouterError::MissingModule)?; match msg { - PacketMsg::Recv(msg) => Ok(recv_packet_execute(ctx, module, msg)?), - PacketMsg::Ack(msg) => Ok(acknowledgement_packet_execute(ctx, module, msg)?), - PacketMsg::Timeout(msg) => Ok(timeout_packet_execute( - ctx, - module, - TimeoutMsgType::Timeout(msg), - )?), - PacketMsg::TimeoutOnClose(msg) => Ok(timeout_packet_execute( - ctx, - module, - TimeoutMsgType::TimeoutOnClose(msg), - )?), + PacketMsg::Recv(msg) => recv_packet_execute(ctx, module, msg)?, + PacketMsg::Ack(msg) => acknowledgement_packet_execute(ctx, module, msg)?, + PacketMsg::Timeout(msg) => { + timeout_packet_execute(ctx, module, TimeoutMsgType::Timeout(msg))? + } + PacketMsg::TimeoutOnClose(msg) => { + timeout_packet_execute(ctx, module, TimeoutMsgType::TimeoutOnClose(msg))? + } } } } + + Ok(()) } From 9045377c51a0ecb85920c221d41a42618298a802 Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Mon, 23 Sep 2024 14:23:13 -0700 Subject: [PATCH 16/18] fix: use RouterError in case of ModuleID not found --- ibc-core/ics25-handler/src/entrypoint.rs | 17 ++++++++--------- ibc-core/ics26-routing/types/src/error.rs | 3 +++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ibc-core/ics25-handler/src/entrypoint.rs b/ibc-core/ics25-handler/src/entrypoint.rs index 3d8fafa2c..f9a0cabc3 100644 --- a/ibc-core/ics25-handler/src/entrypoint.rs +++ b/ibc-core/ics25-handler/src/entrypoint.rs @@ -6,7 +6,6 @@ use ibc_core_channel::handler::{ chan_open_try_execute, chan_open_try_validate, recv_packet_execute, recv_packet_validate, timeout_packet_execute, timeout_packet_validate, TimeoutMsgType, }; -use ibc_core_channel::types::error::ChannelError; use ibc_core_channel::types::msgs::{ channel_msg_to_port_id, packet_msg_to_port_id, ChannelMsg, PacketMsg, }; @@ -80,8 +79,8 @@ where }, MsgEnvelope::Channel(msg) => { let port_id = channel_msg_to_port_id(&msg); - let module_id = router.lookup_module(port_id).ok_or(ChannelError::Host( - HostError::missing_state(format!("failed to look up port {}", port_id.clone())), + let module_id = router.lookup_module(port_id).ok_or(RouterError::Host( + HostError::missing_state(format!("missing module ID for port {}", port_id.clone())), ))?; let module = router .get_route(&module_id) @@ -98,8 +97,8 @@ where } MsgEnvelope::Packet(msg) => { let port_id = packet_msg_to_port_id(&msg); - let module_id = router.lookup_module(port_id).ok_or(ChannelError::Host( - HostError::missing_state(format!("failed to look up port {}", port_id.clone())), + let module_id = router.lookup_module(port_id).ok_or(RouterError::Host( + HostError::missing_state(format!("missing module ID for port {}", port_id.clone())), ))?; let module = router .get_route(&module_id) @@ -154,8 +153,8 @@ where }, MsgEnvelope::Channel(msg) => { let port_id = channel_msg_to_port_id(&msg); - let module_id = router.lookup_module(port_id).ok_or(ChannelError::Host( - HostError::missing_state(format!("failed to look up port {}", port_id.clone())), + let module_id = router.lookup_module(port_id).ok_or(RouterError::Host( + HostError::missing_state(format!("missing module ID for port {}", port_id.clone())), ))?; let module = router .get_route_mut(&module_id) @@ -172,8 +171,8 @@ where } MsgEnvelope::Packet(msg) => { let port_id = packet_msg_to_port_id(&msg); - let module_id = router.lookup_module(port_id).ok_or(ChannelError::Host( - HostError::missing_state(format!("failed to look up port {}", port_id.clone())), + let module_id = router.lookup_module(port_id).ok_or(RouterError::Host( + HostError::missing_state(format!("missing module ID for port {}", port_id.clone())), ))?; let module = router .get_route_mut(&module_id) diff --git a/ibc-core/ics26-routing/types/src/error.rs b/ibc-core/ics26-routing/types/src/error.rs index b49f70993..19ad7c2ad 100644 --- a/ibc-core/ics26-routing/types/src/error.rs +++ b/ibc-core/ics26-routing/types/src/error.rs @@ -1,9 +1,12 @@ use displaydoc::Display; +use ibc_core_host_types::error::HostError; use ibc_primitives::prelude::*; /// Error type for the router module. #[derive(Debug, Display, derive_more::From)] pub enum RouterError { + /// host error: {0} + Host(HostError), /// missing module MissingModule, } From e6022a4d810b5a95d8155bdfca53a62cea412b74 Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Tue, 24 Sep 2024 13:14:47 -0700 Subject: [PATCH 17/18] chore: add changelog --- .../breaking-changes/1311-migrate-cosmwasm-workspace | 3 --- .../breaking-changes/1311-migrate-cosmwasm-workspace.md | 3 +++ .../breaking-changes/1320-define-host-error-type.md | 4 +++- .../1339-merge-packet-error-into-channel-error.md | 2 +- .../1346-remove-generic-string-error-variants.md | 3 ++- .../270-standardize-error-variants-to-be-less-specific.md | 3 +++ ...0-return-DecodingError-when-decoding-Any-to-MsgEnvelope.md | 2 ++ ...=> 1338-remove-redundant-path-constructions-in-testkit.md} | 0 8 files changed, 14 insertions(+), 6 deletions(-) delete mode 100644 .changelog/unreleased/breaking-changes/1311-migrate-cosmwasm-workspace create mode 100644 .changelog/unreleased/breaking-changes/1311-migrate-cosmwasm-workspace.md create mode 100644 .changelog/unreleased/breaking-changes/270-standardize-error-variants-to-be-less-specific.md create mode 100644 .changelog/unreleased/breaking-changes/950-return-DecodingError-when-decoding-Any-to-MsgEnvelope.md rename .changelog/unreleased/improvements/{1336-remove-faulty-receipt-check-during-recv-packet-validate.md => 1338-remove-redundant-path-constructions-in-testkit.md} (100%) diff --git a/.changelog/unreleased/breaking-changes/1311-migrate-cosmwasm-workspace b/.changelog/unreleased/breaking-changes/1311-migrate-cosmwasm-workspace deleted file mode 100644 index b7c0c8eff..000000000 --- a/.changelog/unreleased/breaking-changes/1311-migrate-cosmwasm-workspace +++ /dev/null @@ -1,3 +0,0 @@ -- [cosmwasm] Migrated the `cosmwasm` workspace into its own separate repository - located at [https://github.com/informalsystems/cosmwasm-ibc]. - ([\#1311](https://github.com/cosmos/ibc-rs/issues/1311)) diff --git a/.changelog/unreleased/breaking-changes/1311-migrate-cosmwasm-workspace.md b/.changelog/unreleased/breaking-changes/1311-migrate-cosmwasm-workspace.md new file mode 100644 index 000000000..2f042580c --- /dev/null +++ b/.changelog/unreleased/breaking-changes/1311-migrate-cosmwasm-workspace.md @@ -0,0 +1,3 @@ +- [cosmwasm] Migrate the `cosmwasm` workspace into its own separate repository + located at [cosmwasm-ibc](https://github.com/informalsystems/cosmwasm-ibc). + ([\#1311](https://github.com/cosmos/ibc-rs/issues/1311)) diff --git a/.changelog/unreleased/breaking-changes/1320-define-host-error-type.md b/.changelog/unreleased/breaking-changes/1320-define-host-error-type.md index 35ebe5841..895cd82bc 100644 --- a/.changelog/unreleased/breaking-changes/1320-define-host-error-type.md +++ b/.changelog/unreleased/breaking-changes/1320-define-host-error-type.md @@ -1,2 +1,4 @@ -- [ibc-core] Defined a new `HostError` type in ics24 to draw distinction between protocol errors and host errors +- [ibc-core] Define a new `HostError` type in ICS-24 to draw distinction between + protocol errors and host errors. Additionally, rename `ContextError` to + `HandlerError` to better reflect its use case. ([\1320](https://github.com/cosmos/ibc-rs/issues/1320)) diff --git a/.changelog/unreleased/breaking-changes/1339-merge-packet-error-into-channel-error.md b/.changelog/unreleased/breaking-changes/1339-merge-packet-error-into-channel-error.md index ad33f298c..01647c658 100644 --- a/.changelog/unreleased/breaking-changes/1339-merge-packet-error-into-channel-error.md +++ b/.changelog/unreleased/breaking-changes/1339-merge-packet-error-into-channel-error.md @@ -1,2 +1,2 @@ - [ibc-core-channel] Merge `PacketError` type into `ChannelError` - ([#1339](https://github.com/cosmos/ibc-rs/pull/1343)) + ([#1339](https://github.com/cosmos/ibc-rs/issues/1339)) diff --git a/.changelog/unreleased/breaking-changes/1346-remove-generic-string-error-variants.md b/.changelog/unreleased/breaking-changes/1346-remove-generic-string-error-variants.md index 453d87f01..23df16a16 100644 --- a/.changelog/unreleased/breaking-changes/1346-remove-generic-string-error-variants.md +++ b/.changelog/unreleased/breaking-changes/1346-remove-generic-string-error-variants.md @@ -1,2 +1,3 @@ -- [ibc-core] Remove `ClientError::Other` variant +- [ibc] Clean up multi-purpose variants like the `Other` variant and reduce + unnecessary `String` allocations in `*Error` enums. ([\#1346](https://github.com/cosmos/ibc-rs/issues/1346)) diff --git a/.changelog/unreleased/breaking-changes/270-standardize-error-variants-to-be-less-specific.md b/.changelog/unreleased/breaking-changes/270-standardize-error-variants-to-be-less-specific.md new file mode 100644 index 000000000..7df9ffd07 --- /dev/null +++ b/.changelog/unreleased/breaking-changes/270-standardize-error-variants-to-be-less-specific.md @@ -0,0 +1,3 @@ +- [ibc] Standardize error variants across the codebase to make them less + specific and more consistent. + ([\#270](https://github.com/cosmos/ibc-rs/issues/270)) diff --git a/.changelog/unreleased/breaking-changes/950-return-DecodingError-when-decoding-Any-to-MsgEnvelope.md b/.changelog/unreleased/breaking-changes/950-return-DecodingError-when-decoding-Any-to-MsgEnvelope.md new file mode 100644 index 000000000..bc94b49d5 --- /dev/null +++ b/.changelog/unreleased/breaking-changes/950-return-DecodingError-when-decoding-Any-to-MsgEnvelope.md @@ -0,0 +1,2 @@ +- [ibc-core-handler] Return `DecodingError` for `MsgEnvelope` when trying to + decode from `Any` ([\#950](https://github.com/cosmos/ibc-rs/issues/950)) diff --git a/.changelog/unreleased/improvements/1336-remove-faulty-receipt-check-during-recv-packet-validate.md b/.changelog/unreleased/improvements/1338-remove-redundant-path-constructions-in-testkit.md similarity index 100% rename from .changelog/unreleased/improvements/1336-remove-faulty-receipt-check-during-recv-packet-validate.md rename to .changelog/unreleased/improvements/1338-remove-redundant-path-constructions-in-testkit.md From adb5514c8efb4845197e22f43e43c9deb8e07f55 Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Tue, 24 Sep 2024 13:37:30 -0700 Subject: [PATCH 18/18] chore: add changelog for #1319 --- .../1319-consolidate-decoding-related-errors.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/breaking-changes/1319-consolidate-decoding-related-errors.md diff --git a/.changelog/unreleased/breaking-changes/1319-consolidate-decoding-related-errors.md b/.changelog/unreleased/breaking-changes/1319-consolidate-decoding-related-errors.md new file mode 100644 index 000000000..3a466c375 --- /dev/null +++ b/.changelog/unreleased/breaking-changes/1319-consolidate-decoding-related-errors.md @@ -0,0 +1,2 @@ +- [ibc] Consolidate decoding-related errors into new `DecodingError` type + ([\1319](https://github.com/cosmos/ibc-rs/issues/1319))