Skip to content

Commit

Permalink
Add Never type for to avoid ibc_packet_receive errors
Browse files Browse the repository at this point in the history
  • Loading branch information
webmaster128 committed Nov 23, 2022
1 parent 2c9312f commit 177a36a
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 25 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ and this project adheres to
predictable addresses for `MsgInstantiateContract2` ([#1437]).
- cosmwasm-schema: In contracts, `cosmwasm schema` will now output a separate
JSON Schema file for each entrypoint in the `raw` subdirectory.
- cosmwasm-std: Add `Never` type which cannot be instantiated. This can be used
as the error type for the `ibc_packet_receive` to gain confidence that the
implementations never errors and the transaction does not get reverted.

[#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437
[#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481
Expand Down
52 changes: 30 additions & 22 deletions IBC.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,9 @@ pub fn ibc_packet_receive(
deps: DepsMut,
env: Env,
msg: IbcPacketReceiveMsg,
) -> StdResult<IbcReceiveResponse> { }
) -> Result<IbcReceiveResponse, Never> {
// ...
}
```

This is a very special entry point as it has a unique workflow. (Please see the
Expand Down Expand Up @@ -350,27 +352,33 @@ produced 3 suggestions on how to handle errors and rollbacks _inside
[main dispatch loop in `ibc-reflect`](https://github.com/CosmWasm/cosmwasm/blob/cd784cd1148ee395574f3e564f102d0d7b5adcc3/contracts/ibc-reflect/src/contract.rs#L217-L248):

```rust
(|| {
// which local channel did this packet come on
let caller = packet.dest.channel_id;
let msg: PacketMsg = from_slice(&packet.data)?;
match msg {
PacketMsg::Dispatch { msgs } => receive_dispatch(deps, caller, msgs),
PacketMsg::WhoAmI {} => receive_who_am_i(deps, caller),
PacketMsg::Balances {} => receive_balances(deps, caller),
}
})()
.or_else(|e| {
// we try to capture all app-level errors and convert them into
// acknowledgement packets that contain an error code.
let acknowledgement = encode_ibc_error(format!("invalid packet: {}", e));
Ok(IbcReceiveResponse {
acknowledgement,
submessages: vec![],
messages: vec![],
attributes: vec![],
})
})
pub fn ibc_packet_receive(
deps: DepsMut,
_env: Env,
msg: IbcPacketReceiveMsg,
) -> Result<IbcReceiveResponse, Never> {
(|| {
// which local channel did this packet come on
let caller = packet.dest.channel_id;
let msg: PacketMsg = from_slice(&packet.data)?;
match msg {
PacketMsg::Dispatch { msgs } => receive_dispatch(deps, caller, msgs),
PacketMsg::WhoAmI {} => receive_who_am_i(deps, caller),
PacketMsg::Balances {} => receive_balances(deps, caller),
}
})()
.or_else(|e| {
// we try to capture all app-level errors and convert them into
// acknowledgement packets that contain an error code.
let acknowledgement = encode_ibc_error(format!("invalid packet: {}", e));
Ok(IbcReceiveResponse {
acknowledgement,
submessages: vec![],
messages: vec![],
attributes: vec![],
})
})
}
```

2. If we modify state with an external call, we need to wrap it in a
Expand Down
2 changes: 1 addition & 1 deletion contracts/ibc-reflect-send/src/ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub fn ibc_packet_receive(
_deps: DepsMut,
_env: Env,
_packet: IbcPacketReceiveMsg,
) -> StdResult<IbcReceiveResponse> {
) -> Result<IbcReceiveResponse, Never> {
Ok(IbcReceiveResponse::new()
.set_ack(b"{}")
.add_attribute("action", "ibc_packet_ack"))
Expand Down
4 changes: 2 additions & 2 deletions contracts/ibc-reflect/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use cosmwasm_std::{
entry_point, from_slice, to_binary, wasm_execute, BankMsg, Binary, CosmosMsg, Deps, DepsMut,
Empty, Env, Event, Ibc3ChannelOpenResponse, IbcBasicResponse, IbcChannelCloseMsg,
IbcChannelConnectMsg, IbcChannelOpenMsg, IbcChannelOpenResponse, IbcOrder, IbcPacketAckMsg,
IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Order,
IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Never, Order,
QueryResponse, Reply, Response, StdError, StdResult, SubMsg, SubMsgResponse, SubMsgResult,
WasmMsg,
};
Expand Down Expand Up @@ -233,7 +233,7 @@ pub fn ibc_packet_receive(
deps: DepsMut,
_env: Env,
msg: IbcPacketReceiveMsg,
) -> StdResult<IbcReceiveResponse> {
) -> Result<IbcReceiveResponse, Never> {
// put this in a closure so we can convert all error responses into acknowledgements
(|| {
let packet = msg.packet;
Expand Down
2 changes: 2 additions & 0 deletions packages/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod import_helpers;
#[cfg(feature = "iterator")]
mod iterator;
mod math;
mod never;
mod panic;
mod query;
mod results;
Expand Down Expand Up @@ -48,6 +49,7 @@ pub use crate::math::{
Decimal, Decimal256, Decimal256RangeExceeded, DecimalRangeExceeded, Fraction, Isqrt, Uint128,
Uint256, Uint512, Uint64,
};
pub use crate::never::Never;
#[cfg(feature = "cosmwasm_1_1")]
pub use crate::query::SupplyResponse;
pub use crate::query::{
Expand Down
21 changes: 21 additions & 0 deletions packages/std/src/never.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// Never can never be instantiated. This can be used in places
/// where we want to ensure that no error is returned, such as
/// the `ibc_packet_receive` entry point.
///
/// Once the ! type is stable, this is not needed anymore.
/// See <https://github.com/rust-lang/rust/issues/35121>.
pub enum Never {}

impl core::fmt::Debug for Never {
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// This is unreachable because no instance of Never can exist
unreachable!()
}
}

impl core::fmt::Display for Never {
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// This is unreachable because no instance of Never can exist
unreachable!()
}
}

0 comments on commit 177a36a

Please sign in to comment.