diff --git a/core/src/ibc/connection_03/manager.rs b/core/src/ibc/connection_03/manager.rs index 4572b7e185..fad03393de 100644 --- a/core/src/ibc/connection_03/manager.rs +++ b/core/src/ibc/connection_03/manager.rs @@ -67,8 +67,8 @@ impl<'a> Manager<'a> { counterparty_prefix: CommitmentPrefix, counterparty_client_identifier: Identifier, client_identifier: Identifier, - proof_init: CommitmentProof, - proof_consensus: CommitmentProof, + proof_init: Vec, + proof_consensus: Vec, proof_height: u64, consensus_height: u64, ) -> Result<(), String> { @@ -118,6 +118,45 @@ impl<'a> Manager<'a> { Ok(()) } + pub fn handle_open_ack( + &mut self, + identifier: Identifier, + proof_try: Vec, + proof_consensus: Vec, + proof_height: u64, + consensus_height: u64, + ) -> Result<(), String> { + let current_height = self.ctx.get_current_height(); + if consensus_height > current_height { + return Err(format!( + "Consensus height {} is greater than current height {}", + consensus_height, current_height + )) + } + let mut connection = self + .query(&identifier) + .ok_or_else(|| format!("Cannot find connection with the identifier: {}", identifier))?; + + if connection.state != ConnectionState::INIT && connection.state != ConnectionState::TRYOPEN { + return Err(format!("Invalid connection state expected INIT or TRYOPEN but found {:?}", connection.state)) + } + let expected_connection = ConnectionEnd { + state: ConnectionState::TRYOPEN, + counterparty_connection_identifier: identifier.clone(), + counterparty_prefix: get_commiment_prefix(), + client_identifier: connection.counterparty_client_identifier.clone(), + counterparty_client_identifier: connection.client_identifier.clone(), + }; + self.verify_connection_state(&connection, proof_height, proof_try, identifier.clone(), &expected_connection); + + connection.state = ConnectionState::OPEN; + let kv_store = self.ctx.get_kv_store_mut(); + let path = connection_path(&identifier); + kv_store.set(&path, &connection.rlp_bytes()); + + Ok(()) + } + fn query(&mut self, identifier: &str) -> Option { let kv_store = self.ctx.get_kv_store(); @@ -135,13 +174,19 @@ impl<'a> Manager<'a> { &mut self, connection: &ConnectionEnd, proof_height: u64, - proof: CommitmentProof, + proof: Vec, connection_identifier: Identifier, connection_end: &ConnectionEnd, ) -> bool { + let proof_dec: CommitmentProof = if let Ok(proof) = rlp::decode(&proof) { + proof + } else { + return false + }; + // check values in the connection_end let path = format!("connections/{}", connection_identifier); - self.client_verify_membership(proof_height, proof, path, &rlp::encode(connection_end)) + self.client_verify_membership(proof_height, proof_dec, path, &rlp::encode(connection_end)) } fn client_verify_membership( diff --git a/core/src/ibc/transaction_handler/datagrams.rs b/core/src/ibc/transaction_handler/datagrams.rs index f4299d02a0..751f6c4537 100644 --- a/core/src/ibc/transaction_handler/datagrams.rs +++ b/core/src/ibc/transaction_handler/datagrams.rs @@ -23,6 +23,7 @@ enum DatagramTag { UpdateClient = 2, ConnOpenInit = 3, ConnOpenTry = 4, + ConnOpenAck = 5, } impl Encodable for DatagramTag { @@ -39,6 +40,7 @@ impl Decodable for DatagramTag { 2 => Ok(DatagramTag::UpdateClient), 3 => Ok(DatagramTag::ConnOpenInit), 4 => Ok(DatagramTag::ConnOpenTry), + 5 => Ok(DatagramTag::ConnOpenAck), _ => Err(DecoderError::Custom("Unexpected DatagramTag Value")), } } @@ -74,6 +76,13 @@ pub enum Datagram { proof_height: u64, consensus_height: u64, }, + ConnOpenAck { + identifier: String, + proof_try: Vec, + proof_consensus: Vec, + proof_height: u64, + consensus_height: u64, + }, } impl Encodable for Datagram { @@ -136,6 +145,21 @@ impl Encodable for Datagram { .append(proof_height) .append(consensus_height); } + Datagram::ConnOpenAck { + identifier, + proof_try, + proof_consensus, + proof_height, + consensus_height, + } => { + s.begin_list(6); + s.append(&DatagramTag::ConnOpenAck) + .append(identifier) + .append(proof_try) + .append(proof_consensus) + .append(proof_height) + .append(consensus_height); + } }; } } @@ -208,6 +232,22 @@ impl Decodable for Datagram { consensus_height: rlp.val_at(9)?, }) } + DatagramTag::ConnOpenAck => { + let item_count = rlp.item_count()?; + if item_count != 6 { + return Err(DecoderError::RlpInvalidLength { + expected: 6, + got: item_count, + }) + } + Ok(Datagram::ConnOpenAck { + identifier: rlp.val_at(1)?, + proof_try: rlp.val_at(2)?, + proof_consensus: rlp.val_at(3)?, + proof_height: rlp.val_at(4)?, + consensus_height: rlp.val_at(5)?, + }) + } } } } diff --git a/core/src/ibc/transaction_handler/mod.rs b/core/src/ibc/transaction_handler/mod.rs index b9d88f1996..2b05895a26 100644 --- a/core/src/ibc/transaction_handler/mod.rs +++ b/core/src/ibc/transaction_handler/mod.rs @@ -18,7 +18,7 @@ mod datagrams; use self::datagrams::Datagram; use crate::ibc; -use crate::ibc::commitment_23::types::{CommitmentPrefix, CommitmentProof}; +use crate::ibc::commitment_23::types::CommitmentPrefix; use ckey::{Address, Public}; use cstate::{StateResult, TopLevelState}; use ctypes::errors::RuntimeError; @@ -78,16 +78,8 @@ pub fn execute( proof_height, consensus_height, } => { - let mut context = ibc_context::TopLevelContext::new(state, current_block_number); let mut connection_manager = ibc_connection::Manager::new(&mut context); - let proof_init_dec: CommitmentProof = rlp::Rlp::new(&proof_init) - .as_val() - .map_err(|err| RuntimeError::IBC(format!("ConnOpenTry failed to decode proof_init {}", err)))?; - let proof_consensus_dec: CommitmentProof = rlp::Rlp::new(&proof_consensus) - .as_val() - .map_err(|err| RuntimeError::IBC(format!("ConnOpenTry failed to decode consensus_init {}", err)))?; - connection_manager .handle_open_try( desired_identifier, @@ -97,13 +89,25 @@ pub fn execute( }, counterparty_client_identifier, client_identifier, - proof_init_dec, - proof_consensus_dec, + proof_init, + proof_consensus, proof_height, consensus_height, ) .map_err(|err| RuntimeError::IBC(format!("ConnOpenTry: {}", err)).into()) } + Datagram::ConnOpenAck { + identifier, + proof_try, + proof_consensus, + proof_height, + consensus_height, + } => { + let mut connection_manager = ibc_connection::Manager::new(&mut context); + connection_manager + .handle_open_ack(identifier, proof_try, proof_consensus, proof_height, consensus_height) + .map_err(|err| RuntimeError::IBC(format!("ConnOpenAck: {}", err)).into()) + } } }