Skip to content

Commit 57b9468

Browse files
committed
Merge remote-tracking branch 'origin/main' into plafer/376-docstrings
2 parents 0d5cd8f + aeac915 commit 57b9468

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+598
-686
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Add missing validation checks for all the IBC message types
2+
([#233](https://github.com/cosmos/ibc-rs/issues/233))

crates/ibc/src/applications/transfer/error.rs

+9-22
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,13 @@ use crate::prelude::*;
1515
pub enum TokenTransferError {
1616
/// context error: `{0}`
1717
ContextError(ContextError),
18+
/// invalid identifier: `{0}`
19+
InvalidIdentifier(IdentifierError),
1820
/// destination channel not found in the counterparty of port_id `{port_id}` and channel_id `{channel_id}`
1921
DestinationChannelNotFound {
2022
port_id: PortId,
2123
channel_id: ChannelId,
2224
},
23-
/// invalid port identifier `{context}`, validation error: `{validation_error}`
24-
InvalidPortId {
25-
context: String,
26-
validation_error: IdentifierError,
27-
},
28-
/// invalid channel identifier `{context}`, validation error: `{validation_error}`
29-
InvalidChannelId {
30-
context: String,
31-
validation_error: IdentifierError,
32-
},
33-
/// invalid packet timeout height value `{context}`
34-
InvalidPacketTimeoutHeight { context: String },
35-
/// invalid packet timeout timestamp value `{timestamp}`
36-
InvalidPacketTimeoutTimestamp { timestamp: u64 },
3725
/// base denomination is empty
3826
EmptyBaseDenom,
3927
/// invalid prot id n trace at position: `{pos}`, validation error: `{validation_error}`
@@ -89,14 +77,7 @@ impl std::error::Error for TokenTransferError {
8977
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
9078
match &self {
9179
Self::ContextError(e) => Some(e),
92-
Self::InvalidPortId {
93-
validation_error: e,
94-
..
95-
} => Some(e),
96-
Self::InvalidChannelId {
97-
validation_error: e,
98-
..
99-
} => Some(e),
80+
Self::InvalidIdentifier(e) => Some(e),
10081
Self::InvalidTracePortId {
10182
validation_error: e,
10283
..
@@ -124,3 +105,9 @@ impl From<ContextError> for TokenTransferError {
124105
Self::ContextError(err)
125106
}
126107
}
108+
109+
impl From<IdentifierError> for TokenTransferError {
110+
fn from(err: IdentifierError) -> TokenTransferError {
111+
Self::InvalidIdentifier(err)
112+
}
113+
}

crates/ibc/src/applications/transfer/msgs/transfer.rs

+17-24
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
//! Defines the token transfer message type
22
3-
use crate::applications::transfer::packet::PacketData;
43
use crate::prelude::*;
54

65
use ibc_proto::google::protobuf::Any;
76
use ibc_proto::ibc::applications::transfer::v1::MsgTransfer as RawMsgTransfer;
87
use ibc_proto::protobuf::Protobuf;
98

109
use crate::applications::transfer::error::TokenTransferError;
10+
use crate::applications::transfer::packet::PacketData;
11+
use crate::core::ics04_channel::error::PacketError;
1112
use crate::core::ics04_channel::timeout::TimeoutHeight;
1213
use crate::core::ics24_host::identifier::{ChannelId, PortId};
1314
use crate::core::timestamp::Timestamp;
14-
use crate::core::Msg;
15+
use crate::core::{ContextError, Msg};
1516

1617
pub(crate) const TYPE_URL: &str = "/ibc.applications.transfer.v1.MsgTransfer";
1718

@@ -51,30 +52,22 @@ impl TryFrom<RawMsgTransfer> for MsgTransfer {
5152

5253
fn try_from(raw_msg: RawMsgTransfer) -> Result<Self, Self::Error> {
5354
let timeout_timestamp_on_b = Timestamp::from_nanoseconds(raw_msg.timeout_timestamp)
54-
.map_err(|_| TokenTransferError::InvalidPacketTimeoutTimestamp {
55-
timestamp: raw_msg.timeout_timestamp,
56-
})?;
57-
58-
let timeout_height_on_b: TimeoutHeight =
59-
raw_msg.timeout_height.try_into().map_err(|e| {
60-
TokenTransferError::InvalidPacketTimeoutHeight {
61-
context: format!("invalid timeout height {e}"),
62-
}
63-
})?;
55+
.map_err(PacketError::InvalidPacketTimestamp)
56+
.map_err(ContextError::from)?;
57+
58+
let timeout_height_on_b: TimeoutHeight = raw_msg
59+
.timeout_height
60+
.try_into()
61+
.map_err(ContextError::from)?;
62+
63+
// Packet timeout height and packet timeout timestamp cannot both be unset.
64+
if !timeout_height_on_b.is_set() && !timeout_timestamp_on_b.is_set() {
65+
return Err(PacketError::MissingTimeout).map_err(ContextError::from)?;
66+
}
6467

6568
Ok(MsgTransfer {
66-
port_id_on_a: raw_msg.source_port.parse().map_err(|e| {
67-
TokenTransferError::InvalidPortId {
68-
context: raw_msg.source_port.clone(),
69-
validation_error: e,
70-
}
71-
})?,
72-
chan_id_on_a: raw_msg.source_channel.parse().map_err(|e| {
73-
TokenTransferError::InvalidChannelId {
74-
context: raw_msg.source_channel.clone(),
75-
validation_error: e,
76-
}
77-
})?,
69+
port_id_on_a: raw_msg.source_port.parse()?,
70+
chan_id_on_a: raw_msg.source_channel.parse()?,
7871
packet_data: PacketData {
7972
token: raw_msg
8073
.token

crates/ibc/src/applications/transfer/relay/send_transfer.rs

+6-14
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ where
2828
ctx_a.can_send_coins()?;
2929

3030
let chan_end_path_on_a = ChannelEndPath::new(&msg.port_id_on_a, &msg.chan_id_on_a);
31-
let chan_end_on_a = ctx_a
32-
.channel_end(&chan_end_path_on_a)
33-
.map_err(TokenTransferError::ContextError)?;
31+
let chan_end_on_a = ctx_a.channel_end(&chan_end_path_on_a)?;
3432

3533
let port_id_on_b = chan_end_on_a.counterparty().port_id().clone();
3634
let chan_id_on_b = chan_end_on_a
@@ -43,9 +41,7 @@ where
4341
.clone();
4442

4543
let seq_send_path_on_a = SeqSendPath::new(&msg.port_id_on_a, &msg.chan_id_on_a);
46-
let sequence = ctx_a
47-
.get_next_sequence_send(&seq_send_path_on_a)
48-
.map_err(TokenTransferError::ContextError)?;
44+
let sequence = ctx_a.get_next_sequence_send(&seq_send_path_on_a)?;
4945

5046
let token = &msg.packet_data.token;
5147

@@ -83,7 +79,7 @@ where
8379
}
8480
};
8581

86-
send_packet_validate(ctx_a, &packet).map_err(TokenTransferError::ContextError)?;
82+
send_packet_validate(ctx_a, &packet)?;
8783

8884
Ok(())
8985
}
@@ -97,9 +93,7 @@ where
9793
Ctx: TokenTransferExecutionContext,
9894
{
9995
let chan_end_path_on_a = ChannelEndPath::new(&msg.port_id_on_a, &msg.chan_id_on_a);
100-
let chan_end_on_a = ctx_a
101-
.channel_end(&chan_end_path_on_a)
102-
.map_err(TokenTransferError::ContextError)?;
96+
let chan_end_on_a = ctx_a.channel_end(&chan_end_path_on_a)?;
10397

10498
let port_on_b = chan_end_on_a.counterparty().port_id().clone();
10599
let chan_on_b = chan_end_on_a
@@ -113,9 +107,7 @@ where
113107

114108
// get the next sequence
115109
let seq_send_path_on_a = SeqSendPath::new(&msg.port_id_on_a, &msg.chan_id_on_a);
116-
let sequence = ctx_a
117-
.get_next_sequence_send(&seq_send_path_on_a)
118-
.map_err(TokenTransferError::ContextError)?;
110+
let sequence = ctx_a.get_next_sequence_send(&seq_send_path_on_a)?;
119111

120112
let token = &msg.packet_data.token;
121113

@@ -155,7 +147,7 @@ where
155147
}
156148
};
157149

158-
send_packet_execute(ctx_a, packet).map_err(TokenTransferError::ContextError)?;
150+
send_packet_execute(ctx_a, packet)?;
159151

160152
{
161153
ctx_a.log_message(format!(

crates/ibc/src/clients/ics07_tendermint/client_state/misbehaviour.rs

+2-28
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ impl ClientState {
2323
client_id: &ClientId,
2424
misbehaviour: TmMisbehaviour,
2525
) -> Result<(), ClientError> {
26+
misbehaviour.validate_basic()?;
27+
2628
let header_1 = misbehaviour.header1();
2729
let trusted_consensus_state_1 = {
2830
let consensus_state_path =
@@ -41,39 +43,11 @@ impl ClientState {
4143
downcast_tm_consensus_state(consensus_state.as_ref())
4244
}?;
4345

44-
self.check_misbehaviour_headers_consistency(header_1, header_2)?;
45-
4646
let current_timestamp = ctx.host_timestamp()?;
4747
self.verify_misbehaviour_header(header_1, &trusted_consensus_state_1, current_timestamp)?;
4848
self.verify_misbehaviour_header(header_2, &trusted_consensus_state_2, current_timestamp)
4949
}
5050

51-
pub fn check_misbehaviour_headers_consistency(
52-
&self,
53-
header_1: &TmHeader,
54-
header_2: &TmHeader,
55-
) -> Result<(), ClientError> {
56-
if header_1.signed_header.header.chain_id != header_2.signed_header.header.chain_id {
57-
return Err(Error::InvalidRawMisbehaviour {
58-
reason: "headers must have identical chain_ids".to_owned(),
59-
}
60-
.into());
61-
}
62-
63-
if header_1.height() < header_2.height() {
64-
return Err(Error::InvalidRawMisbehaviour {
65-
reason: format!(
66-
"headers1 height is less than header2 height ({} < {})",
67-
header_1.height(),
68-
header_2.height()
69-
),
70-
}
71-
.into());
72-
}
73-
74-
Ok(())
75-
}
76-
7751
pub fn verify_misbehaviour_header(
7852
&self,
7953
header: &TmHeader,

crates/ibc/src/clients/ics07_tendermint/client_state/update_client.rs

+4-23
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,12 @@ impl ClientState {
2020
client_id: &ClientId,
2121
header: TmHeader,
2222
) -> Result<(), ClientError> {
23+
// Checks that the header fields are valid.
24+
header.validate_basic()?;
25+
2326
// The tendermint-light-client crate though works on heights that are assumed
2427
// to have the same revision number. We ensure this here.
25-
if header.height().revision_number() != self.chain_id().version() {
26-
return Err(ClientError::ClientSpecific {
27-
description: Error::MismatchedRevisions {
28-
current_revision: self.chain_id().version(),
29-
update_revision: header.height().revision_number(),
30-
}
31-
.to_string(),
32-
});
33-
}
34-
35-
// We also need to ensure that the trusted height (representing the
36-
// height of the header already on chain for which this client update is
37-
// based on) must be smaller than height of the new header that we're
38-
// installing.
39-
if header.height() <= header.trusted_height {
40-
return Err(ClientError::HeaderVerificationFailure {
41-
reason: format!(
42-
"header height <= header trusted height ({} <= {})",
43-
header.height(),
44-
header.trusted_height
45-
),
46-
});
47-
}
28+
header.verify_chain_id_version_matches_height(&self.chain_id())?;
4829

4930
// Delegate to tendermint-light-client, which contains the required checks
5031
// of the new header against the trusted consensus state.

crates/ibc/src/clients/ics07_tendermint/consensus_state.rs

+19-11
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ impl TryFrom<RawConsensusState> for ConsensusState {
5151
type Error = Error;
5252

5353
fn try_from(raw: RawConsensusState) -> Result<Self, Self::Error> {
54+
let proto_root = raw
55+
.root
56+
.ok_or(Error::InvalidRawClientState {
57+
reason: "missing commitment root".into(),
58+
})?
59+
.hash;
60+
if proto_root.is_empty() {
61+
return Err(Error::InvalidRawClientState {
62+
reason: "empty commitment root".into(),
63+
});
64+
};
65+
5466
let ibc_proto::google::protobuf::Timestamp { seconds, nanos } =
5567
raw.timestamp.ok_or(Error::InvalidRawClientState {
5668
reason: "missing timestamp".into(),
@@ -64,19 +76,15 @@ impl TryFrom<RawConsensusState> for ConsensusState {
6476
reason: format!("invalid timestamp: {e}"),
6577
})?;
6678

79+
let next_validators_hash = Hash::from_bytes(Algorithm::Sha256, &raw.next_validators_hash)
80+
.map_err(|e| Error::InvalidRawClientState {
81+
reason: e.to_string(),
82+
})?;
83+
6784
Ok(Self {
68-
root: raw
69-
.root
70-
.ok_or(Error::InvalidRawClientState {
71-
reason: "missing commitment root".into(),
72-
})?
73-
.hash
74-
.into(),
85+
root: proto_root.into(),
7586
timestamp,
76-
next_validators_hash: Hash::from_bytes(Algorithm::Sha256, &raw.next_validators_hash)
77-
.map_err(|e| Error::InvalidRawClientState {
78-
reason: e.to_string(),
79-
})?,
87+
next_validators_hash,
8088
})
8189
}
8290
}

crates/ibc/src/clients/ics07_tendermint/error.rs

+10-15
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use displaydoc::Display;
1212
use tendermint::{Error as TendermintError, Hash};
1313
use tendermint_light_client_verifier::errors::VerificationErrorDetail as LightClientErrorDetail;
1414
use tendermint_light_client_verifier::operations::VotingPowerTally;
15-
use tendermint_light_client_verifier::types::Validator;
1615
use tendermint_light_client_verifier::Verdict;
1716

1817
/// The main error type
@@ -71,11 +70,13 @@ pub enum Error {
7170
InvalidHeaderHeight { height: u64 },
7271
/// Disallowed to create a new client with a frozen height
7372
FrozenHeightNotAllowed,
74-
/// the header's current/trusted revision number (`{current_revision}`) and the update's revision number (`{update_revision}`) should be the same
75-
MismatchedRevisions {
76-
current_revision: u64,
77-
update_revision: u64,
73+
/// the header's trusted revision number (`{trusted_revision}`) and the update's revision number (`{header_revision}`) should be the same
74+
MismatchHeightRevisions {
75+
trusted_revision: u64,
76+
header_revision: u64,
7877
},
78+
/// the given chain-id (`{given}`) does not match the chain-id of the client (`{expected}`)
79+
MismatchHeaderChainId { given: String, expected: String },
7980
/// not enough trust because insufficient validators overlap: `{reason}`
8081
NotEnoughTrustedValsSigned { reason: VotingPowerTally },
8182
/// verification failed: `{detail}`
@@ -84,11 +85,10 @@ pub enum Error {
8485
ProcessedTimeNotFound { client_id: ClientId, height: Height },
8586
/// Processed height for the client `{client_id}` at height `{height}` not found
8687
ProcessedHeightNotFound { client_id: ClientId, height: Height },
87-
/// trusted validators `{trusted_validator_set:?}`, does not hash to latest trusted validators. Expected: `{next_validators_hash}`, got: `{trusted_val_hash}`
88-
MisbehaviourTrustedValidatorHashMismatch {
89-
trusted_validator_set: Vec<Validator>,
90-
next_validators_hash: Hash,
91-
trusted_val_hash: Hash,
88+
/// The given hash of the validators does not matches the given hash in the signed header. Expected: `{signed_header_validators_hash}`, got: `{validators_hash}`
89+
MismatchValidatorsHashes {
90+
validators_hash: Hash,
91+
signed_header_validators_hash: Hash,
9292
},
9393
/// current timestamp minus the latest consensus state timestamp is greater than or equal to the trusting period (`{duration_since_consensus_state:?}` >= `{trusting_period:?}`)
9494
ConsensusStateTimestampGteTrustingPeriod {
@@ -99,11 +99,6 @@ pub enum Error {
9999
MisbehaviourHeadersBlockHashesEqual,
100100
/// headers are not at same height and are monotonically increasing
101101
MisbehaviourHeadersNotAtSameHeight,
102-
/// header chain-id `{header_chain_id}` does not match the light client's chain-id `{chain_id}`)
103-
MisbehaviourHeadersChainIdMismatch {
104-
header_chain_id: String,
105-
chain_id: String,
106-
},
107102
/// invalid raw client id: `{client_id}`
108103
InvalidRawClientId { client_id: String },
109104
}

0 commit comments

Comments
 (0)