Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Channel upgradability #3228

Merged
merged 142 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
142 commits
Select commit Hold shift + click to select a range
0657501
Add new channel states
seanchen1991 Mar 31, 2023
b3b0ebc
Change channel state enum discriminants
seanchen1991 Mar 31, 2023
b8b0c2f
Update channel state doc comment
seanchen1991 Mar 31, 2023
98dd3fc
Stub out channel upgrade CLI commands
seanchen1991 Apr 4, 2023
ca83021
Use tx_chan_cmd macro for TxChanOpenInit command
seanchen1991 Apr 5, 2023
ed2cab2
Stub out build_channel_upgrade_init function
seanchen1991 Apr 5, 2023
df882ff
Add MsgChannelUpgradeInit type
seanchen1991 Apr 5, 2023
9915965
Add more tests for MsgChannelUpgradeInit message type
seanchen1991 Apr 6, 2023
d6e0e16
Add chan_upgrade_try file for MsgChannelUpgradeTry message type
seanchen1991 Apr 6, 2023
0e15393
Add build_chan_upgrade_init_and_send method
seanchen1991 Apr 7, 2023
4107486
Add UpgradeInit and UpgradeTry ChannelEvents
seanchen1991 Apr 7, 2023
6baee8f
Fix compilation errors with UpgradeInit and UpgradeTry impls
seanchen1991 Apr 7, 2023
e742f7c
Merge branch 'master' into sean/channel-upgradability
seanchen1991 Apr 7, 2023
5d61c0d
Merge branch 'master' of https://github.com/informalsystems/hermes in…
seanchen1991 Apr 12, 2023
3f80bfc
Stub out MsgChannelUpgradeTry
seanchen1991 Apr 12, 2023
99560ff
Add missing fields to MsgChannelUpgradeInit
seanchen1991 Apr 12, 2023
00691d8
Use ibc-proto branch with channel upgrade messages
romac Apr 13, 2023
c571933
Fill in todos
romac Apr 13, 2023
feb4f7f
Comment out code in tx chan-upgrade-init and add todos
romac Apr 13, 2023
410cb5e
Add `UpgradeTimeout` enum
romac Apr 13, 2023
111b3c5
Fleshing out MsgChannelUpgradeTry
seanchen1991 Apr 13, 2023
78ef69a
Resolve merge conflicts
seanchen1991 Apr 13, 2023
ca22ecd
Clean up MsgChannelUpgradeTry
seanchen1991 Apr 13, 2023
168be50
Clean up MsgChannelUpgradeTry
seanchen1991 Apr 13, 2023
cc8b9b2
Fix error conversion
seanchen1991 Apr 14, 2023
3cfb4da
Formatting and clippy
romac Apr 17, 2023
27c2361
Disable tests and fix more clippy warnings
romac Apr 17, 2023
b131e27
Re-enable tests
romac Apr 17, 2023
a2b9c99
Wrap up channel upgrade init CLI
seanchen1991 Apr 17, 2023
8b5590f
Merge branch 'master' into sean/channel-upgradability
seanchen1991 Apr 17, 2023
90c049e
Cargo fmt
seanchen1991 Apr 17, 2023
41fd57a
Merge branch 'sean/channel-upgradability' of https://github.com/infor…
seanchen1991 Apr 17, 2023
c895ae5
Remove unnecessary CLI parameter
seanchen1991 Apr 17, 2023
67893a8
Pass an `UpgradeTimeout` to `.build_chan_upgrade_init_and_send`
romac Apr 18, 2023
e48553d
Fix bug when converting integer to channel state
romac Apr 18, 2023
1a00b39
Proper implementation of `State::less_or_equal_progress`
romac Apr 18, 2023
47c1d0c
Fix broken test
seanchen1991 Apr 18, 2023
59734bd
Ignore channel upgrade try tests for now
seanchen1991 Apr 18, 2023
056b819
Fix channel upgrade try tests
seanchen1991 Apr 18, 2023
cdb3e18
Stub out build_channel_upgrade_try
seanchen1991 Apr 18, 2023
cf1afa5
Stub out build_channel_upgrade_try
seanchen1991 Apr 18, 2023
73296b7
Fix return type of build_chan_upgrade_try
seanchen1991 Apr 18, 2023
ba248af
Cargo fmt
seanchen1991 Apr 18, 2023
eba95e7
Remove stub function
seanchen1991 Apr 18, 2023
f6c1bd3
Add missing clone
seanchen1991 Apr 18, 2023
f411420
Merge branch 'master' into sean/channel-upgradability
seanchen1991 Apr 18, 2023
d3a5f50
Remove redundant clone
seanchen1991 Apr 18, 2023
9e77f73
Merge branch 'sean/channel-upgradability' of https://github.com/infor…
seanchen1991 Apr 18, 2023
3253b2b
Add integration tests for channel upgradability (#3247)
ljoss17 Apr 19, 2023
b46d3d0
Fix check for new channel ordering
romac Apr 19, 2023
c67fc74
Merge branch 'master' into sean/channel-upgradability
romac Apr 19, 2023
fa87302
Fix broken doc comment link
seanchen1991 Apr 19, 2023
feea74b
Progress on build_chan_upgrade_try
seanchen1991 Apr 19, 2023
6fe71cc
Progress on build_chan_upgrade_try
seanchen1991 Apr 19, 2023
9243470
Update ChanUpgradeInit step to use new design improvements
ljoss17 Apr 20, 2023
b07c03d
Nicely report connection id parsing failures
romac Apr 20, 2023
486d2d1
Address merge conflicts
seanchen1991 Apr 20, 2023
0b30345
Document some fields of MsgChannelUpgradeTry
seanchen1991 Apr 20, 2023
01216d0
Add build_chan_upgrade_try_and_send fn
seanchen1991 Apr 20, 2023
e977d1d
Cargo fmt
seanchen1991 Apr 20, 2023
65d265f
Update UpgradeInit to mirror event attributers from 'channel_upgrade_…
ljoss17 Apr 21, 2023
d50b89a
Treat timestamp 0 as no timestamp
romac Apr 21, 2023
3a7acdd
Fix parsing UpgradeAttributes and improve ChanUpgradeInit test
ljoss17 Apr 21, 2023
678149a
Merge branch 'sean/channel-upgradability' of github.com:informalsyste…
ljoss17 Apr 21, 2023
8e6813d
Add Hermes data requirements document (#3262)
romac Apr 21, 2023
fc911af
Update nix flake to use simd v7.0.0 (#3264)
ljoss17 Apr 21, 2023
fb2e556
Merge branch 'sean/channel-upgradability' of https://github.com/infor…
seanchen1991 Apr 21, 2023
e02acdf
Address compiler errors for now
seanchen1991 Apr 21, 2023
ace5a21
Cargo fmt
seanchen1991 Apr 21, 2023
68cd401
Add channel-upgrade job to the CI
romac Apr 22, 2023
e28ddcc
Format flake.nix
romac Apr 22, 2023
5d42c8f
Update flake.lock
romac Apr 22, 2023
92f1d74
Fix test
romac Apr 22, 2023
b262fc2
Update guide templates
romac Apr 22, 2023
b8ce0a7
Expose `tx chan-upgrade-try` command
romac Apr 22, 2023
1635987
Merge branch 'master' into sean/channel-upgradability + fixes
ljoss17 Jun 21, 2023
8a271b4
Update TRY ste implementation for channel upgrade
ljoss17 Jun 21, 2023
9d36d2e
Fix channel upgrade TRY step
ljoss17 Jun 23, 2023
546842b
Merge branch 'master' into sean/channel-upgradability
ljoss17 Jun 23, 2023
b153c0e
Update nix flake
ljoss17 Jun 23, 2023
7b89a95
Merge branch 'master' into sean/channel-upgradability
ljoss17 Jul 3, 2023
246cf7c
Add integration test for `ChanUpgradeTry` step (#3259)
ljoss17 Jul 4, 2023
464b51a
Merge branch 'master' into sean/channel-upgradability
ljoss17 Jul 19, 2023
128e48e
Add Channel Upgrade ACK and CONFIRM steps (#3462)
ljoss17 Jul 24, 2023
ce6c01f
Merge branch 'master' into sean/channel-upgradability
ljoss17 Jul 24, 2023
8aad9da
Merge branch 'master' into sean/channel-upgradability
ljoss17 Aug 8, 2023
749d7db
Add missing CLIs for channel upgrade (#3495)
ljoss17 Aug 14, 2023
8e70414
Merge branch 'master' into sean/channel-upgradability
ljoss17 Aug 23, 2023
7925add
Update channel upgrade after spec rework
ljoss17 Aug 24, 2023
7a0531d
Update nix flake
ljoss17 Aug 24, 2023
9dd685d
Update nix flake
ljoss17 Aug 24, 2023
eb29842
Add test bootstrap compatibility for pre and post SDK v0.47.0
ljoss17 Aug 24, 2023
f01e40e
Merge branch 'master' into sean/channel-upgradability
ljoss17 Aug 28, 2023
fc58444
Merge branch 'master' into sean/channel-upgradability
ljoss17 Oct 10, 2023
08525ec
Merge branch 'master' into sean/channel-upgradability
ljoss17 Oct 12, 2023
f368a14
Channel upgrade worker handshake (#3569)
ljoss17 Oct 13, 2023
c4a8ecc
Merge branch 'master' into sean/channel-upgradability
ljoss17 Oct 19, 2023
e65dfba
Merge branch 'master' into sean/channel-upgradability
ljoss17 Oct 20, 2023
babc732
Merge branch 'master' into sean/channel-upgradability
ljoss17 Oct 23, 2023
a4dc932
Merge branch 'master' into sean/channel-upgradability
ljoss17 Dec 1, 2023
775cb9a
Merge branch 'master' into sean/channel-upgradability
ljoss17 Dec 5, 2023
3f9d346
Update nix flake and remove log file
ljoss17 Dec 6, 2023
63f2da2
Merge branch 'master' into sean/channel-upgradability
ljoss17 Dec 8, 2023
de88932
Merge branch 'master' into sean/channel-upgradability
ljoss17 Dec 20, 2023
1749a71
Merge branch 'master' into sean/channel-upgradability
ljoss17 Dec 20, 2023
a9175e2
Merge branch 'master' into sean/channel-upgradability
ljoss17 Jan 5, 2024
b07076e
Merge branch 'master' into sean/channel-upgradability
ljoss17 Jan 29, 2024
09181fe
Merge branch 'master' into sean/channel-upgradability
ljoss17 Feb 7, 2024
c3deea4
Merge branch 'master' into sean/channel-upgradability
ljoss17 Mar 6, 2024
b4e1d29
Use governance proposal to initialise channel upgrade tests (#3680)
ljoss17 Mar 8, 2024
9aedc1d
Merge branch 'master' into sean/channel-upgradability
ljoss17 Mar 8, 2024
d2e9452
Remove unnecessary fields from IBC channel upgrade events
ljoss17 Apr 2, 2024
0c241e0
Merge branch 'master' into sean/channel-upgradability
ljoss17 Apr 3, 2024
c6bddb7
Merge branch 'master' into sean/channel-upgradability
ljoss17 Apr 3, 2024
2101474
cargo fmt
ljoss17 Apr 3, 2024
ff43a8d
Fix async ICQ test
ljoss17 Apr 3, 2024
678f3da
Fix cargo doc
ljoss17 Apr 3, 2024
d76b7c4
Remove redundant import
ljoss17 Apr 3, 2024
3481a54
Remove redundant import
ljoss17 Apr 3, 2024
e1039e5
Correctly handle channel upgrade error
ljoss17 Apr 5, 2024
364adf4
Remove validate basic from channel open try
ljoss17 Apr 8, 2024
19d3875
Merge branch 'master' into sean/channel-upgradability
ljoss17 Apr 18, 2024
e258615
Improve detection of channel upgrade cancel when one end is in Flushc…
ljoss17 Apr 19, 2024
bbc7903
Merge branch 'master' into sean/channel-upgradability
ljoss17 Apr 19, 2024
24b9d93
Add changelog entry
romac Apr 23, 2024
a52f66d
Merge branch 'master' into sean/channel-upgradability
romac May 14, 2024
bea6867
Fix post-merge compilation issues
romac May 14, 2024
a185fa1
Rename `State::Flushcomplete` to `State::FlushComplete`
romac May 14, 2024
08d708f
Small cleanup
romac May 14, 2024
fb18998
Sort imports
romac May 15, 2024
29e3e09
Whitespace
romac May 22, 2024
08400d0
Remove patch override
romac May 22, 2024
8ff6cb3
Apply suggestions from code review
ljoss17 May 27, 2024
918cf47
cargo fmt
ljoss17 May 27, 2024
63ad028
Merge branch 'master' into sean/channel-upgradability
ljoss17 May 27, 2024
a97766f
Fix codespell errors
ljoss17 May 27, 2024
e2d02b8
Merge branch 'master' into sean/channel-upgradability
ljoss17 May 29, 2024
f26c275
Use IncludeProof for query_upgrade and query_upgrade_error
ljoss17 May 29, 2024
f4e8310
Add a method to build and send channel upgrade open or cancel
ljoss17 May 29, 2024
9a23149
Merge branch 'master' into sean/channel-upgradability
ljoss17 May 29, 2024
7c56bc2
Remove unnecessary assertions
ljoss17 May 29, 2024
c74f9e5
Add handling of channel upgrade timeout event in channel worker
ljoss17 May 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ members = [
"tools/query-events",
]

# [patch.crates-io]
# ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs.git", branch = "main" }
[patch.crates-io]
ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs.git", branch = "romac/channel-upgrade-only" }
# tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "main" }
# tendermint-rpc = { git = "https://github.com/informalsystems/tendermint-rs", branch = "main" }
# tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "main" }
Expand Down
278 changes: 228 additions & 50 deletions crates/relayer-cli/src/commands/tx/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ use crate::conclude::Output;
use crate::error::Error;
use crate::prelude::*;

/// Macro that generates the `Runnable::run` implementation for a
/// `tx channel` subcommand.
///
/// The macro takes the following arguments:
/// - `$dbg_string`: a string literal that will be used to identify the subcommand
/// in debug logs
/// - `$func`: the method that will be called to build and send the `Channel` message
/// - `$self`: the type that `Runnable` is being implemented for
/// - `$chan`: a closure that specifies how to build the `Channel` object
///
/// The macro spawns a `ChainHandlePair`, fetches the destination connection,
/// creates a `Channel` object via the closure, and then calls the `$func` method
/// with the `Channel` object.
macro_rules! tx_chan_cmd {
($dbg_string:literal, $func:ident, $self:expr, $chan:expr) => {
let config = app_config();
Expand Down Expand Up @@ -110,56 +123,33 @@ pub struct TxChanOpenInitCmd {

impl Runnable for TxChanOpenInitCmd {
fn run(&self) {
let config = app_config();

let chains = match ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) {
Ok(chains) => chains,
Err(e) => Output::error(e).exit(),
};

// Retrieve the connection
let dst_connection = match chains.dst.query_connection(
QueryConnectionRequest {
connection_id: self.dst_conn_id.clone(),
height: QueryHeight::Latest,
},
IncludeProof::No,
) {
Ok((connection, _)) => connection,
Err(e) => Output::error(e).exit(),
};

let channel = Channel {
connection_delay: Default::default(),
ordering: self.order,
a_side: ChannelSide::new(
chains.src,
ClientId::default(),
ConnectionId::default(),
self.src_port_id.clone(),
None,
None,
),
b_side: ChannelSide::new(
chains.dst,
dst_connection.client_id().clone(),
self.dst_conn_id.clone(),
self.dst_port_id.clone(),
None,
None,
),
};

info!("message ChanOpenInit: {}", channel);

let res: Result<IbcEvent, Error> = channel
.build_chan_open_init_and_send()
.map_err(Error::channel);

match res {
Ok(receipt) => Output::success(receipt).exit(),
Err(e) => Output::error(e).exit(),
}
tx_chan_cmd!(
"ChanOpenInit",
build_chan_open_init_and_send,
self,
|chains: ChainHandlePair, dst_connection: ConnectionEnd| {
Channel {
connection_delay: Default::default(),
ordering: self.order,
a_side: ChannelSide::new(
chains.src,
ClientId::default(),
ConnectionId::default(),
self.src_port_id.clone(),
None,
None,
),
b_side: ChannelSide::new(
chains.dst,
dst_connection.client_id().clone(),
self.dst_conn_id.clone(),
self.dst_port_id.clone(),
None,
None,
),
}
}
);
}
}

Expand Down Expand Up @@ -666,6 +656,194 @@ impl Runnable for TxChanCloseConfirmCmd {
}
}

// FIXME: Since the channel already exists, we don't need both the src and dst chain,
// only the src/dst chain and src/dst channel.
romac marked this conversation as resolved.
Show resolved Hide resolved
//
// TODO: Add arguments for version, ordering, connection hops and timeouts.
romac marked this conversation as resolved.
Show resolved Hide resolved

/// Build and send a `ChanUpgradeInit` message to a destination
/// chain that the source chain has an already-existing channel open
/// with, signaling the intent by the source chain to perform
/// the channel upgrade handshake.
#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)]
pub struct TxChanUpgradeInitCmd {
#[clap(
long = "dst-chain",
required = true,
value_name = "DST_CHAIN_ID",
help_heading = "REQUIRED",
help = "Identifier of the destination chain"
)]
dst_chain_id: ChainId,

#[clap(
long = "src-chain",
required = true,
value_name = "SRC_CHAIN_ID",
help_heading = "REQUIRED",
help = "Identifier of the source chain"
)]
src_chain_id: ChainId,

#[clap(
long = "dst-connection",
visible_alias = "dst-conn",
required = true,
value_name = "DST_CONNECTION_ID",
help_heading = "REQUIRED",
help = "Identifier of the destination connection"
)]
dst_conn_id: ConnectionId,

#[clap(
long = "dst-port",
required = true,
value_name = "DST_PORT_ID",
help_heading = "REQUIRED",
help = "Identifier of the destination port"
)]
dst_port_id: PortId,

#[clap(
long = "src-port",
required = true,
value_name = "SRC_PORT_ID",
help_heading = "REQUIRED",
help = "Identifier of the source port"
)]
src_port_id: PortId,

