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

Allow a conn open ack to succeed in the happy case #700

Merged
merged 9 commits into from
Feb 23, 2021
Merged
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

- [ibc]
- Fix overflow bug in ICS03 client consensus height verification method ([#685])
- Allow a conn open ack to succeed in the happy case ([#699])

- [ibc-relayer]
- [nothing yet]
Expand All @@ -40,7 +41,7 @@
### BREAKING CHANGES

- [ibc]
- [nothing yet]
- `MsgConnectionOpenAck.counterparty_connection_id` is now a `ConnectionId` instead of an `Option<ConnectionId>`([#700])

- [ibc-relayer]
- [nothing yet]
Expand All @@ -50,6 +51,8 @@

[#685]: https://github.com/informalsystems/ibc-rs/issues/685
[#689]: https://github.com/informalsystems/ibc-rs/issues/689
[#699]: https://github.com/informalsystems/ibc-rs/issues/699
[#700]: https://github.com/informalsystems/ibc-rs/pull/700

## v0.1.1
*February 17, 2021*
Expand Down
4 changes: 2 additions & 2 deletions modules/src/ics02_client/client_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub trait ClientDef: Clone {
height: Height,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
connection_id: &ConnectionId,
connection_id: Option<&ConnectionId>,
expected_connection_end: &ConnectionEnd,
) -> Result<(), Box<dyn std::error::Error>>;

Expand Down Expand Up @@ -472,7 +472,7 @@ impl ClientDef for AnyClient {
height: Height,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
connection_id: &ConnectionId,
connection_id: Option<&ConnectionId>,
expected_connection_end: &ConnectionEnd,
) -> Result<(), Box<dyn std::error::Error>> {
match self {
Expand Down
45 changes: 15 additions & 30 deletions modules/src/ics03_connection/handler/conn_open_ack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,15 @@ pub(crate) fn process(
|| old_conn_end.state_matches(&State::TryOpen)
&& old_conn_end.versions().get(0).eq(&Some(msg.version()));

// Check that if the msg's counterparty connection id is not empty then it matches
// the old connection's counterparty.
let counterparty_matches = msg.counterparty_connection_id().is_none()
|| old_conn_end.counterparty().connection_id() == msg.counterparty_connection_id();
// Check that, if we have a counterparty connection id, then it
// matches the one in the message.
let counterparty_matches = if let Some(counterparty_connection_id) =
old_conn_end.counterparty().connection_id()
{
&msg.counterparty_connection_id == counterparty_connection_id
} else {
true
};

if state_is_consistent && counterparty_matches {
Ok(old_conn_end)
Expand All @@ -59,8 +64,8 @@ pub(crate) fn process(
Counterparty::new(
// The counterparty is the local chain.
new_conn_end.client_id().clone(), // The local client identifier.
msg.counterparty_connection_id().cloned(), // This chain's connection id as known on counterparty.
ctx.commitment_prefix(), // Local commitment prefix.
Some(msg.counterparty_connection_id().clone()), // This chain's connection id as known on counterparty.
ctx.commitment_prefix(), // Local commitment prefix.
),
vec![msg.version().clone()],
new_conn_end.delay_period,
Expand Down Expand Up @@ -147,7 +152,7 @@ mod tests {
client_id.clone(),
Counterparty::new(
client_id.clone(),
msg_ack.counterparty_connection_id().cloned(),
Some(msg_ack.counterparty_connection_id().clone()),
CommitmentPrefix::from(b"ibc".to_vec()),
),
vec![msg_ack.version().clone()],
Expand All @@ -164,20 +169,10 @@ mod tests {
conn_end_prefix.set_state(State::Init);
conn_end_prefix.set_counterparty(Counterparty::new(
client_id.clone(),
msg_ack.counterparty_connection_id().cloned(),
Some(msg_ack.counterparty_connection_id().clone()),
CommitmentPrefix::from(vec![]), // incorrect field
));

// A connection end with correct state & prefix, but incorrect counterparty; exercises
// unsuccessful processing path.
let mut conn_end_cparty = conn_end_open.clone();
conn_end_cparty.set_state(State::Init);
conn_end_cparty.set_counterparty(Counterparty::new(
client_id.clone(),
None, // incorrect field
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test has been removed as my understanding is that msg.counterparty_connection_id should always be a Some (which hints that it should not be an Option).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now this field is no longer an Option.

CommitmentPrefix::from(b"ibc".to_vec()),
));

let tests: Vec<Test> = vec![
Test {
name: "Successful processing of an Ack message".to_string(),
Expand Down Expand Up @@ -209,21 +204,11 @@ mod tests {
Test {
name: "Processing fails: ConsensusStateVerificationFailure due to empty counterparty prefix".to_string(),
ctx: default_context
.clone()
.with_client(&client_id, proof_height)
.with_connection(conn_id.clone(), conn_end_prefix),
msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())),
want_pass: false,
error_kind: Some(Kind::ConsensusStateVerificationFailure(proof_height))
},
Test {
name: "Processing fails due to mismatching counterparty conn id".to_string(),
ctx: default_context
.with_client(&client_id, proof_height)
.with_connection(conn_id.clone(), conn_end_cparty),
.with_connection(conn_id, conn_end_prefix),
msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack)),
want_pass: false,
error_kind: Some(Kind::ConnectionMismatch(conn_id))
error_kind: Some(Kind::ConsensusStateVerificationFailure(proof_height))
},
/*
Test {
Expand Down
2 changes: 1 addition & 1 deletion modules/src/ics03_connection/handler/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ pub fn verify_connection_proof(
proof_height,
connection_end.counterparty().prefix(),
proof,
&connection_end.counterparty().connection_id().unwrap(),
connection_end.counterparty().connection_id(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the connection is in the Init state, connection_end.counterparty().connection_id() is a None, and thus it's not okay to unwrap.

expected_conn,
)
.map_err(|_| Kind::InvalidProof)?)
Expand Down
22 changes: 8 additions & 14 deletions modules/src/ics03_connection/msgs/conn_open_ack.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::convert::{TryFrom, TryInto};
use std::str::FromStr;

use tendermint::account::Id as AccountId;
use tendermint_proto::Protobuf;
Expand All @@ -22,7 +21,7 @@ pub const TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenAck";
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MsgConnectionOpenAck {
pub connection_id: ConnectionId,
pub counterparty_connection_id: Option<ConnectionId>,
pub counterparty_connection_id: ConnectionId,
pub client_state: Option<AnyClientState>,
pub proofs: Proofs,
pub version: Version,
Expand All @@ -36,8 +35,8 @@ impl MsgConnectionOpenAck {
}

/// Getter for accessing the counterparty's connection identifier from this message.
pub fn counterparty_connection_id(&self) -> Option<&ConnectionId> {
self.counterparty_connection_id.as_ref()
pub fn counterparty_connection_id(&self) -> &ConnectionId {
&self.counterparty_connection_id
}

/// Getter for accessing the client state.
Expand Down Expand Up @@ -107,18 +106,15 @@ impl TryFrom<RawMsgConnectionOpenAck> for MsgConnectionOpenAck {
.filter(|x| !x.is_empty())
.map(CommitmentProofBytes::from);

let counterparty_connection_id = Some(msg.counterparty_connection_id)
.filter(|x| !x.is_empty())
.map(|v| FromStr::from_str(v.as_str()))
.transpose()
.map_err(|e| Kind::IdentifierError.context(e))?;

Ok(Self {
connection_id: msg
.connection_id
.parse()
.map_err(|e| Kind::IdentifierError.context(e))?,
counterparty_connection_id,
counterparty_connection_id: msg
.counterparty_connection_id
.parse()
.map_err(|e| Kind::IdentifierError.context(e))?,
client_state: msg
.client_state
.map(AnyClientState::try_from)
Expand Down Expand Up @@ -146,9 +142,7 @@ impl From<MsgConnectionOpenAck> for RawMsgConnectionOpenAck {
fn from(ics_msg: MsgConnectionOpenAck) -> Self {
RawMsgConnectionOpenAck {
connection_id: ics_msg.connection_id.as_str().to_string(),
counterparty_connection_id: ics_msg
.counterparty_connection_id
.map_or_else(|| "".to_string(), |v| v.as_str().to_string()),
counterparty_connection_id: ics_msg.counterparty_connection_id.as_str().to_string(),
client_state: ics_msg
.client_state
.map_or_else(|| None, |v| Some(v.into())),
Expand Down
2 changes: 1 addition & 1 deletion modules/src/ics07_tendermint/client_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl ClientDef for TendermintClient {
_height: Height,
_prefix: &CommitmentPrefix,
_proof: &CommitmentProofBytes,
_connection_id: &ConnectionId,
_connection_id: Option<&ConnectionId>,
_expected_connection_end: &ConnectionEnd,
) -> Result<(), Box<dyn std::error::Error>> {
todo!()
Expand Down
2 changes: 1 addition & 1 deletion modules/src/mock/client_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl ClientDef for MockClient {
_height: Height,
_prefix: &CommitmentPrefix,
_proof: &CommitmentProofBytes,
_connection_id: &ConnectionId,
_connection_id: Option<&ConnectionId>,
_expected_connection_end: &ConnectionEnd,
) -> Result<(), Box<dyn std::error::Error>> {
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion relayer/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ impl Connection {

let new_msg = MsgConnectionOpenAck {
connection_id: self.dst_connection_id().clone(),
counterparty_connection_id: Option::from(self.src_connection_id().clone()),
counterparty_connection_id: self.src_connection_id().clone(),
client_state,
proofs,
version: src_connection.versions()[0].clone(),
Expand Down