Skip to content

Commit

Permalink
Merge pull request #1513 from CosmWasm/add-Never
Browse files Browse the repository at this point in the history
Add Never type to avoid ibc_packet_receive errors
  • Loading branch information
webmaster128 authored Jan 4, 2023
2 parents 45a122f + 2b8c553 commit d6f5dfc
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 26 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,16 @@ and this project adheres to
- cosmwasm-std: Implement `AsRef<[u8]>` for `Binary` and `HexBinary` ([#1550]).
- cosmwasm-std: Allow constructing `SupplyResponse` via a `Default`
implementation ([#1552], [#1560]).
- cosmwasm-std: Add `Never` type which cannot be instantiated. This can be used
as the error type for `ibc_packet_receive` or `ibc_packet_ack` to gain
confidence that the implementations never errors and the transaction does not
get reverted. ([#1513])

[#1436]: https://github.com/CosmWasm/cosmwasm/issues/1436
[#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437
[#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481
[#1478]: https://github.com/CosmWasm/cosmwasm/pull/1478
[#1513]: https://github.com/CosmWasm/cosmwasm/pull/1513
[#1533]: https://github.com/CosmWasm/cosmwasm/pull/1533
[#1550]: https://github.com/CosmWasm/cosmwasm/issues/1550
[#1552]: https://github.com/CosmWasm/cosmwasm/pull/1552
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
4 changes: 2 additions & 2 deletions contracts/ibc-reflect-send/src/ibc.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use cosmwasm_std::{
entry_point, from_slice, to_binary, DepsMut, Env, IbcBasicResponse, IbcChannelCloseMsg,
IbcChannelConnectMsg, IbcChannelOpenMsg, IbcMsg, IbcOrder, IbcPacketAckMsg,
IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, StdError, StdResult,
IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, Never, StdError, StdResult,
};

use crate::ibc_msg::{
Expand Down 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
27 changes: 27 additions & 0 deletions packages/std/src/never.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/// 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.
///
/// In contrast to `Empty`, this does not have a JSON schema
/// and cannot be used for message and query types.
///
/// Once the ! type is stable, this is not needed anymore.
/// See <https://github.com/rust-lang/rust/issues/35121>.
pub enum Never {}

// The Debug implementation is needed to allow the use of `Result::unwrap`.
impl core::fmt::Debug for Never {
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// Unreachable because no instance of Never can exist
match *self {}
}
}

// The Display implementation is needed to fulfill the ToString requirement of
// entry point errors: `Result<IbcReceiveResponse<C>, E>` with `E: ToString`.
impl core::fmt::Display for Never {
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// Unreachable because no instance of Never can exist
match *self {}
}
}

0 comments on commit d6f5dfc

Please sign in to comment.