Skip to content

Commit

Permalink
Finish implementation of Validation/ExecutionContext (#393)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
plafer authored Feb 8, 2023
1 parent 4a4fe86 commit d11e059
Show file tree
Hide file tree
Showing 15 changed files with 1,161 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Finish implementing ValidationContext::validate() and
ExecutionContext::execute() ([#393](https://github.com/cosmos/ibc-
rs/issues/393))
134 changes: 129 additions & 5 deletions crates/ibc/src/applications/transfer/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ use super::error::TokenTransferError;
use crate::applications::transfer::acknowledgement::TokenTransferAcknowledgement;
use crate::applications::transfer::events::{AckEvent, AckStatusEvent, RecvEvent, TimeoutEvent};
use crate::applications::transfer::packet::PacketData;
use crate::applications::transfer::relay::on_ack_packet::process_ack_packet;
use crate::applications::transfer::relay::on_recv_packet::process_recv_packet;
use crate::applications::transfer::relay::on_timeout_packet::process_timeout_packet;
use crate::applications::transfer::relay::refund_packet_token;
use crate::applications::transfer::{PrefixedCoin, PrefixedDenom, VERSION};
use crate::core::ics04_channel::channel::{Counterparty, Order};
use crate::core::ics04_channel::commitment::PacketCommitment;
Expand Down Expand Up @@ -300,7 +299,9 @@ pub fn on_acknowledgement_packet(
serde_json::from_slice::<TokenTransferAcknowledgement>(acknowledgement.as_ref())
.map_err(|_| TokenTransferError::AckDeserialization)?;

process_ack_packet(ctx, packet, &data, &acknowledgement)?;
if !acknowledgement.is_successful() {
refund_packet_token(ctx, packet, &data)?;
}

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

process_timeout_packet(ctx, packet, &data)?;
refund_packet_token(ctx, packet, &data)?;

let timeout_event = TimeoutEvent {
refund_receiver: data.sender,
Expand All @@ -339,7 +340,9 @@ pub fn on_timeout_packet(
pub use val_exec_ctx::*;
#[cfg(feature = "val_exec_ctx")]
mod val_exec_ctx {
use crate::applications::transfer::relay::on_recv_packet::process_recv_packet_execute;
use crate::applications::transfer::relay::{
on_recv_packet::process_recv_packet_execute, refund_packet_token_validate,
};

pub use super::*;

Expand Down Expand Up @@ -530,6 +533,127 @@ mod val_exec_ctx {

(extras, ack.into())
}

pub fn on_acknowledgement_packet_validate<Ctx>(
_ctx: &Ctx,
packet: &Packet,
acknowledgement: &Acknowledgement,
_relayer: &Signer,
) -> Result<(), TokenTransferError>
where
Ctx: TokenTransferContext,
{
let data = serde_json::from_slice::<PacketData>(&packet.data)
.map_err(|_| TokenTransferError::PacketDataDeserialization)?;

let acknowledgement =
serde_json::from_slice::<TokenTransferAcknowledgement>(acknowledgement.as_ref())
.map_err(|_| TokenTransferError::AckDeserialization)?;

if !acknowledgement.is_successful() {
refund_packet_token_validate::<Ctx>(&data)?;
}

Ok(())
}

pub fn on_acknowledgement_packet_execute(
ctx: &mut impl TokenTransferContext,
packet: &Packet,
acknowledgement: &Acknowledgement,
_relayer: &Signer,
) -> (ModuleExtras, Result<(), TokenTransferError>) {
let data = match serde_json::from_slice::<PacketData>(&packet.data) {
Ok(data) => data,
Err(_) => {
return (
ModuleExtras::empty(),
Err(TokenTransferError::PacketDataDeserialization),
);
}
};

let acknowledgement = match serde_json::from_slice::<TokenTransferAcknowledgement>(
acknowledgement.as_ref(),
) {
Ok(ack) => ack,
Err(_) => {
return (
ModuleExtras::empty(),
Err(TokenTransferError::AckDeserialization),
);
}
};

if !acknowledgement.is_successful() {
if let Err(err) = refund_packet_token(ctx, packet, &data) {
return (ModuleExtras::empty(), Err(err));
}
}

let ack_event = AckEvent {
receiver: data.receiver,
denom: data.token.denom,
amount: data.token.amount,
acknowledgement: acknowledgement.clone(),
};

let extras = ModuleExtras {
events: vec![ack_event.into(), AckStatusEvent { acknowledgement }.into()],
log: Vec::new(),
};

(extras, Ok(()))
}

pub fn on_timeout_packet_validate<Ctx>(
_ctx: &Ctx,
packet: &Packet,
_relayer: &Signer,
) -> Result<(), TokenTransferError>
where
Ctx: TokenTransferContext,
{
let data = serde_json::from_slice::<PacketData>(&packet.data)
.map_err(|_| TokenTransferError::PacketDataDeserialization)?;

refund_packet_token_validate::<Ctx>(&data)?;

Ok(())
}

pub fn on_timeout_packet_execute(
ctx: &mut impl TokenTransferContext,
packet: &Packet,
_relayer: &Signer,
) -> (ModuleExtras, Result<(), TokenTransferError>) {
let data = match serde_json::from_slice::<PacketData>(&packet.data) {
Ok(data) => data,
Err(_) => {
return (
ModuleExtras::empty(),
Err(TokenTransferError::PacketDataDeserialization),
);
}
};

if let Err(err) = refund_packet_token(ctx, packet, &data) {
return (ModuleExtras::empty(), Err(err));
}

let timeout_event = TimeoutEvent {
refund_receiver: data.sender,
refund_denom: data.token.denom,
refund_amount: data.token.amount,
};

let extras = ModuleExtras {
events: vec![timeout_event.into()],
log: Vec::new(),
};

(extras, Ok(()))
}
}

#[cfg(test)]
Expand Down
23 changes: 20 additions & 3 deletions crates/ibc/src/applications/transfer/relay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ use crate::applications::transfer::packet::PacketData;
use crate::core::ics04_channel::packet::Packet;
use crate::prelude::*;

pub mod on_ack_packet;
pub mod on_recv_packet;
pub mod on_timeout_packet;
pub mod send_transfer;

fn refund_packet_token(
pub fn refund_packet_token(
ctx: &mut impl TokenTransferContext,
packet: &Packet,
data: &PacketData,
Expand All @@ -38,3 +36,22 @@ fn refund_packet_token(
ctx.mint_coins(&sender, &data.token)
}
}

#[cfg(feature = "val_exec_ctx")]
pub use val_exec_ctx::*;
#[cfg(feature = "val_exec_ctx")]
mod val_exec_ctx {
use super::*;

pub fn refund_packet_token_validate<Ctx: TokenTransferContext>(
data: &PacketData,
) -> Result<(), TokenTransferError> {
let _sender: <Ctx as TokenTransferContext>::AccountId = data
.sender
.clone()
.try_into()
.map_err(|_| TokenTransferError::ParseAccountFailure)?;

Ok(())
}
}
19 changes: 0 additions & 19 deletions crates/ibc/src/applications/transfer/relay/on_ack_packet.rs

This file was deleted.

13 changes: 0 additions & 13 deletions crates/ibc/src/applications/transfer/relay/on_timeout_packet.rs

This file was deleted.

97 changes: 97 additions & 0 deletions crates/ibc/src/clients/ics07_tendermint/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,38 @@ impl Ics2ClientState for ClientState {
)
}

#[cfg(feature = "val_exec_ctx")]
fn new_verify_packet_acknowledgement(
&self,
ctx: &dyn ValidationContext,
height: Height,
connection_end: &ConnectionEnd,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
port_id: &PortId,
channel_id: &ChannelId,
sequence: Sequence,
ack: AcknowledgementCommitment,
) -> Result<(), ClientError> {
let client_state = downcast_tm_client_state(self)?;
client_state.verify_height(height)?;
new_verify_delay_passed(ctx, height, connection_end)?;

let ack_path = AcksPath {
port_id: port_id.clone(),
channel_id: channel_id.clone(),
sequence,
};
verify_membership(
client_state,
connection_end.counterparty().prefix(),
proof,
root,
ack_path,
ack.into_vec(),
)
}

fn verify_packet_acknowledgement(
&self,
ctx: &dyn ChannelReader,
Expand Down Expand Up @@ -1181,6 +1213,40 @@ impl Ics2ClientState for ClientState {
)
}

#[cfg(feature = "val_exec_ctx")]
#[allow(clippy::too_many_arguments)]
fn new_verify_next_sequence_recv(
&self,
ctx: &dyn ValidationContext,
height: Height,
connection_end: &ConnectionEnd,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
port_id: &PortId,
channel_id: &ChannelId,
sequence: Sequence,
) -> Result<(), ClientError> {
let client_state = downcast_tm_client_state(self)?;
client_state.verify_height(height)?;
new_verify_delay_passed(ctx, height, connection_end)?;

let mut seq_bytes = Vec::new();
u64::from(sequence)
.encode(&mut seq_bytes)
.expect("buffer size too small");

let seq_path = SeqRecvsPath(port_id.clone(), channel_id.clone());

verify_membership(
client_state,
connection_end.counterparty().prefix(),
proof,
root,
seq_path,
seq_bytes,
)
}

fn verify_next_sequence_recv(
&self,
ctx: &dyn ChannelReader,
Expand Down Expand Up @@ -1213,6 +1279,37 @@ impl Ics2ClientState for ClientState {
)
}

#[cfg(feature = "val_exec_ctx")]
#[allow(clippy::too_many_arguments)]
fn new_verify_packet_receipt_absence(
&self,
ctx: &dyn ValidationContext,
height: Height,
connection_end: &ConnectionEnd,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
port_id: &PortId,
channel_id: &ChannelId,
sequence: Sequence,
) -> Result<(), ClientError> {
let client_state = downcast_tm_client_state(self)?;
client_state.verify_height(height)?;
new_verify_delay_passed(ctx, height, connection_end)?;

let receipt_path = ReceiptsPath {
port_id: port_id.clone(),
channel_id: channel_id.clone(),
sequence,
};
verify_non_membership(
client_state,
connection_end.counterparty().prefix(),
proof,
root,
receipt_path,
)
}

fn verify_packet_receipt_absence(
&self,
ctx: &dyn ChannelReader,
Expand Down
Loading

0 comments on commit d11e059

Please sign in to comment.