#[clap(
long = "dst-channel",
visible_alias = "dst-chan",
required = true,
value_name = "DST_CHANNEL_ID",
help_heading = "REQUIRED",
help = "Identifier of the destination channel (required)"
)]
dst_chan_id: ChannelId,

#[clap(
long = "src-channel",
visible_alias = "src-chan",
required = true,
value_name = "SRC_CHANNEL_ID",
help_heading = "REQUIRED",
help = "Identifier of the source channel (required)"
)]
src_chan_id: ChannelId,
}

impl Runnable for TxChanUpgradeInitCmd {
fn run(&self) {
// TODO: Take version, connections hops, ordering and timeouts and hops from the arguments
// and pass them to build_chan_upgrade_init_and_send
romac marked this conversation as resolved.
Show resolved Hide resolved

// tx_chan_cmd!(
// "ChanUpgradeInit",
// build_chan_upgrade_init_and_send,
// self,
// |chains: ChainHandlePair, dst_connection: ConnectionEnd| {
// Channel {
// connection_delay: Default::default(),
// ordering: Order::default(),
// a_side: ChannelSide::new(
// chains.src,
// ClientId::default(),
// ConnectionId::default(),
// self.src_port_id.clone(),
// Some(self.src_chan_id.clone()),
// None,
// ),
// b_side: ChannelSide::new(
// chains.dst,
// dst_connection.client_id().clone(),
// self.dst_conn_id.clone(),
// self.dst_port_id.clone(),
// Some(self.dst_chan_id.clone()),
// None,
// ),
// }
// }
// );
}
}

