Skip to content
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

feat: ibc module testing suite and implementation #4

Merged
merged 11 commits into from
Sep 22, 2023
Merged
672 changes: 622 additions & 50 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,10 @@ secp256k1 = { version = "0.27.0", default-features = false, features = ["global-
# See reth: https://github.com/paradigmxyz/reth/blob/main/Cargo.toml#L79
revm = { git = "https://github.com/bluealloy/revm/", branch = "release/v25" }
revm-primitives = { git = "https://github.com/bluealloy/revm/", branch = "release/v25" }

# Patched to make `app_hash` accessible for the Tendermint Header generation.
# See this issue for more info: https://github.com/informalsystems/tendermint-rs/pull/1344
tendermint = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "farhad/testgen-app-hash" }
tendermint-light-client-verifier = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "farhad/testgen-app-hash" }
tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "farhad/testgen-app-hash" }
tendermint-testgen = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "farhad/testgen-app-hash" }
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ uint = "0.9"
borsh = { workspace = true, features = ["rc"] }

[dev-dependencies]
sov-modules-api = { path = "../../sov-modules-api" }
tempfile = { workspace = true }

[features]
default = ["native"]
serde = ["dep:serde", "dep:serde_json"]
native = ["serde", "sov-modules-api/native", "dep:schemars"]
native = ["serde", "sov-modules-api/native", "schemars"]
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ where
},
)?;

todo!()
Ok(sov_modules_api::CallResponse::default())
}

/// This function returns true if the token to be sent was created by IBC.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ pub mod call;
pub mod context;
mod genesis;

#[cfg(test)]
mod tests;

#[cfg(feature = "native")]
mod query;

