Skip to content

Commit

Permalink
Merge pull request #4 from informalsystems/farhad/setup-ibc-tests
Browse files Browse the repository at this point in the history
feat: ibc module testing suite and implementation
  • Loading branch information
plafer authored Sep 22, 2023
2 parents fe52405 + 88ed73b commit 54db60b
Show file tree
Hide file tree
Showing 35 changed files with 2,501 additions and 71 deletions.
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

0 comments on commit 54db60b

Please sign in to comment.