Skip to content

[ICS] Implement IBC client RPCs #1849

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions codechain/rpc_apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ impl ApiDependencies {
AccountClient::new(Arc::clone(&self.account_provider), Arc::clone(&self.client), Arc::clone(&self.miner))
.to_delegate(),
);
handler.extend_with(IBCClient::new(Arc::clone(&self.client)).to_delegate())
}
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/ibc/client_02/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ use ibc;
pub use self::manager::Manager;
pub use self::types::{ConsensusState, Header, Kind, State, KIND_CODECHAIN};

pub fn new_state(id: &str, ctx: &mut dyn ibc::Context, client_type: Kind) -> Box<dyn State> {
fn new_state(id: &str, ctx: &mut dyn ibc::Context, client_type: Kind) -> Box<dyn State> {
if client_type == KIND_CODECHAIN {
Box::new(codechain::State::new(id, ctx))
} else {
panic!("Invalid client type");
}
}

pub fn get_state(id: &str, ctx: &mut dyn ibc::Context) -> Result<Box<dyn State>, String> {
fn get_state(id: &str, ctx: &mut dyn ibc::Context) -> Result<Box<dyn State>, String> {
let s = codechain::State::find(id);
if s.exists(ctx) {
Ok(Box::new(s))
Expand Down
2 changes: 1 addition & 1 deletion core/src/ibc/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl<'a> Context for TopLevelContext<'a> {
}
}

pub struct TopLevelKVStore<'a> {
struct TopLevelKVStore<'a> {
state: &'a mut TopLevelState,
}

Expand Down
7 changes: 3 additions & 4 deletions core/src/ibc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,16 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

mod client_02;
pub mod client_02;
#[allow(dead_code)]
#[allow(unused_variables)]
mod commitment_23;
#[allow(dead_code)]
#[allow(unused_variables)]
mod context;
pub mod context;
#[allow(dead_code)]
#[allow(unused_variables)]
pub mod custom_action_handler;
mod kv_store;

pub use self::client_02 as client;
pub use self::context::Context;
pub use self::kv_store::KVStore;
2 changes: 1 addition & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ mod db;
mod db_version;
pub mod encoded;
mod error;
mod ibc;
pub mod ibc;
mod invoice;
mod miner;
mod scheme;
Expand Down
18 changes: 18 additions & 0 deletions rpc/src/v1/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ mod codes {
pub const ASSET_TRANSACTION_ONLY_IN_EXECUTE_TRANSACITON: i64 = -32047;
pub const STATE_NOT_EXIST: i64 = -32048;
pub const ACTION_DATA_HANDLER_NOT_FOUND: i64 = -32049;
pub const IBC_CLIENT_NOT_EXIST: i64 = -32050;
pub const IBC_CLIENT_ROOT_NOT_EXIST: i64 = -32051;
pub const UNKNOWN_ERROR: i64 = -32099;
}

Expand Down Expand Up @@ -304,6 +306,22 @@ pub fn invalid_custom_action(err: String) -> Error {
}
}

pub fn ibc_client_not_exist() -> Error {
Error {
code: ErrorCode::ServerError(codes::IBC_CLIENT_NOT_EXIST),
message: "IBC client does not exist".to_string(),
data: None,
}
}

pub fn ibc_client_root_not_exist() -> Error {
Error {
code: ErrorCode::ServerError(codes::IBC_CLIENT_ROOT_NOT_EXIST),
message: "IBC client root does not exist".to_string(),
data: None,
}
}

/// Internal error signifying a logic error in code.
/// Should not be used when function can just fail
/// because of invalid parameters or incomplete node state.
Expand Down
118 changes: 118 additions & 0 deletions rpc/src/v1/impls/ibc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright 2019 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 <https://www.gnu.org/licenses/>.

use std::sync::Arc;

use ccore::ibc;
use ccore::{BlockChainClient, BlockId, StateInfo};
use jsonrpc_core::Result;
use primitives::Bytes;
use rustc_serialize::hex::ToHex;

use super::super::errors;
use super::super::traits::IBC;
use super::super::types::IBCQueryResult;

pub struct IBCClient<C>
where
C: StateInfo + BlockChainClient, {
client: Arc<C>,
}

impl<C> IBCClient<C>
where
C: StateInfo + BlockChainClient,
{
pub fn new(client: Arc<C>) -> Self {
Self {
client,
}
}
}

impl<C> IBC for IBCClient<C>
where
C: StateInfo + 'static + Send + Sync + BlockChainClient,
{
fn query_client_consensus_state(
&self,
client_id: String,
block_number: Option<u64>,
) -> Result<Option<IBCQueryResult>> {
let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest);
let mut state = self.client.state_at(block_id).ok_or_else(errors::state_not_exist)?;
let block_number = match self.client.block_number(&block_id) {
None => return Ok(None),
Some(block_number) => block_number,
};

let mut context = ibc::context::TopLevelContext::new(&mut state);
let client_manager = ibc::client::Manager::new();
let client_state =
client_manager.query(&mut context, &client_id).map_err(|_| errors::ibc_client_not_exist())?;

let consensus_state = client_state.get_consensus_state(&mut context);

let rlp_encoded_consensus_state = consensus_state.encode();

Ok(Some(IBCQueryResult {
block_number,
raw: rlp_encoded_consensus_state.to_hex(),
// FIXME
proof: "".to_string(),
}))
}

fn query_header(&self, block_number: Option<u64>) -> Result<Option<String>> {
let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest);
let header = match self.client.block_header(&block_id) {
None => return Ok(None),
Some(header) => header,
};

Ok(Some(header.into_inner().to_hex()))
}

