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

refactor: generalize ibc-testkit types to allow remote storage and light clients #1270

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
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
77 changes: 52 additions & 25 deletions ibc-testkit/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ use basecoin_store::context::ProvableStore;
use basecoin_store::impls::InMemoryStore;
use ibc::core::channel::types::channel::ChannelEnd;
use ibc::core::channel::types::commitment::PacketCommitment;
use ibc::core::client::context::client_state::ClientStateValidation;
use ibc::core::client::context::client_state::{ClientStateExecution, ClientStateValidation};
use ibc::core::client::context::consensus_state::ConsensusState;
use ibc::core::client::context::{ClientExecutionContext, ClientValidationContext};
use ibc::core::client::types::error::ClientError;
use ibc::core::client::types::Height;
use ibc::core::connection::types::ConnectionEnd;
use ibc::core::entrypoint::{dispatch, execute, validate};
Expand All @@ -20,23 +22,28 @@ use ibc::core::host::types::path::{
};
use ibc::core::host::{ExecutionContext, ValidationContext};
use ibc::primitives::prelude::*;
use ibc::primitives::proto::Any;
use ibc::primitives::Timestamp;

use super::testapp::ibc::core::types::{LightClientState, MockIbcStore};
use crate::fixtures::core::context::TestContextConfig;
use crate::hosts::{HostClientState, MockHost, TendermintHost, TestBlock, TestHeader, TestHost};
use crate::hosts::{
HostClientState, HostConsensusState, MockHost, TendermintHost, TestBlock, TestHeader, TestHost,
};
use crate::relayer::error::RelayerError;
use crate::testapp::ibc::clients::{AnyClientState, AnyConsensusState};
use crate::testapp::ibc::core::router::MockRouter;
use crate::testapp::ibc::core::types::DEFAULT_BLOCK_TIME_SECS;

/// A context implementing the dependencies necessary for testing any IBC module.
#[derive(Debug)]
pub struct StoreGenericTestContext<S, H>
pub struct StoreGenericTestContext<S, H, ACL, ACS>
where
S: ProvableStore + Debug,
H: TestHost,
HostClientState<H>: ClientStateValidation<MockIbcStore<S>>,
ACL: From<HostClientState<H>> + ClientStateExecution<MockIbcStore<S, ACL, ACS>> + Clone,
ACS: From<HostConsensusState<H>> + ConsensusState + Clone,
HostClientState<H>: ClientStateValidation<MockIbcStore<S, ACL, ACS>>,
{
/// The multi store of the context.
/// This is where the IBC store root is stored at IBC commitment prefix.
Expand All @@ -46,16 +53,19 @@ where
pub host: H,

/// An object that stores all IBC related data.
pub ibc_store: MockIbcStore<S>,
pub ibc_store: MockIbcStore<S, ACL, ACS>,

/// A router that can route messages to the appropriate IBC application.
pub ibc_router: MockRouter,
}

