diff --git a/.changelog/unreleased/breaking-changes/442-send-packet-transfer.md b/.changelog/unreleased/breaking-changes/442-send-packet-transfer.md new file mode 100644 index 0000000000..415f57d612 --- /dev/null +++ b/.changelog/unreleased/breaking-changes/442-send-packet-transfer.md @@ -0,0 +1,2 @@ +- Update send_packet/transfer(), and related contexts + ([#442](https://github.com/cosmos/ibc-rs/issues/442)) \ No newline at end of file diff --git a/crates/ibc/src/applications/transfer/context.rs b/crates/ibc/src/applications/transfer/context.rs index 2916443d73..a5150ffa01 100644 --- a/crates/ibc/src/applications/transfer/context.rs +++ b/crates/ibc/src/applications/transfer/context.rs @@ -1,61 +1,54 @@ +use crate::prelude::*; + use sha2::{Digest, Sha256}; 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_recv_packet::process_recv_packet; use crate::applications::transfer::relay::refund_packet_token; +use crate::applications::transfer::relay::{ + on_recv_packet::process_recv_packet_execute, refund_packet_token_validate, +}; use crate::applications::transfer::{PrefixedCoin, PrefixedDenom, VERSION}; use crate::core::ics04_channel::channel::{Counterparty, Order}; -use crate::core::ics04_channel::commitment::PacketCommitment; -use crate::core::ics04_channel::context::SendPacketReader; -use crate::core::ics04_channel::handler::send_packet::SendPacketResult; +use crate::core::ics04_channel::context::{ + SendPacketExecutionContext, SendPacketValidationContext, +}; use crate::core::ics04_channel::handler::ModuleExtras; use crate::core::ics04_channel::msgs::acknowledgement::Acknowledgement; -use crate::core::ics04_channel::packet::{Packet, Sequence}; +use crate::core::ics04_channel::packet::Packet; use crate::core::ics04_channel::Version; use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::core::ics24_host::path::{CommitmentPath, SeqSendPath}; -use crate::core::ics26_routing::context::ModuleOutputBuilder; -use crate::core::{ContextError, ExecutionContext}; -use crate::prelude::*; use crate::signer::Signer; -pub trait TokenTransferKeeper: BankKeeper { - fn store_send_packet_result(&mut self, result: SendPacketResult) -> Result<(), ContextError> { - self.store_next_sequence_send( - result.port_id.clone(), - result.channel_id.clone(), - result.seq_number, - )?; - - self.store_packet_commitment( - result.port_id, - result.channel_id, - result.seq, - result.commitment, - )?; - Ok(()) - } +pub trait TokenTransferExecutionContext: + TokenTransferValidationContext + SendPacketExecutionContext +{ + /// This function should enable sending ibc fungible tokens from one account to another + fn send_coins( + &mut self, + from: &Self::AccountId, + to: &Self::AccountId, + amt: &PrefixedCoin, + ) -> Result<(), TokenTransferError>; - fn store_packet_commitment( + /// This function to enable minting ibc tokens to a user account + fn mint_coins( &mut self, - port_id: PortId, - channel_id: ChannelId, - sequence: Sequence, - commitment: PacketCommitment, - ) -> Result<(), ContextError>; + account: &Self::AccountId, + amt: &PrefixedCoin, + ) -> Result<(), TokenTransferError>; - fn store_next_sequence_send( + /// This function should enable burning of minted tokens in a user account + fn burn_coins( &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - ) -> Result<(), ContextError>; + account: &Self::AccountId, + amt: &PrefixedCoin, + ) -> Result<(), TokenTransferError>; } -pub trait TokenTransferReader: SendPacketReader { +pub trait TokenTransferValidationContext: SendPacketValidationContext { type AccountId: TryFrom; /// get_port returns the portID for the transfer module. @@ -66,7 +59,7 @@ pub trait TokenTransferReader: SendPacketReader { &self, port_id: &PortId, channel_id: &ChannelId, - ) -> Result<::AccountId, TokenTransferError>; + ) -> Result; /// Returns true iff send is enabled. fn is_send_enabled(&self) -> bool; @@ -81,38 +74,6 @@ pub trait TokenTransferReader: SendPacketReader { } } -impl TokenTransferKeeper for T -where - T: ExecutionContext + BankKeeper, -{ - fn store_packet_commitment( - &mut self, - port_id: PortId, - channel_id: ChannelId, - sequence: Sequence, - commitment: PacketCommitment, - ) -> Result<(), ContextError> { - let commitment_path = CommitmentPath { - port_id, - channel_id, - sequence, - }; - - self.store_packet_commitment(&commitment_path, commitment) - } - - fn store_next_sequence_send( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - ) -> Result<(), ContextError> { - let seq_send_path = SeqSendPath(port_id, channel_id); - - self.store_next_sequence_send(&seq_send_path, seq) - } -} - // https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-028-public-key-addresses.md pub fn cosmos_adr028_escrow_address(port_id: &PortId, channel_id: &ChannelId) -> Vec { let contents = format!("{port_id}/{channel_id}"); @@ -127,233 +88,9 @@ pub fn cosmos_adr028_escrow_address(port_id: &PortId, channel_id: &ChannelId) -> hash } -pub trait BankKeeper { - type AccountId; - - /// This function should enable sending ibc fungible tokens from one account to another - fn send_coins( - &mut self, - from: &Self::AccountId, - to: &Self::AccountId, - amt: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; - - /// This function to enable minting ibc tokens to a user account - fn mint_coins( - &mut self, - account: &Self::AccountId, - amt: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; - - /// This function should enable burning of minted tokens in a user account - fn burn_coins( - &mut self, - account: &Self::AccountId, - amt: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; -} - -/// Captures all the dependencies which the ICS20 module requires to be able to dispatch and -/// process IBC messages. -pub trait TokenTransferContext: - TokenTransferKeeper::AccountId> - + TokenTransferReader::AccountId> -{ - type AccountId: TryFrom; -} - -#[allow(clippy::too_many_arguments)] -pub fn on_chan_open_init( - ctx: &mut impl TokenTransferContext, - order: Order, - _connection_hops: &[ConnectionId], - port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - version: &Version, -) -> Result<(ModuleExtras, Version), TokenTransferError> { - if order != Order::Unordered { - return Err(TokenTransferError::ChannelNotUnordered { - expect_order: Order::Unordered, - got_order: order, - }); - } - let bound_port = ctx.get_port()?; - if port_id != &bound_port { - return Err(TokenTransferError::InvalidPort { - port_id: port_id.clone(), - exp_port_id: bound_port, - }); - } - - if !version.is_empty() && version != &Version::new(VERSION.to_string()) { - return Err(TokenTransferError::InvalidVersion { - expect_version: Version::new(VERSION.to_string()), - got_version: version.clone(), - }); - } - - Ok((ModuleExtras::empty(), Version::new(VERSION.to_string()))) -} -#[allow(clippy::too_many_arguments)] -pub fn on_chan_open_try( - _ctx: &mut impl TokenTransferContext, - order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - counterparty_version: &Version, -) -> Result<(ModuleExtras, Version), TokenTransferError> { - if order != Order::Unordered { - return Err(TokenTransferError::ChannelNotUnordered { - expect_order: Order::Unordered, - got_order: order, - }); - } - if counterparty_version != &Version::new(VERSION.to_string()) { - return Err(TokenTransferError::InvalidCounterpartyVersion { - expect_version: Version::new(VERSION.to_string()), - got_version: counterparty_version.clone(), - }); - } - - Ok((ModuleExtras::empty(), Version::new(VERSION.to_string()))) -} - -pub fn on_chan_open_ack( - _ctx: &mut impl TokenTransferContext, - _port_id: &PortId, - _channel_id: &ChannelId, - counterparty_version: &Version, -) -> Result { - if counterparty_version != &Version::new(VERSION.to_string()) { - return Err(TokenTransferError::InvalidCounterpartyVersion { - expect_version: Version::new(VERSION.to_string()), - got_version: counterparty_version.clone(), - }); - } - - Ok(ModuleExtras::empty()) -} - -pub fn on_chan_open_confirm( - _ctx: &mut impl TokenTransferContext, - _port_id: &PortId, - _channel_id: &ChannelId, -) -> Result { - Ok(ModuleExtras::empty()) -} - -pub fn on_chan_close_init( - _ctx: &mut impl TokenTransferContext, - _port_id: &PortId, - _channel_id: &ChannelId, -) -> Result { - Err(TokenTransferError::CantCloseChannel) -} - -pub fn on_chan_close_confirm( - _ctx: &mut impl TokenTransferContext, - _port_id: &PortId, - _channel_id: &ChannelId, -) -> Result { - Ok(ModuleExtras::empty()) -} - -pub fn on_recv_packet( - ctx: &mut Ctx, - output: &mut ModuleOutputBuilder, - packet: &Packet, - _relayer: &Signer, -) -> Acknowledgement { - let data = match serde_json::from_slice::(&packet.data) { - Ok(data) => data, - Err(_) => { - let ack = TokenTransferAcknowledgement::Error( - TokenTransferError::PacketDataDeserialization.to_string(), - ); - return ack.into(); - } - }; - - let ack: TokenTransferAcknowledgement = - match process_recv_packet(ctx, output, packet, data.clone()) { - Ok(()) => TokenTransferAcknowledgement::success(), - Err(e) => TokenTransferAcknowledgement::from_error(e), - }; - - let recv_event = RecvEvent { - receiver: data.receiver, - denom: data.token.denom, - amount: data.token.amount, - success: ack.is_successful(), - }; - output.emit(recv_event.into()); - - ack.into() -} - -pub fn on_acknowledgement_packet( - ctx: &mut impl TokenTransferContext, - output: &mut ModuleOutputBuilder, - packet: &Packet, - acknowledgement: &Acknowledgement, - _relayer: &Signer, -) -> Result<(), TokenTransferError> { - let data = serde_json::from_slice::(&packet.data) - .map_err(|_| TokenTransferError::PacketDataDeserialization)?; - - let acknowledgement = - serde_json::from_slice::(acknowledgement.as_ref()) - .map_err(|_| TokenTransferError::AckDeserialization)?; - - if !acknowledgement.is_successful() { - refund_packet_token(ctx, packet, &data)?; - } - - let ack_event = AckEvent { - receiver: data.receiver, - denom: data.token.denom, - amount: data.token.amount, - acknowledgement: acknowledgement.clone(), - }; - output.emit(ack_event.into()); - output.emit(AckStatusEvent { acknowledgement }.into()); - - Ok(()) -} - -pub fn on_timeout_packet( - ctx: &mut impl TokenTransferContext, - output: &mut ModuleOutputBuilder, - packet: &Packet, - _relayer: &Signer, -) -> Result<(), TokenTransferError> { - let data = serde_json::from_slice::(&packet.data) - .map_err(|_| TokenTransferError::PacketDataDeserialization)?; - - refund_packet_token(ctx, packet, &data)?; - - let timeout_event = TimeoutEvent { - refund_receiver: data.sender, - refund_denom: data.token.denom, - refund_amount: data.token.amount, - }; - output.emit(timeout_event.into()); - - Ok(()) -} - -use crate::applications::transfer::relay::{ - on_recv_packet::process_recv_packet_execute, refund_packet_token_validate, -}; - -pub use super::*; - #[allow(clippy::too_many_arguments)] pub fn on_chan_open_init_validate( - ctx: &impl TokenTransferContext, + ctx: &impl TokenTransferValidationContext, order: Order, _connection_hops: &[ConnectionId], port_id: &PortId, @@ -387,7 +124,7 @@ pub fn on_chan_open_init_validate( #[allow(clippy::too_many_arguments)] pub fn on_chan_open_init_execute( - _ctx: &mut impl TokenTransferContext, + _ctx: &mut impl TokenTransferExecutionContext, _order: Order, _connection_hops: &[ConnectionId], _port_id: &PortId, @@ -400,7 +137,7 @@ pub fn on_chan_open_init_execute( #[allow(clippy::too_many_arguments)] pub fn on_chan_open_try_validate( - _ctx: &impl TokenTransferContext, + _ctx: &impl TokenTransferValidationContext, order: Order, _connection_hops: &[ConnectionId], _port_id: &PortId, @@ -426,7 +163,7 @@ pub fn on_chan_open_try_validate( #[allow(clippy::too_many_arguments)] pub fn on_chan_open_try_execute( - _ctx: &mut impl TokenTransferContext, + _ctx: &mut impl TokenTransferExecutionContext, _order: Order, _connection_hops: &[ConnectionId], _port_id: &PortId, @@ -438,7 +175,7 @@ pub fn on_chan_open_try_execute( } pub fn on_chan_open_ack_validate( - _ctx: &impl TokenTransferContext, + _ctx: &impl TokenTransferValidationContext, _port_id: &PortId, _channel_id: &ChannelId, counterparty_version: &Version, @@ -454,7 +191,7 @@ pub fn on_chan_open_ack_validate( } pub fn on_chan_open_ack_execute( - _ctx: &mut impl TokenTransferContext, + _ctx: &mut impl TokenTransferExecutionContext, _port_id: &PortId, _channel_id: &ChannelId, _counterparty_version: &Version, @@ -463,7 +200,7 @@ pub fn on_chan_open_ack_execute( } pub fn on_chan_open_confirm_validate( - _ctx: &impl TokenTransferContext, + _ctx: &impl TokenTransferValidationContext, _port_id: &PortId, _channel_id: &ChannelId, ) -> Result<(), TokenTransferError> { @@ -471,7 +208,7 @@ pub fn on_chan_open_confirm_validate( } pub fn on_chan_open_confirm_execute( - _ctx: &mut impl TokenTransferContext, + _ctx: &mut impl TokenTransferExecutionContext, _port_id: &PortId, _channel_id: &ChannelId, ) -> Result { @@ -479,14 +216,14 @@ pub fn on_chan_open_confirm_execute( } pub fn on_chan_close_init_validate( - _ctx: &impl TokenTransferContext, + _ctx: &impl TokenTransferValidationContext, _port_id: &PortId, _channel_id: &ChannelId, ) -> Result<(), TokenTransferError> { Err(TokenTransferError::CantCloseChannel) } pub fn on_chan_close_init_execute( - _ctx: &mut impl TokenTransferContext, + _ctx: &mut impl TokenTransferExecutionContext, _port_id: &PortId, _channel_id: &ChannelId, ) -> Result { @@ -494,7 +231,7 @@ pub fn on_chan_close_init_execute( } pub fn on_chan_close_confirm_validate( - _ctx: &impl TokenTransferContext, + _ctx: &impl TokenTransferValidationContext, _port_id: &PortId, _channel_id: &ChannelId, ) -> Result<(), TokenTransferError> { @@ -502,7 +239,7 @@ pub fn on_chan_close_confirm_validate( } pub fn on_chan_close_confirm_execute( - _ctx: &mut impl TokenTransferContext, + _ctx: &mut impl TokenTransferExecutionContext, _port_id: &PortId, _channel_id: &ChannelId, ) -> Result { @@ -510,7 +247,7 @@ pub fn on_chan_close_confirm_execute( } pub fn on_recv_packet_execute( - ctx: &mut impl TokenTransferContext, + ctx: &mut impl TokenTransferExecutionContext, packet: &Packet, ) -> (ModuleExtras, Acknowledgement) { let data = match serde_json::from_slice::(&packet.data) { @@ -546,7 +283,7 @@ pub fn on_acknowledgement_packet_validate( _relayer: &Signer, ) -> Result<(), TokenTransferError> where - Ctx: TokenTransferContext, + Ctx: TokenTransferValidationContext, { let data = serde_json::from_slice::(&packet.data) .map_err(|_| TokenTransferError::PacketDataDeserialization)?; @@ -563,7 +300,7 @@ where } pub fn on_acknowledgement_packet_execute( - ctx: &mut impl TokenTransferContext, + ctx: &mut impl TokenTransferExecutionContext, packet: &Packet, acknowledgement: &Acknowledgement, _relayer: &Signer, @@ -616,7 +353,7 @@ pub fn on_timeout_packet_validate( _relayer: &Signer, ) -> Result<(), TokenTransferError> where - Ctx: TokenTransferContext, + Ctx: TokenTransferValidationContext, { let data = serde_json::from_slice::(&packet.data) .map_err(|_| TokenTransferError::PacketDataDeserialization)?; @@ -627,7 +364,7 @@ where } pub fn on_timeout_packet_execute( - ctx: &mut impl TokenTransferContext, + ctx: &mut impl TokenTransferExecutionContext, packet: &Packet, _relayer: &Signer, ) -> (ModuleExtras, Result<(), TokenTransferError>) { @@ -664,7 +401,7 @@ pub(crate) mod test { use super::*; use subtle_encoding::bech32; - use crate::applications::transfer::context::{cosmos_adr028_escrow_address, on_chan_open_try}; + use crate::applications::transfer::context::cosmos_adr028_escrow_address; use crate::applications::transfer::error::TokenTransferError; use crate::applications::transfer::msgs::transfer::MsgTransfer; use crate::applications::transfer::relay::send_transfer::send_transfer; @@ -673,17 +410,13 @@ pub(crate) mod test { use crate::core::ics04_channel::error::ChannelError; use crate::core::ics04_channel::Version; use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; - use crate::handler::HandlerOutputBuilder; use crate::test_utils::{get_dummy_transfer_module, DummyTransferModule}; - use super::on_chan_open_init; - pub(crate) fn deliver( ctx: &mut DummyTransferModule, - output: &mut HandlerOutputBuilder<()>, msg: MsgTransfer, ) -> Result<(), ChannelError> { - send_transfer(ctx, output, msg).map_err(|e: TokenTransferError| ChannelError::AppModule { + send_transfer(ctx, msg).map_err(|e: TokenTransferError| ChannelError::AppModule { description: e.to_string(), }) } @@ -751,7 +484,7 @@ pub(crate) mod test { let in_version = Version::new("".to_string()); - let (_, out_version) = on_chan_open_init( + let (_, out_version) = on_chan_open_init_execute( &mut ctx, order, &connection_hops, @@ -771,7 +504,7 @@ pub(crate) mod test { let (mut ctx, order, connection_hops, port_id, channel_id, counterparty) = get_defaults(); let in_version = Version::new(VERSION.to_string()); - let (_, out_version) = on_chan_open_init( + let (_, out_version) = on_chan_open_init_execute( &mut ctx, order, &connection_hops, @@ -788,11 +521,11 @@ pub(crate) mod test { /// If the relayer passed in an unsupported version, then fail #[test] fn test_on_chan_open_init_incorrect_version() { - let (mut ctx, order, connection_hops, port_id, channel_id, counterparty) = get_defaults(); + let (ctx, order, connection_hops, port_id, channel_id, counterparty) = get_defaults(); let in_version = Version::new("some-unsupported-version".to_string()); - let res = on_chan_open_init( - &mut ctx, + let res = on_chan_open_init_validate( + &ctx, order, &connection_hops, &port_id, @@ -811,7 +544,7 @@ pub(crate) mod test { let counterparty_version = Version::new(VERSION.to_string()); - let (_, out_version) = on_chan_open_try( + let (_, out_version) = on_chan_open_try_execute( &mut ctx, order, &connection_hops, @@ -828,12 +561,12 @@ pub(crate) mod test { /// If the counterparty doesn't support ics20, then fail #[test] fn test_on_chan_open_try_counterparty_incorrect_version() { - let (mut ctx, order, connection_hops, port_id, channel_id, counterparty) = get_defaults(); + let (ctx, order, connection_hops, port_id, channel_id, counterparty) = get_defaults(); let counterparty_version = Version::new("some-unsupported-version".to_string()); - let res = on_chan_open_try( - &mut ctx, + let res = on_chan_open_try_validate( + &ctx, order, &connection_hops, &port_id, diff --git a/crates/ibc/src/applications/transfer/relay.rs b/crates/ibc/src/applications/transfer/relay.rs index 62e6bdc148..2b5abb5140 100644 --- a/crates/ibc/src/applications/transfer/relay.rs +++ b/crates/ibc/src/applications/transfer/relay.rs @@ -1,16 +1,17 @@ //! This module implements the processing logic for ICS20 (token transfer) message. -use crate::applications::transfer::context::TokenTransferContext; use crate::applications::transfer::error::TokenTransferError; use crate::applications::transfer::is_sender_chain_source; use crate::applications::transfer::packet::PacketData; use crate::core::ics04_channel::packet::Packet; use crate::prelude::*; +use super::context::{TokenTransferExecutionContext, TokenTransferValidationContext}; + pub mod on_recv_packet; pub mod send_transfer; pub fn refund_packet_token( - ctx: &mut impl TokenTransferContext, + ctx: &mut impl TokenTransferExecutionContext, packet: &Packet, data: &PacketData, ) -> Result<(), TokenTransferError> { @@ -37,10 +38,11 @@ pub fn refund_packet_token( } } -pub fn refund_packet_token_validate( - data: &PacketData, -) -> Result<(), TokenTransferError> { - let _sender: ::AccountId = data +pub fn refund_packet_token_validate(data: &PacketData) -> Result<(), TokenTransferError> +where + Ctx: TokenTransferValidationContext, +{ + let _sender: Ctx::AccountId = data .sender .clone() .try_into() diff --git a/crates/ibc/src/applications/transfer/relay/on_recv_packet.rs b/crates/ibc/src/applications/transfer/relay/on_recv_packet.rs index f74b148ee6..f93ccd55f4 100644 --- a/crates/ibc/src/applications/transfer/relay/on_recv_packet.rs +++ b/crates/ibc/src/applications/transfer/relay/on_recv_packet.rs @@ -1,68 +1,13 @@ -use crate::applications::transfer::context::TokenTransferContext; +use crate::applications::transfer::context::TokenTransferExecutionContext; use crate::applications::transfer::error::TokenTransferError; use crate::applications::transfer::events::DenomTraceEvent; use crate::applications::transfer::packet::PacketData; use crate::applications::transfer::{is_receiver_chain_source, TracePrefix}; use crate::core::ics04_channel::handler::ModuleExtras; use crate::core::ics04_channel::packet::Packet; -use crate::core::ics26_routing::context::ModuleOutputBuilder; use crate::prelude::*; -pub fn process_recv_packet( - ctx: &mut Ctx, - output: &mut ModuleOutputBuilder, - packet: &Packet, - data: PacketData, -) -> Result<(), TokenTransferError> { - if !ctx.is_receive_enabled() { - return Err(TokenTransferError::ReceiveDisabled); - } - - let receiver_account = data - .receiver - .clone() - .try_into() - .map_err(|_| TokenTransferError::ParseAccountFailure)?; - - if is_receiver_chain_source( - packet.port_on_a.clone(), - packet.chan_on_a.clone(), - &data.token.denom, - ) { - // sender chain is not the source, unescrow tokens - let prefix = TracePrefix::new(packet.port_on_a.clone(), packet.chan_on_a.clone()); - let coin = { - let mut c = data.token; - c.denom.remove_trace_prefix(&prefix); - c - }; - - let escrow_address = - ctx.get_channel_escrow_address(&packet.port_on_b, &packet.chan_on_b)?; - - ctx.send_coins(&escrow_address, &receiver_account, &coin)?; - } else { - // sender chain is the source, mint vouchers - let prefix = TracePrefix::new(packet.port_on_b.clone(), packet.chan_on_b.clone()); - let coin = { - let mut c = data.token; - c.denom.add_trace_prefix(prefix); - c - }; - - let denom_trace_event = DenomTraceEvent { - trace_hash: ctx.denom_hash_string(&coin.denom), - denom: coin.denom.clone(), - }; - output.emit(denom_trace_event.into()); - - ctx.mint_coins(&receiver_account, &coin)?; - } - - Ok(()) -} - -pub fn process_recv_packet_execute( +pub fn process_recv_packet_execute( ctx: &mut Ctx, packet: &Packet, data: PacketData, diff --git a/crates/ibc/src/applications/transfer/relay/send_transfer.rs b/crates/ibc/src/applications/transfer/relay/send_transfer.rs index 9a5e1c8327..f13ff15b90 100644 --- a/crates/ibc/src/applications/transfer/relay/send_transfer.rs +++ b/crates/ibc/src/applications/transfer/relay/send_transfer.rs @@ -1,33 +1,112 @@ -use crate::applications::transfer::context::TokenTransferContext; +use crate::applications::transfer::context::{ + TokenTransferExecutionContext, TokenTransferValidationContext, +}; use crate::applications::transfer::error::TokenTransferError; use crate::applications::transfer::events::TransferEvent; use crate::applications::transfer::msgs::transfer::MsgTransfer; use crate::applications::transfer::packet::PacketData; use crate::applications::transfer::{is_sender_chain_source, Coin, PrefixedCoin}; -use crate::core::ics04_channel::handler::send_packet::send_packet; +use crate::core::ics04_channel::handler::send_packet::{send_packet_execute, send_packet_validate}; use crate::core::ics04_channel::packet::Packet; use crate::core::ics24_host::path::{ChannelEndPath, SeqSendPath}; use crate::events::ModuleEvent; -use crate::handler::{HandlerOutput, HandlerOutputBuilder}; use crate::prelude::*; /// This function handles the transfer sending logic. /// If this method returns an error, the runtime is expected to rollback all state modifications to /// the `Ctx` caused by all messages from the transaction that this `msg` is a part of. -pub fn send_transfer( - ctx: &mut Ctx, - output: &mut HandlerOutputBuilder<()>, +pub fn send_transfer(ctx_a: &mut Ctx, msg: MsgTransfer) -> Result<(), TokenTransferError> +where + C: TryInto + Clone, + Ctx: TokenTransferExecutionContext, +{ + send_transfer_validate(ctx_a, msg.clone())?; + send_transfer_execute(ctx_a, msg) +} + +pub fn send_transfer_validate( + ctx_a: &Ctx, msg: MsgTransfer, ) -> Result<(), TokenTransferError> where - Ctx: TokenTransferContext, C: TryInto, + Ctx: TokenTransferValidationContext, { - if !ctx.is_send_enabled() { + if !ctx_a.is_send_enabled() { return Err(TokenTransferError::SendDisabled); } + + let chan_end_path_on_a = ChannelEndPath::new(&msg.port_on_a, &msg.chan_on_a); + let chan_end_on_a = ctx_a + .channel_end(&chan_end_path_on_a) + .map_err(TokenTransferError::ContextError)?; + + let port_on_b = chan_end_on_a.counterparty().port_id().clone(); + let chan_on_b = chan_end_on_a + .counterparty() + .channel_id() + .ok_or_else(|| TokenTransferError::DestinationChannelNotFound { + port_id: msg.port_on_a.clone(), + channel_id: msg.chan_on_a.clone(), + })? + .clone(); + + let seq_send_path_on_a = SeqSendPath::new(&msg.port_on_a, &msg.chan_on_a); + let sequence = ctx_a + .get_next_sequence_send(&seq_send_path_on_a) + .map_err(TokenTransferError::ContextError)?; + + let token = msg + .token + .try_into() + .map_err(|_| TokenTransferError::InvalidToken)?; + let denom = token.denom.clone(); + let coin = Coin { + denom, + amount: token.amount, + }; + + let _sender: Ctx::AccountId = msg + .sender + .clone() + .try_into() + .map_err(|_| TokenTransferError::ParseAccountFailure)?; + + let data = { + let data = PacketData { + token: coin, + sender: msg.sender.clone(), + receiver: msg.receiver.clone(), + }; + serde_json::to_vec(&data).expect("PacketData's infallible Serialize impl failed") + }; + + let packet = Packet { + sequence, + port_on_a: msg.port_on_a, + chan_on_a: msg.chan_on_a, + port_on_b, + chan_on_b, + data, + timeout_height_on_b: msg.timeout_height_on_b, + timeout_timestamp_on_b: msg.timeout_timestamp_on_b, + }; + + send_packet_validate(ctx_a, &packet).map_err(TokenTransferError::ContextError)?; + + Ok(()) +} + +pub fn send_transfer_execute( + ctx_a: &mut Ctx, + msg: MsgTransfer, +) -> Result<(), TokenTransferError> +where + C: TryInto, + Ctx: TokenTransferExecutionContext, +{ let chan_end_path_on_a = ChannelEndPath::new(&msg.port_on_a, &msg.chan_on_a); - let chan_end_on_a = ctx + let chan_end_on_a = ctx_a .channel_end(&chan_end_path_on_a) .map_err(TokenTransferError::ContextError)?; @@ -43,7 +122,7 @@ where // get the next sequence let seq_send_path_on_a = SeqSendPath::new(&msg.port_on_a, &msg.chan_on_a); - let sequence = ctx + let sequence = ctx_a .get_next_sequence_send(&seq_send_path_on_a) .map_err(TokenTransferError::ContextError)?; @@ -64,10 +143,10 @@ where .map_err(|_| TokenTransferError::ParseAccountFailure)?; if is_sender_chain_source(msg.port_on_a.clone(), msg.chan_on_a.clone(), &denom) { - let escrow_address = ctx.get_channel_escrow_address(&msg.port_on_a, &msg.chan_on_a)?; - ctx.send_coins(&sender, &escrow_address, &coin)?; + let escrow_address = ctx_a.get_channel_escrow_address(&msg.port_on_a, &msg.chan_on_a)?; + ctx_a.send_coins(&sender, &escrow_address, &coin)?; } else { - ctx.burn_coins(&sender, &coin)?; + ctx_a.burn_coins(&sender, &coin)?; } let data = { @@ -90,32 +169,20 @@ where timeout_timestamp_on_b: msg.timeout_timestamp_on_b, }; - let HandlerOutput { - result, - log, - events, - } = send_packet(ctx, packet).map_err(TokenTransferError::ContextError)?; + send_packet_execute(ctx_a, packet).map_err(TokenTransferError::ContextError)?; - ctx.store_send_packet_result(result) - .map_err(TokenTransferError::ContextError)?; + { + ctx_a.log_message(format!( + "IBC fungible token transfer: {} --({})--> {}", + msg.sender, token, msg.receiver + )); - output.merge_output( - HandlerOutput::builder() - .with_log(log) - .with_events(events) - .with_result(()), - ); - - output.log(format!( - "IBC fungible token transfer: {} --({})--> {}", - msg.sender, token, msg.receiver - )); - - let transfer_event = TransferEvent { - sender: msg.sender, - receiver: msg.receiver, - }; - output.emit(ModuleEvent::from(transfer_event).into()); + let transfer_event = TransferEvent { + sender: msg.sender, + receiver: msg.receiver, + }; + ctx_a.emit_ibc_event(ModuleEvent::from(transfer_event).into()); + } Ok(()) } diff --git a/crates/ibc/src/core/context.rs b/crates/ibc/src/core/context.rs index e9e6fca8ad..5f06e7539d 100644 --- a/crates/ibc/src/core/context.rs +++ b/crates/ibc/src/core/context.rs @@ -356,7 +356,7 @@ pub trait ValidationContext: Router { /// `{revision_number: 0, revision_height: 0}` to be consistent with ibc-go, /// where this value is used to mean "no timeout height": /// - fn packet_commitment( + fn compute_packet_commitment( &self, packet_data: &[u8], timeout_height: &TimeoutHeight, diff --git a/crates/ibc/src/core/context/acknowledgement.rs b/crates/ibc/src/core/context/acknowledgement.rs index 95dece455c..d054a8368b 100644 --- a/crates/ibc/src/core/context/acknowledgement.rs +++ b/crates/ibc/src/core/context/acknowledgement.rs @@ -165,7 +165,7 @@ mod tests { let packet = msg.packet.clone(); - let packet_commitment = ctx.packet_commitment( + let packet_commitment = ctx.compute_packet_commitment( &msg.packet.data, &msg.packet.timeout_height_on_b, &msg.packet.timeout_timestamp_on_b, diff --git a/crates/ibc/src/core/context/timeout.rs b/crates/ibc/src/core/context/timeout.rs index 4ebc48c115..3ec5de845c 100644 --- a/crates/ibc/src/core/context/timeout.rs +++ b/crates/ibc/src/core/context/timeout.rs @@ -200,7 +200,7 @@ mod tests { let packet = msg.packet.clone(); - let packet_commitment = ctx.packet_commitment( + let packet_commitment = ctx.compute_packet_commitment( &msg.packet.data, &msg.packet.timeout_height_on_b, &msg.packet.timeout_timestamp_on_b, diff --git a/crates/ibc/src/core/handler.rs b/crates/ibc/src/core/handler.rs index a2aaf69ad5..7a7d192ba7 100644 --- a/crates/ibc/src/core/handler.rs +++ b/crates/ibc/src/core/handler.rs @@ -85,7 +85,6 @@ mod tests { use crate::core::ics26_routing::msgs::MsgEnvelope; use crate::core::{dispatch, ValidationContext}; use crate::events::IbcEvent; - use crate::handler::HandlerOutputBuilder; use crate::mock::client_state::MockClientState; use crate::mock::consensus_state::MockConsensusState; use crate::mock::context::MockContext; @@ -477,7 +476,6 @@ mod tests { .as_any_mut() .downcast_mut::() .unwrap(), - &mut HandlerOutputBuilder::new(), msg, ) .map(|_| ()) diff --git a/crates/ibc/src/core/ics04_channel/context.rs b/crates/ibc/src/core/ics04_channel/context.rs index 8bb6ae98f9..b94a13f0b8 100644 --- a/crates/ibc/src/core/ics04_channel/context.rs +++ b/crates/ibc/src/core/ics04_channel/context.rs @@ -1,8 +1,11 @@ //! ICS4 (channel) context. use crate::core::ics02_client::client_state::ClientState; -use crate::core::ics24_host::path::{ChannelEndPath, ClientConsensusStatePath, SeqSendPath}; -use crate::core::{ContextError, ValidationContext}; +use crate::core::ics24_host::path::{ + ChannelEndPath, ClientConsensusStatePath, CommitmentPath, SeqSendPath, +}; +use crate::core::{ContextError, ExecutionContext, ValidationContext}; +use crate::events::IbcEvent; use crate::prelude::*; use core::time::Duration; use num_traits::float::FloatCore; @@ -17,7 +20,7 @@ use crate::timestamp::Timestamp; use super::packet::Sequence; use super::timeout::TimeoutHeight; -pub trait SendPacketReader { +pub trait SendPacketValidationContext { /// Returns the ChannelEnd for the given `port_id` and `chan_id`. fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result; @@ -38,28 +41,15 @@ pub trait SendPacketReader { fn hash(&self, value: &[u8]) -> Vec; - fn packet_commitment( + fn compute_packet_commitment( &self, packet_data: &[u8], timeout_height: &TimeoutHeight, timeout_timestamp: &Timestamp, - ) -> PacketCommitment { - let mut hash_input = timeout_timestamp.nanoseconds().to_be_bytes().to_vec(); - - let revision_number = timeout_height.commitment_revision_number().to_be_bytes(); - hash_input.append(&mut revision_number.to_vec()); - - let revision_height = timeout_height.commitment_revision_height().to_be_bytes(); - hash_input.append(&mut revision_height.to_vec()); - - let packet_data_hash = self.hash(packet_data); - hash_input.append(&mut packet_data_hash.to_vec()); - - self.hash(&hash_input).into() - } + ) -> PacketCommitment; } -impl SendPacketReader for T +impl SendPacketValidationContext for T where T: ValidationContext, { @@ -92,6 +82,64 @@ where fn hash(&self, value: &[u8]) -> Vec { self.hash(value) } + + fn compute_packet_commitment( + &self, + packet_data: &[u8], + timeout_height: &TimeoutHeight, + timeout_timestamp: &Timestamp, + ) -> PacketCommitment { + self.compute_packet_commitment(packet_data, timeout_height, timeout_timestamp) + } +} + +pub trait SendPacketExecutionContext: SendPacketValidationContext { + fn store_next_sequence_send( + &mut self, + seq_send_path: &SeqSendPath, + seq: Sequence, + ) -> Result<(), ContextError>; + + fn store_packet_commitment( + &mut self, + commitment_path: &CommitmentPath, + commitment: PacketCommitment, + ) -> Result<(), ContextError>; + + /// Ibc events + fn emit_ibc_event(&mut self, event: IbcEvent); + + /// Logging facility + fn log_message(&mut self, message: String); +} + +impl SendPacketExecutionContext for T +where + T: ExecutionContext, +{ + fn store_next_sequence_send( + &mut self, + seq_send_path: &SeqSendPath, + seq: Sequence, + ) -> Result<(), ContextError> { + self.store_next_sequence_send(seq_send_path, seq) + } + + fn store_packet_commitment( + &mut self, + commitment_path: &CommitmentPath, + commitment: PacketCommitment, + ) -> Result<(), ContextError> { + self.store_packet_commitment(commitment_path, commitment) + } + + fn emit_ibc_event(&mut self, event: IbcEvent) { + self.emit_ibc_event(event) + } + + fn log_message(&mut self, message: String) { + self.log_message(message) + } } pub fn calculate_block_delay( diff --git a/crates/ibc/src/core/ics04_channel/handler/acknowledgement.rs b/crates/ibc/src/core/ics04_channel/handler/acknowledgement.rs index 309fdbfe6f..78689a3468 100644 --- a/crates/ibc/src/core/ics04_channel/handler/acknowledgement.rs +++ b/crates/ibc/src/core/ics04_channel/handler/acknowledgement.rs @@ -61,7 +61,7 @@ where }; if commitment_on_a - != ctx_a.packet_commitment( + != ctx_a.compute_packet_commitment( &packet.data, &packet.timeout_height_on_b, &packet.timeout_timestamp_on_b, @@ -168,7 +168,7 @@ mod tests { .unwrap(); let packet = msg.packet.clone(); - let packet_commitment = context.packet_commitment( + let packet_commitment = context.compute_packet_commitment( &packet.data, &packet.timeout_height_on_b, &packet.timeout_timestamp_on_b, diff --git a/crates/ibc/src/core/ics04_channel/handler/recv_packet.rs b/crates/ibc/src/core/ics04_channel/handler/recv_packet.rs index 62c67d5692..cfdce180cd 100644 --- a/crates/ibc/src/core/ics04_channel/handler/recv_packet.rs +++ b/crates/ibc/src/core/ics04_channel/handler/recv_packet.rs @@ -79,7 +79,7 @@ where ClientConsensusStatePath::new(client_id_on_b, &msg.proof_height_on_a); let consensus_state_of_a_on_b = ctx_b.consensus_state(&client_cons_state_path_on_b)?; - let expected_commitment_on_a = ctx_b.packet_commitment( + let expected_commitment_on_a = ctx_b.compute_packet_commitment( &msg.packet.data, &msg.packet.timeout_height_on_b, &msg.packet.timeout_timestamp_on_b, diff --git a/crates/ibc/src/core/ics04_channel/handler/send_packet.rs b/crates/ibc/src/core/ics04_channel/handler/send_packet.rs index fa25bb77e2..5811d00976 100644 --- a/crates/ibc/src/core/ics04_channel/handler/send_packet.rs +++ b/crates/ibc/src/core/ics04_channel/handler/send_packet.rs @@ -1,41 +1,39 @@ use crate::core::ics04_channel::channel::Counterparty; use crate::core::ics04_channel::channel::State; -use crate::core::ics04_channel::commitment::PacketCommitment; +use crate::core::ics04_channel::context::SendPacketExecutionContext; use crate::core::ics04_channel::events::SendPacket; -use crate::core::ics04_channel::packet::Sequence; -use crate::core::ics04_channel::{context::SendPacketReader, error::PacketError, packet::Packet}; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::core::ics04_channel::{ + context::SendPacketValidationContext, error::PacketError, packet::Packet, +}; use crate::core::ics24_host::path::ChannelEndPath; use crate::core::ics24_host::path::ClientConsensusStatePath; +use crate::core::ics24_host::path::CommitmentPath; use crate::core::ics24_host::path::SeqSendPath; use crate::core::ContextError; use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; use crate::prelude::*; use crate::timestamp::Expiry; -#[derive(Clone, Debug)] -pub struct SendPacketResult { - pub port_id: PortId, - pub channel_id: ChannelId, - pub seq: Sequence, - pub seq_number: Sequence, - pub commitment: PacketCommitment, -} - /// Per our convention, this message is processed on chain A. pub fn send_packet( - ctx_a: &impl SendPacketReader, + ctx_a: &mut impl SendPacketExecutionContext, packet: Packet, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); +) -> Result<(), ContextError> { + send_packet_validate(ctx_a, &packet)?; + send_packet_execute(ctx_a, packet) +} +/// Per our convention, this message is processed on chain A. +pub fn send_packet_validate( + ctx_a: &impl SendPacketValidationContext, + packet: &Packet, +) -> Result<(), ContextError> { let chan_end_path_on_a = ChannelEndPath::new(&packet.port_on_a, &packet.chan_on_a); let chan_end_on_a = ctx_a.channel_end(&chan_end_path_on_a)?; if chan_end_on_a.state_matches(&State::Closed) { return Err(PacketError::ChannelClosed { - channel_id: packet.chan_on_a, + channel_id: packet.chan_on_a.clone(), } .into()); } @@ -45,7 +43,7 @@ pub fn send_packet( if !chan_end_on_a.counterparty_matches(&counterparty) { return Err(PacketError::InvalidPacketCounterparty { port_id: packet.port_on_b.clone(), - channel_id: packet.chan_on_b, + channel_id: packet.chan_on_b.clone(), } .into()); } @@ -94,27 +92,45 @@ pub fn send_packet( .into()); } - output.log("success: packet send "); + Ok(()) +} + +/// Per our convention, this message is processed on chain A. +pub fn send_packet_execute( + ctx_a: &mut impl SendPacketExecutionContext, + packet: Packet, +) -> Result<(), ContextError> { + { + let seq_send_path_on_a = SeqSendPath::new(&packet.port_on_a, &packet.chan_on_a); + let next_seq_send_on_a = ctx_a.get_next_sequence_send(&seq_send_path_on_a)?; + + ctx_a.store_next_sequence_send(&seq_send_path_on_a, next_seq_send_on_a.increment())?; + } - let result = SendPacketResult { - port_id: packet.port_on_a.clone(), - channel_id: packet.chan_on_a.clone(), - seq: packet.sequence, - seq_number: next_seq_send_on_a.increment(), - commitment: ctx_a.packet_commitment( + ctx_a.store_packet_commitment( + &CommitmentPath::new(&packet.port_on_a, &packet.chan_on_a, packet.sequence), + ctx_a.compute_packet_commitment( &packet.data, &packet.timeout_height_on_b, &packet.timeout_timestamp_on_b, ), - }; - - output.emit(IbcEvent::SendPacket(SendPacket::new( - packet, - chan_end_on_a.ordering, - conn_id_on_a.clone(), - ))); + )?; + + // emit events and logs + { + let chan_end_path_on_a = ChannelEndPath::new(&packet.port_on_a, &packet.chan_on_a); + let chan_end_on_a = ctx_a.channel_end(&chan_end_path_on_a)?; + let conn_id_on_a = &chan_end_on_a.connection_hops()[0]; + + ctx_a.log_message("success: packet send".to_string()); + ctx_a.emit_ibc_event(IbcEvent::SendPacket(SendPacket::new( + packet, + chan_end_on_a.ordering, + conn_id_on_a.clone(), + ))); + } - Ok(output.with_result(result)) + Ok(()) } #[cfg(test)] @@ -269,11 +285,11 @@ mod tests { .into_iter() .collect(); - for test in tests { - let res = send_packet(&test.ctx, test.packet.clone()); + for mut test in tests { + let res = send_packet(&mut test.ctx, test.packet.clone()); // Additionally check the events and the output objects in the result. match res { - Ok(proto_output) => { + Ok(()) => { assert!( test.want_pass, "send_packet: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", @@ -282,10 +298,10 @@ mod tests { test.ctx.clone() ); - assert!(!proto_output.events.is_empty()); // Some events must exist. + assert!(!test.ctx.events.is_empty()); // Some events must exist. // TODO: The object in the output is a PacketResult what can we check on it? - for e in proto_output.events.iter() { + for e in test.ctx.events.iter() { assert!(matches!(e, &IbcEvent::SendPacket(_))); } } diff --git a/crates/ibc/src/core/ics04_channel/handler/timeout.rs b/crates/ibc/src/core/ics04_channel/handler/timeout.rs index 095d82dcdb..d7e39aac0c 100644 --- a/crates/ibc/src/core/ics04_channel/handler/timeout.rs +++ b/crates/ibc/src/core/ics04_channel/handler/timeout.rs @@ -59,7 +59,7 @@ where Err(_) => return Ok(()), }; - let expected_commitment_on_a = ctx_a.packet_commitment( + let expected_commitment_on_a = ctx_a.compute_packet_commitment( &msg.packet.data, &msg.packet.timeout_height_on_b, &msg.packet.timeout_timestamp_on_b, @@ -196,7 +196,7 @@ mod tests { .unwrap(); let packet = msg.packet.clone(); - let packet_commitment = context.packet_commitment( + let packet_commitment = context.compute_packet_commitment( &msg.packet.data, &msg.packet.timeout_height_on_b, &msg.packet.timeout_timestamp_on_b, diff --git a/crates/ibc/src/core/ics04_channel/handler/timeout_on_close.rs b/crates/ibc/src/core/ics04_channel/handler/timeout_on_close.rs index 650d2684fa..a9e15df60a 100644 --- a/crates/ibc/src/core/ics04_channel/handler/timeout_on_close.rs +++ b/crates/ibc/src/core/ics04_channel/handler/timeout_on_close.rs @@ -44,7 +44,7 @@ where Err(_) => return Ok(()), }; - let expected_commitment_on_a = ctx_a.packet_commitment( + let expected_commitment_on_a = ctx_a.compute_packet_commitment( &packet.data, &packet.timeout_height_on_b, &packet.timeout_timestamp_on_b, @@ -204,7 +204,7 @@ mod tests { let packet = msg.packet.clone(); - let packet_commitment = context.packet_commitment( + let packet_commitment = context.compute_packet_commitment( &msg.packet.data, &msg.packet.timeout_height_on_b, &msg.packet.timeout_timestamp_on_b, diff --git a/crates/ibc/src/core/ics26_routing/context.rs b/crates/ibc/src/core/ics26_routing/context.rs index 8c346b06e5..78dc2e3e68 100644 --- a/crates/ibc/src/core/ics26_routing/context.rs +++ b/crates/ibc/src/core/ics26_routing/context.rs @@ -14,8 +14,6 @@ use crate::core::ics04_channel::msgs::acknowledgement::Acknowledgement; use crate::core::ics04_channel::packet::Packet; use crate::core::ics04_channel::Version; use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::events::ModuleEvent; -use crate::handler::HandlerOutputBuilder; use crate::signer::Signer; #[derive(Debug, PartialEq, Eq)] @@ -67,8 +65,6 @@ impl Borrow for ModuleId { } } -pub type ModuleOutputBuilder = HandlerOutputBuilder<(), ModuleEvent>; - pub trait Module: Send + Sync + AsAnyMut + Debug { #[allow(clippy::too_many_arguments)] fn on_chan_open_init_validate( @@ -92,17 +88,6 @@ pub trait Module: Send + Sync + AsAnyMut + Debug { version: &Version, ) -> Result<(ModuleExtras, Version), ChannelError>; - #[allow(clippy::too_many_arguments)] - fn on_chan_open_init( - &mut self, - order: Order, - connection_hops: &[ConnectionId], - port_id: &PortId, - channel_id: &ChannelId, - counterparty: &Counterparty, - version: &Version, - ) -> Result<(ModuleExtras, Version), ChannelError>; - #[allow(clippy::too_many_arguments)] fn on_chan_open_try_validate( &self, @@ -125,17 +110,6 @@ pub trait Module: Send + Sync + AsAnyMut + Debug { counterparty_version: &Version, ) -> Result<(ModuleExtras, Version), ChannelError>; - #[allow(clippy::too_many_arguments)] - fn on_chan_open_try( - &mut self, - order: Order, - connection_hops: &[ConnectionId], - port_id: &PortId, - channel_id: &ChannelId, - counterparty: &Counterparty, - counterparty_version: &Version, - ) -> Result<(ModuleExtras, Version), ChannelError>; - fn on_chan_open_ack_validate( &self, _port_id: &PortId, @@ -154,15 +128,6 @@ pub trait Module: Send + Sync + AsAnyMut + Debug { Ok(ModuleExtras::empty()) } - fn on_chan_open_ack( - &mut self, - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty_version: &Version, - ) -> Result { - Ok(ModuleExtras::empty()) - } - fn on_chan_open_confirm_validate( &self, _port_id: &PortId, @@ -179,14 +144,6 @@ pub trait Module: Send + Sync + AsAnyMut + Debug { Ok(ModuleExtras::empty()) } - fn on_chan_open_confirm( - &mut self, - _port_id: &PortId, - _channel_id: &ChannelId, - ) -> Result { - Ok(ModuleExtras::empty()) - } - fn on_chan_close_init_validate( &self, _port_id: &PortId, @@ -203,14 +160,6 @@ pub trait Module: Send + Sync + AsAnyMut + Debug { Ok(ModuleExtras::empty()) } - fn on_chan_close_init( - &mut self, - _port_id: &PortId, - _channel_id: &ChannelId, - ) -> Result { - Ok(ModuleExtras::empty()) - } - fn on_chan_close_confirm_validate( &self, _port_id: &PortId, @@ -227,27 +176,12 @@ pub trait Module: Send + Sync + AsAnyMut + Debug { Ok(ModuleExtras::empty()) } - fn on_chan_close_confirm( - &mut self, - _port_id: &PortId, - _channel_id: &ChannelId, - ) -> Result { - Ok(ModuleExtras::empty()) - } - fn on_recv_packet_execute( &mut self, packet: &Packet, relayer: &Signer, ) -> (ModuleExtras, Acknowledgement); - fn on_recv_packet( - &mut self, - _output: &mut ModuleOutputBuilder, - _packet: &Packet, - _relayer: &Signer, - ) -> Acknowledgement; - fn on_acknowledgement_packet_validate( &self, _packet: &Packet, @@ -262,16 +196,6 @@ pub trait Module: Send + Sync + AsAnyMut + Debug { _relayer: &Signer, ) -> (ModuleExtras, Result<(), PacketError>); - fn on_acknowledgement_packet( - &mut self, - _output: &mut ModuleOutputBuilder, - _packet: &Packet, - _acknowledgement: &Acknowledgement, - _relayer: &Signer, - ) -> Result<(), PacketError> { - Ok(()) - } - /// Note: `MsgTimeout` and `MsgTimeoutOnClose` use the same callback fn on_timeout_packet_validate( @@ -287,15 +211,6 @@ pub trait Module: Send + Sync + AsAnyMut + Debug { packet: &Packet, relayer: &Signer, ) -> (ModuleExtras, Result<(), PacketError>); - - fn on_timeout_packet( - &mut self, - _output: &mut ModuleOutputBuilder, - _packet: &Packet, - _relayer: &Signer, - ) -> Result<(), PacketError> { - Ok(()) - } } pub trait AsAnyMut: Any { diff --git a/crates/ibc/src/mock/context.rs b/crates/ibc/src/mock/context.rs index 18ea08c7e7..6f6dd85343 100644 --- a/crates/ibc/src/mock/context.rs +++ b/crates/ibc/src/mock/context.rs @@ -1407,7 +1407,7 @@ mod tests { use crate::core::ics04_channel::Version; use crate::core::ics24_host::identifier::ChainId; use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; - use crate::core::ics26_routing::context::{Module, ModuleId, ModuleOutputBuilder}; + use crate::core::ics26_routing::context::{Module, ModuleId}; use crate::mock::context::MockContext; use crate::mock::host::HostType; use crate::signer::Signer; @@ -1585,18 +1585,6 @@ mod tests { Ok((ModuleExtras::empty(), version.clone())) } - fn on_chan_open_init( - &mut self, - _order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - version: &Version, - ) -> Result<(ModuleExtras, Version), ChannelError> { - Ok((ModuleExtras::empty(), version.clone())) - } - fn on_chan_open_try_validate( &self, _order: Order, @@ -1621,18 +1609,6 @@ mod tests { Ok((ModuleExtras::empty(), counterparty_version.clone())) } - fn on_chan_open_try( - &mut self, - _order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - counterparty_version: &Version, - ) -> Result<(ModuleExtras, Version), ChannelError> { - Ok((ModuleExtras::empty(), counterparty_version.clone())) - } - fn on_recv_packet_execute( &mut self, _packet: &Packet, @@ -1646,17 +1622,6 @@ mod tests { ) } - fn on_recv_packet( - &mut self, - _output: &mut ModuleOutputBuilder, - _packet: &Packet, - _relayer: &Signer, - ) -> Acknowledgement { - self.counter += 1; - - Acknowledgement::try_from(vec![1u8]).unwrap() - } - fn on_timeout_packet_validate( &self, _packet: &Packet, @@ -1720,18 +1685,6 @@ mod tests { Ok((ModuleExtras::empty(), version.clone())) } - fn on_chan_open_init( - &mut self, - _order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - version: &Version, - ) -> Result<(ModuleExtras, Version), ChannelError> { - Ok((ModuleExtras::empty(), version.clone())) - } - fn on_chan_open_try_validate( &self, _order: Order, @@ -1756,18 +1709,6 @@ mod tests { Ok((ModuleExtras::empty(), counterparty_version.clone())) } - fn on_chan_open_try( - &mut self, - _order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - counterparty_version: &Version, - ) -> Result<(ModuleExtras, Version), ChannelError> { - Ok((ModuleExtras::empty(), counterparty_version.clone())) - } - fn on_recv_packet_execute( &mut self, _packet: &Packet, @@ -1779,15 +1720,6 @@ mod tests { ) } - fn on_recv_packet( - &mut self, - _output: &mut ModuleOutputBuilder, - _packet: &Packet, - _relayer: &Signer, - ) -> Acknowledgement { - Acknowledgement::try_from(vec![1u8]).unwrap() - } - fn on_timeout_packet_validate( &self, _packet: &Packet, @@ -1837,8 +1769,7 @@ mod tests { let mut on_recv_packet_result = |module_id: &'static str| { let module_id = ModuleId::from_str(module_id).unwrap(); let m = ctx.get_route_mut(&module_id).unwrap(); - let result = m.on_recv_packet( - &mut ModuleOutputBuilder::new(), + let result = m.on_recv_packet_execute( &Packet::default(), &get_dummy_bech32_account().parse().unwrap(), ); diff --git a/crates/ibc/src/test_utils.rs b/crates/ibc/src/test_utils.rs index acecd65c28..40576d5ace 100644 --- a/crates/ibc/src/test_utils.rs +++ b/crates/ibc/src/test_utils.rs @@ -5,8 +5,7 @@ use subtle_encoding::bech32; use tendermint::{block, consensus, evidence, public_key::Algorithm}; use crate::applications::transfer::context::{ - cosmos_adr028_escrow_address, BankKeeper, TokenTransferContext, TokenTransferKeeper, - TokenTransferReader, + cosmos_adr028_escrow_address, TokenTransferExecutionContext, TokenTransferValidationContext, }; use crate::applications::transfer::{error::TokenTransferError, PrefixedCoin}; use crate::core::ics02_client::client_state::ClientState; @@ -16,16 +15,21 @@ use crate::core::ics03_connection::connection::ConnectionEnd; use crate::core::ics03_connection::error::ConnectionError; use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order}; use crate::core::ics04_channel::commitment::PacketCommitment; -use crate::core::ics04_channel::context::SendPacketReader; +use crate::core::ics04_channel::context::{ + SendPacketExecutionContext, SendPacketValidationContext, +}; use crate::core::ics04_channel::error::{ChannelError, PacketError}; use crate::core::ics04_channel::handler::ModuleExtras; use crate::core::ics04_channel::msgs::acknowledgement::Acknowledgement; use crate::core::ics04_channel::packet::{Packet, Sequence}; use crate::core::ics04_channel::Version; use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; -use crate::core::ics24_host::path::{ChannelEndPath, ClientConsensusStatePath, SeqSendPath}; -use crate::core::ics26_routing::context::{Module, ModuleOutputBuilder}; +use crate::core::ics24_host::path::{ + ChannelEndPath, ClientConsensusStatePath, CommitmentPath, SeqSendPath, +}; +use crate::core::ics26_routing::context::Module; use crate::core::ContextError; +use crate::events::IbcEvent; use crate::mock::context::MockIbcStore; use crate::prelude::*; use crate::signer::Signer; @@ -105,24 +109,6 @@ impl Module for DummyTransferModule { Ok((ModuleExtras::empty(), version.clone())) } - fn on_chan_open_init( - &mut self, - _order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - version: &Version, - ) -> Result<(ModuleExtras, Version), ChannelError> { - Ok(( - ModuleExtras { - events: Vec::new(), - log: Vec::new(), - }, - version.clone(), - )) - } - fn on_chan_open_try_validate( &self, _order: Order, @@ -147,24 +133,6 @@ impl Module for DummyTransferModule { Ok((ModuleExtras::empty(), counterparty_version.clone())) } - fn on_chan_open_try( - &mut self, - _order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - counterparty_version: &Version, - ) -> Result<(ModuleExtras, Version), ChannelError> { - Ok(( - ModuleExtras { - events: Vec::new(), - log: Vec::new(), - }, - counterparty_version.clone(), - )) - } - fn on_recv_packet_execute( &mut self, _packet: &Packet, @@ -176,15 +144,6 @@ impl Module for DummyTransferModule { ) } - fn on_recv_packet( - &mut self, - _output: &mut ModuleOutputBuilder, - _packet: &Packet, - _relayer: &Signer, - ) -> Acknowledgement { - Acknowledgement::try_from(vec![1u8]).unwrap() - } - fn on_timeout_packet_validate( &self, _packet: &Packet, @@ -220,44 +179,32 @@ impl Module for DummyTransferModule { } } -impl TokenTransferKeeper for DummyTransferModule { - fn store_packet_commitment( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - commitment: PacketCommitment, - ) -> Result<(), ContextError> { - self.ibc_store - .lock() - .packet_commitment - .entry(port_id) - .or_default() - .entry(channel_id) - .or_default() - .insert(seq, commitment); - Ok(()) +impl TokenTransferValidationContext for DummyTransferModule { + type AccountId = Signer; + + fn get_port(&self) -> Result { + Ok(PortId::transfer()) } - fn store_next_sequence_send( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - ) -> Result<(), ContextError> { - self.ibc_store - .lock() - .next_sequence_send - .entry(port_id) - .or_default() - .insert(channel_id, seq); - Ok(()) + fn get_channel_escrow_address( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result { + let addr = cosmos_adr028_escrow_address(port_id, channel_id); + Ok(bech32::encode("cosmos", addr).parse().unwrap()) } -} -impl BankKeeper for DummyTransferModule { - type AccountId = Signer; + fn is_send_enabled(&self) -> bool { + true + } + fn is_receive_enabled(&self) -> bool { + true + } +} + +impl TokenTransferExecutionContext for DummyTransferModule { fn send_coins( &mut self, _from: &Self::AccountId, @@ -284,32 +231,7 @@ impl BankKeeper for DummyTransferModule { } } -impl TokenTransferReader for DummyTransferModule { - type AccountId = Signer; - - fn get_port(&self) -> Result { - Ok(PortId::transfer()) - } - - fn get_channel_escrow_address( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result<::AccountId, TokenTransferError> { - let addr = cosmos_adr028_escrow_address(port_id, channel_id); - Ok(bech32::encode("cosmos", addr).parse().unwrap()) - } - - fn is_send_enabled(&self) -> bool { - true - } - - fn is_receive_enabled(&self) -> bool { - true - } -} - -impl SendPacketReader for DummyTransferModule { +impl SendPacketValidationContext for DummyTransferModule { fn channel_end(&self, chan_end_path: &ChannelEndPath) -> Result { match self .ibc_store @@ -409,8 +331,67 @@ impl SendPacketReader for DummyTransferModule { sha2::Sha256::digest(value).to_vec() } + + fn compute_packet_commitment( + &self, + packet_data: &[u8], + timeout_height: &crate::core::ics04_channel::timeout::TimeoutHeight, + timeout_timestamp: &crate::timestamp::Timestamp, + ) -> PacketCommitment { + let mut hash_input = timeout_timestamp.nanoseconds().to_be_bytes().to_vec(); + + let revision_number = timeout_height.commitment_revision_number().to_be_bytes(); + hash_input.append(&mut revision_number.to_vec()); + + let revision_height = timeout_height.commitment_revision_height().to_be_bytes(); + hash_input.append(&mut revision_height.to_vec()); + + let packet_data_hash = self.hash(packet_data); + hash_input.append(&mut packet_data_hash.to_vec()); + + self.hash(&hash_input).into() + } } -impl TokenTransferContext for DummyTransferModule { - type AccountId = Signer; +impl SendPacketExecutionContext for DummyTransferModule { + fn store_packet_commitment( + &mut self, + commitment_path: &CommitmentPath, + commitment: PacketCommitment, + ) -> Result<(), ContextError> { + let port_id = commitment_path.port_id.clone(); + let channel_id = commitment_path.channel_id.clone(); + let seq = commitment_path.sequence; + + self.ibc_store + .lock() + .packet_commitment + .entry(port_id) + .or_default() + .entry(channel_id) + .or_default() + .insert(seq, commitment); + Ok(()) + } + + fn store_next_sequence_send( + &mut self, + seq_send_path: &SeqSendPath, + seq: Sequence, + ) -> Result<(), ContextError> { + let port_id = seq_send_path.0.clone(); + let channel_id = seq_send_path.1.clone(); + + self.ibc_store + .lock() + .next_sequence_send + .entry(port_id) + .or_default() + .insert(channel_id, seq); + Ok(()) + } + + fn emit_ibc_event(&mut self, _event: IbcEvent) {} + + fn log_message(&mut self, _message: String) {} }