fn query_client_root(
&self,
client_id: String,
other_block_number: u64,
this_block_number: Option<u64>,
) -> Result<Option<IBCQueryResult>> {
let block_id = this_block_number.map(BlockId::Number).unwrap_or(BlockId::Latest);
let mut state = self.client.state_at(block_id).ok_or_else(errors::state_not_exist)?;
let block_number = match self.client.block_number(&block_id) {
None => return Ok(None),
Some(block_number) => block_number,
};

let mut context = ibc::context::TopLevelContext::new(&mut state);
let client_manager = ibc::client::Manager::new();
let client_state =
client_manager.query(&mut context, &client_id).map_err(|_| errors::ibc_client_not_exist())?;

let root =
client_state.get_root(&mut context, other_block_number).map_err(|_| errors::ibc_client_root_not_exist())?;
let rlp_encoded_root = root.encode();

Ok(Some(IBCQueryResult {
block_number,
raw: rlp_encoded_root.to_hex(),
// FIXME
proof: "".to_string(),
}))
}
}
2 changes: 2 additions & 0 deletions rpc/src/v1/impls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod account;
mod chain;
mod devel;
mod engine;
mod ibc;
mod mempool;
mod miner;
mod net;
Expand All @@ -26,6 +27,7 @@ pub use self::account::AccountClient;
pub use self::chain::ChainClient;
pub use self::devel::DevelClient;
pub use self::engine::EngineClient;
pub use self::ibc::IBCClient;
pub use self::mempool::MempoolClient;
pub use self::miner::MinerClient;
pub use self::net::NetClient;
43 changes: 43 additions & 0 deletions rpc/src/v1/traits/ibc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2019 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 <https://www.gnu.org/licenses/>.

use jsonrpc_core::Result;
use primitives::Bytes;

use super::super::types::IBCQueryResult;


#[rpc(server)]
pub trait IBC {
#[rpc(name = "ibc_query_client_consensus_state")]
fn query_client_consensus_state(
&self,
client_id: String,
block_number: Option<u64>,
) -> Result<Option<IBCQueryResult>>;

#[rpc(name = "ibc_query_header")]
fn query_header(&self, block_number: Option<u64>) -> Result<Option<String>>;

/// Gets the other chain's root saved in the light client
#[rpc(name = "ibc_query_client_root")]
fn query_client_root(
&self,
client_id: String,
other_block_number: u64,
this_block_number: Option<u64>,
) -> Result<Option<IBCQueryResult>>;
}
2 changes: 2 additions & 0 deletions rpc/src/v1/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod account;
mod chain;
mod devel;
mod engine;
mod ibc;
mod mempool;
mod miner;
mod net;
Expand All @@ -26,6 +27,7 @@ pub use self::account::Account;
pub use self::chain::Chain;
pub use self::devel::Devel;
pub use self::engine::Engine;
pub use self::ibc::IBC;
pub use self::mempool::Mempool;
pub use self::miner::Miner;
pub use self::net::Net;
23 changes: 23 additions & 0 deletions rpc/src/v1/types/ibc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2019 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 <https://www.gnu.org/licenses/>.

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct IBCQueryResult {
pub block_number: u64,
pub raw: String,
pub proof: String,
}
2 changes: 2 additions & 0 deletions rpc/src/v1/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod asset_input;
mod asset_output;
mod asset_scheme;
mod block;
mod ibc;
mod text;
mod transaction;
mod unsigned_transaction;
Expand All @@ -34,6 +35,7 @@ pub use self::asset::OwnedAsset;
pub use self::asset_scheme::AssetScheme;
pub use self::block::Block;
pub use self::block::BlockNumberAndHash;
pub use self::ibc::IBCQueryResult;
pub use self::text::Text;
pub use self::transaction::{PendingTransactions, Transaction};
pub use self::unsigned_transaction::UnsignedTransaction;
Expand Down