Open joaotav opened 6 months ago
Great find and writeup @joaotav.
So build_chan_open_init()
(called from build_chan_open_init_and_send
) doesn't use the source chain and we indeed don't do any validation in the tx chan-open-init
CLI when we build the Channel
struct before calling build_chan_open_init_and_send
These tx ..
CLIs were used early to help with the development process and were not really meant to be used in production. So not much attention was given to these, although we did some cleanup as we found issues. There are some redundant parameters in the tx CLIs and in this case probably src-chain
param should be dropped and rather derived from the dst-connection
.
The "production" CLI for creating channels does not allow both, e.g. you will see something like:
$ hermes create channel --a-chain chain2 --a-connection connection-0 --b-chain chain1 --a-port transfer --b-port transfer
error: The argument '--a-connection <A_CONNECTION_ID>' cannot be used with '--b-chain <B_CHAIN_ID>'
You can see here how we get the "src_chain" (chain_b
in this function) from the "dst_connection" (connection_a
). If we keep the "src_chain" parameter we can check it against the chain_b
determined in a similar way.
There are other CLIs with redundant params and missing checks, for example if we continue with the try step we get a chain error because we don't do the check and send a bad IBC payload to the chain:
$ hermes tx chan-open-try --dst-chain chain1 --dst-connection connection-0 --dst-port transfer --src-chain chain2 --src-channel channel-0 --src-port transfer
...
ERROR channel error: failed during a transaction submission step to chain 'chain1': gRPC call `send_tx_simulate` failed with status: status: Unknown, message: "failed to execute message; message index: 1: channel handshake open try failed: failed channel state verification for client (07-tendermint-0): chained membership proof failed to verify membership of value: 080110011A0A0A087472616E73666572220C636F6E6E656374696F6E2D312A0769637332302D31 in subroot 8C1078ABB4CD0C802BBEC0A24A70DC91B47AE893ACA0C5471DDD1A685A7F48A4 at index 0. Please ensure the path and value are both correct.: invalid proof [cosmos/ibc-go/v8/modules/core/23-commitment/types/merkle.go:218] With gas wanted: '18446744073709551615' and gas used: '125054' ", details: [], metadata: MetadataMap { headers: {"content-type": "application/grpc", "x-cosmos-block-height": "1457"} }
As you see the error is really cryptic and not easy to figure out that this is a misconfiguration.
Note: while using the setup I found some bad UX:
$ hermes query channel ends --chain chain2 --channel channel-0 --port transfer
2024-05-21T23:13:00.753873Z INFO ThreadId(01) using default configuration from '/Users/ancaz/.hermes/config.toml' 2024-05-21T23:13:00.762028Z INFO ThreadId(01) running Hermes v1.8.2+25f547595 ERROR channel end for transfer/channel-0 on chain chain2 @ Height { revision: 0, height: 1030 } does not have counterparty channel id: ChannelEnd { state: Init, ordering: Unordered, remote: Counterparty { port_id: PortId("transfer"), channel_id: None }, connection_hops: [ConnectionId("connection-0")], version: Version("ics20-1"), upgrade_sequence: 0 }
Thanks for your investigation and insights @ancazamfir. I'll keep looking out for such issues as we go through each step of the channel handshake, and will open a tracking issue to clean up those CLIs in case we identify other problems.
Summary of Bug
When attempting to open a channel using
hermes tx chan-open-init
, the chain-id passed to--src-chain
has no influence on the subsequent steps of the channel handshake. This allows a channel handshake to be started between a pair of chainschain1
andchain2
, but end up creating a channel between a pair of chainschain2
andchain3
.Consider the following topology:
By executing the following commands:
hermes tx chan-open-init --dst-chain chain2 --src-chain chain1 --dst-connection connection-0 --dst-port transfer --src-port transfer
hermes tx chan-open-try --dst-chain chain3 --dst-connection connection-0 --dst-port transfer --src-chain chain2 --src-channel channel-0 --src-port transfer
hermes tx chan-open-ack --dst-chain chain2 --src-chain chain3 --dst-connection connection-0 --dst-port transfer --src-port transfer --dst-channel channel-0 --src-channel channel-0
hermes tx chan-open-confirm --dst-chain chain3 --src-chain chain2 --dst-connection connection-0 --dst-port transfer --src-port transfer --dst-channel channel-0 --src-channel channel-0
chain2
has now a channel withchain3
in theOPEN
state on both ends.Notice that
chain1
is passed to--src-chain
ontx chan-open-init
, but the channel is eventually opened betweenchain2
andchain3
.Version
hermes
:hermes 1.8.2+06dfbafb
simd
:8.0.0-beta.1-517-gedeefa8f0
Steps to Reproduce
Here's a minimum working example. Hermes
config.toml
file:Replace
HERMES_BINARY
,HERMES_CONFIG_DIR
andCHAIN_BIN
with your own configs.We can check that the channel has been successfully opened with:
simd --node tcp://localhost:26657 query ibc channel channels --output json | jq # For chain2
simd --node tcp://localhost:36657 query ibc channel channels --output json | jq # For chain3
Additional comments
The problems seems to be that Hermes checks
--dst-chain
for the existence of--dst-connection
intx chan-open-init
, but does not check whether this connection is with the chain passed to--src-chain
or not. So whichever chain is the counterparty of--dst-connection
in--dst-chain
can continue the handshake.Acceptance Criteria
TBD
For Admin Use