/// Build and send a `ChanUpgradeTry` message in response to
/// a `ChanUpgradeInnit` message, signaling the chain's intent to
/// cooperate with the source chain on upgrading the specified channel
/// and initiating the upgrade handshake.
#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)]
pub struct TxChanUpgradeTryCmd {
#[clap(
long = "dst-chain",
required = true,
value_name = "DST_CHAIN_ID",
help_heading = "REQUIRED",
help = "Identifier of the destination chain"
)]
dst_chain_id: ChainId,

#[clap(
long = "src-chain",
required = true,
value_name = "SRC_CHAIN_ID",
help_heading = "REQUIRED",
help = "Identifier of the source chain"
)]
src_chain_id: ChainId,

#[clap(
long = "dst-connection",
visible_alias = "dst-conn",
required = true,
value_name = "DST_CONNECTION_ID",
help_heading = "REQUIRED",
help = "Identifier of the destination connection"
)]
dst_conn_id: ConnectionId,

#[clap(
long = "dst-port",
required = true,
value_name = "DST_PORT_ID",
help_heading = "REQUIRED",
help = "Identifier of the destination port"
)]
dst_port_id: PortId,

#[clap(
long = "src-port",
required = true,
value_name = "SRC_PORT_ID",
help_heading = "REQUIRED",
help = "Identifier of the source port"
)]
src_port_id: PortId,

