-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cf-guest-cw: add light client implementation for the guest blockchain (…
…#478) --------- Signed-off-by: Michal Nazarewicz <mina86@mina86.com> Co-authored-by: Dhruv D Jain <dhruv@iamsizzling.com>
- Loading branch information
Showing
13 changed files
with
2,241 additions
and
195 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
[package] | ||
name = "cf-guest-cw" | ||
version = "0.0.0" | ||
authors = ["Michal Nazarewicz <mina86@mina86.com>"] | ||
edition = "2021" | ||
|
||
exclude = [ | ||
# Those files are rust-optimizer artifacts. You might want to | ||
# commit them for convenience but they should not be part of the | ||
# source code publication. | ||
"contract.wasm", | ||
"hash.txt", | ||
] | ||
|
||
[lib] | ||
crate-type = ["cdylib", "rlib"] | ||
|
||
[package.metadata.scripts] | ||
optimize = """docker run --rm -v "$(pwd)":/code \ | ||
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ | ||
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ | ||
cosmwasm/rust-optimizer:0.12.6 | ||
""" | ||
|
||
[dependencies] | ||
cf-guest = { git = "https://github.com/ComposableFi/emulated-light-client/", default-features = false } | ||
guestchain = { git = "https://github.com/ComposableFi/emulated-light-client/", default-features = false } | ||
|
||
base64 = { version = "0.22", default-features = false, features = ["alloc"] } | ||
borsh = { version = "0.10.3", default-features = false } | ||
cosmwasm-schema = "1.5.3" | ||
cosmwasm-std = "1.5.3" | ||
derive_more = "0.99.17" | ||
ed25519-dalek = { version = "2.1.1", default-features = false, features = ["pkcs8"] } | ||
|
||
# Same version emulated-light-client uses | ||
ibc = { git = "https://github.com/cosmos/ibc-rs", rev = "6dd3c6465e594d4c177f21724dd896a15e8f3634", default-features = false, features = ["borsh", "serde"] } | ||
|
||
prost = { version = "0.12.3", default-features = false } | ||
schemars = "0.8.10" | ||
serde = { version = "1.0.145", default-features = false, features = ["derive"] } | ||
sha2 = "0.10" | ||
|
||
[features] | ||
# for more explicit tests, cargo test --features=backtraces | ||
backtraces = ["cosmwasm-std/backtraces"] | ||
# use library feature to disable all instantiate/execute/query exports | ||
library = [] | ||
default = [] | ||
std = [ | ||
"base64/std", | ||
"ed25519-dalek/std", | ||
"ibc/std", | ||
"prost/std", | ||
"serde/std", | ||
"sha2/std", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Copyright (C) 2022 ComposableFi. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use cf_guest_cw::msg; | ||
use cosmwasm_schema::write_api; | ||
|
||
fn main() { | ||
write_api! { | ||
instantiate: msg::InstantiateMsg, | ||
sudo: msg::SudoMsg, | ||
query: msg::QueryMsg, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
// Copyright (C) 2022 ComposableFi. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use core::str::FromStr; | ||
|
||
use cosmwasm_std::{Api, Deps, DepsMut, Env, Storage}; | ||
|
||
use crate::{ibc, state}; | ||
|
||
type Result<T, E = crate::Error> = core::result::Result<T, E>; | ||
|
||
/// Base context for handling CosmWasm operations. | ||
/// | ||
/// It wraps together access to CosmWasm API and information about the request | ||
/// such as block height, current time and IBC client id corresponding to this | ||
/// contract. | ||
/// | ||
/// The object dereferences into [`state::Metadata`] such that metadata fields | ||
/// are directly accessible through this object. | ||
#[derive(derive_more::Deref)] | ||
pub(crate) struct ContextBase<'a> { | ||
#[deref] | ||
pub metadata: state::Metadata, | ||
pub client_id: ibc::ClientId, | ||
pub api: &'a dyn Api, | ||
} | ||
|
||
/// Mutable execution context for handling CosmWasm operations. | ||
/// | ||
/// It wraps together access to CosmWasm APIs, storage and information about the | ||
/// request. To construct a new context object use [`new`] function. | ||
#[derive(derive_more::Deref)] | ||
pub(crate) struct ContextMut<'a> { | ||
#[deref] | ||
base: ContextBase<'a>, | ||
storage: &'a mut dyn Storage, | ||
} | ||
|
||
/// Constructs a new mutable execution context. | ||
pub(crate) fn new<'a>(deps: DepsMut<'a>, env: Env) -> ContextMut<'a> { | ||
ContextMut { base: ContextBase::new(env, deps.api), storage: deps.storage } | ||
} | ||
|
||
/// Read-only execution context for handling CosmWasm operations. | ||
/// | ||
/// It wraps together access to CosmWasm APIs, storage and information about the | ||
/// request. To construct a new context object use [`new_ro`] function. | ||
/// | ||
/// The object dereferences into [`ContextBase`] which holds data common between | ||
/// read-only and mutable execution contexts. | ||
#[derive(derive_more::Deref)] | ||
pub(crate) struct Context<'a> { | ||
#[deref] | ||
base: ContextBase<'a>, | ||
storage: &'a dyn Storage, | ||
} | ||
|
||
/// Constructs a new read-only execution context. | ||
pub(crate) fn new_ro<'a>(deps: Deps<'a>, env: Env) -> Context<'a> { | ||
Context { base: ContextBase::new(env, deps.api), storage: deps.storage } | ||
} | ||
|
||
impl<'a> ContextBase<'a> { | ||
fn new(env: Env, api: &'a dyn Api) -> Self { | ||
let metadata = state::Metadata { | ||
host_timestamp_ns: env.block.time.nanos(), | ||
host_height: env.block.height, | ||
}; | ||
let address = env.contract.address.as_str(); | ||
let client_id = ibc::ClientId::from_str(address).unwrap(); | ||
Self { client_id, metadata, api } | ||
} | ||
|
||
pub fn log(&self, msg: impl alloc::string::ToString) { | ||
self.api.debug(&msg.to_string()) | ||
} | ||
} | ||
|
||
/// Logs formatted text using CosmWasm API. | ||
/// | ||
/// To log string literals prefer [`ContextBase::log`] method. | ||
macro_rules! log { | ||
($self:expr, $($tt:tt)*) => { | ||
$self.log(format_args!($($tt)*)) | ||
}; | ||
} | ||
|
||
pub(crate) use log; | ||
|
||
impl<'a> Context<'a> { | ||
/// Reads this light client’s client state from storage. | ||
pub fn client_state(&self) -> Result<state::ClientState> { | ||
req_client_state(&self.client_id, self.client_states().get()) | ||
} | ||
|
||
/// Returns object providing access to read client state from the | ||
/// storage. | ||
pub fn client_states(&self) -> &'a state::ClientStates { | ||
state::ClientStates::new_ro(self.storage) | ||
} | ||
|
||
/// Reads this light client’s consensus state at given height from | ||
/// storage. | ||
pub fn consensus_state(&self, height: ibc::Height) -> Result<state::ConsensusState> { | ||
req_consensus_state(&self.client_id, height, self.consensus_states().get(height)) | ||
} | ||
|
||
/// Returns object providing access to read consensus states from the | ||
/// storage. | ||
pub fn consensus_states(&self) -> &'a state::ConsensusStates { | ||
state::ConsensusStates::new_ro(self.storage) | ||
} | ||
} | ||
|
||
impl<'a> ContextMut<'a> { | ||
/// Reads this light client’s client state from storage. | ||
pub fn client_state(&self) -> Result<state::ClientState> { | ||
req_client_state(&self.client_id, self.client_states().get()) | ||
} | ||
|
||
/// Returns object providing access to read client state from the | ||
/// storage. | ||
pub fn client_states(&self) -> &state::ClientStates { | ||
state::ClientStates::new_ro(self.storage) | ||
} | ||
|
||
/// Returns object providing access to read or write client state | ||
/// from/to the storage. | ||
pub fn client_states_mut(&mut self) -> &mut state::ClientStates { | ||
state::ClientStates::new(self.storage) | ||
} | ||
|
||
/// Reads this light client’s consensus state at given height from | ||
/// storage. | ||
pub fn consensus_state(&self, height: ibc::Height) -> Result<state::ConsensusState> { | ||
req_consensus_state(&self.client_id, height, self.consensus_states().get(height)) | ||
} | ||
|
||
/// Returns object providing access to read consensus states from the | ||
/// storage. | ||
pub fn consensus_states(&self) -> &state::ConsensusStates { | ||
state::ConsensusStates::new_ro(self.storage) | ||
} | ||
|
||
/// Returns object providing access to read or write consensus states | ||
/// from/to the storage. | ||
pub fn consensus_states_mut(&mut self) -> &mut state::ConsensusStates { | ||
state::ConsensusStates::new(self.storage) | ||
} | ||
} | ||
|
||
/// Returns an error if client state is not present. | ||
fn req_client_state( | ||
client_id: &ibc::ClientId, | ||
state: Result<Option<state::ClientState>>, | ||
) -> Result<state::ClientState> { | ||
let make_err = || ibc::ClientError::ClientStateNotFound { client_id: client_id.clone() }.into(); | ||
state.and_then(|state| state.ok_or_else(make_err)) | ||
} | ||
|
||
/// Returns an error if consensus state is not present. | ||
fn req_consensus_state( | ||
client_id: &ibc::ClientId, | ||
height: ibc::Height, | ||
state: Result<Option<(state::ConsensusState, state::Metadata)>>, | ||
) -> Result<state::ConsensusState> { | ||
let make_err = | ||
|| ibc::ClientError::ConsensusStateNotFound { client_id: client_id.clone(), height }.into(); | ||
state.and_then(|state| state.map(|(state, _metadata)| state).ok_or_else(make_err)) | ||
} |
Oops, something went wrong.