From 58a3313f46747477dfdca06180739c295f9bfcb9 Mon Sep 17 00:00:00 2001 From: Park Juhyung Date: Wed, 12 Feb 2020 19:21:44 +0900 Subject: [PATCH 1/3] Use enum for DatagramTag --- core/src/ibc/transaction_handler/datagrams.rs | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/core/src/ibc/transaction_handler/datagrams.rs b/core/src/ibc/transaction_handler/datagrams.rs index a0012b118f..05596d6938 100644 --- a/core/src/ibc/transaction_handler/datagrams.rs +++ b/core/src/ibc/transaction_handler/datagrams.rs @@ -16,8 +16,29 @@ use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; -const DATAGRAM_CREATE_CLIENT: u8 = 1; -const DATAGRAM_UPDATE_CLIENT: u8 = 2; +#[repr(u8)] +#[derive(Clone, Copy)] +enum DatagramTag { + CreateClient = 1, + UpdateClient = 2, +} + +impl Encodable for DatagramTag { + fn rlp_append(&self, s: &mut RlpStream) { + s.append_single_value(&(*self as u8)); + } +} + +impl Decodable for DatagramTag { + fn decode(rlp: &Rlp) -> Result { + let byte: u8 = rlp.as_val()?; + match byte { + 1 => Ok(DatagramTag::CreateClient), + 2 => Ok(DatagramTag::UpdateClient), + _ => Err(DecoderError::Custom("Unexpected DatagramTag Value")), + } + } +} #[derive(Debug, PartialEq)] pub enum Datagram { @@ -40,13 +61,13 @@ impl Encodable for Datagram { kind, consensus_state, } => { - s.begin_list(4).append(&DATAGRAM_CREATE_CLIENT).append(id).append(kind).append(consensus_state); + s.begin_list(4).append(&DatagramTag::CreateClient).append(id).append(kind).append(consensus_state); } Datagram::UpdateClient { id, header, } => { - s.begin_list(3).append(&DATAGRAM_UPDATE_CLIENT).append(id).append(header); + s.begin_list(3).append(&DatagramTag::UpdateClient).append(id).append(header); } }; } @@ -56,7 +77,7 @@ impl Decodable for Datagram { fn decode(rlp: &Rlp) -> Result { let tag = rlp.val_at(0)?; match tag { - DATAGRAM_CREATE_CLIENT => { + DatagramTag::CreateClient => { let item_count = rlp.item_count()?; if item_count != 4 { return Err(DecoderError::RlpInvalidLength { @@ -70,7 +91,7 @@ impl Decodable for Datagram { consensus_state: rlp.val_at(3)?, }) } - DATAGRAM_UPDATE_CLIENT => { + DatagramTag::UpdateClient => { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpInvalidLength { @@ -83,7 +104,6 @@ impl Decodable for Datagram { header: rlp.val_at(2)?, }) } - _ => Err(DecoderError::Custom("Unexpected IBC Datagram Type")), } } } From 5eb5e75f5320a71e0ede435854fa72b53c9881a7 Mon Sep 17 00:00:00 2001 From: Park Juhyung Date: Wed, 12 Feb 2020 18:36:54 +0900 Subject: [PATCH 2/3] Implement handle_open_init function --- core/src/ibc/connection_03/manager.rs | 77 +++++++++++++++++++++ core/src/ibc/connection_03/mod.rs | 26 +++++++ core/src/ibc/connection_03/types.rs | 97 +++++++++++++++++++++++++++ core/src/ibc/mod.rs | 3 + 4 files changed, 203 insertions(+) create mode 100644 core/src/ibc/connection_03/manager.rs create mode 100644 core/src/ibc/connection_03/mod.rs create mode 100644 core/src/ibc/connection_03/types.rs diff --git a/core/src/ibc/connection_03/manager.rs b/core/src/ibc/connection_03/manager.rs new file mode 100644 index 0000000000..44a5487f45 --- /dev/null +++ b/core/src/ibc/connection_03/manager.rs @@ -0,0 +1,77 @@ +// Copyright 2020 Kodebox, Inc. +// This file is part of CodeChain. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use super::path as connection_path; +use super::types::{CommitmentPrefix, Identifier}; +use crate::ibc; +use crate::ibc::connection_03::client_connections_path; +use crate::ibc::connection_03::types::{ConnectionEnd, ConnectionIdentifiersInClient, ConnectionState}; +use rlp::{Encodable, Rlp}; + +#[derive(Default)] +pub struct Manager {} + +impl Manager { + pub fn new() -> Self { + Manager {} + } + + pub fn handle_open_init( + &self, + ctx: &mut dyn ibc::Context, + identifier: Identifier, + desired_counterparty_connection_identifier: Identifier, + counterparty_prefix: CommitmentPrefix, + client_identifier: Identifier, + counterparty_client_identifier: Identifier, + ) -> Result<(), String> { + let kv_store = ctx.get_kv_store(); + if kv_store.has(&connection_path(&identifier)) { + return Err("Connection exist".to_owned()) + } + let state = ConnectionState::INIT; + let connection = ConnectionEnd { + state, + counterparty_connection_identifier: desired_counterparty_connection_identifier, + counterparty_prefix, + client_identifier: client_identifier.clone(), + counterparty_client_identifier, + }; + kv_store.set(&connection_path(&identifier), &connection.rlp_bytes()); + self.add_connection_to_client(ctx, client_identifier, identifier)?; + Ok(()) + } + + fn add_connection_to_client( + &self, + ctx: &mut dyn ibc::Context, + client_identifier: Identifier, + connection_identifier: Identifier, + ) -> Result<(), String> { + let kv_store = ctx.get_kv_store(); + if kv_store.has(&connection_path(&connection_identifier)) { + return Err("Connection exist".to_owned()) + } + let bytes = kv_store.get(&client_connections_path(&client_identifier)); + let rlp = Rlp::new(&bytes); + let mut conns: ConnectionIdentifiersInClient = rlp.as_val().expect("data from DB"); + + conns.add(connection_identifier); + + kv_store.set(&client_connections_path(&client_identifier), &rlp::encode(&conns)); + Ok(()) + } +} diff --git a/core/src/ibc/connection_03/mod.rs b/core/src/ibc/connection_03/mod.rs new file mode 100644 index 0000000000..f12d3541d2 --- /dev/null +++ b/core/src/ibc/connection_03/mod.rs @@ -0,0 +1,26 @@ +// Copyright 2020 Kodebox, Inc. +// This file is part of CodeChain. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +mod manager; +mod types; + +pub fn path(id: &str) -> String { + format!("connections/{}", id) +} + +pub fn client_connections_path(client_id: &str) -> String { + format!("clients/{}/connections", client_id) +} diff --git a/core/src/ibc/connection_03/types.rs b/core/src/ibc/connection_03/types.rs new file mode 100644 index 0000000000..6622242f3f --- /dev/null +++ b/core/src/ibc/connection_03/types.rs @@ -0,0 +1,97 @@ +// Copyright 2020 Kodebox, Inc. +// This file is part of CodeChain. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use rlp; +use rlp::{DecoderError, Rlp, RlpStream}; + +#[repr(u8)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum ConnectionState { + INIT = 0, + TRYOPEN = 1, + OPEN = 2, +} + +impl rlp::Encodable for ConnectionState { + fn rlp_append(&self, s: &mut RlpStream) { + s.append_single_value(&(*self as u8)); + } +} + +impl rlp::Decodable for ConnectionState { + fn decode(rlp: &Rlp) -> Result { + let byte: u8 = rlp.as_val()?; + match byte { + 0 => Ok(ConnectionState::INIT), + 1 => Ok(ConnectionState::TRYOPEN), + 2 => Ok(ConnectionState::OPEN), + _ => Err(DecoderError::Custom("Unexpected ConsensusState Value")), + } + } +} + +// FIXME: current commitment_23::Prefix is too generic. +pub type CommitmentPrefix = String; +pub type Identifier = String; + +#[derive(RlpEncodable, RlpDecodable, PartialEq, Debug)] +pub struct ConnectionEnd { + pub state: ConnectionState, + pub counterparty_connection_identifier: Identifier, + pub counterparty_prefix: CommitmentPrefix, + pub client_identifier: Identifier, + pub counterparty_client_identifier: Identifier, + // FIXME: implement version +} + +#[derive(RlpEncodableWrapper, RlpDecodableWrapper, PartialEq, Debug)] +pub struct ConnectionIdentifiersInClient(Vec); + +impl ConnectionIdentifiersInClient { + pub fn add(&mut self, identifier: Identifier) { + self.0.push(identifier); + } +} + +#[cfg(test)] +mod tests { + use rlp::{self, rlp_encode_and_decode_test}; + + use super::*; + + #[test] + fn connection_state() { + rlp_encode_and_decode_test!(ConnectionState::INIT); + } + + #[test] + fn connection_end() { + let connection_end = ConnectionEnd { + state: ConnectionState::INIT, + counterparty_connection_identifier: "counterparty_connection_identifier".to_owned(), + counterparty_prefix: "counterparty_prefix".to_owned(), + client_identifier: "client_identifier".to_owned(), + counterparty_client_identifier: "counterparty_client_identifier".to_owned(), + }; + rlp_encode_and_decode_test!(connection_end); + } + + #[test] + fn connection_identifiers_in_client() { + let identifiers = ConnectionIdentifiersInClient(vec!["a".to_owned(), "b".to_owned()]); + rlp_encode_and_decode_test!(identifiers); + } +} diff --git a/core/src/ibc/mod.rs b/core/src/ibc/mod.rs index 1952c23347..5eadfc86a4 100644 --- a/core/src/ibc/mod.rs +++ b/core/src/ibc/mod.rs @@ -18,6 +18,9 @@ pub mod client_02; #[allow(dead_code)] #[allow(unused_variables)] mod commitment_23; +#[allow(dead_code)] +#[allow(unused_variables)] +mod connection_03; pub mod context; mod kv_store; mod transaction_handler; From 71c696ca1c5b542d923914d0dd3b32a2d2e00463 Mon Sep 17 00:00:00 2001 From: Park Juhyung Date: Wed, 12 Feb 2020 19:48:28 +0900 Subject: [PATCH 3/3] Add ConnOpenInit datagram --- core/src/ibc/connection_03/mod.rs | 2 + core/src/ibc/transaction_handler/datagrams.rs | 40 +++++++++++++++++++ core/src/ibc/transaction_handler/mod.rs | 21 ++++++++++ 3 files changed, 63 insertions(+) diff --git a/core/src/ibc/connection_03/mod.rs b/core/src/ibc/connection_03/mod.rs index f12d3541d2..d376d8f7eb 100644 --- a/core/src/ibc/connection_03/mod.rs +++ b/core/src/ibc/connection_03/mod.rs @@ -24,3 +24,5 @@ pub fn path(id: &str) -> String { pub fn client_connections_path(client_id: &str) -> String { format!("clients/{}/connections", client_id) } + +pub use manager::Manager; diff --git a/core/src/ibc/transaction_handler/datagrams.rs b/core/src/ibc/transaction_handler/datagrams.rs index 05596d6938..cd013524b3 100644 --- a/core/src/ibc/transaction_handler/datagrams.rs +++ b/core/src/ibc/transaction_handler/datagrams.rs @@ -21,6 +21,7 @@ use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; enum DatagramTag { CreateClient = 1, UpdateClient = 2, + ConnOpenInit = 3, } impl Encodable for DatagramTag { @@ -35,6 +36,7 @@ impl Decodable for DatagramTag { match byte { 1 => Ok(DatagramTag::CreateClient), 2 => Ok(DatagramTag::UpdateClient), + 3 => Ok(DatagramTag::ConnOpenInit), _ => Err(DecoderError::Custom("Unexpected DatagramTag Value")), } } @@ -51,6 +53,13 @@ pub enum Datagram { id: String, header: Vec, }, + ConnOpenInit { + identifier: String, + desired_counterparty_connection_identifier: String, + counterparty_prefix: String, + client_identifier: String, + counterparty_client_identifier: String, + }, } impl Encodable for Datagram { @@ -69,6 +78,21 @@ impl Encodable for Datagram { } => { s.begin_list(3).append(&DatagramTag::UpdateClient).append(id).append(header); } + Datagram::ConnOpenInit { + identifier, + desired_counterparty_connection_identifier, + counterparty_prefix, + client_identifier, + counterparty_client_identifier, + } => { + s.begin_list(6); + s.append(&DatagramTag::ConnOpenInit) + .append(identifier) + .append(desired_counterparty_connection_identifier) + .append(counterparty_prefix) + .append(client_identifier) + .append(counterparty_client_identifier); + } }; } } @@ -104,6 +128,22 @@ impl Decodable for Datagram { header: rlp.val_at(2)?, }) } + DatagramTag::ConnOpenInit => { + let item_count = rlp.item_count()?; + if item_count != 6 { + return Err(DecoderError::RlpInvalidLength { + expected: 6, + got: item_count, + }) + } + Ok(Datagram::ConnOpenInit { + identifier: rlp.val_at(1)?, + desired_counterparty_connection_identifier: rlp.val_at(2)?, + counterparty_prefix: rlp.val_at(3)?, + client_identifier: rlp.val_at(4)?, + counterparty_client_identifier: rlp.val_at(5)?, + }) + } } } } diff --git a/core/src/ibc/transaction_handler/mod.rs b/core/src/ibc/transaction_handler/mod.rs index 0eb348f13f..ed345e8706 100644 --- a/core/src/ibc/transaction_handler/mod.rs +++ b/core/src/ibc/transaction_handler/mod.rs @@ -23,6 +23,7 @@ use cstate::{StateResult, TopLevelState}; use ctypes::errors::RuntimeError; use ibc::client_02 as ibc_client; use ibc::client_02::foundry as ibc_foundry; +use ibc::connection_03 as ibc_connection; use ibc::context as ibc_context; use rlp::{Decodable, Rlp}; @@ -43,6 +44,26 @@ pub fn execute( id, header, } => update_client(state, &id, &header), + Datagram::ConnOpenInit { + identifier, + desired_counterparty_connection_identifier, + counterparty_prefix, + client_identifier, + counterparty_client_identifier, + } => { + let mut context = ibc_context::TopLevelContext::new(state); + let connection_manager = ibc_connection::Manager::new(); + connection_manager + .handle_open_init( + &mut context, + identifier, + desired_counterparty_connection_identifier, + counterparty_prefix, + client_identifier, + counterparty_client_identifier, + ) + .map_err(|err| RuntimeError::IBC(format!("ConnOpenInit: {}", err)).into()) + } } }