Expand All @@ -25,7 +22,7 @@ pub struct Transfer<C: sov_modules_api::Context> {

/// Reference to the Bank module.
#[module]
pub(crate) bank: sov_bank::Bank<C>,
pub bank: sov_bank::Bank<C>,

/// Keeps track of the address of each token we minted by token denom.
#[state]
Expand All @@ -42,7 +39,7 @@ pub struct Transfer<C: sov_modules_api::Context> {
/// 1. when tokens are escrowed, save the mapping `denom -> token address`
/// 2. when tokens are unescrowed, lookup the token address by `denom`
#[state]
pub(crate) escrowed_tokens: sov_state::StateMap<String, C::Address>,
pub escrowed_tokens: sov_state::StateMap<String, C::Address>,
}

impl<C: sov_modules_api::Context> sov_modules_api::Module for Transfer<C> {
Expand Down

This file was deleted.

11 changes: 8 additions & 3 deletions module-system/module-implementations/sov-ibc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ resolver = "2"
anyhow = { workspace = true }
sov-bank = { path = "../sov-bank", default-features = false }
sov-chain-state = { path = "../sov-chain-state", default-features = false }
sov-ibc-transfer = { path = "../sov-ibc-transfer", default-features = false }
sov-ibc-transfer = { path = "../sov-ibc-transfer", default-features = false, features = ["native"]}
sov-modules-api = { path = "../../sov-modules-api", default-features = false }
sov-modules-macros = { path = "../../sov-modules-macros" }
sov-state = { path = "../../sov-state", default-features = false }
Expand All @@ -35,10 +35,15 @@ derive_more = { version = "0.99", default-features = false, features = ["from",


[dev-dependencies]
sov-modules-api = { path = "../../sov-modules-api" }
basecoin-app = { git = "https://github.com/informalsystems/basecoin-rs.git", rev = "91eeab8" }
basecoin-store = { git = "https://github.com/informalsystems/basecoin-rs.git", rev = "91eeab8" }
tendermint-testgen = { version = "0.33", default-features = false }
tokio = { workspace = true }
tower-abci = "0.9"
tower = { version = "0.4", features = ["full"] }
tempfile = { workspace = true }

[features]
default = ["native"]
serde = ["dep:serde", "dep:serde_json"]
native = ["serde", "sov-modules-api/native", "dep:schemars"]
native = ["serde", "sov-modules-api/native", "schemars"]
6 changes: 3 additions & 3 deletions module-system/module-implementations/sov-ibc/src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ibc_proto::protobuf::{Error, Protobuf};
use prost::Message;
use sov_state::codec::{BorshCodec, StateCodec, StateValueCodec};

#[derive(Default)]
#[derive(Default, Clone)]
pub struct ProtobufCodec<Raw> {
borsh_codec: BorshCodec,
_raw: PhantomData<Raw>,
Expand Down Expand Up @@ -43,7 +43,7 @@ impl<Raw> StateCodec for ProtobufCodec<Raw> {
}
}

#[derive(Default)]
#[derive(Default, Clone)]
pub struct PacketCommitmentCodec {
borsh_codec: BorshCodec,
}
Expand Down Expand Up @@ -74,7 +74,7 @@ impl StateCodec for PacketCommitmentCodec {
}
}

#[derive(Default)]
#[derive(Default, Clone)]
pub struct AcknowledgementCommitmentCodec {
borsh_codec: BorshCodec,
}
Expand Down
5 changes: 3 additions & 2 deletions module-system/module-implementations/sov-ibc/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub(crate) mod clients;
pub mod clients;

use core::time::Duration;
use std::cell::RefCell;
Expand Down Expand Up @@ -29,6 +29,7 @@ use crate::Ibc;
/// The SDK doesn't have a concept of a "revision number", so we default to 1
const HOST_REVISION_NUMBER: u64 = 1;

#[derive(Clone)]
pub struct IbcExecutionContext<'a, C, Da>
where
C: sov_modules_api::Context,
Expand Down Expand Up @@ -353,7 +354,7 @@ where
// all DAs have predictable block times (such as Bitcoin and Avalanche),
// so we cannot support connection block delays as they are defined
// today.
Duration::ZERO
Duration::ZERO
}

fn validate_message_signer(&self, signer: &ibc::Signer) -> Result<(), ContextError> {
Expand Down
104 changes: 102 additions & 2 deletions module-system/module-implementations/sov-ibc/src/context/clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,14 +319,114 @@ where
client_id: &ClientId,
height: &ibc::Height,
) -> Result<Option<Self::AnyConsensusState>, ContextError> {
todo!()
// Searches for the most recent height at which a client has been
// updated and a consensus state has been stored.
let latest_height = self
.ibc
.client_state_map
.get(client_id, *self.working_set.borrow_mut())
.map(|cs| cs.latest_height())
.ok_or(ClientError::ClientStateNotFound {
client_id: client_id.clone(),
})?;

if height.revision_number() != latest_height.revision_number() {
return Err(ClientError::Other {
description: "height revision number must match the chain's revision number"
.to_string(),
})?;
}

// If the height is greater equal than the latest height, there is no
// next consensus state
if height >= &latest_height {
return Ok(None);
}

// Otherwise, we iterate over the heights between the given height and
// the latest height, and return the first consensus state we find
//
// NOTE: this is not the efficient way to do this, but no other way at
// the moment as we don't have access to an iterator over the map keys

let mut target_height = *height;

while height.revision_height() < latest_height.revision_height() {
target_height = target_height.increment();

let cons_state_path = ClientConsensusStatePath::new(client_id, &target_height);

let next_cons_state = self
.ibc
.consensus_state_map
.get(&cons_state_path, *self.working_set.borrow_mut());

if next_cons_state.is_some() {
return Ok(next_cons_state);
}
}

Ok(None)
}

fn prev_consensus_state(
&self,
client_id: &ClientId,
height: &ibc::Height,
) -> Result<Option<Self::AnyConsensusState>, ContextError> {
todo!()
// Searches for the most recent height at which a client has been
// updated and a consensus state has been stored.
let latest_height = self
.ibc
.client_state_map
.get(client_id, *self.working_set.borrow_mut())
.map(|cs| cs.latest_height())
.ok_or(ClientError::ClientStateNotFound {
client_id: client_id.clone(),
})?;

if height.revision_number() != latest_height.revision_number() {
return Err(ClientError::Other {
description: "height revision number must match the chain's revision number"
.to_string(),
})?;
}

// If the height is greater equal than the latest height, the previous
// consensus state is the latest consensus state
if height >= &latest_height {
let cons_state_path = ClientConsensusStatePath::new(client_id, &latest_height);

let prev_cons_state = self
.ibc
.consensus_state_map
.get(&cons_state_path, *self.working_set.borrow_mut());

return Ok(prev_cons_state);
}

// Otherwise, we decrement the height until we reach the first consensus
// state we find
//
// NOTE: this is not the efficient way to do this, but no other way at
// the moment as we don't have access to an iterator over the map keys
let mut target_height = *height;

while target_height.revision_height() > 0 {
let cons_state_path = ClientConsensusStatePath::new(client_id, &target_height);

let prev_cons_state = self
.ibc
.consensus_state_map
.get(&cons_state_path, *self.working_set.borrow_mut());

if prev_cons_state.is_some() {
return Ok(prev_cons_state);
}

target_height = target_height.decrement()?;
}

Ok(None)
}
}
8 changes: 7 additions & 1 deletion module-system/module-implementations/sov-ibc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ pub mod call;
pub mod codec;
pub mod genesis;

#[cfg(test)]
pub mod test_utils;

#[cfg(test)]
pub mod tests;

pub(crate) mod context;
mod router;

Expand Down Expand Up @@ -35,7 +41,7 @@ pub struct ExampleModuleConfig {}
/// utilized to form prefixes for `state` fields. This naming adheres to the
/// module naming convention used throughout the codebase, ensuring created
/// prefixes by modules are in harmony.
#[derive(ModuleInfo)]
#[derive(ModuleInfo, Clone)]
pub struct Ibc<C: sov_modules_api::Context, Da: sov_modules_api::DaSpec> {
#[address]
pub address: C::Address,
Expand Down
Loading