#[clap(
long = "src-channel",
visible_alias = "src-chan",
required = true,
value_name = "SRC_CHANNEL_ID",
help_heading = "REQUIRED",
help = "Identifier of the source channel (required)"
)]
src_chan_id: ChannelId,

#[clap(
long = "dst-channel",
visible_alias = "dst-chan",
value_name = "DST_CHANNEL_ID",
help = "Identifier of the destination channel (optional)"
)]
dst_chan_id: Option<ChannelId>,
}

impl Runnable for TxChanUpgradeTryCmd {
fn run(&self) {}
}

#[cfg(test)]
mod tests {
use super::{
Expand Down
19 changes: 17 additions & 2 deletions crates/relayer-types/src/core/ics04_channel/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ impl From<Counterparty> for RawCounterparty {
}
}

pub type Ordering = Order;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub enum Order {
None = 0,
Expand Down Expand Up @@ -371,13 +373,22 @@ impl FromStr for Order {
}
}

/// The possible state variants that a channel can exhibit.
///
/// These are encoded with integer discriminants so that there is
/// an easy way to compare channel states against one another. More
/// explicitly, this is an attempt to capture the lifecycle of a
/// channel, beginning from the `Uninitialized` state, through the
/// `Open` state, before finally being `Closed`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum State {
Uninitialized = 0,
Init = 1,
TryOpen = 2,
Open = 3,
Closed = 4,
InitUpgrade = 4,
TryUpgrade = 5,
Closed = 6,
romac marked this conversation as resolved.
Show resolved Hide resolved
}

impl State {
Expand All @@ -389,6 +400,8 @@ impl State {
Self::TryOpen => "TRYOPEN",
Self::Open => "OPEN",
Self::Closed => "CLOSED",
Self::InitUpgrade => "INITUPGRADE",
Self::TryUpgrade => "TRYUPGRADE",
}
}

Expand All @@ -399,7 +412,9 @@ impl State {
1 => Ok(Self::Init),
2 => Ok(Self::TryOpen),
3 => Ok(Self::Open),
4 => Ok(Self::Closed),
4 => Ok(Self::InitUpgrade),
5 => Ok(Self::TryUpgrade),
6 => Ok(Self::Closed),
romac marked this conversation as resolved.
Show resolved Hide resolved
_ => Err(Error::unknown_state(s)),
}
}
Expand Down
Loading