Skip to content

Commit 2c10355

Browse files
committed
Add Never type for to avoid ibc_packet_receive errors
1 parent 45a122f commit 2c10355

File tree

6 files changed

+60
-26
lines changed

6 files changed

+60
-26
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ and this project adheres to
2525
- cosmwasm-std: Implement `AsRef<[u8]>` for `Binary` and `HexBinary` ([#1550]).
2626
- cosmwasm-std: Allow constructing `SupplyResponse` via a `Default`
2727
implementation ([#1552], [#1560]).
28+
- cosmwasm-std: Add `Never` type which cannot be instantiated. This can be used
29+
as the error type for the `ibc_packet_receive` to gain confidence that the
30+
implementations never errors and the transaction does not get reverted.
2831

2932
[#1436]: https://github.com/CosmWasm/cosmwasm/issues/1436
3033
[#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437

IBC.md

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,9 @@ pub fn ibc_packet_receive(
264264
deps: DepsMut,
265265
env: Env,
266266
msg: IbcPacketReceiveMsg,
267-
) -> StdResult<IbcReceiveResponse> { }
267+
) -> Result<IbcReceiveResponse, Never> {
268+
// ...
269+
}
268270
```
269271

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

352354
```rust
353-
(|| {
354-
// which local channel did this packet come on
355-
let caller = packet.dest.channel_id;
356-
let msg: PacketMsg = from_slice(&packet.data)?;
357-
match msg {
358-
PacketMsg::Dispatch { msgs } => receive_dispatch(deps, caller, msgs),
359-
PacketMsg::WhoAmI {} => receive_who_am_i(deps, caller),
360-
PacketMsg::Balances {} => receive_balances(deps, caller),
361-
}
362-
})()
363-
.or_else(|e| {
364-
// we try to capture all app-level errors and convert them into
365-
// acknowledgement packets that contain an error code.
366-
let acknowledgement = encode_ibc_error(format!("invalid packet: {}", e));
367-
Ok(IbcReceiveResponse {
368-
acknowledgement,
369-
submessages: vec![],
370-
messages: vec![],
371-
attributes: vec![],
372-
})
373-
})
355+
pub fn ibc_packet_receive(
356+
deps: DepsMut,
357+
_env: Env,
358+
msg: IbcPacketReceiveMsg,
359+
) -> Result<IbcReceiveResponse, Never> {
360+
(|| {
361+
// which local channel did this packet come on
362+
let caller = packet.dest.channel_id;
363+
let msg: PacketMsg = from_slice(&packet.data)?;
364+
match msg {
365+
PacketMsg::Dispatch { msgs } => receive_dispatch(deps, caller, msgs),
366+
PacketMsg::WhoAmI {} => receive_who_am_i(deps, caller),
367+
PacketMsg::Balances {} => receive_balances(deps, caller),
368+
}
369+
})()
370+
.or_else(|e| {
371+
// we try to capture all app-level errors and convert them into
372+
// acknowledgement packets that contain an error code.
373+
let acknowledgement = encode_ibc_error(format!("invalid packet: {}", e));
374+
Ok(IbcReceiveResponse {
375+
acknowledgement,
376+
submessages: vec![],
377+
messages: vec![],
378+
attributes: vec![],
379+
})
380+
})
381+
}
374382
```
375383

376384
2. If we modify state with an external call, we need to wrap it in a

contracts/ibc-reflect-send/src/ibc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use cosmwasm_std::{
22
entry_point, from_slice, to_binary, DepsMut, Env, IbcBasicResponse, IbcChannelCloseMsg,
33
IbcChannelConnectMsg, IbcChannelOpenMsg, IbcMsg, IbcOrder, IbcPacketAckMsg,
4-
IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, StdError, StdResult,
4+
IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, Never, StdError, StdResult,
55
};
66

77
use crate::ibc_msg::{
@@ -95,7 +95,7 @@ pub fn ibc_packet_receive(
9595
_deps: DepsMut,
9696
_env: Env,
9797
_packet: IbcPacketReceiveMsg,
98-
) -> StdResult<IbcReceiveResponse> {
98+
) -> Result<IbcReceiveResponse, Never> {
9999
Ok(IbcReceiveResponse::new()
100100
.set_ack(b"{}")
101101
.add_attribute("action", "ibc_packet_ack"))

contracts/ibc-reflect/src/contract.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use cosmwasm_std::{
22
entry_point, from_slice, to_binary, wasm_execute, BankMsg, Binary, CosmosMsg, Deps, DepsMut,
33
Empty, Env, Event, Ibc3ChannelOpenResponse, IbcBasicResponse, IbcChannelCloseMsg,
44
IbcChannelConnectMsg, IbcChannelOpenMsg, IbcChannelOpenResponse, IbcOrder, IbcPacketAckMsg,
5-
IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Order,
5+
IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Never, Order,
66
QueryResponse, Reply, Response, StdError, StdResult, SubMsg, SubMsgResponse, SubMsgResult,
77
WasmMsg,
88
};
@@ -233,7 +233,7 @@ pub fn ibc_packet_receive(
233233
deps: DepsMut,
234234
_env: Env,
235235
msg: IbcPacketReceiveMsg,
236-
) -> StdResult<IbcReceiveResponse> {
236+
) -> Result<IbcReceiveResponse, Never> {
237237
// put this in a closure so we can convert all error responses into acknowledgements
238238
(|| {
239239
let packet = msg.packet;

packages/std/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod import_helpers;
1515
#[cfg(feature = "iterator")]
1616
mod iterator;
1717
mod math;
18+
mod never;
1819
mod panic;
1920
mod query;
2021
mod results;
@@ -48,6 +49,7 @@ pub use crate::math::{
4849
Decimal, Decimal256, Decimal256RangeExceeded, DecimalRangeExceeded, Fraction, Isqrt, Uint128,
4950
Uint256, Uint512, Uint64,
5051
};
52+
pub use crate::never::Never;
5153
#[cfg(feature = "cosmwasm_1_1")]
5254
pub use crate::query::SupplyResponse;
5355
pub use crate::query::{

packages/std/src/never.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/// Never can never be instantiated. This can be used in places
2+
/// where we want to ensure that no error is returned, such as
3+
/// the `ibc_packet_receive` entry point.
4+
///
5+
/// Once the ! type is stable, this is not needed anymore.
6+
/// See <https://github.com/rust-lang/rust/issues/35121>.
7+
pub enum Never {}
8+
9+
impl core::fmt::Debug for Never {
10+
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
11+
// This is unreachable because no instance of Never can exist
12+
unreachable!()
13+
}
14+
}
15+
16+
impl core::fmt::Display for Never {
17+
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
18+
// This is unreachable because no instance of Never can exist
19+
unreachable!()
20+
}
21+
}

0 commit comments

Comments
 (0)