ibc_core_channel/handler/
send_packet.rs1use ibc_core_channel_types::channel::Counterparty;
2use ibc_core_channel_types::commitment::compute_packet_commitment;
3use ibc_core_channel_types::error::ChannelError;
4use ibc_core_channel_types::events::SendPacket;
5use ibc_core_channel_types::packet::Packet;
6use ibc_core_client::context::prelude::*;
7use ibc_core_handler_types::events::{IbcEvent, MessageEvent};
8use ibc_core_host::types::path::{
9 ChannelEndPath, ClientConsensusStatePath, CommitmentPath, SeqSendPath,
10};
11use ibc_primitives::prelude::*;
12
13use crate::context::{SendPacketExecutionContext, SendPacketValidationContext};
14
15pub fn send_packet(
19 ctx_a: &mut impl SendPacketExecutionContext,
20 packet: Packet,
21) -> Result<(), ChannelError> {
22 send_packet_validate(ctx_a, &packet)?;
23 send_packet_execute(ctx_a, packet)
24}
25
26pub fn send_packet_validate(
28 ctx_a: &impl SendPacketValidationContext,
29 packet: &Packet,
30) -> Result<(), ChannelError> {
31 if !packet.timeout_height_on_b.is_set() && !packet.timeout_timestamp_on_b.is_set() {
32 return Err(ChannelError::MissingTimeout);
33 }
34
35 let chan_end_path_on_a = ChannelEndPath::new(&packet.port_id_on_a, &packet.chan_id_on_a);
36 let chan_end_on_a = ctx_a.channel_end(&chan_end_path_on_a)?;
37
38 chan_end_on_a.verify_not_closed()?;
41
42 let counterparty = Counterparty::new(
43 packet.port_id_on_b.clone(),
44 Some(packet.chan_id_on_b.clone()),
45 );
46
47 chan_end_on_a.verify_counterparty_matches(&counterparty)?;
48
49 let conn_id_on_a = &chan_end_on_a.connection_hops()[0];
50
51 let conn_end_on_a = ctx_a.connection_end(conn_id_on_a)?;
52
53 let client_id_on_a = conn_end_on_a.client_id();
54
55 let client_val_ctx_a = ctx_a.get_client_validation_context();
56
57 let client_state_of_b_on_a = client_val_ctx_a.client_state(client_id_on_a)?;
58
59 client_state_of_b_on_a
60 .status(ctx_a.get_client_validation_context(), client_id_on_a)?
61 .verify_is_active()?;
62
63 let latest_height_on_a = client_state_of_b_on_a.latest_height();
64
65 if packet.timeout_height_on_b.has_expired(latest_height_on_a) {
66 return Err(ChannelError::InsufficientPacketHeight {
67 chain_height: latest_height_on_a,
68 timeout_height: packet.timeout_height_on_b,
69 });
70 }
71
72 let client_cons_state_path_on_a = ClientConsensusStatePath::new(
73 client_id_on_a.clone(),
74 latest_height_on_a.revision_number(),
75 latest_height_on_a.revision_height(),
76 );
77 let consensus_state_of_b_on_a =
78 client_val_ctx_a.consensus_state(&client_cons_state_path_on_a)?;
79 let latest_timestamp = consensus_state_of_b_on_a.timestamp()?;
80 let packet_timestamp = packet.timeout_timestamp_on_b;
81 if packet_timestamp.has_expired(&latest_timestamp) {
82 return Err(ChannelError::ExpiredPacketTimestamp);
83 }
84
85 let seq_send_path_on_a = SeqSendPath::new(&packet.port_id_on_a, &packet.chan_id_on_a);
86 let next_seq_send_on_a = ctx_a.get_next_sequence_send(&seq_send_path_on_a)?;
87
88 if packet.seq_on_a != next_seq_send_on_a {
89 return Err(ChannelError::MismatchedPacketSequence {
90 actual: packet.seq_on_a,
91 expected: next_seq_send_on_a,
92 });
93 }
94
95 Ok(())
96}
97
98pub fn send_packet_execute(
102 ctx_a: &mut impl SendPacketExecutionContext,
103 packet: Packet,
104) -> Result<(), ChannelError> {
105 {
106 let seq_send_path_on_a = SeqSendPath::new(&packet.port_id_on_a, &packet.chan_id_on_a);
107 let next_seq_send_on_a = ctx_a.get_next_sequence_send(&seq_send_path_on_a)?;
108
109 ctx_a.store_next_sequence_send(&seq_send_path_on_a, next_seq_send_on_a.increment())?;
110 }
111
112 ctx_a.store_packet_commitment(
113 &CommitmentPath::new(&packet.port_id_on_a, &packet.chan_id_on_a, packet.seq_on_a),
114 compute_packet_commitment(
115 &packet.data,
116 &packet.timeout_height_on_b,
117 &packet.timeout_timestamp_on_b,
118 ),
119 )?;
120
121 {
123 let chan_end_path_on_a = ChannelEndPath::new(&packet.port_id_on_a, &packet.chan_id_on_a);
124 let chan_end_on_a = ctx_a.channel_end(&chan_end_path_on_a)?;
125 let conn_id_on_a = &chan_end_on_a.connection_hops()[0];
126
127 ctx_a.log_message("success: packet send".to_string())?;
128 let event = IbcEvent::SendPacket(SendPacket::new(
129 packet,
130 chan_end_on_a.ordering,
131 conn_id_on_a.clone(),
132 ));
133 ctx_a.emit_ibc_event(IbcEvent::Message(MessageEvent::Channel))?;
134 ctx_a.emit_ibc_event(event)?;
135 }
136
137 Ok(())
138}