Skip to content

Commit d11e059

Browse files
authored
Finish implementation of Validation/ExecutionContext (#393)
* timeout validate scaffolding * validate still not done * complete timeout validate * timeout validate: accept noop * timeout packet execute * timeout_on_close validation * timeout_on_close done * ack validate * Acknowledgement execute * fix on_timeout_validate * ics20 new ack cbs * ics-20 new timeout cb * PacketError * ack: move ordered check * ics-20 ack packet validate * ics-20 refund packet validate * changelog
1 parent 4a4fe86 commit d11e059

File tree

15 files changed

+1161
-52
lines changed

15 files changed

+1161
-52
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- Finish implementing ValidationContext::validate() and
2+
ExecutionContext::execute() ([#393](https://github.com/cosmos/ibc-
3+
rs/issues/393))

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

Lines changed: 129 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ use super::error::TokenTransferError;
44
use crate::applications::transfer::acknowledgement::TokenTransferAcknowledgement;
55
use crate::applications::transfer::events::{AckEvent, AckStatusEvent, RecvEvent, TimeoutEvent};
66
use crate::applications::transfer::packet::PacketData;
7-
use crate::applications::transfer::relay::on_ack_packet::process_ack_packet;
87
use crate::applications::transfer::relay::on_recv_packet::process_recv_packet;
9-
use crate::applications::transfer::relay::on_timeout_packet::process_timeout_packet;
8+
use crate::applications::transfer::relay::refund_packet_token;
109
use crate::applications::transfer::{PrefixedCoin, PrefixedDenom, VERSION};
1110
use crate::core::ics04_channel::channel::{Counterparty, Order};
1211
use crate::core::ics04_channel::commitment::PacketCommitment;
@@ -300,7 +299,9 @@ pub fn on_acknowledgement_packet(
300299
serde_json::from_slice::<TokenTransferAcknowledgement>(acknowledgement.as_ref())
301300
.map_err(|_| TokenTransferError::AckDeserialization)?;
302301

303-
process_ack_packet(ctx, packet, &data, &acknowledgement)?;
302+
if !acknowledgement.is_successful() {
303+
refund_packet_token(ctx, packet, &data)?;
304+
}
304305

305306
let ack_event = AckEvent {
306307
receiver: data.receiver,
@@ -323,7 +324,7 @@ pub fn on_timeout_packet(
323324
let data = serde_json::from_slice::<PacketData>(&packet.data)
324325
.map_err(|_| TokenTransferError::PacketDataDeserialization)?;
325326

326-
process_timeout_packet(ctx, packet, &data)?;
327+
refund_packet_token(ctx, packet, &data)?;
327328

328329
let timeout_event = TimeoutEvent {
329330
refund_receiver: data.sender,
@@ -339,7 +340,9 @@ pub fn on_timeout_packet(
339340
pub use val_exec_ctx::*;
340341
#[cfg(feature = "val_exec_ctx")]
341342
mod val_exec_ctx {
342-
use crate::applications::transfer::relay::on_recv_packet::process_recv_packet_execute;
343+
use crate::applications::transfer::relay::{
344+
on_recv_packet::process_recv_packet_execute, refund_packet_token_validate,
345+
};
343346

344347
pub use super::*;
345348

@@ -530,6 +533,127 @@ mod val_exec_ctx {
530533

531534
(extras, ack.into())
532535
}
536+
537+
pub fn on_acknowledgement_packet_validate<Ctx>(
538+
_ctx: &Ctx,
539+
packet: &Packet,
540+
acknowledgement: &Acknowledgement,
541+
_relayer: &Signer,
542+
) -> Result<(), TokenTransferError>
543+
where
544+
Ctx: TokenTransferContext,
545+
{
546+
let data = serde_json::from_slice::<PacketData>(&packet.data)
547+
.map_err(|_| TokenTransferError::PacketDataDeserialization)?;
548+
549+
let acknowledgement =
550+
serde_json::from_slice::<TokenTransferAcknowledgement>(acknowledgement.as_ref())
551+
.map_err(|_| TokenTransferError::AckDeserialization)?;
552+
553+
if !acknowledgement.is_successful() {
554+
refund_packet_token_validate::<Ctx>(&data)?;
555+
}
556+
557+
Ok(())
558+
}
559+
560+
pub fn on_acknowledgement_packet_execute(
561+
ctx: &mut impl TokenTransferContext,
562+
packet: &Packet,
563+
acknowledgement: &Acknowledgement,
564+
_relayer: &Signer,
565+
) -> (ModuleExtras, Result<(), TokenTransferError>) {
566+
let data = match serde_json::from_slice::<PacketData>(&packet.data) {
567+
Ok(data) => data,
568+
Err(_) => {
569+
return (
570+
ModuleExtras::empty(),
571+
Err(TokenTransferError::PacketDataDeserialization),
572+
);
573+
}
574+
};
575+
576+
let acknowledgement = match serde_json::from_slice::<TokenTransferAcknowledgement>(
577+
acknowledgement.as_ref(),
578+
) {
579+
Ok(ack) => ack,
580+
Err(_) => {
581+
return (
582+
ModuleExtras::empty(),
583+
Err(TokenTransferError::AckDeserialization),
584+
);
585+
}
586+
};
587+
588+
if !acknowledgement.is_successful() {
589+
if let Err(err) = refund_packet_token(ctx, packet, &data) {
590+
return (ModuleExtras::empty(), Err(err));
591+
}
592+
}
593+
594+
let ack_event = AckEvent {
595+
receiver: data.receiver,
596+
denom: data.token.denom,
597+
amount: data.token.amount,
598+
acknowledgement: acknowledgement.clone(),
599+
};
600+
601+
let extras = ModuleExtras {
602+
events: vec![ack_event.into(), AckStatusEvent { acknowledgement }.into()],
603+
log: Vec::new(),
604+
};
605+
606+
(extras, Ok(()))
607+
}
608+
609+
pub fn on_timeout_packet_validate<Ctx>(
610+
_ctx: &Ctx,
611+
packet: &Packet,
612+
_relayer: &Signer,
613+
) -> Result<(), TokenTransferError>
614+
where
615+
Ctx: TokenTransferContext,
616+
{
617+
let data = serde_json::from_slice::<PacketData>(&packet.data)
618+
.map_err(|_| TokenTransferError::PacketDataDeserialization)?;
619+
620+
refund_packet_token_validate::<Ctx>(&data)?;
621+
622+
Ok(())
623+
}
624+
625+
pub fn on_timeout_packet_execute(
626+
ctx: &mut impl TokenTransferContext,
627+
packet: &Packet,
628+
_relayer: &Signer,
629+
) -> (ModuleExtras, Result<(), TokenTransferError>) {
630+
let data = match serde_json::from_slice::<PacketData>(&packet.data) {
631+
Ok(data) => data,
632+
Err(_) => {
633+
return (
634+
ModuleExtras::empty(),
635+
Err(TokenTransferError::PacketDataDeserialization),
636+
);
637+
}
638+
};
639+
640+
if let Err(err) = refund_packet_token(ctx, packet, &data) {
641+
return (ModuleExtras::empty(), Err(err));
642+
}
643+
644+
let timeout_event = TimeoutEvent {
645+
refund_receiver: data.sender,
646+
refund_denom: data.token.denom,
647+
refund_amount: data.token.amount,
648+
};
649+
650+
let extras = ModuleExtras {
651+
events: vec![timeout_event.into()],
652+
log: Vec::new(),
653+
};
654+
655+
(extras, Ok(()))
656+
}
533657
}
534658

535659
#[cfg(test)]

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

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@ use crate::applications::transfer::packet::PacketData;
66
use crate::core::ics04_channel::packet::Packet;
77
use crate::prelude::*;
88

9-
pub mod on_ack_packet;
109
pub mod on_recv_packet;
11-
pub mod on_timeout_packet;
1210
pub mod send_transfer;
1311

14-
fn refund_packet_token(
12+
pub fn refund_packet_token(
1513
ctx: &mut impl TokenTransferContext,
1614
packet: &Packet,
1715
data: &PacketData,
@@ -38,3 +36,22 @@ fn refund_packet_token(
3836
ctx.mint_coins(&sender, &data.token)
3937
}
4038
}
39+
40+
#[cfg(feature = "val_exec_ctx")]
41+
pub use val_exec_ctx::*;
42+
#[cfg(feature = "val_exec_ctx")]
43+
mod val_exec_ctx {
44+
use super::*;
45+
46+
pub fn refund_packet_token_validate<Ctx: TokenTransferContext>(
47+
data: &PacketData,
48+
) -> Result<(), TokenTransferError> {
49+
let _sender: <Ctx as TokenTransferContext>::AccountId = data
50+
.sender
51+
.clone()
52+
.try_into()
53+
.map_err(|_| TokenTransferError::ParseAccountFailure)?;
54+
55+
Ok(())
56+
}
57+
}

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

Lines changed: 0 additions & 19 deletions
This file was deleted.

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

Lines changed: 0 additions & 13 deletions
This file was deleted.

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

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,38 @@ impl Ics2ClientState for ClientState {
11501150
)
11511151
}
11521152

1153+
#[cfg(feature = "val_exec_ctx")]
1154+
fn new_verify_packet_acknowledgement(
1155+
&self,
1156+
ctx: &dyn ValidationContext,
1157+
height: Height,
1158+
connection_end: &ConnectionEnd,
1159+
proof: &CommitmentProofBytes,
1160+
root: &CommitmentRoot,
1161+
port_id: &PortId,
1162+
channel_id: &ChannelId,
1163+
sequence: Sequence,
1164+
ack: AcknowledgementCommitment,
1165+
) -> Result<(), ClientError> {
1166+
let client_state = downcast_tm_client_state(self)?;
1167+
client_state.verify_height(height)?;
1168+
new_verify_delay_passed(ctx, height, connection_end)?;
1169+
1170+
let ack_path = AcksPath {
1171+
port_id: port_id.clone(),
1172+
channel_id: channel_id.clone(),
1173+
sequence,
1174+
};
1175+
verify_membership(
1176+
client_state,
1177+
connection_end.counterparty().prefix(),
1178+
proof,
1179+
root,
1180+
ack_path,
1181+
ack.into_vec(),
1182+
)
1183+
}
1184+
11531185
fn verify_packet_acknowledgement(
11541186
&self,
11551187
ctx: &dyn ChannelReader,
@@ -1181,6 +1213,40 @@ impl Ics2ClientState for ClientState {
11811213
)
11821214
}
11831215

1216+
#[cfg(feature = "val_exec_ctx")]
1217+
#[allow(clippy::too_many_arguments)]
1218+
fn new_verify_next_sequence_recv(
1219+
&self,
1220+
ctx: &dyn ValidationContext,
1221+
height: Height,
1222+
connection_end: &ConnectionEnd,
1223+
proof: &CommitmentProofBytes,
1224+
root: &CommitmentRoot,
1225+
port_id: &PortId,
1226+
channel_id: &ChannelId,
1227+
sequence: Sequence,
1228+
) -> Result<(), ClientError> {
1229+
let client_state = downcast_tm_client_state(self)?;
1230+
client_state.verify_height(height)?;
1231+
new_verify_delay_passed(ctx, height, connection_end)?;
1232+
1233+
let mut seq_bytes = Vec::new();
1234+
u64::from(sequence)
1235+
.encode(&mut seq_bytes)
1236+
.expect("buffer size too small");
1237+
1238+
let seq_path = SeqRecvsPath(port_id.clone(), channel_id.clone());
1239+
1240+
verify_membership(
1241+
client_state,
1242+
connection_end.counterparty().prefix(),
1243+
proof,
1244+
root,
1245+
seq_path,
1246+
seq_bytes,
1247+
)
1248+
}
1249+
11841250
fn verify_next_sequence_recv(
11851251
&self,
11861252
ctx: &dyn ChannelReader,
@@ -1213,6 +1279,37 @@ impl Ics2ClientState for ClientState {
12131279
)
12141280
}
12151281

1282+
#[cfg(feature = "val_exec_ctx")]
1283+
#[allow(clippy::too_many_arguments)]
1284+
fn new_verify_packet_receipt_absence(
1285+
&self,
1286+
ctx: &dyn ValidationContext,
1287+
height: Height,
1288+
connection_end: &ConnectionEnd,
1289+
proof: &CommitmentProofBytes,
1290+
root: &CommitmentRoot,
1291+
port_id: &PortId,
1292+
channel_id: &ChannelId,
1293+
sequence: Sequence,
1294+
) -> Result<(), ClientError> {
1295+
let client_state = downcast_tm_client_state(self)?;
1296+
client_state.verify_height(height)?;
1297+
new_verify_delay_passed(ctx, height, connection_end)?;
1298+
1299+
let receipt_path = ReceiptsPath {
1300+
port_id: port_id.clone(),
1301+
channel_id: channel_id.clone(),
1302+
sequence,
1303+
};
1304+
verify_non_membership(
1305+
client_state,
1306+
connection_end.counterparty().prefix(),
1307+
proof,
1308+
root,
1309+
receipt_path,
1310+
)
1311+
}
1312+
12161313
fn verify_packet_receipt_absence(
12171314
&self,
12181315
ctx: &dyn ChannelReader,

0 commit comments

Comments
 (0)