From db33a780eff07e034702b9f0ba3800ff2c6f60f1 Mon Sep 17 00:00:00 2001 From: Park Juhyung Date: Mon, 17 Feb 2020 15:38:50 +0900 Subject: [PATCH] Implement ICS connection's open_try datagram I omit vector commitment and light client part. I will fill the part after we merge them in the PoC branch. --- core/src/ibc/connection_03/manager.rs | 106 +++++++++++++++++- core/src/ibc/connection_03/types.rs | 2 + core/src/ibc/transaction_handler/datagrams.rs | 56 +++++++++ core/src/ibc/transaction_handler/mod.rs | 28 +++++ 4 files changed, 191 insertions(+), 1 deletion(-) diff --git a/core/src/ibc/connection_03/manager.rs b/core/src/ibc/connection_03/manager.rs index 44a5487f45..cbc70b1a12 100644 --- a/core/src/ibc/connection_03/manager.rs +++ b/core/src/ibc/connection_03/manager.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use super::path as connection_path; -use super::types::{CommitmentPrefix, Identifier}; +use super::types::{CommitmentPrefix, CommitmentProof, Identifier}; use crate::ibc; use crate::ibc::connection_03::client_connections_path; use crate::ibc::connection_03::types::{ConnectionEnd, ConnectionIdentifiersInClient, ConnectionState}; @@ -24,6 +24,11 @@ use rlp::{Encodable, Rlp}; #[derive(Default)] pub struct Manager {} +// FIXME: this will be changed after implementing Vector commitment +fn get_commiment_prefix() -> String { + "".to_owned() +} + impl Manager { pub fn new() -> Self { Manager {} @@ -55,6 +60,105 @@ impl Manager { Ok(()) } + // We all following ICS spec. + #[allow(clippy::too_many_arguments)] + pub fn handle_open_try( + &self, + ctx: &mut dyn ibc::Context, + desired_identifier: Identifier, + counterparty_connection_identifier: Identifier, + counterparty_prefix: CommitmentPrefix, + counterparty_client_identifier: Identifier, + client_identifier: Identifier, + proof_init: CommitmentProof, + proof_consensus: CommitmentProof, + proof_height: u64, + consensus_height: u64, + ) -> Result<(), String> { + let current_height = ctx.get_current_height(); + if consensus_height > current_height { + return Err(format!( + "Consensus height {} is greater than current height {}", + consensus_height, current_height + )) + } + let expected = ConnectionEnd { + state: ConnectionState::INIT, + counterparty_connection_identifier: desired_identifier.clone(), + counterparty_prefix: get_commiment_prefix(), + client_identifier: counterparty_client_identifier.clone(), + counterparty_client_identifier: client_identifier.clone(), + }; + + let connection = ConnectionEnd { + state: ConnectionState::TRYOPEN, + counterparty_connection_identifier: counterparty_client_identifier.clone(), + counterparty_prefix: counterparty_prefix.clone(), + client_identifier: client_identifier.clone(), + counterparty_client_identifier: counterparty_client_identifier.clone(), + }; + + self.verify_connection_state(ctx, &connection, proof_height, proof_init, desired_identifier.clone(), &expected); + + if let Some(previous_connection_end) = self.query(ctx, &desired_identifier) { + let expected_init = ConnectionEnd { + state: ConnectionState::INIT, + counterparty_connection_identifier, + counterparty_prefix, + client_identifier, + counterparty_client_identifier, + }; + if previous_connection_end != expected_init { + return Err(format!( + "Invalid previous connection status: previous: {:?}, expected: {:?}", + previous_connection_end, expected_init + )) + } + } + + let kv_store = ctx.get_kv_store(); + kv_store.set(&connection_path(&desired_identifier), &connection.rlp_bytes()); + Ok(()) + } + + fn query(&self, ctx: &mut dyn ibc::Context, identifier: &str) -> Option { + let kv_store = ctx.get_kv_store(); + + let path = connection_path(&identifier); + if kv_store.has(&path) { + let raw = kv_store.get(&path); + let connection_end = rlp::decode(&raw).expect("Only the connection code can save the code"); + return Some(connection_end) + } + + None + } + + fn verify_connection_state( + &self, + ctx: &mut dyn ibc::Context, + connection: &ConnectionEnd, + proof_height: u64, + proof: CommitmentProof, + connection_identifier: Identifier, + connection_end: &ConnectionEnd, + ) -> bool { + // check values in the connection_end + let path = format!("connections/{}", connection_identifier); + self.client_verify_membership(proof_height, proof, path, &rlp::encode(connection_end)) + } + + fn client_verify_membership( + &self, + _height: u64, + _commitment_proof: CommitmentProof, + _path: String, + _value: &[u8], + ) -> bool { + // FIXME + true + } + fn add_connection_to_client( &self, ctx: &mut dyn ibc::Context, diff --git a/core/src/ibc/connection_03/types.rs b/core/src/ibc/connection_03/types.rs index 6622242f3f..a2a041d4d2 100644 --- a/core/src/ibc/connection_03/types.rs +++ b/core/src/ibc/connection_03/types.rs @@ -45,6 +45,8 @@ impl rlp::Decodable for ConnectionState { // FIXME: current commitment_23::Prefix is too generic. pub type CommitmentPrefix = String; +// FIXME: This type will be replaced after commitment code changed. +pub type CommitmentProof = String; pub type Identifier = String; #[derive(RlpEncodable, RlpDecodable, PartialEq, Debug)] diff --git a/core/src/ibc/transaction_handler/datagrams.rs b/core/src/ibc/transaction_handler/datagrams.rs index cd013524b3..5b8e128bc5 100644 --- a/core/src/ibc/transaction_handler/datagrams.rs +++ b/core/src/ibc/transaction_handler/datagrams.rs @@ -22,6 +22,7 @@ enum DatagramTag { CreateClient = 1, UpdateClient = 2, ConnOpenInit = 3, + ConnOpenTry = 4, } impl Encodable for DatagramTag { @@ -37,6 +38,7 @@ impl Decodable for DatagramTag { 1 => Ok(DatagramTag::CreateClient), 2 => Ok(DatagramTag::UpdateClient), 3 => Ok(DatagramTag::ConnOpenInit), + 4 => Ok(DatagramTag::ConnOpenTry), _ => Err(DecoderError::Custom("Unexpected DatagramTag Value")), } } @@ -60,6 +62,17 @@ pub enum Datagram { client_identifier: String, counterparty_client_identifier: String, }, + ConnOpenTry { + desired_identifier: String, + counterparty_connection_identifier: String, + counterparty_prefix: String, + counterparty_client_identifier: String, + client_identifier: String, + proof_init: String, + proof_consensus: String, + proof_height: u64, + consensus_height: u64, + }, } impl Encodable for Datagram { @@ -93,6 +106,29 @@ impl Encodable for Datagram { .append(client_identifier) .append(counterparty_client_identifier); } + Datagram::ConnOpenTry { + desired_identifier, + counterparty_connection_identifier, + counterparty_prefix, + counterparty_client_identifier, + client_identifier, + proof_init, + proof_consensus, + proof_height, + consensus_height, + } => { + s.begin_list(10); + s.append(&DatagramTag::ConnOpenTry) + .append(desired_identifier) + .append(counterparty_connection_identifier) + .append(counterparty_prefix) + .append(counterparty_client_identifier) + .append(client_identifier) + .append(proof_init) + .append(proof_consensus) + .append(proof_height) + .append(consensus_height); + } }; } } @@ -144,6 +180,26 @@ impl Decodable for Datagram { counterparty_client_identifier: rlp.val_at(5)?, }) } + DatagramTag::ConnOpenTry => { + let item_count = rlp.item_count()?; + if item_count != 10 { + return Err(DecoderError::RlpInvalidLength { + expected: 10, + got: item_count, + }) + } + Ok(Datagram::ConnOpenTry { + desired_identifier: rlp.val_at(1)?, + counterparty_connection_identifier: rlp.val_at(2)?, + counterparty_prefix: rlp.val_at(3)?, + counterparty_client_identifier: rlp.val_at(4)?, + client_identifier: rlp.val_at(5)?, + proof_init: rlp.val_at(6)?, + proof_consensus: rlp.val_at(7)?, + proof_height: rlp.val_at(8)?, + consensus_height: rlp.val_at(9)?, + }) + } } } } diff --git a/core/src/ibc/transaction_handler/mod.rs b/core/src/ibc/transaction_handler/mod.rs index d4d8c656b9..3f050267c4 100644 --- a/core/src/ibc/transaction_handler/mod.rs +++ b/core/src/ibc/transaction_handler/mod.rs @@ -65,6 +65,34 @@ pub fn execute( ) .map_err(|err| RuntimeError::IBC(format!("ConnOpenInit: {}", err)).into()) } + Datagram::ConnOpenTry { + desired_identifier, + counterparty_connection_identifier, + counterparty_prefix, + counterparty_client_identifier, + client_identifier, + proof_init, + proof_consensus, + proof_height, + consensus_height, + } => { + let mut context = ibc_context::TopLevelContext::new(state, current_block_number); + let connection_manager = ibc_connection::Manager::new(); + connection_manager + .handle_open_try( + &mut context, + desired_identifier, + counterparty_connection_identifier, + counterparty_prefix, + counterparty_client_identifier, + client_identifier, + proof_init, + proof_consensus, + proof_height, + consensus_height, + ) + .map_err(|err| RuntimeError::IBC(format!("ConnOpenTry: {}", err)).into()) + } } }