/// A mock store type using basecoin-storage implementations.
pub type MockStore = InMemoryStore;
/// A [`StoreGenericTestContext`] using [`MockStore`].
pub type TestContext<H> = StoreGenericTestContext<MockStore, H>;
/// A [`StoreGenericTestContext`] using [`MockStore`], [`AnyClientState`], and [`AnyConsensusState`].
pub type TestContext<H> = StoreGenericTestContext<MockStore, H, AnyClientState, AnyConsensusState>;
/// A [`LightClientState`] using [`MockStore`], [`AnyClientState`] and [`AnyConsensusState`].
pub type DefaultLightClientState<H> =
LightClientState<H, MockStore, AnyClientState, AnyConsensusState>;
/// A [`StoreGenericTestContext`] using [`MockStore`] and [`MockHost`].
pub type MockContext = TestContext<MockHost>;
/// A [`StoreGenericTestContext`] using [`MockStore`] and [`TendermintHost`].
Expand All @@ -64,11 +74,16 @@ pub type TendermintContext = TestContext<TendermintHost>;
/// Returns a [`StoreGenericTestContext`] with bare minimum initialization: no clients, no connections, and no channels are
/// present, and the chain has Height(5). This should be used sparingly, mostly for testing the
/// creation of new domain objects.
impl<S, H> Default for StoreGenericTestContext<S, H>
impl<S, H, ACL, ACS> Default for StoreGenericTestContext<S, H, ACL, ACS>
where
S: ProvableStore + Debug + Default,
H: TestHost,
HostClientState<H>: ClientStateValidation<MockIbcStore<S>>,
ACL: From<HostClientState<H>> + ClientStateExecution<MockIbcStore<S, ACL, ACS>> + Clone,
ACS: From<HostConsensusState<H>> + ConsensusState + Clone,
HostClientState<H>: ClientStateValidation<MockIbcStore<S, ACL, ACS>>,
MockIbcStore<S, ACL, ACS>:
ClientExecutionContext<ClientStateMut = ACL, ConsensusStateRef = ACS>,
ClientError: From<<ACL as TryFrom<Any>>::Error>,
{
fn default() -> Self {
TestContextConfig::builder().build()
Expand All @@ -77,19 +92,24 @@ where

/// Implementation of internal interface for use in testing. The methods in this interface should
/// _not_ be accessible to any ICS handler.
impl<S, H> StoreGenericTestContext<S, H>
impl<S, H, ACL, ACS> StoreGenericTestContext<S, H, ACL, ACS>
where
S: ProvableStore + Debug,
H: TestHost,
HostClientState<H>: ClientStateValidation<MockIbcStore<S>>,
ACL: From<HostClientState<H>> + ClientStateExecution<MockIbcStore<S, ACL, ACS>> + Clone,
ACS: From<HostConsensusState<H>> + ConsensusState + Clone,
HostClientState<H>: ClientStateValidation<MockIbcStore<S, ACL, ACS>>,
MockIbcStore<S, ACL, ACS>:
ClientExecutionContext<ClientStateMut = ACL, ConsensusStateRef = ACS>,
ClientError: From<<ACL as TryFrom<Any>>::Error>,
{
/// Returns an immutable reference to the IBC store.
pub fn ibc_store(&self) -> &MockIbcStore<S> {
pub fn ibc_store(&self) -> &MockIbcStore<S, ACL, ACS> {
&self.ibc_store
}

/// Returns a mutable reference to the IBC store.
pub fn ibc_store_mut(&mut self) -> &mut MockIbcStore<S> {
pub fn ibc_store_mut(&mut self) -> &mut MockIbcStore<S, ACL, ACS> {
&mut self.ibc_store
}

Expand Down Expand Up @@ -170,12 +190,12 @@ where
/// and consensus, and prepares the context for the next block. This includes
/// the latest consensus state and the latest IBC commitment proof.
pub fn begin_block(&mut self) {
let consensus_state = self
.host
.latest_block()
.into_header()
.into_consensus_state()
.into();
let consensus_state = ACS::from(
self.host
.latest_block()
.into_header()
.into_consensus_state(),
);

let ibc_commitment_proof = self
.multi_store
Expand Down Expand Up @@ -274,7 +294,7 @@ where
}

/// Bootstraps the context with a client state and its corresponding [`ClientId`].
pub fn with_client_state(mut self, client_id: &ClientId, client_state: AnyClientState) -> Self {
pub fn with_client_state(mut self, client_id: &ClientId, client_state: ACL) -> Self {
let client_state_path = ClientStatePath::new(client_id.clone());
self.ibc_store
.store_client_state(client_state_path, client_state)
Expand All @@ -287,7 +307,7 @@ where
mut self,
client_id: &ClientId,
height: Height,
consensus_state: AnyConsensusState,
consensus_state: ACS,
) -> Self {
let consensus_state_path = ClientConsensusStatePath::new(
client_id.clone(),
Expand All @@ -308,7 +328,7 @@ where
&self,
mut consensus_heights: Vec<Height>,
client_params: &H::LightClientParams,
) -> LightClientState<H> {
) -> LightClientState<H, S, ACL, ACS> {
let client_height = if let Some(&height) = consensus_heights.last() {
height
} else {
Expand Down Expand Up @@ -336,22 +356,25 @@ where
LightClientState {
client_state,
consensus_states,
_phantom: core::marker::PhantomData,
}
}

/// Bootstrap a light client with ClientState and its ConsensusState(s) to this context.
pub fn with_light_client<RH>(
mut self,
client_id: &ClientId,
light_client: LightClientState<RH>,
light_client: LightClientState<RH, S, ACL, ACS>,
) -> Self
where
RH: TestHost,
ACL: From<HostClientState<RH>>,
ACS: From<HostConsensusState<RH>>,
{
self = self.with_client_state(client_id, light_client.client_state.into());
self = self.with_client_state(client_id, ACL::from(light_client.client_state));

for (height, consensus_state) in light_client.consensus_states {
self = self.with_consensus_state(client_id, height, consensus_state.into());
self = self.with_consensus_state(client_id, height, ACS::from(consensus_state));

self.ibc_store
.store_update_meta(
Expand Down Expand Up @@ -512,6 +535,8 @@ mod tests {
pub struct Test<H: TestHost>
where
H: TestHost,
AnyClientState: From<HostClientState<H>>,
AnyConsensusState: From<HostConsensusState<H>>,
HostConsensusState<H>: ConsensusState,
HostClientState<H>: ClientStateValidation<DefaultIbcStore>,
{
Expand All @@ -522,6 +547,8 @@ mod tests {
fn run_tests<H>(sub_title: &str)
where
H: TestHost,
AnyClientState: From<HostClientState<H>>,
AnyConsensusState: From<HostConsensusState<H>>,
HostConsensusState<H>: ConsensusState,
HostClientState<H>: ClientStateValidation<DefaultIbcStore>,
{
Expand Down
18 changes: 14 additions & 4 deletions ibc-testkit/src/fixtures/core/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ use alloc::fmt::Debug;
use core::time::Duration;

use basecoin_store::context::ProvableStore;
use ibc::core::client::context::client_state::ClientStateValidation;
use ibc::core::client::context::client_state::{ClientStateExecution, ClientStateValidation};
use ibc::core::client::context::consensus_state::ConsensusState;
use ibc::core::client::context::ClientExecutionContext;
use ibc::core::client::types::error::ClientError;
use ibc::core::client::types::Height;
use ibc::core::primitives::prelude::*;
use ibc::core::primitives::Timestamp;
use ibc::primitives::proto::Any;
use typed_builder::TypedBuilder;

use crate::context::StoreGenericTestContext;
use crate::hosts::{HostClientState, TestBlock, TestHost};
use crate::hosts::{HostClientState, HostConsensusState, TestBlock, TestHost};
use crate::testapp::ibc::core::router::MockRouter;
use crate::testapp::ibc::core::types::{MockIbcStore, DEFAULT_BLOCK_TIME_SECS};
use crate::utils::year_2023;
Expand Down Expand Up @@ -37,11 +41,17 @@ where
latest_height: Height,
}

impl<S, H> From<TestContextConfig<H>> for StoreGenericTestContext<S, H>
impl<S, H, ACL, ACS> From<TestContextConfig<H>> for StoreGenericTestContext<S, H, ACL, ACS>
where
S: ProvableStore + Debug + Default,
H: TestHost,
HostClientState<H>: ClientStateValidation<MockIbcStore<S>>,
S: ProvableStore + Debug,
ACL: From<HostClientState<H>> + ClientStateExecution<MockIbcStore<S, ACL, ACS>> + Clone,
ACS: From<HostConsensusState<H>> + ConsensusState + Clone,
HostClientState<H>: ClientStateValidation<MockIbcStore<S, ACL, ACS>>,
MockIbcStore<S, ACL, ACS>:
ClientExecutionContext<ClientStateMut = ACL, ConsensusStateRef = ACS>,
ClientError: From<<ACL as TryFrom<Any>>::Error>,
{
fn from(params: TestContextConfig<H>) -> Self {
assert_ne!(
Expand Down
5 changes: 2 additions & 3 deletions ibc-testkit/src/hosts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use ibc::primitives::proto::Any;

pub use self::mock::MockHost;
pub use self::tendermint::TendermintHost;
use crate::testapp::ibc::clients::{AnyClientState, AnyConsensusState};

pub type HostClientState<H> = <H as TestHost>::ClientState;
pub type HostBlock<H> = <H as TestHost>::Block;
Expand All @@ -28,7 +27,7 @@ pub trait TestHost: Default + Debug + Sized {
type Block: TestBlock;

/// The type of client state produced by the host.
type ClientState: Into<AnyClientState> + Debug;
type ClientState: Debug;

/// The type of block parameter to produce a block.
type BlockParams: Debug + Default;
Expand Down Expand Up @@ -142,7 +141,7 @@ pub trait TestBlock: Clone + Debug {
/// submitted by relayer from the host blockchain.
pub trait TestHeader: Clone + Debug + Into<Any> {
/// The type of consensus state can be extracted from the header.
type ConsensusState: ConsensusState + Into<AnyConsensusState> + From<Self> + Clone + Debug;
type ConsensusState: ConsensusState + From<Self> + Clone + Debug;

/// The height of the block, as recorded in the header.
fn height(&self) -> Height;
Expand Down
Loading
Loading