Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ibc-core): reject packets with no timeouts in send_packet_validate #1205

Merged
merged 7 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ibc-core/ics04-channel/src/handler/send_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ pub fn send_packet_validate(
ctx_a: &impl SendPacketValidationContext,
packet: &Packet,
) -> Result<(), ContextError> {
if !packet.timeout_height_on_b.is_set() && !packet.timeout_timestamp_on_b.is_set() {
return Err(ContextError::PacketError(PacketError::MissingTimeout));
}
Comment on lines +33 to +35
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we do a similar check in recv, timeout and timeoutOnClose?
All the on_a vs on_b cause a lot of duplicate code, ideally this check should be done in one place for all messages that include a packet.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good question! Here's my argument:

  • OnRecvPacket: timeout doesn't matter - as this would generate packet_ack anyway.
  • OnTimeout/OnTimeoutClose: we added send_packet with timeout height or timeout timestamp (invariant).

Also, I didn't find these checks in IBC spec and in ibc-go.


let chan_end_path_on_a = ChannelEndPath::new(&packet.port_id_on_a, &packet.chan_id_on_a);
let chan_end_on_a = ctx_a.channel_end(&chan_end_path_on_a)?;

Expand Down
8 changes: 4 additions & 4 deletions ibc-testkit/src/fixtures/core/channel/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ mod tests {

let proof_height = 10;
let default_raw_packet = dummy_raw_packet(proof_height, 1000);
let raw_packet_no_timeout_or_timestamp = dummy_raw_packet(10, 0);
let raw_packet_no_timeout_timestamp = dummy_raw_packet(10, 0);

let mut raw_packet_invalid_timeout_height = dummy_raw_packet(0, 10);
raw_packet_invalid_timeout_height.timeout_height = Some(RawHeight {
Expand All @@ -101,8 +101,8 @@ mod tests {
Test {
// Note: ibc-go currently (July 2022) incorrectly rejects this
// case, even though it is allowed in ICS-4.
name: "Packet with no timeout of timestamp".to_string(),
raw: raw_packet_no_timeout_or_timestamp.clone(),
name: "Packet with no timeout timestamp".to_string(),
raw: raw_packet_no_timeout_timestamp.clone(),
want_pass: true,
},
Test {
Expand Down Expand Up @@ -225,7 +225,7 @@ mod tests {
name: "Missing both timeout height and timestamp".to_string(),
raw: RawPacket {
timeout_height: None,
..raw_packet_no_timeout_or_timestamp
..raw_packet_no_timeout_timestamp
},
want_pass: false,
}
Expand Down
23 changes: 23 additions & 0 deletions ibc-testkit/tests/core/ics04_channel/send_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use core::time::Duration;
use ibc::core::channel::handler::send_packet;
use ibc::core::channel::types::channel::{ChannelEnd, Counterparty, Order, State};
use ibc::core::channel::types::packet::Packet;
use ibc::core::channel::types::timeout::TimeoutHeight;
use ibc::core::channel::types::Version;
use ibc::core::client::types::Height;
use ibc::core::commitment_types::commitment::CommitmentPrefix;
Expand Down Expand Up @@ -84,6 +85,13 @@ fn send_packet_processing() {

let client_height = Height::new(0, client_raw_height).unwrap();

let packet_with_no_timeout: Packet = {
let mut packet: Packet = dummy_raw_packet(10, 10).try_into().unwrap();
packet.timeout_height_on_b = TimeoutHeight::no_timeout();
packet.timeout_timestamp_on_b = Timestamp::none();
packet
};

let tests: Vec<Test> = vec![
Test {
name: "Processing fails because no channel exists in the context".to_string(),
Expand Down Expand Up @@ -136,6 +144,21 @@ fn send_packet_processing() {
packet: packet_timeout_one_before_client_height,
want_pass: false,
},
Test {
name: "Packet without height and timestamp timeout".to_string(),
ctx: context
.clone()
.with_client_config(
MockClientConfig::builder()
.latest_height(client_height)
.build(),
)
.with_connection(ConnectionId::zero(), conn_end_on_a.clone())
.with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a.clone())
.with_send_sequence(PortId::transfer(), ChannelId::zero(), 1.into()),
packet: packet_with_no_timeout,
want_pass: false,
},
Test {
name: "Packet timeout due to timestamp".to_string(),
ctx: context
Expand Down
5 changes: 3 additions & 2 deletions ibc-testkit/tests/core/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ fn routing_module_and_keepers() {

let msg_transfer_no_timeout_or_timestamp = MsgTransferConfig::builder()
.packet_data(packet_data.clone())
// Timestamp::from_nanoseconds(0) and Timestamp::none() are equivalent
.timeout_timestamp_on_b(Timestamp::from_nanoseconds(0).unwrap())
.build();

Expand Down Expand Up @@ -348,13 +349,13 @@ fn routing_module_and_keepers() {
Test {
name: "Transfer message no timeout".to_string(),
msg: msg_transfer_no_timeout.into(),
want_pass: true,
want_pass: false,
state_check: None,
},
Test {
name: "Transfer message no timeout nor timestamp".to_string(),
msg: msg_transfer_no_timeout_or_timestamp.into(),
want_pass: true,
want_pass: false,
state_check: None,
},
//ICS04-close channel
Expand Down
Loading