Skip to content

Commit d6f5dfc

Browse files
authored
Merge pull request #1513 from CosmWasm/add-Never
Add Never type to avoid ibc_packet_receive errors
2 parents 45a122f + 2b8c553 commit d6f5dfc

File tree

6 files changed

+68
-26
lines changed

6 files changed

+68
-26
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,16 @@ 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 `ibc_packet_receive` or `ibc_packet_ack` to gain
30+
confidence that the implementations never errors and the transaction does not
31+
get reverted. ([#1513])
2832

2933
[#1436]: https://github.com/CosmWasm/cosmwasm/issues/1436
3034
[#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437
3135
[#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481
3236
[#1478]: https://github.com/CosmWasm/cosmwasm/pull/1478
37+
[#1513]: https://github.com/CosmWasm/cosmwasm/pull/1513
3338
[#1533]: https://github.com/CosmWasm/cosmwasm/pull/1533
3439
[#1550]: https://github.com/CosmWasm/cosmwasm/issues/1550
3540
[#1552]: https://github.com/CosmWasm/cosmwasm/pull/1552

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: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
/// In contrast to `Empty`, this does not have a JSON schema
6+
/// and cannot be used for message and query types.
7+
///
8+
/// Once the ! type is stable, this is not needed anymore.
9+
/// See <https://github.com/rust-lang/rust/issues/35121>.
10+
pub enum Never {}
11+
12+
// The Debug implementation is needed to allow the use of `Result::unwrap`.
13+
impl core::fmt::Debug for Never {
14+
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
15+
// Unreachable because no instance of Never can exist
16+
match *self {}
17+
}
18+
}
19+
20+
// The Display implementation is needed to fulfill the ToString requirement of
21+
// entry point errors: `Result<IbcReceiveResponse<C>, E>` with `E: ToString`.
22+
impl core::fmt::Display for Never {
23+
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
24+
// Unreachable because no instance of Never can exist
25+
match *self {}
26+
}
27+
}

0 commit comments

Comments
 (0)