diff --git a/ibc-core/ics23-commitment/types/src/commitment.rs b/ibc-core/ics23-commitment/types/src/commitment.rs index f5c23edc2..25f4ca579 100644 --- a/ibc-core/ics23-commitment/types/src/commitment.rs +++ b/ibc-core/ics23-commitment/types/src/commitment.rs @@ -148,12 +148,6 @@ pub struct CommitmentPrefix { bytes: Vec, } -impl Default for CommitmentPrefix { - fn default() -> Self { - Self { bytes: vec![0x00] } - } -} - impl CommitmentPrefix { pub fn as_bytes(&self) -> &[u8] { &self.bytes diff --git a/ibc-testkit/src/context.rs b/ibc-testkit/src/context.rs new file mode 100644 index 000000000..846c08a91 --- /dev/null +++ b/ibc-testkit/src/context.rs @@ -0,0 +1,488 @@ +use core::fmt::Debug; +use core::time::Duration; + +use basecoin_store::avl::get_proof_spec as basecoin_proof_spec; +use basecoin_store::context::ProvableStore; +use basecoin_store::impls::{GrowingStore, InMemoryStore, RevertibleStore}; +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::ClientExecutionContext; +use ibc::core::client::types::Height; +use ibc::core::commitment_types::specs::ProofSpecs; +use ibc::core::connection::types::ConnectionEnd; +use ibc::core::entrypoint::dispatch; +use ibc::core::handler::types::events::IbcEvent; +use ibc::core::handler::types::msgs::MsgEnvelope; +use ibc::core::host::types::identifiers::{ChannelId, ClientId, ConnectionId, PortId, Sequence}; +use ibc::core::host::types::path::{ + ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ConnectionPath, + SeqAckPath, SeqRecvPath, SeqSendPath, +}; +use ibc::core::host::{ExecutionContext, ValidationContext}; +use ibc::core::router::router::Router; +use ibc::primitives::prelude::*; +use ibc::primitives::Timestamp; +use typed_builder::TypedBuilder; + +use super::testapp::ibc::core::types::{LightClientState, MockIbcStore}; +use crate::fixtures::core::context::MockContextConfig; +use crate::hosts::{HostClientState, TestBlock, TestHeader, TestHost}; +use crate::relayer::error::RelayerError; +use crate::testapp::ibc::clients::{AnyClientState, AnyConsensusState}; +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 MockGenericContext +where + S: ProvableStore + Debug, + H: TestHost, + HostClientState: ClientStateValidation>, +{ + /// The type of host chain underlying this mock context. + pub host: H, + + /// An object that stores all IBC related data. + pub ibc_store: MockIbcStore, +} + +pub type MockStore = RevertibleStore>; +pub type MockContext = MockGenericContext; + +#[derive(Debug, TypedBuilder)] +pub struct MockClientConfig { + #[builder(default = Duration::from_secs(64000))] + pub trusting_period: Duration, + #[builder(default = Duration::from_millis(3000))] + pub max_clock_drift: Duration, + #[builder(default = Duration::from_secs(128_000))] + pub unbonding_period: Duration, + #[builder(default = vec![basecoin_proof_spec()].into())] + pub proof_specs: ProofSpecs, +} + +impl Default for MockClientConfig { + fn default() -> Self { + Self::builder().build() + } +} + +/// Returns a MockContext 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 Default for MockGenericContext +where + S: ProvableStore + Debug + Default, + H: TestHost, + HostClientState: ClientStateValidation>, +{ + fn default() -> Self { + MockContextConfig::builder().build() + } +} + +/// Implementation of internal interface for use in testing. The methods in this interface should +/// _not_ be accessible to any Ics handler. +impl MockGenericContext +where + S: ProvableStore + Debug, + H: TestHost, + HostClientState: ClientStateValidation>, +{ + pub fn ibc_store(&self) -> &MockIbcStore { + &self.ibc_store + } + + pub fn host_block(&self, target_height: &Height) -> Option { + self.host.get_block(target_height) + } + + pub fn query_latest_block(&self) -> Option { + self.host.get_block(&self.latest_height()) + } + + pub fn advance_block_up_to(mut self, target_height: Height) -> Self { + let latest_height = self.host.latest_height(); + if target_height.revision_number() != latest_height.revision_number() { + panic!("Cannot advance history of the chain to a different revision number!") + } else if target_height.revision_height() < latest_height.revision_height() { + panic!("Cannot rewind history of the chain to a smaller revision height!") + } else { + // Repeatedly advance the host chain height till we hit the desired height + while self.host.latest_height().revision_height() < target_height.revision_height() { + self.advance_block() + } + } + self + } + + pub fn generate_genesis_block(&mut self, genesis_time: Timestamp, params: &H::BlockParams) { + // commit store + let app_hash = self.ibc_store.commit().expect("no error"); + + // generate and push genesis block + let genesis_block = self.host.generate_block(app_hash, 1, genesis_time, params); + self.host.push_block(genesis_block); + + // store it in ibc context as host consensus state + self.ibc_store.store_host_consensus_state( + self.host + .latest_block() + .into_header() + .into_consensus_state() + .into(), + ); + } + + pub fn advance_with_block_params(&mut self, block_time: Duration, params: &H::BlockParams) { + // commit store + let app_hash = self.ibc_store.commit().expect("no error"); + + // generate a new block + self.host.advance_block(app_hash, block_time, params); + + // store it in ibc context as host consensus state + self.ibc_store.store_host_consensus_state( + self.host + .latest_block() + .into_header() + .into_consensus_state() + .into(), + ); + } + + pub fn advance_block(&mut self) { + self.advance_with_block_params( + Duration::from_secs(DEFAULT_BLOCK_TIME_SECS), + &Default::default(), + ) + } + + pub fn prune_block_till(&mut self, height: &Height) { + self.host.prune_block_till(height); + self.ibc_store.prune_host_consensus_states_till(height); + } + + pub fn latest_height(&self) -> Height { + let latest_ibc_height = self.ibc_store.host_height().expect("Never fails"); + let latest_host_height = self.host.latest_height(); + assert_eq!( + latest_ibc_height, latest_host_height, + "The IBC store and the host chain must have the same height" + ); + latest_ibc_height + } + + pub fn latest_timestamp(&self) -> Timestamp { + self.host.latest_block().timestamp() + } + + pub fn timestamp_at(&self, height: Height) -> Timestamp { + self.host + .get_block(&height) + .expect("block exists") + .timestamp() + } + + pub fn with_client_state(mut self, client_id: &ClientId, client_state: AnyClientState) -> Self { + let client_state_path = ClientStatePath::new(client_id.clone()); + self.ibc_store + .store_client_state(client_state_path, client_state) + .expect("error writing to store"); + self + } + + pub fn with_consensus_state( + mut self, + client_id: &ClientId, + height: Height, + consensus_state: AnyConsensusState, + ) -> Self { + let consensus_state_path = ClientConsensusStatePath::new( + client_id.clone(), + height.revision_number(), + height.revision_height(), + ); + self.ibc_store + .store_consensus_state(consensus_state_path, consensus_state) + .expect("error writing to store"); + + self + } + + pub fn generate_light_client( + &self, + mut consensus_heights: Vec, + client_params: &H::LightClientParams, + ) -> LightClientState { + let client_height = if let Some(&height) = consensus_heights.last() { + height + } else { + consensus_heights.push(self.latest_height()); + self.latest_height() + }; + + let client_state = self + .host + .generate_client_state(&client_height, client_params); + + let consensus_states = consensus_heights + .into_iter() + .map(|height| { + ( + height, + self.host_block(&height) + .expect("block exists") + .into_header() + .into_consensus_state(), + ) + }) + .collect(); + + LightClientState { + client_state, + consensus_states, + } + } + + pub fn with_light_client( + mut self, + client_id: &ClientId, + light_client: LightClientState, + ) -> Self + where + RH: TestHost, + { + self = self.with_client_state(client_id, light_client.client_state.into()); + + for (height, consensus_state) in light_client.consensus_states { + self = self.with_consensus_state(client_id, height, consensus_state.into()); + + self.ibc_store + .store_update_meta( + client_id.clone(), + height, + self.latest_timestamp(), + self.latest_height(), + ) + .expect("error writing to store"); + } + + self + } + + /// Associates a connection to this context. + pub fn with_connection( + mut self, + connection_id: ConnectionId, + connection_end: ConnectionEnd, + ) -> Self { + let connection_path = ConnectionPath::new(&connection_id); + self.ibc_store + .store_connection(&connection_path, connection_end) + .expect("error writing to store"); + self + } + + /// Associates a channel (in an arbitrary state) to this context. + pub fn with_channel( + mut self, + port_id: PortId, + chan_id: ChannelId, + channel_end: ChannelEnd, + ) -> Self { + let channel_end_path = ChannelEndPath::new(&port_id, &chan_id); + self.ibc_store + .store_channel(&channel_end_path, channel_end) + .expect("error writing to store"); + self + } + + pub fn with_send_sequence( + mut self, + port_id: PortId, + chan_id: ChannelId, + seq_number: Sequence, + ) -> Self { + let seq_send_path = SeqSendPath::new(&port_id, &chan_id); + self.ibc_store + .store_next_sequence_send(&seq_send_path, seq_number) + .expect("error writing to store"); + self + } + + pub fn with_recv_sequence( + mut self, + port_id: PortId, + chan_id: ChannelId, + seq_number: Sequence, + ) -> Self { + let seq_recv_path = SeqRecvPath::new(&port_id, &chan_id); + self.ibc_store + .store_next_sequence_recv(&seq_recv_path, seq_number) + .expect("error writing to store"); + self + } + + pub fn with_ack_sequence( + mut self, + port_id: PortId, + chan_id: ChannelId, + seq_number: Sequence, + ) -> Self { + let seq_ack_path = SeqAckPath::new(&port_id, &chan_id); + self.ibc_store + .store_next_sequence_ack(&seq_ack_path, seq_number) + .expect("error writing to store"); + self + } + + pub fn with_packet_commitment( + mut self, + port_id: PortId, + chan_id: ChannelId, + seq: Sequence, + data: PacketCommitment, + ) -> Self { + let commitment_path = CommitmentPath::new(&port_id, &chan_id, seq); + self.ibc_store + .store_packet_commitment(&commitment_path, data) + .expect("error writing to store"); + self + } + + /// A datagram passes from the relayer to the IBC module (on host chain). + /// Alternative method to `Ics18Context::send` that does not exercise any serialization. + /// Used in testing the Ics18 algorithms, hence this may return a Ics18Error. + pub fn deliver( + &mut self, + router: &mut impl Router, + msg: MsgEnvelope, + ) -> Result<(), RelayerError> { + dispatch(&mut self.ibc_store, router, msg).map_err(RelayerError::TransactionFailed)?; + // Create a new block. + self.advance_block(); + Ok(()) + } + + pub fn get_events(&self) -> Vec { + self.ibc_store.events.lock().clone() + } + + pub fn get_logs(&self) -> Vec { + self.ibc_store.logs.lock().clone() + } +} + +#[cfg(test)] +mod tests { + use ibc::core::client::context::consensus_state::ConsensusState; + + use super::*; + use crate::hosts::{HostConsensusState, MockHost, TendermintHost}; + use crate::testapp::ibc::core::types::DefaultIbcStore; + + #[test] + fn test_mock_history_validation() { + pub struct Test + where + H: TestHost, + HostConsensusState: ConsensusState, + HostClientState: ClientStateValidation, + { + name: String, + ctx: MockContext, + } + + fn run_tests(sub_title: &str) + where + H: TestHost, + HostConsensusState: ConsensusState, + HostClientState: ClientStateValidation, + { + let cv = 0; // The version to use for all chains. + + let tests: Vec> = vec![ + Test { + name: "Empty history, small pruning window".to_string(), + ctx: MockContextConfig::builder() + .latest_height(Height::new(cv, 1).expect("Never fails")) + .build(), + }, + Test { + name: "Large pruning window".to_string(), + ctx: MockContextConfig::builder() + .latest_height(Height::new(cv, 2).expect("Never fails")) + .build(), + }, + Test { + name: "Small pruning window".to_string(), + ctx: MockContextConfig::builder() + .latest_height(Height::new(cv, 30).expect("Never fails")) + .build(), + }, + Test { + name: "Small pruning window, small starting height".to_string(), + ctx: MockContextConfig::builder() + .latest_height(Height::new(cv, 2).expect("Never fails")) + .build(), + }, + // This is disabled, as now we generate all the blocks till latest_height + // Generating 2000 Tendermint blocks is slow. + // Test { + // name: "Large pruning window, large starting height".to_string(), + // ctx: MockContextConfig::builder() + // .latest_height(Height::new(cv, 2000).expect("Never fails")) + // .build(), + // }, + ]; + + for mut test in tests { + // All tests should yield a valid context after initialization. + assert!( + test.ctx.host.validate().is_ok(), + "failed in test [{}] {} while validating context {:?}", + sub_title, + test.name, + test.ctx + ); + + let current_height = test.ctx.latest_height(); + + // After advancing the chain's height, the context should still be valid. + test.ctx.advance_block(); + assert!( + test.ctx.host.validate().is_ok(), + "failed in test [{}] {} while validating context {:?}", + sub_title, + test.name, + test.ctx + ); + + let next_height = current_height.increment(); + assert_eq!( + test.ctx.latest_height(), + next_height, + "failed while increasing height for context {:?}", + test.ctx + ); + + assert_eq!( + test.ctx + .host + .get_block(¤t_height) + .expect("Never fails") + .height(), + current_height, + "failed while fetching height {:?} of context {:?}", + current_height, + test.ctx + ); + } + } + + run_tests::("Mock Host"); + run_tests::("Synthetic TM Host"); + } +} diff --git a/ibc-testkit/src/fixtures/applications/transfer.rs b/ibc-testkit/src/fixtures/applications/transfer.rs index 35e71fac0..dfd16a5e0 100644 --- a/ibc-testkit/src/fixtures/applications/transfer.rs +++ b/ibc-testkit/src/fixtures/applications/transfer.rs @@ -26,7 +26,7 @@ pub struct MsgTransferConfig { impl From for MsgTransfer { fn from(config: MsgTransferConfig) -> Self { - MsgTransfer { + Self { port_id_on_a: config.port_id_on_a, chan_id_on_a: config.chan_id_on_a, packet_data: config.packet_data, @@ -67,7 +67,7 @@ pub struct PacketDataConfig { impl From for PacketData { fn from(config: PacketDataConfig) -> Self { - PacketData { + Self { token: config.token, sender: config.sender, receiver: config.receiver, diff --git a/ibc-testkit/src/fixtures/clients/tendermint.rs b/ibc-testkit/src/fixtures/clients/tendermint.rs index f96ad0e6b..e10ed576c 100644 --- a/ibc-testkit/src/fixtures/clients/tendermint.rs +++ b/ibc-testkit/src/fixtures/clients/tendermint.rs @@ -100,7 +100,7 @@ impl TryFrom for TmClientState { config.allow_update, )?; - Ok(TmClientState::from(client_state)) + Ok(client_state.into()) } } @@ -146,7 +146,7 @@ pub fn dummy_ics07_header() -> Header { // Build a set of validators. // Below are test values inspired form `test_validator_set()` in tendermint-rs. - let v1: ValidatorInfo = ValidatorInfo::new( + let v1 = ValidatorInfo::new( PublicKey::from_raw_ed25519( &hex::decode_upper("F349539C7E5EF7C49549B09C4BFC2335318AB0FE51FBFAA2433B4F13E816F4A7") .expect("Never fails"), diff --git a/ibc-testkit/src/fixtures/core/channel/mod.rs b/ibc-testkit/src/fixtures/core/channel/mod.rs index a1375cd72..65a507075 100644 --- a/ibc-testkit/src/fixtures/core/channel/mod.rs +++ b/ibc-testkit/src/fixtures/core/channel/mod.rs @@ -10,22 +10,23 @@ mod recv_packet; mod timeout; mod timeout_on_close; -pub use acknowledgement::*; -pub use chan_close_confirm::*; -pub use chan_close_init::*; -pub use chan_open_ack::*; -pub use chan_open_confirm::*; -pub use chan_open_init::*; -pub use chan_open_try::*; use ibc::core::channel::types::proto::v1::{ Channel as RawChannel, Counterparty as RawCounterparty, }; use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc::primitives::prelude::*; -pub use packet::*; -pub use recv_packet::*; -pub use timeout::*; -pub use timeout_on_close::*; + +pub use self::acknowledgement::*; +pub use self::chan_close_confirm::*; +pub use self::chan_close_init::*; +pub use self::chan_open_ack::*; +pub use self::chan_open_confirm::*; +pub use self::chan_open_init::*; +pub use self::chan_open_try::*; +pub use self::packet::*; +pub use self::recv_packet::*; +pub use self::timeout::*; +pub use self::timeout_on_close::*; /// Returns a dummy `RawCounterparty`, for testing purposes only! /// Can be optionally parametrized with a specific channel identifier. diff --git a/ibc-testkit/src/fixtures/core/channel/packet.rs b/ibc-testkit/src/fixtures/core/channel/packet.rs index b33e1b2a4..97815a728 100644 --- a/ibc-testkit/src/fixtures/core/channel/packet.rs +++ b/ibc-testkit/src/fixtures/core/channel/packet.rs @@ -31,7 +31,7 @@ pub struct PacketConfig { impl From for Packet { fn from(config: PacketConfig) -> Self { - Packet { + Self { seq_on_a: config.seq_on_a, port_id_on_a: config.port_id_on_a, chan_id_on_a: config.chan_id_on_a, diff --git a/ibc-testkit/src/fixtures/core/client/mod.rs b/ibc-testkit/src/fixtures/core/client/mod.rs index a536d778c..442bed21d 100644 --- a/ibc-testkit/src/fixtures/core/client/mod.rs +++ b/ibc-testkit/src/fixtures/core/client/mod.rs @@ -5,10 +5,10 @@ mod msg_update_client; mod msg_upgrade_client; #[cfg(feature = "serde")] -pub use msg_create_client::*; +pub use self::msg_create_client::*; #[cfg(feature = "serde")] -pub use msg_update_client::*; -pub use msg_upgrade_client::*; +pub use self::msg_update_client::*; +pub use self::msg_upgrade_client::*; #[cfg(test)] mod tests { diff --git a/ibc-testkit/src/fixtures/core/connection/mod.rs b/ibc-testkit/src/fixtures/core/connection/mod.rs index 5b8388147..3460a3f10 100644 --- a/ibc-testkit/src/fixtures/core/connection/mod.rs +++ b/ibc-testkit/src/fixtures/core/connection/mod.rs @@ -3,16 +3,17 @@ mod conn_open_confirm; mod conn_open_init; mod conn_open_try; -pub use conn_open_ack::*; -pub use conn_open_confirm::*; -pub use conn_open_init::*; -pub use conn_open_try::*; use ibc::core::commitment_types::proto::v1::MerklePrefix; use ibc::core::connection::types::proto::v1::Counterparty as RawCounterparty; use ibc::core::host::types::identifiers::ConnectionId; use ibc::core::primitives::prelude::*; use typed_builder::TypedBuilder; +pub use self::conn_open_ack::*; +pub use self::conn_open_confirm::*; +pub use self::conn_open_init::*; +pub use self::conn_open_try::*; + #[derive(TypedBuilder, Debug)] #[builder(build_method(into = RawCounterparty))] pub struct CounterpartyConfig { diff --git a/ibc-testkit/src/fixtures/core/context.rs b/ibc-testkit/src/fixtures/core/context.rs index 2a047eba4..724a706a6 100644 --- a/ibc-testkit/src/fixtures/core/context.rs +++ b/ibc-testkit/src/fixtures/core/context.rs @@ -1,17 +1,16 @@ use alloc::fmt::Debug; -use core::cmp::min; -use core::ops::{Add, Sub}; use core::time::Duration; use basecoin_store::context::ProvableStore; +use ibc::core::client::context::client_state::ClientStateValidation; use ibc::core::client::types::Height; -use ibc::core::host::types::identifiers::ChainId; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Timestamp; use typed_builder::TypedBuilder; -use crate::hosts::TestHost; -use crate::testapp::ibc::core::types::{MockGenericContext, MockIbcStore, DEFAULT_BLOCK_TIME_SECS}; +use crate::context::MockGenericContext; +use crate::hosts::{HostClientState, TestBlock, TestHost}; +use crate::testapp::ibc::core::types::{MockIbcStore, DEFAULT_BLOCK_TIME_SECS}; use crate::utils::year_2023; /// Configuration of the `MockContext` type for generating dummy contexts. @@ -21,108 +20,78 @@ pub struct MockContextConfig where H: TestHost, { - #[builder(default = ChainId::new("mockgaia-0").expect("Never fails"))] - host_id: ChainId, + #[builder(default)] + pub host: H, #[builder(default = Duration::from_secs(DEFAULT_BLOCK_TIME_SECS))] block_time: Duration, - // may panic if validator_set_history size is less than max_history_size + 1 - #[builder(default = 5)] - max_history_size: u64, + #[builder(default = year_2023())] + latest_timestamp: Timestamp, - #[builder(default, setter(strip_option))] - block_params_history: Option>, + #[builder(default)] + block_params_history: Vec, #[builder(default = Height::new(0, 5).expect("Never fails"))] latest_height: Height, - - #[builder(default = year_2023())] - latest_timestamp: Timestamp, } impl From> for MockGenericContext where S: ProvableStore + Debug + Default, H: TestHost, + HostClientState: ClientStateValidation>, { fn from(params: MockContextConfig) -> Self { - assert_ne!( - params.max_history_size, 0, - "The chain must have a non-zero max_history_size" - ); - assert_ne!( params.latest_height.revision_height(), 0, "The chain must have a non-zero revision_height" ); - // Compute the number of blocks to store. - let n = min( - params.max_history_size, - params.latest_height.revision_height(), + // timestamp at height 1 + let genesis_timestamp = (params.latest_timestamp + - (params.block_time + * u32::try_from(params.latest_height.revision_height() - 1).expect("no overflow"))) + .expect("no underflow"); + + let mut context = Self { + ibc_store: MockIbcStore::new( + params.latest_height.revision_number(), + Default::default(), + ), + host: params.host, + }; + + // store is a height 0; no block + + context.generate_genesis_block(genesis_timestamp, &Default::default()); + + // store is a height 1; one block + + context = context.advance_block_up_to( + params + .latest_height + .sub(params.block_params_history.len() as u64) + .expect("no error"), ); + for block_params in params.block_params_history { + context.advance_with_block_params(params.block_time, &block_params); + } + assert_eq!( - params.host_id.revision_number(), - params.latest_height.revision_number(), - "The version in the chain identifier must match the version in the latest height" + context.host.latest_block().height(), + params.latest_height, + "The latest height in the host must match the latest height in the context" ); - let next_block_timestamp = params - .latest_timestamp - .add(params.block_time) - .expect("Never fails"); - - let host = H::with_chain_id(params.host_id); - - let history = if let Some(validator_set_history) = params.block_params_history { - (0..n) - .rev() - .map(|i| { - // generate blocks with timestamps -> N, N - BT, N - 2BT, ... - // where N = now(), BT = block_time - host.generate_block( - params - .latest_height - .sub(i) - .expect("Never fails") - .revision_height(), - next_block_timestamp - .sub(params.block_time * ((i + 1) as u32)) - .expect("Never fails"), - &validator_set_history[(n - i) as usize - 1], - ) - }) - .collect() - } else { - (0..n) - .rev() - .map(|i| { - // generate blocks with timestamps -> N, N - BT, N - 2BT, ... - // where N = now(), BT = block_time - host.generate_block( - params - .latest_height - .sub(i) - .expect("Never fails") - .revision_height(), - next_block_timestamp - .sub(params.block_time * ((i + 1) as u32)) - .expect("Never fails"), - &H::BlockParams::default(), - ) - }) - .collect() - }; + assert_eq!( + context.host.latest_block().timestamp(), + params.latest_timestamp, + "The latest timestamp in the host must match the latest timestamp in the context" + ); - MockGenericContext { - host, - max_history_size: params.max_history_size, - history, - block_time: params.block_time, - ibc_store: MockIbcStore::default(), - } + context } } diff --git a/ibc-testkit/src/fixtures/mod.rs b/ibc-testkit/src/fixtures/mod.rs index 686274bd6..f6b51ef46 100644 --- a/ibc-testkit/src/fixtures/mod.rs +++ b/ibc-testkit/src/fixtures/mod.rs @@ -6,8 +6,7 @@ use alloc::fmt::Debug; use ibc::core::handler::types::error::ContextError; use ibc::core::primitives::prelude::*; -use crate::hosts::MockHost; -use crate::testapp::ibc::core::types::MockContext; +use crate::testapp::ibc::core::types::DefaultIbcStore; pub enum Expect { Success, Failure(Option), @@ -15,7 +14,7 @@ pub enum Expect { #[derive(Debug)] pub struct Fixture { - pub ctx: MockContext, + pub ctx: DefaultIbcStore, pub msg: M, } diff --git a/ibc-testkit/src/hosts/mock.rs b/ibc-testkit/src/hosts/mock.rs index 6fdec6309..067d41a14 100644 --- a/ibc-testkit/src/hosts/mock.rs +++ b/ibc-testkit/src/hosts/mock.rs @@ -1,52 +1,80 @@ +use alloc::collections::VecDeque; +use alloc::vec::Vec; + use ibc::core::client::types::Height; use ibc::core::host::types::identifiers::ChainId; use ibc::core::primitives::Timestamp; +use typed_builder::TypedBuilder; use super::{TestBlock, TestHeader, TestHost}; use crate::testapp::ibc::clients::mock::client_state::MockClientState; use crate::testapp::ibc::clients::mock::consensus_state::MockConsensusState; use crate::testapp::ibc::clients::mock::header::MockHeader; -#[derive(Debug)] -pub struct Host(ChainId); +#[derive(TypedBuilder, Debug)] +pub struct MockHost { + /// Unique identifier for the chain. + #[builder(default = ChainId::new("mock-0").expect("Never fails"))] + pub chain_id: ChainId, + /// The chain of blocks underlying this context. + #[builder(default)] + pub history: VecDeque, +} + +impl Default for MockHost { + fn default() -> Self { + Self::builder().build() + } +} -impl TestHost for Host { +impl TestHost for MockHost { type Block = MockHeader; + type ClientState = MockClientState; type BlockParams = (); type LightClientParams = (); - type ClientState = MockClientState; - fn with_chain_id(chain_id: ChainId) -> Self { - Self(chain_id) + fn history(&self) -> &VecDeque { + &self.history } - fn chain_id(&self) -> &ChainId { - &self.0 + fn push_block(&mut self, block: Self::Block) { + self.history.push_back(block); + } + + fn prune_block_till(&mut self, height: &Height) { + while let Some(block) = self.history.front() { + if &block.height() <= height { + self.history.pop_front(); + } else { + break; + } + } } fn generate_block( &self, + _: Vec, height: u64, timestamp: Timestamp, _: &Self::BlockParams, ) -> Self::Block { MockHeader { - height: Height::new(self.chain_id().revision_number(), height).expect("Never fails"), + height: Height::new(self.chain_id.revision_number(), height).expect("Never fails"), timestamp, } } fn generate_client_state( &self, - latest_block: &Self::Block, + latest_height: &Height, _: &Self::LightClientParams, ) -> Self::ClientState { - MockClientState::new(*latest_block) + MockClientState::new(self.get_block(latest_height).expect("height exists")) } } impl TestBlock for MockHeader { - type Header = MockHeader; + type Header = Self; fn height(&self) -> Height { self.height @@ -59,7 +87,7 @@ impl TestBlock for MockHeader { impl From for MockConsensusState { fn from(block: MockHeader) -> Self { - MockConsensusState::new(block) + Self::new(block) } } diff --git a/ibc-testkit/src/hosts/mod.rs b/ibc-testkit/src/hosts/mod.rs index 056efd7cb..387723a64 100644 --- a/ibc-testkit/src/hosts/mod.rs +++ b/ibc-testkit/src/hosts/mod.rs @@ -1,27 +1,35 @@ +pub mod mock; +pub mod tendermint; + +use alloc::collections::VecDeque; use core::fmt::Debug; +use core::ops::Add; +use core::time::Duration; use ibc::core::client::context::consensus_state::ConsensusState; use ibc::core::client::types::Height; -use ibc::core::host::types::identifiers::ChainId; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Timestamp; use ibc::primitives::proto::Any; +pub use self::mock::MockHost; +pub use self::tendermint::TendermintHost; use crate::testapp::ibc::clients::{AnyClientState, AnyConsensusState}; -pub mod mock; -pub mod tendermint; - -pub use mock::Host as MockHost; -pub use tendermint::Host as TendermintHost; +pub type HostClientState = ::ClientState; +pub type HostBlock = ::Block; +pub type HostBlockParams = ::BlockParams; +pub type HostLightClientParams = ::LightClientParams; +pub type HostHeader = as TestBlock>::Header; +pub type HostConsensusState = as TestHeader>::ConsensusState; /// TestHost is a trait that defines the interface for a host blockchain. -pub trait TestHost: Debug { +pub trait TestHost: Default + Debug + Sized { /// The type of block produced by the host. type Block: TestBlock; /// The type of client state produced by the host. - type ClientState: Into; + type ClientState: Into + Debug; /// The type of block parameters to produce a block type BlockParams: Debug + Default; @@ -29,15 +37,63 @@ pub trait TestHost: Debug { /// The type of light client parameters to produce a light client state type LightClientParams: Debug + Default; - /// Create a new host with the given chain identifier. - fn with_chain_id(chain_id: ChainId) -> Self; + /// The history of blocks produced by the host chain. + fn history(&self) -> &VecDeque; - /// The chain identifier of the host. - fn chain_id(&self) -> &ChainId; + /// Returns true if the host chain has no blocks. + fn is_empty(&self) -> bool { + self.history().is_empty() + } + + /// The latest height of the host chain. + fn latest_height(&self) -> Height { + self.latest_block().height() + } + + /// The latest block of the host chain. + fn latest_block(&self) -> Self::Block { + self.history().back().cloned().expect("no error") + } + + /// Get the block at the given height. + fn get_block(&self, target_height: &Height) -> Option { + self.history() + .get(target_height.revision_height() as usize - 1) + .cloned() // indexed from 1 + } + + /// Add a block to the host chain. + fn push_block(&mut self, block: Self::Block); + + /// Prune blocks until the given height. + fn prune_block_till(&mut self, height: &Height); + + /// Triggers the advancing of the host chain, by extending the history of blocks (or headers). + fn advance_block( + &mut self, + commitment_root: Vec, + block_time: Duration, + params: &Self::BlockParams, + ) { + let latest_block = self.latest_block(); + + let height = TestBlock::height(&latest_block) + .increment() + .revision_height(); + let timestamp = TestBlock::timestamp(&latest_block) + .add(block_time) + .expect("Never fails"); + + let new_block = self.generate_block(commitment_root, height, timestamp, params); + + // History is not full yet. + self.push_block(new_block); + } /// Generate a block at the given height and timestamp, using the provided parameters. fn generate_block( &self, + commitment_root: Vec, height: u64, timestamp: Timestamp, params: &Self::BlockParams, @@ -46,9 +102,23 @@ pub trait TestHost: Debug { /// Generate a client state using the block at the given height and the provided parameters. fn generate_client_state( &self, - latest_block: &Self::Block, + latest_height: &Height, params: &Self::LightClientParams, ) -> Self::ClientState; + + fn validate(&self) -> Result<(), String> { + // Check that headers in the history are in sequential order. + let latest_height = self.latest_height(); + let mut current_height = Height::min(latest_height.revision_number()); + + while current_height <= latest_height { + if current_height != self.get_block(¤t_height).expect("no error").height() { + return Err("block height does not match".to_owned()); + } + current_height = current_height.increment(); + } + Ok(()) + } } /// TestBlock is a trait that defines the interface for a block produced by a host blockchain. @@ -71,7 +141,7 @@ pub trait TestBlock: Clone + Debug { /// TestHeader is a trait that defines the interface for a header produced by a host blockchain. pub trait TestHeader: Clone + Debug + Into { /// The type of consensus state can be extracted from the header. - type ConsensusState: ConsensusState + Into + From; + type ConsensusState: ConsensusState + Into + From + Clone + Debug; /// The height of the block, as recorded in the header. fn height(&self) -> Height; diff --git a/ibc-testkit/src/hosts/tendermint.rs b/ibc-testkit/src/hosts/tendermint.rs index 67cccc11c..91c19b2f8 100644 --- a/ibc-testkit/src/hosts/tendermint.rs +++ b/ibc-testkit/src/hosts/tendermint.rs @@ -1,3 +1,4 @@ +use alloc::collections::VecDeque; use core::str::FromStr; use ibc::clients::tendermint::client_state::ClientState; @@ -17,30 +18,55 @@ use tendermint_testgen::{ Generator, Header as TestgenHeader, LightBlock as TestgenLightBlock, Validator as TestgenValidator, }; +use typed_builder::TypedBuilder; -use super::{TestBlock, TestHeader, TestHost}; +use crate::context::MockClientConfig; use crate::fixtures::clients::tendermint::ClientStateConfig; -use crate::testapp::ibc::core::types::MockClientConfig; +use crate::hosts::{TestBlock, TestHeader, TestHost}; + +#[derive(TypedBuilder, Debug)] +pub struct TendermintHost { + /// Unique identifier for the chain. + #[builder(default = ChainId::new("mock-0").expect("Never fails"))] + pub chain_id: ChainId, + /// The chain of blocks underlying this context. + #[builder(default)] + pub history: VecDeque, +} -#[derive(Debug)] -pub struct Host(ChainId); +impl Default for TendermintHost { + fn default() -> Self { + Self::builder().build() + } +} -impl TestHost for Host { +impl TestHost for TendermintHost { type Block = TendermintBlock; + type ClientState = ClientState; type BlockParams = BlockParams; type LightClientParams = MockClientConfig; - type ClientState = ClientState; - fn with_chain_id(chain_id: ChainId) -> Self { - Self(chain_id) + fn history(&self) -> &VecDeque { + &self.history } - fn chain_id(&self) -> &ChainId { - &self.0 + fn push_block(&mut self, block: Self::Block) { + self.history.push_back(block); + } + + fn prune_block_till(&mut self, height: &Height) { + while let Some(block) = self.history.front() { + if &block.height() <= height { + self.history.pop_front(); + } else { + break; + } + } } fn generate_block( &self, + commitment_root: Vec, height: u64, timestamp: Timestamp, params: &Self::BlockParams, @@ -48,8 +74,9 @@ impl TestHost for Host { TendermintBlock( TestgenLightBlock::new_default_with_header( TestgenHeader::new(¶ms.validators) + .app_hash(commitment_root.try_into().expect("infallible")) .height(height) - .chain_id(self.chain_id().as_str()) + .chain_id(self.chain_id.as_str()) .next_validators(¶ms.next_validators) .time(timestamp.into_tm_time().expect("Never fails")), ) @@ -62,15 +89,20 @@ impl TestHost for Host { fn generate_client_state( &self, - latest_block: &Self::Block, + latest_height: &Height, params: &Self::LightClientParams, ) -> Self::ClientState { let client_state: ClientState = ClientStateConfig::builder() - .chain_id(self.chain_id().clone()) - .latest_height(latest_block.height()) + .chain_id(self.chain_id.clone()) + .latest_height( + self.get_block(latest_height) + .expect("block exists") + .height(), + ) .trusting_period(params.trusting_period) .max_clock_drift(params.max_clock_drift) .unbonding_period(params.unbonding_period) + .proof_specs(params.proof_specs.clone()) .build() .try_into() .expect("never fails"); @@ -92,6 +124,7 @@ impl TendermintBlock { impl TestBlock for TendermintBlock { type Header = TendermintHeader; + fn height(&self) -> Height { Height::new( ChainId::from_str(self.0.signed_header.header.chain_id.as_str()) @@ -107,7 +140,7 @@ impl TestBlock for TendermintBlock { } } -#[derive(Debug)] +#[derive(Debug, TypedBuilder)] pub struct BlockParams { pub validators: Vec, pub next_validators: Vec, @@ -117,9 +150,11 @@ impl BlockParams { pub fn from_validator_history(validator_history: Vec>) -> Vec { validator_history .windows(2) - .map(|vals| Self { - validators: vals[0].clone(), - next_validators: vals[1].clone(), + .map(|vals| { + Self::builder() + .validators(vals[0].clone()) + .next_validators(vals[1].clone()) + .build() }) .collect() } @@ -127,15 +162,16 @@ impl BlockParams { impl Default for BlockParams { fn default() -> Self { - let validators = vec![ - TestgenValidator::new("1").voting_power(50), - TestgenValidator::new("2").voting_power(50), - ]; - - Self { - validators: validators.clone(), - next_validators: validators, - } + Self::builder() + .validators(vec![ + TestgenValidator::new("1").voting_power(50), + TestgenValidator::new("2").voting_power(50), + ]) + .next_validators(vec![ + TestgenValidator::new("1").voting_power(50), + TestgenValidator::new("2").voting_power(50), + ]) + .build() } } @@ -182,7 +218,7 @@ impl From for Header { impl From for ConsensusState { fn from(header: TendermintHeader) -> Self { - ConsensusState::from(header.0.signed_header.header) + header.0.signed_header.header.into() } } diff --git a/ibc-testkit/src/lib.rs b/ibc-testkit/src/lib.rs index bfc4ac35d..f4326ba1d 100644 --- a/ibc-testkit/src/lib.rs +++ b/ibc-testkit/src/lib.rs @@ -15,6 +15,7 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std; +pub mod context; pub mod fixtures; pub mod hosts; pub mod relayer; diff --git a/ibc-testkit/src/relayer/context.rs b/ibc-testkit/src/relayer/context.rs index 1ea3441be..7694749ed 100644 --- a/ibc-testkit/src/relayer/context.rs +++ b/ibc-testkit/src/relayer/context.rs @@ -1,17 +1,19 @@ use alloc::fmt::Debug; use basecoin_store::context::ProvableStore; +use ibc::clients::tendermint::context::ValidationContext; +use ibc::core::client::context::client_state::ClientStateValidation; use ibc::core::client::context::ClientValidationContext; use ibc::core::client::types::Height; use ibc::core::handler::types::error::ContextError; use ibc::core::host::types::identifiers::ClientId; -use ibc::core::host::ValidationContext; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Signer; -use crate::hosts::TestHost; +use crate::context::MockGenericContext; +use crate::hosts::{HostClientState, TestHost}; use crate::testapp::ibc::clients::AnyClientState; -use crate::testapp::ibc::core::types::MockGenericContext; +use crate::testapp::ibc::core::types::MockIbcStore; /// Trait capturing all dependencies (i.e., the context) which algorithms in ICS18 require to /// relay packets between chains. This trait comprises the dependencies towards a single chain. /// Most of the functions in this represent wrappers over the ABCI interface. @@ -33,14 +35,15 @@ impl RelayerContext for MockGenericContext where S: ProvableStore + Debug, H: TestHost, + HostClientState: ClientStateValidation>, { fn query_latest_height(&self) -> Result { - ValidationContext::host_height(self) + self.ibc_store.host_height() } fn query_client_full_state(&self, client_id: &ClientId) -> Option { // Forward call to Ics2. - self.client_state(client_id).ok() + self.ibc_store.client_state(client_id).ok() } fn signer(&self) -> Signer { @@ -53,7 +56,6 @@ where #[cfg(test)] mod tests { use ibc::clients::tendermint::types::client_type as tm_client_type; - use ibc::core::client::context::client_state::ClientStateCommon; use ibc::core::client::types::msgs::{ClientMsg, MsgUpdateClient}; use ibc::core::client::types::Height; use ibc::core::handler::types::msgs::MsgEnvelope; @@ -62,13 +64,14 @@ mod tests { use tracing::debug; use super::RelayerContext; + use crate::context::MockContext; use crate::fixtures::core::context::MockContextConfig; - use crate::hosts::{MockHost, TendermintHost, TestBlock, TestHeader}; + use crate::hosts::{MockHost, TendermintHost, TestBlock, TestHeader, TestHost}; use crate::relayer::context::ClientId; use crate::relayer::error::RelayerError; use crate::testapp::ibc::clients::mock::client_state::client_type as mock_client_type; use crate::testapp::ibc::core::router::MockRouter; - use crate::testapp::ibc::core::types::{LightClientBuilder, MockContext}; + use crate::testapp::ibc::core::types::LightClientBuilder; /// Builds a `ClientMsg::UpdateClient` for a client with id `client_id` running on the `dest` /// context, assuming that the latest header on the source context is `src_header`. @@ -133,12 +136,12 @@ mod tests { // Create two mock contexts, one for each chain. let mut ctx_a = MockContextConfig::builder() - .host_id(chain_id_a.clone()) + .host(MockHost::builder().chain_id(chain_id_a).build()) .latest_height(chain_a_start_height) .build::>(); let mut ctx_b = MockContextConfig::builder() - .host_id(chain_id_b.clone()) + .host(TendermintHost::builder().chain_id(chain_id_b).build()) .latest_height(chain_b_start_height) .latest_timestamp(ctx_a.timestamp_at(chain_a_start_height.decrement().unwrap())) // chain B is running slower than chain A .build::>(); @@ -185,7 +188,7 @@ mod tests { // - send the message to B. We bypass ICS18 interface and call directly into // MockContext `recv` method (to avoid additional serialization steps). let dispatch_res_b = ctx_b.deliver(&mut router_b, MsgEnvelope::Client(client_msg_b)); - let validation_res = ctx_b.validate(); + let validation_res = ctx_b.host.validate(); assert!( validation_res.is_ok(), "context validation failed with error {validation_res:?} for context {ctx_b:?}", @@ -224,7 +227,7 @@ mod tests { // - send the message to A let dispatch_res_a = ctx_a.deliver(&mut router_a, MsgEnvelope::Client(client_msg_a)); - let validation_res = ctx_a.validate(); + let validation_res = ctx_a.host.validate(); assert!( validation_res.is_ok(), "context validation failed with error {validation_res:?} for context {ctx_a:?}", diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs index 17f3a3bde..658d97fe4 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs @@ -98,9 +98,13 @@ impl TryFrom for MockClientState { impl From for RawMockClientState { fn from(value: MockClientState) -> Self { - RawMockClientState { + Self { header: Some(value.header.into()), - trusting_period: value.trusting_period.as_nanos() as _, + trusting_period: value + .trusting_period + .as_nanos() + .try_into() + .expect("no overflow"), frozen: value.frozen, } } @@ -130,7 +134,7 @@ impl TryFrom for MockClientState { impl From for Any { fn from(client_state: MockClientState) -> Self { - Any { + Self { type_url: MOCK_CLIENT_STATE_TYPE_URL.to_string(), value: Protobuf::::encode_vec(client_state), } @@ -188,7 +192,7 @@ impl ClientStateCommon for MockClientState { _proof_upgrade_consensus_state: CommitmentProofBytes, _root: &CommitmentRoot, ) -> Result<(), ClientError> { - let upgraded_mock_client_state = MockClientState::try_from(upgraded_client_state)?; + let upgraded_mock_client_state = Self::try_from(upgraded_client_state)?; MockConsensusState::try_from(upgraded_consensus_state)?; if self.latest_height() >= upgraded_mock_client_state.latest_height() { return Err(UpgradeClientError::LowUpgradeHeight { @@ -305,7 +309,7 @@ where impl ClientStateExecution for MockClientState where E: ClientExecutionContext + MockClientContext, - E::ClientStateRef: From, + E::ClientStateRef: From, E::ConsensusStateRef: ConsensusStateConverter, { fn initialise( @@ -338,7 +342,7 @@ where let header = MockHeader::try_from(header)?; let header_height = header.height; - let new_client_state = MockClientState::new(header); + let new_client_state = Self::new(header); let new_consensus_state = MockConsensusState::new(header); ctx.store_consensus_state( @@ -386,7 +390,7 @@ where upgraded_client_state: Any, upgraded_consensus_state: Any, ) -> Result { - let new_client_state = MockClientState::try_from(upgraded_client_state)?; + let new_client_state = Self::try_from(upgraded_client_state)?; let new_consensus_state = MockConsensusState::try_from(upgraded_consensus_state)?; let latest_height = new_client_state.latest_height(); diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs index 43db3edc4..0640970e1 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/consensus_state.rs @@ -18,7 +18,7 @@ pub struct MockConsensusState { impl MockConsensusState { pub fn new(header: MockHeader) -> Self { - MockConsensusState { + Self { header, root: CommitmentRoot::from(vec![0]), } @@ -46,7 +46,7 @@ impl TryFrom for MockConsensusState { impl From for RawMockConsensusState { fn from(value: MockConsensusState) -> Self { - RawMockConsensusState { + Self { header: Some(value.header.into()), } } @@ -78,7 +78,7 @@ impl TryFrom for MockConsensusState { impl From for Any { fn from(consensus_state: MockConsensusState) -> Self { - Any { + Self { type_url: MOCK_CONSENSUS_STATE_TYPE_URL.to_string(), value: Protobuf::::encode_vec(consensus_state), } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/header.rs b/ibc-testkit/src/testapp/ibc/clients/mock/header.rs index 9e874e7d4..804db7ab0 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/header.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/header.rs @@ -42,7 +42,7 @@ impl TryFrom for MockHeader { type Error = ClientError; fn try_from(raw: RawMockHeader) -> Result { - Ok(MockHeader { + Ok(Self { height: raw .height .ok_or(ClientError::Other { @@ -60,7 +60,7 @@ impl TryFrom for MockHeader { impl From for RawMockHeader { fn from(value: MockHeader) -> Self { - RawMockHeader { + Self { height: Some(value.height.into()), timestamp: value.timestamp.nanoseconds(), } @@ -112,7 +112,7 @@ impl TryFrom for MockHeader { impl From for Any { fn from(header: MockHeader) -> Self { - Any { + Self { type_url: MOCK_HEADER_TYPE_URL.to_string(), value: Protobuf::::encode_vec(header), } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs b/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs index 15ea17a40..ff4664da4 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/misbehaviour.rs @@ -38,7 +38,7 @@ impl TryFrom for Misbehaviour { impl From for RawMisbehaviour { fn from(value: Misbehaviour) -> Self { - RawMisbehaviour { + Self { client_id: value.client_id.to_string(), header1: Some(value.header1.into()), header2: Some(value.header2.into()), @@ -70,7 +70,7 @@ impl TryFrom for Misbehaviour { impl From for Any { fn from(misbehaviour: Misbehaviour) -> Self { - Any { + Self { type_url: MOCK_MISBEHAVIOUR_TYPE_URL.to_string(), value: Protobuf::::encode_vec(misbehaviour), } diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/mod.rs b/ibc-testkit/src/testapp/ibc/clients/mock/mod.rs index ec880383c..d26c2865c 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/mod.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/mod.rs @@ -6,5 +6,5 @@ pub mod misbehaviour; /// Re-exports mock proto types from the `ibc-proto` crate pub mod proto { - pub use ibc_proto::ibc::mock::*; + pub use ::ibc_proto::ibc::mock::*; } diff --git a/ibc-testkit/src/testapp/ibc/clients/mod.rs b/ibc-testkit/src/testapp/ibc/clients/mod.rs index cb57570f7..05fe539da 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mod.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mod.rs @@ -11,27 +11,43 @@ use ibc::clients::tendermint::types::{ TENDERMINT_CLIENT_STATE_TYPE_URL, TENDERMINT_CONSENSUS_STATE_TYPE_URL, }; use ibc::core::client::types::error::ClientError; +use ibc::core::client::types::Height; use ibc::core::primitives::prelude::*; use ibc::derive::{ClientState, ConsensusState}; use ibc::primitives::proto::{Any, Protobuf}; -use crate::hosts::TestHost; +use super::core::types::MockIbcStore; use crate::testapp::ibc::clients::mock::client_state::{ MockClientState, MOCK_CLIENT_STATE_TYPE_URL, }; use crate::testapp::ibc::clients::mock::consensus_state::{ MockConsensusState, MOCK_CONSENSUS_STATE_TYPE_URL, }; -use crate::testapp::ibc::core::types::MockGenericContext; #[derive(Debug, Clone, From, PartialEq, ClientState)] -#[validation(MockGenericContext)] -#[execution(MockGenericContext)] +#[validation(MockIbcStore)] +#[execution(MockIbcStore)] pub enum AnyClientState { Tendermint(TmClientState), Mock(MockClientState), } +impl AnyClientState { + pub fn latest_height(&self) -> Height { + match self { + Self::Tendermint(cs) => cs.inner().latest_height, + Self::Mock(cs) => cs.latest_height(), + } + } + + pub fn is_frozen(&self) -> bool { + match self { + Self::Tendermint(cs) => cs.inner().is_frozen(), + Self::Mock(cs) => cs.is_frozen(), + } + } +} + impl Protobuf for AnyClientState {} impl TryFrom for AnyClientState { @@ -61,13 +77,13 @@ impl From for Any { impl From for AnyClientState { fn from(client_state: ClientStateType) -> Self { - AnyClientState::Tendermint(client_state.into()) + Self::Tendermint(client_state.into()) } } impl From for AnyConsensusState { fn from(consensus_state: ConsensusStateType) -> Self { - AnyConsensusState::Tendermint(consensus_state.into()) + Self::Tendermint(consensus_state.into()) } } @@ -77,8 +93,6 @@ pub enum AnyConsensusState { Mock(MockConsensusState), } -impl Protobuf for AnyConsensusState {} - impl TryFrom for AnyConsensusState { type Error = ClientError; diff --git a/ibc-testkit/src/testapp/ibc/core/client_ctx.rs b/ibc-testkit/src/testapp/ibc/core/client_ctx.rs index d491cb6ac..b06c40746 100644 --- a/ibc-testkit/src/testapp/ibc/core/client_ctx.rs +++ b/ibc-testkit/src/testapp/ibc/core/client_ctx.rs @@ -15,10 +15,9 @@ use ibc::core::host::ValidationContext; use ibc::core::primitives::Timestamp; use ibc::primitives::prelude::*; -use crate::hosts::TestHost; +use super::types::MockIbcStore; use crate::testapp::ibc::clients::mock::client_state::MockClientContext; use crate::testapp::ibc::clients::{AnyClientState, AnyConsensusState}; -use crate::testapp::ibc::core::types::MockGenericContext; pub type PortChannelIdMap = BTreeMap>; @@ -33,10 +32,9 @@ pub struct MockClientRecord { pub consensus_states: BTreeMap, } -impl MockClientContext for MockGenericContext +impl MockClientContext for MockIbcStore where S: ProvableStore + Debug, - H: TestHost, { fn host_timestamp(&self) -> Result { ValidationContext::host_timestamp(self) @@ -47,10 +45,9 @@ where } } -impl TmValidationContext for MockGenericContext +impl TmValidationContext for MockIbcStore where S: ProvableStore + Debug, - H: TestHost, { fn host_timestamp(&self) -> Result { ValidationContext::host_timestamp(self) @@ -68,11 +65,10 @@ where description: "Invalid consensus state path".into(), })?; - self.ibc_store - .consensus_state_store + self.consensus_state_store .get_keys(&path) .into_iter() - .flat_map(|path| { + .filter_map(|path| { if let Ok(Path::ClientConsensusState(consensus_path)) = path.try_into() { Some(consensus_path) } else { @@ -97,7 +93,7 @@ where .try_into() .unwrap(); // safety - path must be valid since ClientId and height are valid Identifiers - let keys = self.ibc_store.store.get_keys(&path); + let keys = self.store.get_keys(&path); let found_path = keys.into_iter().find_map(|path| { if let Ok(Path::ClientConsensusState(path)) = path.try_into() { if height @@ -111,8 +107,7 @@ where let consensus_state = found_path .map(|path| { - self.ibc_store - .consensus_state_store + self.consensus_state_store .get(StoreHeight::Pending, &path) .ok_or_else(|| ClientError::ConsensusStateNotFound { client_id: client_id.clone(), @@ -133,7 +128,7 @@ where .try_into() .unwrap(); // safety - path must be valid since ClientId and height are valid Identifiers - let keys = self.ibc_store.store.get_keys(&path); + let keys = self.store.get_keys(&path); let found_path = keys.into_iter().rev().find_map(|path| { if let Ok(Path::ClientConsensusState(path)) = path.try_into() { if height @@ -147,8 +142,7 @@ where let consensus_state = found_path .map(|path| { - self.ibc_store - .consensus_state_store + self.consensus_state_store .get(StoreHeight::Pending, &path) .ok_or_else(|| ClientError::ConsensusStateNotFound { client_id: client_id.clone(), @@ -161,17 +155,15 @@ where } } -impl ClientValidationContext for MockGenericContext +impl ClientValidationContext for MockIbcStore where S: ProvableStore + Debug, - H: TestHost, { type ClientStateRef = AnyClientState; type ConsensusStateRef = AnyConsensusState; fn client_state(&self, client_id: &ClientId) -> Result { Ok(self - .ibc_store .client_state_store .get(StoreHeight::Pending, &ClientStatePath(client_id.clone())) .ok_or(ClientError::ClientStateNotFound { @@ -189,7 +181,6 @@ where ) .map_err(|_| ClientError::InvalidHeight)?; let consensus_state = self - .ibc_store .consensus_state_store .get(StoreHeight::Pending, client_cons_state_path) .ok_or(ClientError::ConsensusStateNotFound { @@ -213,7 +204,6 @@ where height.revision_height(), ); let processed_timestamp = self - .ibc_store .client_processed_times .get(StoreHeight::Pending, &client_update_time_path) .ok_or(ClientError::UpdateMetaDataNotFound { @@ -226,7 +216,6 @@ where height.revision_height(), ); let processed_height = self - .ibc_store .client_processed_heights .get(StoreHeight::Pending, &client_update_height_path) .ok_or(ClientError::UpdateMetaDataNotFound { @@ -238,10 +227,9 @@ where } } -impl ClientExecutionContext for MockGenericContext +impl ClientExecutionContext for MockIbcStore where S: ProvableStore + Debug, - H: TestHost, { type ClientStateMut = AnyClientState; @@ -251,9 +239,8 @@ where client_state_path: ClientStatePath, client_state: Self::ClientStateRef, ) -> Result<(), ContextError> { - self.ibc_store - .client_state_store - .set(client_state_path.clone(), client_state) + self.client_state_store + .set(client_state_path, client_state) .map_err(|_| ClientError::Other { description: "Client state store error".to_string(), })?; @@ -267,8 +254,7 @@ where consensus_state_path: ClientConsensusStatePath, consensus_state: Self::ConsensusStateRef, ) -> Result<(), ContextError> { - self.ibc_store - .consensus_state_store + self.consensus_state_store .set(consensus_state_path, consensus_state) .map_err(|_| ClientError::Other { description: "Consensus state store error".to_string(), @@ -280,9 +266,7 @@ where &mut self, consensus_state_path: ClientConsensusStatePath, ) -> Result<(), ContextError> { - self.ibc_store - .consensus_state_store - .delete(consensus_state_path); + self.consensus_state_store.delete(consensus_state_path); Ok(()) } @@ -298,16 +282,13 @@ where height.revision_number(), height.revision_height(), ); - self.ibc_store - .client_processed_times - .delete(client_update_time_path); + self.client_processed_times.delete(client_update_time_path); let client_update_height_path = ClientUpdateHeightPath::new( - client_id.clone(), + client_id, height.revision_number(), height.revision_height(), ); - self.ibc_store - .client_processed_heights + self.client_processed_heights .delete(client_update_height_path); Ok(()) } @@ -327,19 +308,17 @@ where height.revision_number(), height.revision_height(), ); - self.ibc_store - .client_processed_times + self.client_processed_times .set(client_update_time_path, host_timestamp) .map_err(|_| ClientError::Other { description: "store update error".into(), })?; let client_update_height_path = ClientUpdateHeightPath::new( - client_id.clone(), + client_id, height.revision_number(), height.revision_height(), ); - self.ibc_store - .client_processed_heights + self.client_processed_heights .set(client_update_height_path, host_height) .map_err(|_| ClientError::Other { description: "store update error".into(), diff --git a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs index 9ec048898..37a74b20f 100644 --- a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs +++ b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs @@ -3,7 +3,7 @@ use core::fmt::Debug; use core::time::Duration; -use basecoin_store::context::ProvableStore; +use basecoin_store::context::{ProvableStore, Store}; use basecoin_store::types::Height as StoreHeight; use ibc::core::channel::types::channel::{ChannelEnd, IdentifiedChannelEnd}; use ibc::core::channel::types::commitment::{AcknowledgementCommitment, PacketCommitment}; @@ -29,24 +29,22 @@ use ibc::core::primitives::{Signer, Timestamp}; use ibc::primitives::ToVec; use ibc_query::core::context::{ProvableContext, QueryContext}; -use crate::hosts::{TestBlock, TestHeader, TestHost}; -use crate::testapp::ibc::clients::mock::client_state::MockClientState; -use crate::testapp::ibc::core::types::MockGenericContext; -use crate::testapp::ibc::utils::blocks_since; +use super::types::{MockIbcStore, DEFAULT_BLOCK_TIME_SECS}; +use crate::testapp::ibc::clients::{AnyClientState, AnyConsensusState}; -impl ValidationContext for MockGenericContext +impl ValidationContext for MockIbcStore where S: ProvableStore + Debug, - H: TestHost, { type V = Self; - type HostClientState = MockClientState; - type HostConsensusState = - <<::Block as TestBlock>::Header as TestHeader>::ConsensusState; + type HostClientState = AnyClientState; + type HostConsensusState = AnyConsensusState; fn host_height(&self) -> Result { - // TODO(rano): height sync with block and merkle tree - Ok(self.history.last().expect("atleast one block").height()) + Ok(Height::new( + *self.revision_number.lock(), + self.store.current_height(), + )?) } fn host_timestamp(&self) -> Result { @@ -57,7 +55,6 @@ where fn client_counter(&self) -> Result { Ok(self - .ibc_store .client_counter .get(StoreHeight::Pending, &NextClientSequencePath) .ok_or(ClientError::Other { @@ -69,20 +66,11 @@ where &self, height: &Height, ) -> Result { - // TODO(rano): height sync with block and merkle tree - let height_delta = blocks_since(self.host_height().expect("no error"), *height) - .expect("no error") as usize; - - let index = self - .history - .len() - .checked_sub(1 + height_delta) - .ok_or(ClientError::MissingLocalConsensusState { height: *height })?; - - Ok(self.history[index] - .clone() - .into_header() - .into_consensus_state()) + let consensus_states_binding = self.host_consensus_states.lock(); + Ok(consensus_states_binding + .get(&height.revision_height()) + .cloned() + .ok_or(ClientError::MissingLocalConsensusState { height: *height })?) } fn validate_self_client( @@ -96,8 +84,9 @@ where .into()); } - let self_chain_id = &self.host.chain_id(); - let self_revision_number = self_chain_id.revision_number(); + let latest_height = self.host_height()?; + + let self_revision_number = latest_height.revision_number(); if self_revision_number != client_state_of_host_on_counterparty .latest_height() @@ -116,7 +105,7 @@ where )); } - let host_current_height = self.latest_height().increment(); + let host_current_height = latest_height.increment(); if client_state_of_host_on_counterparty.latest_height() >= host_current_height { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { @@ -134,7 +123,6 @@ where fn connection_end(&self, conn_id: &ConnectionId) -> Result { Ok(self - .ibc_store .connection_end_store .get(StoreHeight::Pending, &ConnectionPath::new(conn_id)) .ok_or(ConnectionError::ConnectionNotFound { @@ -150,7 +138,6 @@ where fn connection_counter(&self) -> Result { Ok(self - .ibc_store .conn_counter .get(StoreHeight::Pending, &NextConnectionSequencePath) .ok_or(ConnectionError::Other { @@ -160,7 +147,6 @@ where fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result { Ok(self - .ibc_store .channel_end_store .get( StoreHeight::Pending, @@ -174,7 +160,6 @@ where seq_send_path: &SeqSendPath, ) -> Result { Ok(self - .ibc_store .send_sequence_store .get( StoreHeight::Pending, @@ -188,7 +173,6 @@ where seq_recv_path: &SeqRecvPath, ) -> Result { Ok(self - .ibc_store .recv_sequence_store .get( StoreHeight::Pending, @@ -199,7 +183,6 @@ where fn get_next_sequence_ack(&self, seq_ack_path: &SeqAckPath) -> Result { Ok(self - .ibc_store .ack_sequence_store .get( StoreHeight::Pending, @@ -213,7 +196,6 @@ where commitment_path: &CommitmentPath, ) -> Result { Ok(self - .ibc_store .packet_commitment_store .get( StoreHeight::Pending, @@ -228,7 +210,6 @@ where fn get_packet_receipt(&self, receipt_path: &ReceiptPath) -> Result { Ok(self - .ibc_store .packet_receipt_store .is_path_set( StoreHeight::Pending, @@ -249,7 +230,6 @@ where ack_path: &AckPath, ) -> Result { Ok(self - .ibc_store .packet_ack_store .get( StoreHeight::Pending, @@ -265,7 +245,6 @@ where /// `ChannelKeeper::increase_channel_counter`. fn channel_counter(&self) -> Result { Ok(self - .ibc_store .channel_counter .get(StoreHeight::Pending, &NextChannelSequencePath) .ok_or(ChannelError::Other { @@ -275,7 +254,7 @@ where /// Returns the maximum expected time per block fn max_expected_time_per_block(&self) -> Duration { - self.block_time + Duration::from_secs(DEFAULT_BLOCK_TIME_SECS) } fn validate_message_signer(&self, _signer: &Signer) -> Result<(), ContextError> { @@ -288,32 +267,28 @@ where } /// Trait to provide proofs in gRPC service blanket implementations. -impl ProvableContext for MockGenericContext +impl ProvableContext for MockIbcStore where S: ProvableStore + Debug, - H: TestHost, { /// Returns the proof for the given [`Height`] and [`Path`] fn get_proof(&self, height: Height, path: &Path) -> Option> { - self.ibc_store - .store + self.store .get_proof(height.revision_height().into(), &path.to_string().into()) .map(|p| p.to_vec()) } } /// Trait to complete the gRPC service blanket implementations. -impl QueryContext for MockGenericContext +impl QueryContext for MockIbcStore where S: ProvableStore + Debug, - H: TestHost, { /// Returns the list of all client states. fn client_states(&self) -> Result)>, ContextError> { let path = "clients".to_owned().into(); - self.ibc_store - .client_state_store + self.client_state_store .get_keys(&path) .into_iter() .filter_map(|path| { @@ -325,7 +300,6 @@ where }) .map(|client_state_path| { let client_state = self - .ibc_store .client_state_store .get(StoreHeight::Pending, &client_state_path) .ok_or_else(|| ClientError::ClientStateNotFound { @@ -347,11 +321,10 @@ where description: "Invalid consensus state path".into(), })?; - self.ibc_store - .consensus_state_store + self.consensus_state_store .get_keys(&path) .into_iter() - .flat_map(|path| { + .filter_map(|path| { if let Ok(Path::ClientConsensusState(consensus_path)) = path.try_into() { Some(consensus_path) } else { @@ -364,7 +337,6 @@ where consensus_path.revision_height, )?; let client_state = self - .ibc_store .consensus_state_store .get(StoreHeight::Pending, &consensus_path) .ok_or({ @@ -386,11 +358,10 @@ where description: "Invalid consensus state path".into(), })?; - self.ibc_store - .consensus_state_store + self.consensus_state_store .get_keys(&path) .into_iter() - .flat_map(|path| { + .filter_map(|path| { if let Ok(Path::ClientConsensusState(consensus_path)) = path.try_into() { Some(consensus_path) } else { @@ -410,11 +381,10 @@ where fn connection_ends(&self) -> Result, ContextError> { let path = "connections".to_owned().into(); - self.ibc_store - .connection_end_store + self.connection_end_store .get_keys(&path) .into_iter() - .flat_map(|path| { + .filter_map(|path| { if let Ok(Path::Connection(connection_path)) = path.try_into() { Some(connection_path) } else { @@ -423,7 +393,6 @@ where }) .map(|connection_path| { let connection_end = self - .ibc_store .connection_end_store .get(StoreHeight::Pending, &connection_path) .ok_or_else(|| ConnectionError::ConnectionNotFound { @@ -445,7 +414,6 @@ where let client_connection_path = ClientConnectionPath::new(client_id.clone()); Ok(self - .ibc_store .connection_ids_store .get(StoreHeight::Pending, &client_connection_path) .unwrap_or_default()) @@ -455,11 +423,10 @@ where fn channel_ends(&self) -> Result, ContextError> { let path = "channelEnds".to_owned().into(); - self.ibc_store - .channel_end_store + self.channel_end_store .get_keys(&path) .into_iter() - .flat_map(|path| { + .filter_map(|path| { if let Ok(Path::ChannelEnd(channel_path)) = path.try_into() { Some(channel_path) } else { @@ -468,7 +435,6 @@ where }) .map(|channel_path| { let channel_end = self - .ibc_store .channel_end_store .get(StoreHeight::Pending, &channel_path) .ok_or_else(|| ChannelError::ChannelNotFound { @@ -498,11 +464,10 @@ where description: "Invalid commitment path".into(), })?; - self.ibc_store - .packet_commitment_store + self.packet_commitment_store .get_keys(&path) .into_iter() - .flat_map(|path| { + .filter_map(|path| { if let Ok(Path::Commitment(commitment_path)) = path.try_into() { Some(commitment_path) } else { @@ -510,8 +475,7 @@ where } }) .filter(|commitment_path| { - self.ibc_store - .packet_commitment_store + self.packet_commitment_store .get(StoreHeight::Pending, commitment_path) .is_some() }) @@ -545,11 +509,10 @@ where description: "Invalid ack path".into(), })?; - self.ibc_store - .packet_ack_store + self.packet_ack_store .get_keys(&ack_path_prefix) .into_iter() - .flat_map(|path| { + .filter_map(|path| { if let Ok(Path::Ack(ack_path)) = path.try_into() { Some(ack_path) } else { @@ -567,8 +530,7 @@ where collected_paths .into_iter() .filter(|ack_path| { - self.ibc_store - .packet_ack_store + self.packet_ack_store .get(StoreHeight::Pending, ack_path) .is_some() }) @@ -599,8 +561,7 @@ where .into_iter() .map(|seq| ReceiptPath::new(&channel_end_path.0, &channel_end_path.1, seq)) .filter(|receipt_path| { - self.ibc_store - .packet_receipt_store + self.packet_receipt_store .get(StoreHeight::Pending, receipt_path) .is_none() }) @@ -626,11 +587,10 @@ where description: "Invalid commitment path".into(), })?; - self.ibc_store - .packet_commitment_store + self.packet_commitment_store .get_keys(&commitment_path_prefix) .into_iter() - .flat_map(|path| { + .filter_map(|path| { if let Ok(Path::Commitment(commitment_path)) = path.try_into() { Some(commitment_path) } else { @@ -648,8 +608,7 @@ where Ok(collected_paths .into_iter() .filter(|commitment_path: &CommitmentPath| -> bool { - self.ibc_store - .packet_commitment_store + self.packet_commitment_store .get(StoreHeight::Pending, commitment_path) .is_some() }) @@ -658,10 +617,9 @@ where } } -impl ExecutionContext for MockGenericContext +impl ExecutionContext for MockIbcStore where S: ProvableStore + Debug, - H: TestHost, { type E = Self; @@ -674,15 +632,13 @@ where /// Should never fail. fn increase_client_counter(&mut self) -> Result<(), ContextError> { let current_sequence = self - .ibc_store .client_counter .get(StoreHeight::Pending, &NextClientSequencePath) .ok_or(ClientError::Other { description: "client counter not found".into(), })?; - self.ibc_store - .client_counter + self.client_counter .set(NextClientSequencePath, current_sequence + 1) .map_err(|e| ClientError::Other { description: format!("client counter update failed: {e:?}"), @@ -697,8 +653,7 @@ where connection_path: &ConnectionPath, connection_end: ConnectionEnd, ) -> Result<(), ContextError> { - self.ibc_store - .connection_end_store + self.connection_end_store .set(connection_path.clone(), connection_end) .map_err(|_| ConnectionError::Other { description: "Connection end store error".to_string(), @@ -713,13 +668,11 @@ where conn_id: ConnectionId, ) -> Result<(), ContextError> { let mut conn_ids: Vec = self - .ibc_store .connection_ids_store .get(StoreHeight::Pending, client_connection_path) .unwrap_or_default(); conn_ids.push(conn_id); - self.ibc_store - .connection_ids_store + self.connection_ids_store .set(client_connection_path.clone(), conn_ids) .map_err(|_| ConnectionError::Other { description: "Connection ids store error".to_string(), @@ -732,15 +685,13 @@ where /// Should never fail. fn increase_connection_counter(&mut self) -> Result<(), ContextError> { let current_sequence = self - .ibc_store .conn_counter .get(StoreHeight::Pending, &NextConnectionSequencePath) .ok_or(ConnectionError::Other { description: "connection counter not found".into(), })?; - self.ibc_store - .conn_counter + self.conn_counter .set(NextConnectionSequencePath, current_sequence + 1) .map_err(|e| ConnectionError::Other { description: format!("connection counter update failed: {e:?}"), @@ -754,8 +705,7 @@ where commitment_path: &CommitmentPath, commitment: PacketCommitment, ) -> Result<(), ContextError> { - self.ibc_store - .packet_commitment_store + self.packet_commitment_store .set(commitment_path.clone(), commitment) .map_err(|_| PacketError::ImplementationSpecific)?; Ok(()) @@ -765,9 +715,7 @@ where &mut self, commitment_path: &CommitmentPath, ) -> Result<(), ContextError> { - self.ibc_store - .packet_commitment_store - .delete(commitment_path.clone()); + self.packet_commitment_store.delete(commitment_path.clone()); Ok(()) } @@ -776,8 +724,7 @@ where receipt_path: &ReceiptPath, _receipt: Receipt, ) -> Result<(), ContextError> { - self.ibc_store - .packet_receipt_store + self.packet_receipt_store .set_path(receipt_path.clone()) .map_err(|_| PacketError::ImplementationSpecific)?; Ok(()) @@ -788,15 +735,14 @@ where ack_path: &AckPath, ack_commitment: AcknowledgementCommitment, ) -> Result<(), ContextError> { - self.ibc_store - .packet_ack_store + self.packet_ack_store .set(ack_path.clone(), ack_commitment) .map_err(|_| PacketError::ImplementationSpecific)?; Ok(()) } fn delete_packet_acknowledgement(&mut self, ack_path: &AckPath) -> Result<(), ContextError> { - self.ibc_store.packet_ack_store.delete(ack_path.clone()); + self.packet_ack_store.delete(ack_path.clone()); Ok(()) } @@ -805,8 +751,7 @@ where channel_end_path: &ChannelEndPath, channel_end: ChannelEnd, ) -> Result<(), ContextError> { - self.ibc_store - .channel_end_store + self.channel_end_store .set(channel_end_path.clone(), channel_end) .map_err(|_| ChannelError::Other { description: "Channel end store error".to_string(), @@ -819,8 +764,7 @@ where seq_send_path: &SeqSendPath, seq: Sequence, ) -> Result<(), ContextError> { - self.ibc_store - .send_sequence_store + self.send_sequence_store .set(seq_send_path.clone(), seq) .map_err(|_| PacketError::ImplementationSpecific)?; Ok(()) @@ -831,8 +775,7 @@ where seq_recv_path: &SeqRecvPath, seq: Sequence, ) -> Result<(), ContextError> { - self.ibc_store - .recv_sequence_store + self.recv_sequence_store .set(seq_recv_path.clone(), seq) .map_err(|_| PacketError::ImplementationSpecific)?; Ok(()) @@ -843,8 +786,7 @@ where seq_ack_path: &SeqAckPath, seq: Sequence, ) -> Result<(), ContextError> { - self.ibc_store - .ack_sequence_store + self.ack_sequence_store .set(seq_ack_path.clone(), seq) .map_err(|_| PacketError::ImplementationSpecific)?; Ok(()) @@ -852,15 +794,13 @@ where fn increase_channel_counter(&mut self) -> Result<(), ContextError> { let current_sequence = self - .ibc_store .channel_counter .get(StoreHeight::Pending, &NextChannelSequencePath) .ok_or(ChannelError::Other { description: "channel counter not found".into(), })?; - self.ibc_store - .channel_counter + self.channel_counter .set(NextChannelSequencePath, current_sequence + 1) .map_err(|e| ChannelError::Other { description: format!("channel counter update failed: {e:?}"), @@ -870,12 +810,12 @@ where } fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), ContextError> { - self.ibc_store.events.lock().push(event); + self.events.lock().push(event); Ok(()) } fn log_message(&mut self, message: String) -> Result<(), ContextError> { - self.ibc_store.logs.lock().push(message); + self.logs.lock().push(message); Ok(()) } } diff --git a/ibc-testkit/src/testapp/ibc/core/router/mod.rs b/ibc-testkit/src/testapp/ibc/core/router/mod.rs index 6629c0e08..faaf47994 100644 --- a/ibc-testkit/src/testapp/ibc/core/router/mod.rs +++ b/ibc-testkit/src/testapp/ibc/core/router/mod.rs @@ -1,4 +1,4 @@ mod context; mod types; -pub use types::*; +pub use self::types::*; diff --git a/ibc-testkit/src/testapp/ibc/core/types.rs b/ibc-testkit/src/testapp/ibc/core/types.rs index 28037cf5d..8fe4cddcf 100644 --- a/ibc-testkit/src/testapp/ibc/core/types.rs +++ b/ibc-testkit/src/testapp/ibc/core/types.rs @@ -2,31 +2,25 @@ use alloc::sync::Arc; use core::fmt::Debug; -use core::ops::{Add, Sub}; -use core::time::Duration; -use basecoin_store::context::ProvableStore; -use basecoin_store::impls::{GrowingStore, InMemoryStore, RevertibleStore, SharedStore}; +use basecoin_store::context::{ProvableStore, Store}; +use basecoin_store::impls::SharedStore; use basecoin_store::types::{BinStore, JsonStore, ProtobufStore, TypedSet, TypedStore}; use ibc::core::channel::types::channel::ChannelEnd; use ibc::core::channel::types::commitment::{AcknowledgementCommitment, PacketCommitment}; -use ibc::core::client::context::{ClientExecutionContext, ClientValidationContext}; +use ibc::core::client::context::client_state::ClientStateValidation; use ibc::core::client::types::Height; use ibc::core::connection::types::ConnectionEnd; -use ibc::core::entrypoint::dispatch; use ibc::core::handler::types::events::IbcEvent; -use ibc::core::handler::types::msgs::MsgEnvelope; -use ibc::core::host::types::identifiers::{ChannelId, ClientId, ConnectionId, PortId, Sequence}; +use ibc::core::host::types::identifiers::{ConnectionId, Sequence}; use ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, ClientStatePath, ClientUpdateHeightPath, ClientUpdateTimePath, CommitmentPath, ConnectionPath, NextChannelSequencePath, NextClientSequencePath, NextConnectionSequencePath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; -use ibc::core::host::{ExecutionContext, ValidationContext}; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Timestamp; -use ibc::core::router::router::Router; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::channel::v1::Channel as RawChannelEnd; use ibc_proto::ibc::core::client::v1::Height as RawHeight; @@ -34,19 +28,24 @@ use ibc_proto::ibc::core::connection::v1::ConnectionEnd as RawConnectionEnd; use parking_lot::Mutex; use typed_builder::TypedBuilder; +use crate::context::{MockContext, MockStore}; use crate::fixtures::core::context::MockContextConfig; -use crate::hosts::{TestBlock, TestHeader, TestHost}; -use crate::relayer::error::RelayerError; +use crate::hosts::{HostClientState, TestBlock, TestHeader, TestHost}; +use crate::testapp::ibc::clients::mock::header::MockHeader; use crate::testapp::ibc::clients::{AnyClientState, AnyConsensusState}; -use crate::testapp::ibc::utils::blocks_since; pub const DEFAULT_BLOCK_TIME_SECS: u64 = 3; +pub type DefaultIbcStore = MockIbcStore; + /// An object that stores all IBC related data. #[derive(Debug)] pub struct MockIbcStore where S: ProvableStore + Debug, { + /// chain revision number, + pub revision_number: Arc>, + /// Handle to store instance. /// The module is guaranteed exclusive access to all paths in the store key-space. pub store: SharedStore, @@ -86,7 +85,7 @@ where /// A typed-store for packet ack pub packet_ack_store: BinStore, AckPath, AcknowledgementCommitment>, /// Map of host consensus states - pub consensus_states: Arc>>, + pub host_consensus_states: Arc>>, /// IBC Events pub events: Arc>>, /// message logs @@ -97,7 +96,7 @@ impl MockIbcStore where S: ProvableStore + Debug, { - pub fn new(store: S) -> Self { + pub fn new(revision_number: u64, store: S) -> Self { let shared_store = SharedStore::new(store); let mut client_counter = TypedStore::new(shared_store.clone()); @@ -117,12 +116,13 @@ where .expect("no error"); Self { + revision_number: Arc::new(Mutex::new(revision_number)), client_counter, conn_counter, channel_counter, client_processed_times: TypedStore::new(shared_store.clone()), client_processed_heights: TypedStore::new(shared_store.clone()), - consensus_states: Arc::new(Mutex::new(Default::default())), + host_consensus_states: Arc::new(Mutex::new(Default::default())), client_state_store: TypedStore::new(shared_store.clone()), consensus_state_store: TypedStore::new(shared_store.clone()), connection_end_store: TypedStore::new(shared_store.clone()), @@ -139,431 +139,34 @@ where store: shared_store, } } -} -impl Default for MockIbcStore -where - S: ProvableStore + Debug + Default, -{ - fn default() -> Self { - Self::new(S::default()) + pub fn commit(&mut self) -> Result, as Store>::Error> { + self.store.commit() } -} -/// A context implementing the dependencies necessary for testing any IBC module. -#[derive(Debug)] -pub struct MockGenericContext -where - S: ProvableStore + Debug, - H: TestHost, -{ - /// The type of host chain underlying this mock context. - pub host: H, - - /// Maximum size for the history of the host chain. Any block older than this is pruned. - pub max_history_size: u64, - - /// The chain of blocks underlying this context. A vector of size up to `max_history_size` - /// blocks, ascending order by their height (latest block is on the last position). - pub history: Vec, - - /// Average time duration between blocks - pub block_time: Duration, - - /// An object that stores all IBC related data. - pub ibc_store: MockIbcStore, -} - -pub type MockContext = MockGenericContext>, H>; - -#[derive(Debug, TypedBuilder)] -pub struct MockClientConfig { - #[builder(default = Duration::from_secs(64000))] - pub trusting_period: Duration, - #[builder(default = Duration::from_millis(3000))] - pub max_clock_drift: Duration, - #[builder(default = Duration::from_secs(128_000))] - pub unbonding_period: Duration, -} - -impl Default for MockClientConfig { - fn default() -> Self { - Self::builder().build() + pub fn store_host_consensus_state(&mut self, consensus_state: AnyConsensusState) { + self.host_consensus_states + .lock() + .insert(self.store.current_height(), consensus_state); } -} -/// Returns a MockContext 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 Default for MockGenericContext -where - S: ProvableStore + Debug + Default, - H: TestHost, -{ - fn default() -> Self { - MockContextConfig::builder().build() + pub fn prune_host_consensus_states_till(&self, height: &Height) { + assert!(height.revision_number() == *self.revision_number.lock()); + let mut history = self.host_consensus_states.lock(); + history.retain(|h, _| h > &height.revision_height()); } } -pub struct LightClientState { - pub client_state: H::ClientState, - pub consensus_states: - BTreeMap::Header as TestHeader>::ConsensusState>, -} - -impl Default for LightClientState +impl Default for MockIbcStore where - H: TestHost, + S: ProvableStore + Debug + Default, { fn default() -> Self { - let context = MockContext::::default(); - LightClientBuilder::init().context(&context).build() - } -} - -impl LightClientState -where - H: TestHost, -{ - pub fn with_latest_height(height: Height) -> Self { - let context = MockContextConfig::builder() - .latest_height(height) - .build::>(); - LightClientBuilder::init().context(&context).build() - } -} - -#[derive(TypedBuilder)] -#[builder(builder_method(name = init), build_method(into))] -pub struct LightClientBuilder<'a, H: TestHost> { - context: &'a MockContext, - #[builder(default, setter(into))] - consensus_heights: Vec, - #[builder(default)] - params: H::LightClientParams, -} - -impl<'a, H> From> for LightClientState -where - H: TestHost, -{ - fn from(builder: LightClientBuilder<'a, H>) -> Self { - let LightClientBuilder { - context, - consensus_heights, - params, - } = builder; - - context.generate_light_client(consensus_heights, ¶ms) - } -} - -/// Implementation of internal interface for use in testing. The methods in this interface should -/// _not_ be accessible to any Ics handler. -impl MockGenericContext -where - S: ProvableStore + Debug, - H: TestHost, -{ - pub fn with_client_state(mut self, client_id: &ClientId, client_state: AnyClientState) -> Self { - let client_state_path = ClientStatePath::new(client_id.clone()); - self.store_client_state(client_state_path, client_state) - .expect("error writing to store"); - self - } - - pub fn with_consensus_state( - mut self, - client_id: &ClientId, - height: Height, - consensus_state: AnyConsensusState, - ) -> Self { - let consensus_state_path = ClientConsensusStatePath::new( - client_id.clone(), - height.revision_number(), - height.revision_height(), - ); - self.store_consensus_state(consensus_state_path, consensus_state) - .expect("error writing to store"); - - self - } - - pub fn generate_light_client( - &self, - mut consensus_heights: Vec, - client_params: &H::LightClientParams, - ) -> LightClientState { - let client_height = if let Some(&height) = consensus_heights.last() { - height - } else { - consensus_heights.push(self.latest_height()); - self.latest_height() - }; - - let client_state = self.host.generate_client_state( - self.host_block(&client_height) - .expect("latest block exists"), - client_params, - ); - - let consensus_states = consensus_heights - .into_iter() - .map(|height| { - ( - height, - self.host_block(&height) - .expect("block exists") - .clone() - .into_header() - .into_consensus_state(), - ) - }) - .collect(); - - LightClientState { - client_state, - consensus_states, - } - } - - pub fn with_light_client( - mut self, - client_id: &ClientId, - light_client: LightClientState, - ) -> Self - where - RH: TestHost, - { - self = self.with_client_state(client_id, light_client.client_state.into()); - - for (height, consensus_state) in light_client.consensus_states { - self = self.with_consensus_state(client_id, height, consensus_state.into()); - } - - self - } - - /// Associates a connection to this context. - pub fn with_connection( - mut self, - connection_id: ConnectionId, - connection_end: ConnectionEnd, - ) -> Self { - let connection_path = ConnectionPath::new(&connection_id); - self.store_connection(&connection_path, connection_end) - .expect("error writing to store"); - self - } - - /// Associates a channel (in an arbitrary state) to this context. - pub fn with_channel( - mut self, - port_id: PortId, - chan_id: ChannelId, - channel_end: ChannelEnd, - ) -> Self { - let channel_end_path = ChannelEndPath::new(&port_id, &chan_id); - self.store_channel(&channel_end_path, channel_end) - .expect("error writing to store"); - self - } - - pub fn with_send_sequence( - mut self, - port_id: PortId, - chan_id: ChannelId, - seq_number: Sequence, - ) -> Self { - let seq_send_path = SeqSendPath::new(&port_id, &chan_id); - self.store_next_sequence_send(&seq_send_path, seq_number) - .expect("error writing to store"); - self - } - - pub fn with_recv_sequence( - mut self, - port_id: PortId, - chan_id: ChannelId, - seq_number: Sequence, - ) -> Self { - let seq_recv_path = SeqRecvPath::new(&port_id, &chan_id); - self.store_next_sequence_recv(&seq_recv_path, seq_number) - .expect("error writing to store"); - self - } - - pub fn with_ack_sequence( - mut self, - port_id: PortId, - chan_id: ChannelId, - seq_number: Sequence, - ) -> Self { - let seq_ack_path = SeqAckPath::new(&port_id, &chan_id); - self.store_next_sequence_ack(&seq_ack_path, seq_number) - .expect("error writing to store"); - self - } - - pub fn with_height(self, target_height: Height) -> Self { - let latest_height = self.latest_height(); - if target_height.revision_number() > latest_height.revision_number() { - unimplemented!() - } else if target_height.revision_number() < latest_height.revision_number() { - panic!("Cannot rewind history of the chain to a smaller revision number!") - } else if target_height.revision_height() < latest_height.revision_height() { - panic!("Cannot rewind history of the chain to a smaller revision height!") - } else if target_height.revision_height() > latest_height.revision_height() { - // Repeatedly advance the host chain height till we hit the desired height - let mut ctx = self; - while ctx.latest_height().revision_height() < target_height.revision_height() { - ctx.advance_host_chain_height() - } - ctx - } else { - // Both the revision number and height match - self - } - } - - pub fn with_packet_commitment( - mut self, - port_id: PortId, - chan_id: ChannelId, - seq: Sequence, - data: PacketCommitment, - ) -> Self { - let commitment_path = CommitmentPath::new(&port_id, &chan_id, seq); - self.store_packet_commitment(&commitment_path, data) - .expect("error writing to store"); - self - } - - /// Accessor for a block of the local (host) chain from this context. - /// Returns `None` if the block at the requested height does not exist. - pub fn host_block(&self, target_height: &Height) -> Option<&H::Block> { - let target = target_height.revision_height(); - let latest = self.latest_height().revision_height(); - - // Check that the block is not too advanced, nor has it been pruned. - if (target > latest) || (target <= latest - self.history.len() as u64) { - None // Block for requested height does not exist in history. - } else { - Some(&self.history[self.history.len() + target as usize - latest as usize - 1]) - } - } - - /// Triggers the advancing of the host chain, by extending the history of blocks (or headers). - pub fn advance_host_chain_height(&mut self) { - let latest_block = self.history.last().expect("history cannot be empty"); - - let new_block = self.host.generate_block( - latest_block.height().increment().revision_height(), - latest_block - .timestamp() - .add(self.block_time) - .expect("Never fails"), - &H::BlockParams::default(), - ); - - // Append the new header at the tip of the history. - if self.history.len() as u64 >= self.max_history_size { - // History is full, we rotate and replace the tip with the new header. - self.history.rotate_left(1); - self.history[self.max_history_size as usize - 1] = new_block; - } else { - // History is not full yet. - self.history.push(new_block); - } - } - - /// A datagram passes from the relayer to the IBC module (on host chain). - /// Alternative method to `Ics18Context::send` that does not exercise any serialization. - /// Used in testing the Ics18 algorithms, hence this may return a Ics18Error. - pub fn deliver( - &mut self, - router: &mut impl Router, - msg: MsgEnvelope, - ) -> Result<(), RelayerError> { - dispatch(self, router, msg).map_err(RelayerError::TransactionFailed)?; - // Create a new block. - self.advance_host_chain_height(); - Ok(()) - } - - /// Validates this context. Should be called after the context is mutated by a test. - pub fn validate(&self) -> Result<(), String> { - // Check that the number of entries is not higher than window size. - if self.history.len() as u64 > self.max_history_size { - return Err("too many entries".to_string()); - } - - // Check the content of the history. - if !self.history.is_empty() { - // Get the highest block. - let lh = &self.history[self.history.len() - 1]; - // Check latest is properly updated with highest header height. - if lh.height() != self.latest_height() { - return Err("latest height is not updated".to_string()); - } - } - - // Check that headers in the history are in sequential order. - for i in 1..self.history.len() { - let ph = &self.history[i - 1]; - let h = &self.history[i]; - if ph.height().increment() != h.height() { - return Err("headers in history not sequential".to_string()); - } - } - Ok(()) - } - - pub fn latest_client_states(&self, client_id: &ClientId) -> AnyClientState { - self.client_state(client_id) - .expect("error reading from store") - } - - pub fn latest_consensus_states( - &self, - client_id: &ClientId, - height: &Height, - ) -> AnyConsensusState { - self.consensus_state(&ClientConsensusStatePath::new( - client_id.clone(), - height.revision_number(), - height.revision_height(), - )) - .expect("error reading from store") - } - - pub fn latest_height(&self) -> Height { - self.host_height().expect("Never fails") - } - - pub fn latest_timestamp(&self) -> Timestamp { - self.host_block(&self.latest_height()) - .expect("Never fails") - .timestamp() - } - - pub fn timestamp_at(&self, height: Height) -> Timestamp { - let n_blocks = blocks_since(self.latest_height(), height).expect("less or equal height"); - self.latest_timestamp() - .sub(self.block_time * (n_blocks as u32)) - .expect("Never fails") - } - - pub fn query_latest_block(&self) -> Option<&H::Block> { - self.host_block(&self.latest_height()) - } - - pub fn get_events(&self) -> Vec { - self.ibc_store.events.lock().clone() - } - - pub fn get_logs(&self) -> Vec { - self.ibc_store.logs.lock().clone() + // Note: this creates a MockIbcStore which has MockConsensusState as Host ConsensusState + let mut ibc_store = Self::new(0, S::default()); + ibc_store.commit().expect("no error"); + ibc_store.store_host_consensus_state(MockHeader::default().into_consensus_state().into()); + ibc_store } } @@ -574,118 +177,17 @@ mod tests { use ibc::core::channel::types::error::{ChannelError, PacketError}; use ibc::core::channel::types::packet::Packet; use ibc::core::channel::types::Version; - use ibc::core::host::types::identifiers::ChainId; + use ibc::core::host::types::identifiers::{ChannelId, PortId}; use ibc::core::primitives::Signer; use ibc::core::router::module::Module; + use ibc::core::router::router::Router; use ibc::core::router::types::module::{ModuleExtras, ModuleId}; use super::*; use crate::fixtures::core::channel::PacketConfig; use crate::fixtures::core::signer::dummy_bech32_account; - use crate::hosts::{MockHost, TendermintHost}; use crate::testapp::ibc::core::router::MockRouter; - #[test] - fn test_history_manipulation_mock() { - pub struct Test { - name: String, - ctx: MockContext, - } - - fn run_tests(sub_title: &str) { - let cv = 1; // The version to use for all chains. - let mock_chain_id = ChainId::new(&format!("mockgaia-{cv}")).unwrap(); - - let tests: Vec> = vec![ - Test { - name: "Empty history, small pruning window".to_string(), - ctx: MockContextConfig::builder() - .host_id(mock_chain_id.clone()) - .max_history_size(2) - .latest_height(Height::new(cv, 1).expect("Never fails")) - .build(), - }, - Test { - name: "Large pruning window".to_string(), - ctx: MockContextConfig::builder() - .host_id(mock_chain_id.clone()) - .max_history_size(30) - .latest_height(Height::new(cv, 2).expect("Never fails")) - .build(), - }, - Test { - name: "Small pruning window".to_string(), - ctx: MockContextConfig::builder() - .host_id(mock_chain_id.clone()) - .max_history_size(3) - .latest_height(Height::new(cv, 30).expect("Never fails")) - .build(), - }, - Test { - name: "Small pruning window, small starting height".to_string(), - ctx: MockContextConfig::builder() - .host_id(mock_chain_id.clone()) - .max_history_size(3) - .latest_height(Height::new(cv, 2).expect("Never fails")) - .build(), - }, - Test { - name: "Large pruning window, large starting height".to_string(), - ctx: MockContextConfig::builder() - .host_id(mock_chain_id.clone()) - .max_history_size(50) - .latest_height(Height::new(cv, 2000).expect("Never fails")) - .build(), - }, - ]; - - for mut test in tests { - // All tests should yield a valid context after initialization. - assert!( - test.ctx.validate().is_ok(), - "failed in test [{}] {} while validating context {:?}", - sub_title, - test.name, - test.ctx - ); - - let current_height = test.ctx.latest_height(); - - // After advancing the chain's height, the context should still be valid. - test.ctx.advance_host_chain_height(); - assert!( - test.ctx.validate().is_ok(), - "failed in test [{}] {} while validating context {:?}", - sub_title, - test.name, - test.ctx - ); - - let next_height = current_height.increment(); - assert_eq!( - test.ctx.latest_height(), - next_height, - "failed while increasing height for context {:?}", - test.ctx - ); - - assert_eq!( - test.ctx - .host_block(¤t_height) - .expect("Never fails") - .height(), - current_height, - "failed while fetching height {:?} of context {:?}", - current_height, - test.ctx - ); - } - } - - run_tests::("Mock Host"); - run_tests::("Synthetic TM Host"); - } - #[test] fn test_router() { #[derive(Debug, Default)] @@ -912,3 +414,63 @@ mod tests { ]; } } + +pub struct LightClientState { + pub client_state: H::ClientState, + pub consensus_states: + BTreeMap::Header as TestHeader>::ConsensusState>, +} + +impl Default for LightClientState +where + H: TestHost, + HostClientState: ClientStateValidation, +{ + fn default() -> Self { + let context = MockContext::::default(); + LightClientBuilder::init().context(&context).build() + } +} + +impl LightClientState +where + H: TestHost, + HostClientState: ClientStateValidation, +{ + pub fn with_latest_height(height: Height) -> Self { + let context = MockContextConfig::builder() + .latest_height(height) + .build::>(); + LightClientBuilder::init().context(&context).build() + } +} + +#[derive(TypedBuilder)] +#[builder(builder_method(name = init), build_method(into))] +pub struct LightClientBuilder<'a, H> +where + H: TestHost, + HostClientState: ClientStateValidation, +{ + context: &'a MockContext, + #[builder(default, setter(into))] + consensus_heights: Vec, + #[builder(default)] + params: H::LightClientParams, +} + +impl<'a, H> From> for LightClientState +where + H: TestHost, + HostClientState: ClientStateValidation, +{ + fn from(builder: LightClientBuilder<'a, H>) -> Self { + let LightClientBuilder { + context, + consensus_heights, + params, + } = builder; + + context.generate_light_client(consensus_heights, ¶ms) + } +} diff --git a/ibc-testkit/src/testapp/ibc/mod.rs b/ibc-testkit/src/testapp/ibc/mod.rs index fb9937e58..f13a3c645 100644 --- a/ibc-testkit/src/testapp/ibc/mod.rs +++ b/ibc-testkit/src/testapp/ibc/mod.rs @@ -1,4 +1,3 @@ pub mod applications; pub mod clients; pub mod core; -pub mod utils; diff --git a/ibc-testkit/src/testapp/ibc/utils.rs b/ibc-testkit/src/testapp/ibc/utils.rs deleted file mode 100644 index d5032cae1..000000000 --- a/ibc-testkit/src/testapp/ibc/utils.rs +++ /dev/null @@ -1,6 +0,0 @@ -use ibc::core::client::types::Height; - -pub fn blocks_since(a: Height, b: Height) -> Option { - (a.revision_number() == b.revision_number() && a.revision_height() >= b.revision_height()) - .then(|| a.revision_height() - b.revision_height()) -} diff --git a/ibc-testkit/src/utils/mod.rs b/ibc-testkit/src/utils/mod.rs index 50880f7e1..502eff987 100644 --- a/ibc-testkit/src/utils/mod.rs +++ b/ibc-testkit/src/utils/mod.rs @@ -3,9 +3,9 @@ use tendermint::Time; /// Returns a `Timestamp` representation of beginning of year 2023. /// -/// This is introduced to initialize [`MockGenericContext`](crate::testapp::ibc::core::types::MockGenericContext)s +/// This is introduced to initialize [`MockGenericContext`](crate::context::MockGenericContext)s /// with the same latest timestamp by default. -/// If two [`MockGenericContext`](crate::testapp::ibc::core::types::MockGenericContext) +/// If two [`MockGenericContext`](crate::context::MockGenericContext) /// are initialized using [`Time::now()`], second one will have a greater timestamp than the first one. /// So, the latest header of the second context can not be submitted to first one. /// We can still set a custom timestamp via [`MockContextConfig`](crate::fixtures::core::context::MockContextConfig). diff --git a/ibc-testkit/tests/core/ics02_client/create_client.rs b/ibc-testkit/tests/core/ics02_client/create_client.rs index 827c00ca7..d2b0dffdd 100644 --- a/ibc-testkit/tests/core/ics02_client/create_client.rs +++ b/ibc-testkit/tests/core/ics02_client/create_client.rs @@ -1,3 +1,4 @@ +use basecoin_store::impls::InMemoryStore; use ibc::clients::tendermint::types::{ client_type as tm_client_type, ConsensusState as TmConsensusState, }; @@ -14,19 +15,18 @@ use ibc_testkit::fixtures::clients::tendermint::{ dummy_tendermint_header, dummy_tm_client_state_from_header, }; use ibc_testkit::fixtures::core::signer::dummy_account_id; -use ibc_testkit::hosts::{MockHost, TendermintHost}; use ibc_testkit::testapp::ibc::clients::mock::client_state::{ client_type as mock_client_type, MockClientState, }; use ibc_testkit::testapp::ibc::clients::mock::consensus_state::MockConsensusState; use ibc_testkit::testapp::ibc::clients::mock::header::MockHeader; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::MockContext; +use ibc_testkit::testapp::ibc::core::types::{DefaultIbcStore, MockIbcStore}; use test_log::test; #[test] fn test_create_client_ok() { - let mut ctx = MockContext::::default(); + let mut ctx = DefaultIbcStore::default(); let mut router = MockRouter::new_with_transfer(); let signer = dummy_account_id(); let height = Height::new(0, 42).unwrap(); @@ -51,7 +51,7 @@ fn test_create_client_ok() { assert!(res.is_ok(), "execution happy path"); let expected_client_state = - ClientStateRef::>::try_from(msg.client_state).unwrap(); + ClientStateRef::::try_from(msg.client_state).unwrap(); assert_eq!(expected_client_state.client_type(), client_type); assert_eq!(ctx.client_state(&client_id).unwrap(), expected_client_state); } @@ -60,7 +60,7 @@ fn test_create_client_ok() { fn test_tm_create_client_ok() { let signer = dummy_account_id(); - let mut ctx = MockContext::::default(); + let mut ctx = DefaultIbcStore::default(); let mut router = MockRouter::new_with_transfer(); @@ -88,7 +88,7 @@ fn test_tm_create_client_ok() { assert!(res.is_ok(), "tendermint client execution happy path"); let expected_client_state = - ClientStateRef::>::try_from(msg.client_state).unwrap(); + ClientStateRef::>::try_from(msg.client_state).unwrap(); assert_eq!(expected_client_state.client_type(), client_type); assert_eq!(ctx.client_state(&client_id).unwrap(), expected_client_state); } @@ -97,7 +97,7 @@ fn test_tm_create_client_ok() { fn test_invalid_frozen_tm_client_creation() { let signer = dummy_account_id(); - let ctx = MockContext::::default(); + let ctx = DefaultIbcStore::default(); let router = MockRouter::new_with_transfer(); @@ -114,9 +114,9 @@ fn test_invalid_frozen_tm_client_creation() { signer, ); - let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg.clone())); + let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope.clone()); + let res = validate(&ctx, &router, msg_envelope); assert!(matches!( res, diff --git a/ibc-testkit/tests/core/ics02_client/update_client.rs b/ibc-testkit/tests/core/ics02_client/update_client.rs index be3542f6e..818dedfdb 100644 --- a/ibc-testkit/tests/core/ics02_client/update_client.rs +++ b/ibc-testkit/tests/core/ics02_client/update_client.rs @@ -1,13 +1,15 @@ +use core::fmt::Debug; use core::str::FromStr; use core::time::Duration; +use basecoin_store::context::ProvableStore; use ibc::clients::tendermint::client_state::ClientState; use ibc::clients::tendermint::types::proto::v1::{ClientState as RawTmClientState, Fraction}; use ibc::clients::tendermint::types::{ client_type as tm_client_type, ClientState as TmClientState, Header as TmHeader, Misbehaviour as TmMisbehaviour, }; -use ibc::core::client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc::core::client::context::client_state::ClientStateValidation; use ibc::core::client::context::ClientValidationContext; use ibc::core::client::types::msgs::{ClientMsg, MsgUpdateClient}; use ibc::core::client::types::proto::v1::Height as RawHeight; @@ -22,6 +24,7 @@ use ibc::core::host::ValidationContext; use ibc::core::primitives::Timestamp; use ibc::primitives::proto::Any; use ibc::primitives::ToVec; +use ibc_testkit::context::{MockClientConfig, MockContext}; use ibc_testkit::fixtures::core::context::MockContextConfig; use ibc_testkit::fixtures::core::signer::dummy_account_id; use ibc_testkit::hosts::tendermint::BlockParams; @@ -33,10 +36,7 @@ use ibc_testkit::testapp::ibc::clients::mock::header::MockHeader; use ibc_testkit::testapp::ibc::clients::mock::misbehaviour::Misbehaviour as MockMisbehaviour; use ibc_testkit::testapp::ibc::clients::AnyConsensusState; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{ - LightClientBuilder, LightClientState, MockClientConfig, MockContext, -}; -use ibc_testkit::testapp::ibc::utils::blocks_since; +use ibc_testkit::testapp::ibc::core::types::{LightClientBuilder, LightClientState, MockIbcStore}; use rstest::*; use tendermint_testgen::Validator as TestgenValidator; @@ -97,16 +97,16 @@ fn test_update_client_ok(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg.clone())); - let res = validate(&ctx, &router, msg_envelope.clone()); + let res = validate(&ctx.ibc_store, &router, msg_envelope.clone()); assert!(res.is_ok(), "validation happy path"); - let res = execute(&mut ctx, &mut router, msg_envelope); + let res = execute(&mut ctx.ibc_store, &mut router, msg_envelope); assert!(res.is_ok(), "execution happy path"); assert_eq!( - ctx.client_state(&msg.client_id).unwrap(), + ctx.ibc_store.client_state(&msg.client_id).unwrap(), MockClientState::new(MockHeader::new(height).with_timestamp(timestamp)).into() ); } @@ -123,14 +123,21 @@ fn test_update_client_with_prev_header() { let height_2 = Height::new(0, 44).unwrap(); let ctx_b = MockContextConfig::builder() - .host_id(chain_id_b.clone()) + .host( + TendermintHost::builder() + .chain_id(chain_id_b.clone()) + .build(), + ) .latest_height(latest_height) .build::>(); - let mut ctx = MockContext::::default().with_light_client( - &client_id, - LightClientBuilder::init().context(&ctx_b).build(), - ); + let mut ctx = MockContext::::default() + .with_light_client( + &client_id, + LightClientBuilder::init().context(&ctx_b).build(), + ) + .ibc_store; + let mut router = MockRouter::new_with_transfer(); fn build_msg_from_header( @@ -139,8 +146,11 @@ fn test_update_client_with_prev_header() { target_height: Height, trusted_height: Height, ) -> MsgEnvelope { - let mut tm_block = TendermintHost::with_chain_id(chain_id) + let mut tm_block = TendermintHost::builder() + .chain_id(chain_id) + .build() .generate_block( + Vec::new(), target_height.revision_height(), Timestamp::now(), &Default::default(), @@ -210,15 +220,14 @@ fn test_consensus_state_pruning() { let client_id = tm_client_type().build_client_id(0); let ctx_b = MockContextConfig::builder() - .host_id(chain_id.clone()) + .host(TendermintHost::builder().chain_id(chain_id.clone()).build()) .latest_height(client_height) .build::>(); let mut ctx = MockContextConfig::builder() - .host_id(chain_id.clone()) + .host(TendermintHost::builder().chain_id(chain_id).build()) .latest_height(client_height) .latest_timestamp(Timestamp::now()) - .max_history_size(u64::MAX) .build::>() .with_light_client( &client_id, @@ -234,7 +243,7 @@ fn test_consensus_state_pruning() { let mut router = MockRouter::new_with_transfer(); - let start_host_timestamp = ctx.host_timestamp().unwrap(); + let start_host_timestamp = ctx.ibc_store.host_timestamp().unwrap(); // Move the chain forward by 2 blocks to pass the trusting period. for _ in 1..=2 { @@ -242,7 +251,7 @@ fn test_consensus_state_pruning() { let update_height = ctx.latest_height(); - ctx.advance_host_chain_height(); + ctx.advance_block(); let block = ctx.host_block(&update_height).unwrap().clone(); let mut block = block.into_header(); @@ -257,8 +266,8 @@ fn test_consensus_state_pruning() { let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg)); - let _ = validate(&ctx, &router, msg_envelope.clone()); - let _ = execute(&mut ctx, &mut router, msg_envelope); + let _ = validate(&ctx.ibc_store, &router, msg_envelope.clone()); + let _ = execute(&mut ctx.ibc_store, &mut router, msg_envelope); } // Check that latest expired consensus state is pruned. @@ -268,8 +277,14 @@ fn test_consensus_state_pruning() { expired_height.revision_number(), expired_height.revision_height(), ); - assert!(ctx.client_update_meta(&client_id, &expired_height).is_err()); - assert!(ctx.consensus_state(&client_cons_state_path).is_err()); + assert!(ctx + .ibc_store + .client_update_meta(&client_id, &expired_height) + .is_err()); + assert!(ctx + .ibc_store + .consensus_state(&client_cons_state_path) + .is_err()); // Check that latest valid consensus state exists. let earliest_valid_height = Height::new(1, 2).unwrap(); @@ -280,11 +295,15 @@ fn test_consensus_state_pruning() { ); assert!(ctx + .ibc_store .client_update_meta(&client_id, &earliest_valid_height) .is_ok()); - assert!(ctx.consensus_state(&client_cons_state_path).is_ok()); + assert!(ctx + .ibc_store + .consensus_state(&client_cons_state_path) + .is_ok()); - let end_host_timestamp = ctx.host_timestamp().unwrap(); + let end_host_timestamp = ctx.ibc_store.host_timestamp().unwrap(); assert_eq!( end_host_timestamp, @@ -306,7 +325,7 @@ fn test_update_nonexisting_client(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!(res.is_err()); } @@ -319,12 +338,16 @@ fn test_update_synthetic_tendermint_client_adjacent_ok() { let chain_id_b = ChainId::new("mockgaiaB-1").unwrap(); let ctx_b = MockContextConfig::builder() - .host_id(chain_id_b) + .host(TendermintHost::builder().chain_id(chain_id_b).build()) .latest_height(update_height) .build::>(); let mut ctx = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(Height::new(1, 1).unwrap()) .build::>() .with_light_client( @@ -339,7 +362,7 @@ fn test_update_synthetic_tendermint_client_adjacent_ok() { let signer = dummy_account_id(); - let block = ctx_b.host_block(&update_height).unwrap().clone(); + let block = ctx_b.host_block(&update_height).unwrap(); let mut block = block.into_header(); block.set_trusted_height(client_height); @@ -351,16 +374,16 @@ fn test_update_synthetic_tendermint_client_adjacent_ok() { }; let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg.clone())); - let res = validate(&ctx, &router, msg_envelope.clone()); + let res = validate(&ctx.ibc_store, &router, msg_envelope.clone()); assert!(res.is_ok()); - let res = execute(&mut ctx, &mut router, msg_envelope); + let res = execute(&mut ctx.ibc_store, &mut router, msg_envelope); assert!(res.is_ok(), "result: {res:?}"); - let client_state = ctx.client_state(&msg.client_id).unwrap(); + let client_state = ctx.ibc_store.client_state(&msg.client_id).unwrap(); assert!(client_state - .status(&ctx, &msg.client_id) + .status(&ctx.ibc_store, &msg.client_id) .unwrap() .is_active()); @@ -406,14 +429,17 @@ fn test_update_synthetic_tendermint_client_validator_change_ok() { assert_eq!(update_height.revision_height(), 22); let ctx_b = MockContextConfig::builder() - .host_id(chain_id_b.clone()) + .host(TendermintHost::builder().chain_id(chain_id_b).build()) .latest_height(update_height) - .max_history_size(block_params.len() as u64) .block_params_history(block_params) .build::>(); let mut ctx_a = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(Height::new(1, 1).unwrap()) .build::>() .with_light_client( @@ -429,11 +455,7 @@ fn test_update_synthetic_tendermint_client_validator_change_ok() { let signer = dummy_account_id(); - let mut block = ctx_b - .host_block(&update_height) - .unwrap() - .clone() - .into_header(); + let mut block = ctx_b.host_block(&update_height).unwrap().into_header(); let trusted_next_validator_set = ctx_b .host_block(&client_height) @@ -453,15 +475,15 @@ fn test_update_synthetic_tendermint_client_validator_change_ok() { }; let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg.clone())); - let res = validate(&ctx_a, &router_a, msg_envelope.clone()); + let res = validate(&ctx_a.ibc_store, &router_a, msg_envelope.clone()); assert!(res.is_ok()); - let res = execute(&mut ctx_a, &mut router_a, msg_envelope); + let res = execute(&mut ctx_a.ibc_store, &mut router_a, msg_envelope); assert!(res.is_ok(), "result: {res:?}"); - let client_state = ctx_a.client_state(&msg.client_id).unwrap(); + let client_state = ctx_a.ibc_store.client_state(&msg.client_id).unwrap(); assert!(client_state - .status(&ctx_a, &msg.client_id) + .status(&ctx_a.ibc_store, &msg.client_id) .unwrap() .is_active()); assert_eq!(client_state.latest_height(), latest_header_height); @@ -507,14 +529,17 @@ fn test_update_synthetic_tendermint_client_wrong_trusted_validator_change_fail() assert_eq!(update_height.revision_height(), 22); let ctx_b = MockContextConfig::builder() - .host_id(chain_id_b.clone()) + .host(TendermintHost::builder().chain_id(chain_id_b).build()) .latest_height(update_height) - .max_history_size(block_params.len() as u64) .block_params_history(block_params) .build::>(); let ctx_a = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(Height::new(1, 1).unwrap()) .build::>() .with_light_client( @@ -552,11 +577,7 @@ fn test_update_synthetic_tendermint_client_wrong_trusted_validator_change_fail() trusted_next_validator_set.hash() ); - let mut block = ctx_b - .host_block(&update_height) - .unwrap() - .clone() - .into_header(); + let mut block = ctx_b.host_block(&update_height).unwrap().into_header(); // set the trusted height to height-20 block.set_trusted_height(client_height); @@ -571,7 +592,7 @@ fn test_update_synthetic_tendermint_client_wrong_trusted_validator_change_fail() let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg)); - let res = validate(&ctx_a, &router, msg_envelope); + let res = validate(&ctx_a.ibc_store, &router, msg_envelope); assert!(res.is_err()); } @@ -616,14 +637,17 @@ fn test_update_synthetic_tendermint_client_validator_change_fail() { assert_eq!(update_height.revision_height(), 22); let ctx_b = MockContextConfig::builder() - .host_id(chain_id_b.clone()) + .host(TendermintHost::builder().chain_id(chain_id_b).build()) .latest_height(update_height) - .max_history_size(block_params.len() as u64) .block_params_history(block_params) .build::>(); let ctx_a = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(Height::new(1, 1).unwrap()) .build::>() .with_light_client( @@ -646,11 +670,7 @@ fn test_update_synthetic_tendermint_client_validator_change_fail() { .next_validators .clone(); - let mut block = ctx_b - .host_block(&update_height) - .unwrap() - .clone() - .into_header(); + let mut block = ctx_b.host_block(&update_height).unwrap().into_header(); block.set_trusted_height(client_height); block.set_trusted_next_validators_set(trusted_next_validator_set); @@ -660,9 +680,9 @@ fn test_update_synthetic_tendermint_client_validator_change_fail() { client_message: block.into(), signer, }; - let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg.clone())); + let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg)); - let res = validate(&ctx_a, &router_a, msg_envelope.clone()); + let res = validate(&ctx_a.ibc_store, &router_a, msg_envelope); assert!(res.is_err()); } @@ -712,14 +732,17 @@ fn test_update_synthetic_tendermint_client_malicious_validator_change_pass() { assert_eq!(update_height.revision_height(), 22); let ctx_b = MockContextConfig::builder() - .host_id(chain_id_b.clone()) + .host(TendermintHost::builder().chain_id(chain_id_b).build()) .latest_height(update_height) - .max_history_size(block_params.len() as u64) .block_params_history(block_params) .build::>(); let mut ctx_a = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(Height::new(1, 1).unwrap()) .build::>() .with_light_client( @@ -735,11 +758,7 @@ fn test_update_synthetic_tendermint_client_malicious_validator_change_pass() { let signer = dummy_account_id(); - let mut block = ctx_b - .host_block(&update_height) - .unwrap() - .clone() - .into_header(); + let mut block = ctx_b.host_block(&update_height).unwrap().into_header(); let trusted_next_validator_set = ctx_b .host_block(&client_height) @@ -759,15 +778,15 @@ fn test_update_synthetic_tendermint_client_malicious_validator_change_pass() { }; let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg.clone())); - let res = validate(&ctx_a, &router_a, msg_envelope.clone()); + let res = validate(&ctx_a.ibc_store, &router_a, msg_envelope.clone()); assert!(res.is_ok()); - let res = execute(&mut ctx_a, &mut router_a, msg_envelope); + let res = execute(&mut ctx_a.ibc_store, &mut router_a, msg_envelope); assert!(res.is_ok(), "result: {res:?}"); - let client_state = ctx_a.client_state(&msg.client_id).unwrap(); + let client_state = ctx_a.ibc_store.client_state(&msg.client_id).unwrap(); assert!(client_state - .status(&ctx_a, &msg.client_id) + .status(&ctx_a.ibc_store, &msg.client_id) .unwrap() .is_active()); assert_eq!(client_state.latest_height(), latest_header_height); @@ -810,14 +829,17 @@ fn test_update_synthetic_tendermint_client_adjacent_malicious_validator_change_f assert_eq!(update_height.revision_height(), 22); let ctx_b = MockContextConfig::builder() - .host_id(chain_id_b.clone()) + .host(TendermintHost::builder().chain_id(chain_id_b).build()) .latest_height(update_height) - .max_history_size(block_params.len() as u64) .block_params_history(block_params) .build::>(); let ctx_a = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(Height::new(1, 1).unwrap()) .build::>() .with_light_client( @@ -833,11 +855,7 @@ fn test_update_synthetic_tendermint_client_adjacent_malicious_validator_change_f let signer = dummy_account_id(); - let mut block = ctx_b - .host_block(&update_height) - .unwrap() - .clone() - .into_header(); + let mut block = ctx_b.host_block(&update_height).unwrap().into_header(); let trusted_next_validator_set = ctx_b .host_block(&client_height) @@ -854,9 +872,9 @@ fn test_update_synthetic_tendermint_client_adjacent_malicious_validator_change_f client_message: block.into(), signer, }; - let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg.clone())); + let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg)); - let res = validate(&ctx_a, &router_a, msg_envelope.clone()); + let res = validate(&ctx_a.ibc_store, &router_a, msg_envelope); assert!(res.is_err()); } @@ -869,12 +887,16 @@ fn test_update_synthetic_tendermint_client_non_adjacent_ok() { let chain_id_b = ChainId::new("mockgaiaB-1").unwrap(); let ctx_b = MockContextConfig::builder() - .host_id(chain_id_b) + .host(TendermintHost::builder().chain_id(chain_id_b).build()) .latest_height(update_height) .build::>(); let mut ctx = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(Height::new(1, 1).unwrap()) .build::>() .with_light_client( @@ -889,7 +911,7 @@ fn test_update_synthetic_tendermint_client_non_adjacent_ok() { let signer = dummy_account_id(); - let block = ctx_b.host_block(&update_height).unwrap().clone(); + let block = ctx_b.host_block(&update_height).unwrap(); let mut block = block.into_header(); let trusted_height = client_height.clone().sub(1).unwrap(); block.set_trusted_height(trusted_height); @@ -903,16 +925,16 @@ fn test_update_synthetic_tendermint_client_non_adjacent_ok() { let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg.clone())); - let res = validate(&ctx, &router, msg_envelope.clone()); + let res = validate(&ctx.ibc_store, &router, msg_envelope.clone()); assert!(res.is_ok()); - let res = execute(&mut ctx, &mut router, msg_envelope); + let res = execute(&mut ctx.ibc_store, &mut router, msg_envelope); assert!(res.is_ok(), "result: {res:?}"); - let client_state = ctx.client_state(&msg.client_id).unwrap(); + let client_state = ctx.ibc_store.client_state(&msg.client_id).unwrap(); assert!(client_state - .status(&ctx, &msg.client_id) + .status(&ctx.ibc_store, &msg.client_id) .unwrap() .is_active()); @@ -929,13 +951,12 @@ fn test_update_synthetic_tendermint_client_duplicate_ok() { let start_height = Height::new(1, 11).unwrap(); let ctx_b = MockContextConfig::builder() - .host_id(ctx_b_chain_id) + .host(TendermintHost::builder().chain_id(ctx_b_chain_id).build()) .latest_height(client_height) - .max_history_size(blocks_since(client_height, start_height).expect("no error") + 1) .build::>(); let mut ctx_a = MockContextConfig::builder() - .host_id(ctx_a_chain_id) + .host(MockHost::builder().chain_id(ctx_a_chain_id).build()) .latest_height(start_height) .build::>() .with_light_client( @@ -950,7 +971,7 @@ fn test_update_synthetic_tendermint_client_duplicate_ok() { let signer = dummy_account_id(); - let block = ctx_b.host_block(&client_height).unwrap().clone(); + let block = ctx_b.host_block(&client_height).unwrap(); let mut block = block.into_header(); // Update the trusted height of the header to point to the previous height @@ -1026,19 +1047,18 @@ fn test_update_synthetic_tendermint_client_duplicate_ok() { let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg.clone())); - let res = validate(&ctx_a, &router_a, msg_envelope.clone()); + let res = validate(&ctx_a.ibc_store, &router_a, msg_envelope.clone()); assert!(res.is_ok(), "result: {res:?}"); - let res = execute(&mut ctx_a, &mut router_a, msg_envelope); + let res = execute(&mut ctx_a.ibc_store, &mut router_a, msg_envelope); assert!(res.is_ok(), "result: {res:?}"); - let client_state = ctx_a.client_state(&msg.client_id).unwrap(); + let client_state = ctx_a.ibc_store.client_state(&msg.client_id).unwrap(); assert!(client_state - .status(&ctx_a, &msg.client_id) + .status(&ctx_a.ibc_store, &msg.client_id) .unwrap() .is_active()); assert_eq!(client_state.latest_height(), latest_header_height); - assert_eq!(client_state, ctx_a.latest_client_states(&msg.client_id)); } #[rstest] @@ -1051,12 +1071,20 @@ fn test_update_synthetic_tendermint_client_lower_height() { let chain_start_height = Height::new(1, 11).unwrap(); let ctx_b = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaB-1").unwrap()) + .host( + TendermintHost::builder() + .chain_id(ChainId::new("mockgaiaB-1").unwrap()) + .build(), + ) .latest_height(client_height) .build::>(); let ctx = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(chain_start_height) .build::>() .with_light_client( @@ -1072,13 +1100,13 @@ fn test_update_synthetic_tendermint_client_lower_height() { let msg = MsgUpdateClient { client_id, - client_message: block_ref.clone().into_header().into(), + client_message: block_ref.into_header().into(), signer, }; let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!(res.is_err()); } @@ -1102,7 +1130,7 @@ fn test_update_client_events(fixture: Fixture) { }; let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg)); - let res = execute(&mut ctx, &mut router, msg_envelope); + let res = execute(&mut ctx.ibc_store, &mut router, msg_envelope); assert!(res.is_ok()); let ibc_events = ctx.get_events(); @@ -1123,8 +1151,8 @@ fn test_update_client_events(fixture: Fixture) { assert_eq!(update_client_event.header(), &header.to_vec()); } -fn ensure_misbehaviour( - ctx: &MockContext, +fn ensure_misbehaviour( + ctx: &MockIbcStore, client_id: &ClientId, client_type: &ClientType, ) { @@ -1134,7 +1162,7 @@ fn ensure_misbehaviour( assert!(status.is_frozen(), "client_state status: {status}"); // check events - let ibc_events = ctx.get_events(); + let ibc_events = ctx.events.lock(); assert_eq!(ibc_events.len(), 2); assert!(matches!( ibc_events[0], @@ -1161,13 +1189,13 @@ fn test_misbehaviour_client_ok(fixture: Fixture) { let client_id = ClientId::new("07-tendermint", 0).expect("no error"); let msg_envelope = msg_update_client(&client_id); - let res = validate(&ctx, &router, msg_envelope.clone()); + let res = validate(&ctx.ibc_store, &router, msg_envelope.clone()); assert!(res.is_ok()); - let res = execute(&mut ctx, &mut router, msg_envelope); + let res = execute(&mut ctx.ibc_store, &mut router, msg_envelope); assert!(res.is_ok()); - ensure_misbehaviour(&ctx, &client_id, &mock_client_type()); + ensure_misbehaviour(&ctx.ibc_store, &client_id, &mock_client_type()); } #[rstest] @@ -1182,7 +1210,7 @@ fn test_submit_misbehaviour_nonexisting_client(fixture: Fixture) { &client_id, LightClientState::::with_latest_height(Height::new(0, 42).unwrap()), ); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!(res.is_err()); } @@ -1198,7 +1226,7 @@ fn test_client_update_misbehaviour_nonexisting_client(fixture: Fixture) { &client_id, LightClientState::::with_latest_height(Height::new(0, 42).unwrap()), ); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!(res.is_err()); } @@ -1213,13 +1241,21 @@ fn test_misbehaviour_synthetic_tendermint_equivocation() { // Create a mock context for chain-B let ctx_b = MockContextConfig::builder() - .host_id(chain_id_b.clone()) + .host( + TendermintHost::builder() + .chain_id(chain_id_b.clone()) + .build(), + ) .latest_height(misbehaviour_height) .build::>(); // Create a mock context for chain-A with a synthetic tendermint light client for chain-B let mut ctx_a = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(Height::new(1, 1).unwrap()) .build::>() .with_light_client( @@ -1234,7 +1270,7 @@ fn test_misbehaviour_synthetic_tendermint_equivocation() { // Get chain-B's header at `misbehaviour_height` let header1: TmHeader = { - let block = ctx_b.host_block(&misbehaviour_height).unwrap().clone(); + let block = ctx_b.host_block(&misbehaviour_height).unwrap(); let mut block = block.into_header(); block.set_trusted_height(client_height); block.into() @@ -1242,8 +1278,11 @@ fn test_misbehaviour_synthetic_tendermint_equivocation() { // Generate an equivocal header for chain-B at `misbehaviour_height` let header2 = { - let mut tm_block = TendermintHost::with_chain_id(chain_id_b) + let mut tm_block = TendermintHost::builder() + .chain_id(chain_id_b) + .build() .generate_block( + Vec::new(), misbehaviour_height.revision_height(), Timestamp::now(), &Default::default(), @@ -1260,11 +1299,11 @@ fn test_misbehaviour_synthetic_tendermint_equivocation() { }; let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg)); - let res = validate(&ctx_a, &router_a, msg_envelope.clone()); + let res = validate(&ctx_a.ibc_store, &router_a, msg_envelope.clone()); assert!(res.is_ok()); - let res = execute(&mut ctx_a, &mut router_a, msg_envelope); + let res = execute(&mut ctx_a.ibc_store, &mut router_a, msg_envelope); assert!(res.is_ok()); - ensure_misbehaviour(&ctx_a, &client_id, &tm_client_type()); + ensure_misbehaviour(&ctx_a.ibc_store, &client_id, &tm_client_type()); } #[rstest] @@ -1275,13 +1314,21 @@ fn test_misbehaviour_synthetic_tendermint_bft_time() { let chain_id_b = ChainId::new("mockgaiaB-1").unwrap(); let ctx_b = MockContextConfig::builder() - .host_id(chain_id_b.clone()) + .host( + TendermintHost::builder() + .chain_id(chain_id_b.clone()) + .build(), + ) .latest_height(client_height) .build::>(); // Create a mock context for chain-A with a synthetic tendermint light client for chain-B let mut ctx_a = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(Height::new(1, 1).unwrap()) .build::>() .with_light_client( @@ -1293,8 +1340,11 @@ fn test_misbehaviour_synthetic_tendermint_bft_time() { // Generate `header1` for chain-B let header1 = { - let mut tm_block = TendermintHost::with_chain_id(chain_id_b.clone()) + let mut tm_block = TendermintHost::builder() + .chain_id(chain_id_b.clone()) + .build() .generate_block( + Vec::new(), misbehaviour_height.revision_height(), Timestamp::now(), &Default::default(), @@ -1309,8 +1359,11 @@ fn test_misbehaviour_synthetic_tendermint_bft_time() { let header2 = { let timestamp = Timestamp::from_nanoseconds(Timestamp::now().nanoseconds() + 1_000_000_000).unwrap(); - let mut tm_block = TendermintHost::with_chain_id(chain_id_b) + let mut tm_block = TendermintHost::builder() + .chain_id(chain_id_b) + .build() .generate_block( + Vec::new(), misbehaviour_height.revision_height(), timestamp, &Default::default(), @@ -1329,11 +1382,11 @@ fn test_misbehaviour_synthetic_tendermint_bft_time() { let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg)); - let res = validate(&ctx_a, &router_a, msg_envelope.clone()); + let res = validate(&ctx_a.ibc_store, &router_a, msg_envelope.clone()); assert!(res.is_ok()); - let res = execute(&mut ctx_a, &mut router_a, msg_envelope); + let res = execute(&mut ctx_a.ibc_store, &mut router_a, msg_envelope); assert!(res.is_ok()); - ensure_misbehaviour(&ctx_a, &client_id, &tm_client_type()); + ensure_misbehaviour(&ctx_a.ibc_store, &client_id, &tm_client_type()); } #[rstest] @@ -1350,13 +1403,17 @@ fn test_expired_client() { let trusting_period = Duration::from_secs(64); let ctx_b = MockContextConfig::builder() - .host_id(chain_id_b) + .host(TendermintHost::builder().chain_id(chain_id_b).build()) .latest_height(client_height) .latest_timestamp(timestamp) .build::>(); let mut ctx = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(Height::new(1, 1).unwrap()) .latest_timestamp(timestamp) .build::>() @@ -1372,14 +1429,18 @@ fn test_expired_client() { .build(), ); - while ctx.host_timestamp().expect("no error") < (timestamp + trusting_period).expect("no error") + while ctx.ibc_store.host_timestamp().expect("no error") + < (timestamp + trusting_period).expect("no error") { - ctx.advance_host_chain_height(); + ctx.advance_block(); } - let client_state = ctx.client_state(&client_id).unwrap(); + let client_state = ctx.ibc_store.client_state(&client_id).unwrap(); - assert!(client_state.status(&ctx, &client_id).unwrap().is_expired()); + assert!(client_state + .status(&ctx.ibc_store, &client_id) + .unwrap() + .is_expired()); } #[rstest] @@ -1395,14 +1456,17 @@ fn test_client_update_max_clock_drift() { let max_clock_drift = Duration::from_secs(64); let mut ctx_b = MockContextConfig::builder() - .host_id(chain_id_b.clone()) + .host(TendermintHost::builder().chain_id(chain_id_b).build()) .latest_height(client_height) .latest_timestamp(timestamp) - .max_history_size(u64::MAX) .build::>(); let ctx_a = MockContextConfig::builder() - .host_id(ChainId::new("mockgaiaA-1").unwrap()) + .host( + MockHost::builder() + .chain_id(ChainId::new("mockgaiaA-1").unwrap()) + .build(), + ) .latest_height(Height::new(1, 1).unwrap()) .latest_timestamp(timestamp) .build::>() @@ -1420,20 +1484,20 @@ fn test_client_update_max_clock_drift() { let router_a = MockRouter::new_with_transfer(); - while ctx_b.host_timestamp().expect("no error") - < (ctx_a.host_timestamp().expect("no error") + max_clock_drift).expect("no error") + while ctx_b.ibc_store.host_timestamp().expect("no error") + < (ctx_a.ibc_store.host_timestamp().expect("no error") + max_clock_drift).expect("no error") { - ctx_b.advance_host_chain_height(); + ctx_b.advance_block(); } // include current block - ctx_b.advance_host_chain_height(); + ctx_b.advance_block(); let update_height = ctx_b.latest_height(); let signer = dummy_account_id(); - let block = ctx_b.host_block(&update_height).unwrap().clone(); + let block = ctx_b.host_block(&update_height).unwrap(); let mut block = block.into_header(); block.set_trusted_height(client_height); @@ -1454,6 +1518,6 @@ fn test_client_update_max_clock_drift() { let msg_envelope = MsgEnvelope::from(ClientMsg::from(msg)); - let res = validate(&ctx_a, &router_a, msg_envelope); + let res = validate(&ctx_a.ibc_store, &router_a, msg_envelope); assert!(res.is_err()); } diff --git a/ibc-testkit/tests/core/ics02_client/upgrade_client.rs b/ibc-testkit/tests/core/ics02_client/upgrade_client.rs index 620b00e9a..5f7d1af34 100644 --- a/ibc-testkit/tests/core/ics02_client/upgrade_client.rs +++ b/ibc-testkit/tests/core/ics02_client/upgrade_client.rs @@ -1,3 +1,4 @@ +use ibc::clients::tendermint::context::ValidationContext; use ibc::clients::tendermint::types::client_type; use ibc::core::client::context::ClientValidationContext; use ibc::core::client::types::error::{ClientError, UpgradeClientError}; @@ -8,6 +9,7 @@ use ibc::core::handler::types::error::ContextError; use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::path::ClientConsensusStatePath; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::clients::tendermint::{ dummy_tendermint_header, dummy_tm_client_state_from_header, }; @@ -17,7 +19,7 @@ use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::clients::mock::client_state::client_type as mock_client_type; use ibc_testkit::testapp::ibc::clients::{AnyClientState, AnyConsensusState}; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; enum Ctx { Default, @@ -39,8 +41,8 @@ fn msg_upgrade_client_fixture(ctx_variant: Ctx, msg_variant: Msg) -> Fixture::with_latest_height(Height::new(0, 42).unwrap()), ); let ctx = match ctx_variant { - Ctx::Default => ctx_default, - Ctx::WithClient => ctx_with_client, + Ctx::Default => ctx_default.ibc_store, + Ctx::WithClient => ctx_with_client.ibc_store, }; let upgrade_height = Height::new(1, 26).unwrap(); @@ -95,7 +97,7 @@ fn upgrade_client_execute(fxt: &mut Fixture, expect: Expect) { } Expect::Success => { assert!(res.is_ok(), "{err_msg}"); - let ibc_events = fxt.ctx.get_events(); + let ibc_events = fxt.ctx.events.lock(); assert!(matches!( ibc_events[0], IbcEvent::Message(MessageEvent::Client) @@ -152,7 +154,7 @@ fn upgrade_client_fail_low_upgrade_height() { msg_upgrade_client_fixture(Ctx::WithClient, Msg::LowUpgradeHeight); let expected_err: ClientError = UpgradeClientError::LowUpgradeHeight { upgraded_height: Height::new(0, 26).unwrap(), - client_height: fxt.ctx.latest_height(), + client_height: fxt.ctx.host_height().unwrap(), } .into(); upgrade_client_validate( diff --git a/ibc-testkit/tests/core/ics03_connection/conn_open_ack.rs b/ibc-testkit/tests/core/ics03_connection/conn_open_ack.rs index bf2d9c6d4..75b2db444 100644 --- a/ibc-testkit/tests/core/ics03_connection/conn_open_ack.rs +++ b/ibc-testkit/tests/core/ics03_connection/conn_open_ack.rs @@ -1,5 +1,6 @@ use core::str::FromStr; +use basecoin_store::impls::{GrowingStore, InMemoryStore, RevertibleStore}; use ibc::core::client::types::Height; use ibc::core::commitment_types::commitment::CommitmentPrefix; use ibc::core::connection::types::error::ConnectionError; @@ -13,12 +14,13 @@ use ibc::core::host::types::identifiers::{ChainId, ClientId}; use ibc::core::host::ValidationContext; use ibc::core::primitives::prelude::*; use ibc::core::primitives::ZERO_DURATION; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::connection::dummy_msg_conn_open_ack; use ibc_testkit::fixtures::core::context::MockContextConfig; use ibc_testkit::fixtures::{Expect, Fixture}; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockIbcStore}; use test_log::test; enum Ctx { @@ -60,29 +62,44 @@ fn conn_open_ack_fixture(ctx: Ctx) -> Fixture { let ctx_default = MockContext::::default(); let ctx_new = MockContextConfig::builder() - .host_id(ChainId::new(&format!("mockgaia-{}", latest_height.revision_number())).unwrap()) + .host( + MockHost::builder() + .chain_id( + ChainId::new(&format!("mockgaia-{}", latest_height.revision_number())).unwrap(), + ) + .build(), + ) .latest_height(latest_height) .build::>(); let ctx = match ctx { - Ctx::New => ctx_new, - Ctx::NewWithConnection => ctx_new - .with_light_client( - &client_id, - LightClientState::::with_latest_height(proof_height), - ) - .with_connection(conn_id, default_conn_end), - Ctx::DefaultWithConnection => ctx_default - .with_light_client( - &client_id, - LightClientState::::with_latest_height(proof_height), - ) - .with_connection(conn_id, default_conn_end), - Ctx::NewWithConnectionEndOpen => ctx_new - .with_light_client( - &client_id, - LightClientState::::with_latest_height(proof_height), - ) - .with_connection(conn_id, conn_end_open), + Ctx::New => ctx_new.ibc_store, + Ctx::NewWithConnection => { + ctx_new + .with_light_client( + &client_id, + LightClientState::::with_latest_height(proof_height), + ) + .with_connection(conn_id, default_conn_end) + .ibc_store + } + Ctx::DefaultWithConnection => { + ctx_default + .with_light_client( + &client_id, + LightClientState::::with_latest_height(proof_height), + ) + .with_connection(conn_id, default_conn_end) + .ibc_store + } + Ctx::NewWithConnectionEndOpen => { + ctx_new + .with_light_client( + &client_id, + LightClientState::::with_latest_height(proof_height), + ) + .with_connection(conn_id, conn_end_open) + .ibc_store + } }; Fixture { ctx, msg } @@ -137,7 +154,7 @@ fn conn_open_ack_execute(fxt: &mut Fixture, expect: Expect assert!(res.is_err(), "{err_msg}"); } Expect::Success => { - let ibc_events = fxt.ctx.get_events(); + let ibc_events = fxt.ctx.events.lock(); assert!(res.is_ok(), "{err_msg}"); assert_eq!(ibc_events.len(), 2); @@ -151,7 +168,7 @@ fn conn_open_ack_execute(fxt: &mut Fixture, expect: Expect let IbcEvent::OpenAckConnection(conn_open_try_event) = event else { unreachable!() }; - let conn_end = as ValidationContext>::connection_end( + let conn_end = >> as ValidationContext>::connection_end( &fxt.ctx, conn_open_try_event.conn_id_on_a(), ) diff --git a/ibc-testkit/tests/core/ics03_connection/conn_open_confirm.rs b/ibc-testkit/tests/core/ics03_connection/conn_open_confirm.rs index fbc96574b..70a838460 100644 --- a/ibc-testkit/tests/core/ics03_connection/conn_open_confirm.rs +++ b/ibc-testkit/tests/core/ics03_connection/conn_open_confirm.rs @@ -11,11 +11,12 @@ use ibc::core::host::types::identifiers::ClientId; use ibc::core::host::ValidationContext; use ibc::core::primitives::prelude::*; use ibc::core::primitives::ZERO_DURATION; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::connection::dummy_conn_open_confirm; use ibc_testkit::fixtures::{Expect, Fixture}; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; use test_log::test; enum Ctx { @@ -39,7 +40,7 @@ fn conn_open_confirm_fixture(ctx: Ctx) -> Fixture { State::Init, client_id.clone(), counterparty, - ValidationContext::get_compatible_versions(&ctx_default), + ValidationContext::get_compatible_versions(&ctx_default.ibc_store), ZERO_DURATION, ) .unwrap(); @@ -48,19 +49,25 @@ fn conn_open_confirm_fixture(ctx: Ctx) -> Fixture { correct_conn_end.set_state(State::TryOpen); let ctx = match ctx { - Ctx::Default => ctx_default, - Ctx::IncorrectConnection => ctx_default - .with_light_client( - &client_id, - LightClientState::::with_latest_height(Height::new(0, 10).unwrap()), - ) - .with_connection(msg.conn_id_on_b.clone(), incorrect_conn_end_state), - Ctx::CorrectConnection => ctx_default - .with_light_client( - &client_id, - LightClientState::::with_latest_height(Height::new(0, 10).unwrap()), - ) - .with_connection(msg.conn_id_on_b.clone(), correct_conn_end), + Ctx::Default => ctx_default.ibc_store, + Ctx::IncorrectConnection => { + ctx_default + .with_light_client( + &client_id, + LightClientState::::with_latest_height(Height::new(0, 10).unwrap()), + ) + .with_connection(msg.conn_id_on_b.clone(), incorrect_conn_end_state) + .ibc_store + } + Ctx::CorrectConnection => { + ctx_default + .with_light_client( + &client_id, + LightClientState::::with_latest_height(Height::new(0, 10).unwrap()), + ) + .with_connection(msg.conn_id_on_b.clone(), correct_conn_end) + .ibc_store + } }; Fixture { ctx, msg } @@ -91,7 +98,7 @@ fn conn_open_confirm_execute(fxt: &mut Fixture, expect assert!(res.is_err(), "{err_msg}"); } Expect::Success => { - let ibc_events = fxt.ctx.get_events(); + let ibc_events = fxt.ctx.events.lock(); assert!(res.is_ok(), "{err_msg}"); assert_eq!(ibc_events.len(), 2); diff --git a/ibc-testkit/tests/core/ics03_connection/conn_open_init.rs b/ibc-testkit/tests/core/ics03_connection/conn_open_init.rs index 74b0aac1d..ded2d15e7 100644 --- a/ibc-testkit/tests/core/ics03_connection/conn_open_init.rs +++ b/ibc-testkit/tests/core/ics03_connection/conn_open_init.rs @@ -7,6 +7,7 @@ use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::ValidationContext; use ibc::core::primitives::prelude::*; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::connection::{ dummy_msg_conn_open_init, msg_conn_open_init_with_counterparty_conn_id, msg_conn_open_with_version, @@ -14,7 +15,7 @@ use ibc_testkit::fixtures::core::connection::{ use ibc_testkit::fixtures::{Expect, Fixture}; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; use test_log::test; enum Ctx { @@ -32,7 +33,7 @@ enum Msg { fn conn_open_init_fixture(ctx_variant: Ctx, msg_variant: Msg) -> Fixture { let msg_default = dummy_msg_conn_open_init(); let msg = match msg_variant { - Msg::Default => msg_default.clone(), + Msg::Default => msg_default, Msg::NoVersion => msg_conn_open_with_version(msg_default, None), Msg::BadVersion => { msg_conn_open_with_version(msg_default, Some("random identifier 424242")) @@ -42,11 +43,15 @@ fn conn_open_init_fixture(ctx_variant: Ctx, msg_variant: Msg) -> Fixture::default(); let ctx = match ctx_variant { - Ctx::WithClient => ctx_default.with_light_client( - &msg.client_id_on_a, - LightClientState::::with_latest_height(Height::new(0, 10).unwrap()), - ), - _ => ctx_default, + Ctx::WithClient => { + ctx_default + .with_light_client( + &msg.client_id_on_a, + LightClientState::::with_latest_height(Height::new(0, 10).unwrap()), + ) + .ibc_store + } + _ => ctx_default.ibc_store, }; Fixture { ctx, msg } @@ -81,7 +86,7 @@ fn conn_open_init_execute( assert!(res.is_err(), "{err_msg}") } Expect::Success => { - let ibc_events = fxt.ctx.get_events(); + let ibc_events = fxt.ctx.events.lock(); assert!(res.is_ok(), "{err_msg}"); diff --git a/ibc-testkit/tests/core/ics03_connection/conn_open_try.rs b/ibc-testkit/tests/core/ics03_connection/conn_open_try.rs index 18de31183..b587e33f6 100644 --- a/ibc-testkit/tests/core/ics03_connection/conn_open_try.rs +++ b/ibc-testkit/tests/core/ics03_connection/conn_open_try.rs @@ -6,12 +6,13 @@ use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::ValidationContext; use ibc::core::primitives::prelude::*; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::connection::dummy_msg_conn_open_try; use ibc_testkit::fixtures::core::context::MockContextConfig; use ibc_testkit::fixtures::{Expect, Fixture}; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::{DefaultIbcStore, LightClientState}; use test_log::test; enum Ctx { @@ -27,13 +28,10 @@ enum Msg { } fn conn_open_try_fixture(ctx_variant: Ctx, msg_variant: Msg) -> Fixture { - let max_history_size = 5; + let retained_history_size = 5; let client_cons_state_height = 10; let host_chain_height = Height::new(0, 35).unwrap(); - let pruned_height = host_chain_height - .sub(max_history_size + 1) - .unwrap() - .revision_height(); + let pruned_height = host_chain_height.sub(retained_history_size + 1).unwrap(); let msg = match msg_variant { Msg::Default => dummy_msg_conn_open_try( @@ -44,7 +42,9 @@ fn conn_open_try_fixture(ctx_variant: Ctx, msg_variant: Msg) -> Fixture dummy_msg_conn_open_try(client_cons_state_height, pruned_height), + Msg::HeightOld => { + dummy_msg_conn_open_try(client_cons_state_height, pruned_height.revision_height()) + } Msg::ProofHeightMissing => dummy_msg_conn_open_try( client_cons_state_height - 1, host_chain_height.revision_height(), @@ -52,18 +52,23 @@ fn conn_open_try_fixture(ctx_variant: Ctx, msg_variant: Msg) -> Fixture>(); let ctx = match ctx_variant { - Ctx::Default => MockContext::::default(), - Ctx::WithClient => ctx_new.with_light_client( - &msg.client_id_on_b, - LightClientState::::with_latest_height( - Height::new(0, client_cons_state_height).unwrap(), - ), - ), + Ctx::Default => DefaultIbcStore::default(), + Ctx::WithClient => { + ctx_new + .with_light_client( + &msg.client_id_on_b, + LightClientState::::with_latest_height( + Height::new(0, client_cons_state_height).unwrap(), + ), + ) + .ibc_store + } }; + + ctx.prune_host_consensus_states_till(&pruned_height); Fixture { ctx, msg } } @@ -96,7 +101,7 @@ fn conn_open_try_execute(fxt: &mut Fixture, expect: Expect assert_eq!(fxt.ctx.connection_counter().unwrap(), 1); - let ibc_events = fxt.ctx.get_events(); + let ibc_events = fxt.ctx.events.lock(); assert_eq!(ibc_events.len(), 2); diff --git a/ibc-testkit/tests/core/ics04_channel/acknowledgement.rs b/ibc-testkit/tests/core/ics04_channel/acknowledgement.rs index 2637686d0..d614c4981 100644 --- a/ibc-testkit/tests/core/ics04_channel/acknowledgement.rs +++ b/ibc-testkit/tests/core/ics04_channel/acknowledgement.rs @@ -2,7 +2,6 @@ use ibc::core::channel::types::channel::{ChannelEnd, Counterparty, Order, State} use ibc::core::channel::types::commitment::{compute_packet_commitment, PacketCommitment}; use ibc::core::channel::types::msgs::{MsgAcknowledgement, PacketMsg}; use ibc::core::channel::types::Version; -use ibc::core::client::context::ClientExecutionContext; use ibc::core::client::types::Height; use ibc::core::commitment_types::commitment::CommitmentPrefix; use ibc::core::connection::types::version::Version as ConnectionVersion; @@ -13,12 +12,12 @@ use ibc::core::entrypoint::{execute, validate}; use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::{ChannelId, ClientId, ConnectionId, PortId}; -use ibc::core::host::ExecutionContext; use ibc::core::primitives::*; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_acknowledgement; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; use rstest::*; use test_log::test; @@ -74,7 +73,7 @@ fn fixture() -> Fixture { ConnectionState::Open, default_client_id.clone(), ConnectionCounterparty::new( - default_client_id.clone(), + default_client_id, Some(ConnectionId::zero()), CommitmentPrefix::try_from(vec![0]).expect("no error"), ), @@ -90,8 +89,8 @@ fn fixture() -> Fixture { msg, packet_commitment, conn_end_on_a, - chan_end_on_a_unordered, chan_end_on_a_ordered, + chan_end_on_a_unordered, } } @@ -103,7 +102,7 @@ fn ack_fail_no_channel(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!( res.is_err(), @@ -137,7 +136,7 @@ fn ack_success_no_packet_commitment(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!( res.is_ok(), @@ -147,7 +146,6 @@ fn ack_success_no_packet_commitment(fixture: Fixture) { #[rstest] fn ack_success_happy_path(fixture: Fixture) { - let default_client_id = ClientId::new("07-tendermint", 0).expect("no error"); let Fixture { ctx, router, @@ -158,7 +156,7 @@ fn ack_success_happy_path(fixture: Fixture) { client_height, .. } = fixture; - let mut ctx = ctx + let ctx = ctx .with_light_client( &ClientId::new("07-tendermint", 0).expect("no error"), LightClientState::::with_latest_height(client_height), @@ -175,18 +173,10 @@ fn ack_success_happy_path(fixture: Fixture) { msg.packet.seq_on_a, packet_commitment, ); - ctx.get_client_execution_context() - .store_update_meta( - default_client_id, - client_height, - Timestamp::from_nanoseconds(1000).unwrap(), - Height::new(0, 4).unwrap(), - ) - .unwrap(); let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!( res.is_ok(), @@ -221,7 +211,7 @@ fn ack_unordered_chan_execute(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = execute(&mut ctx, &mut router, msg_envelope); + let res = execute(&mut ctx.ibc_store, &mut router, msg_envelope); assert!(res.is_ok()); @@ -258,7 +248,7 @@ fn ack_ordered_chan_execute(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = execute(&mut ctx, &mut router, msg_envelope); + let res = execute(&mut ctx.ibc_store, &mut router, msg_envelope); assert!(res.is_ok()); diff --git a/ibc-testkit/tests/core/ics04_channel/chan_close_confirm.rs b/ibc-testkit/tests/core/ics04_channel/chan_close_confirm.rs index 3f4e08fe9..e8e806288 100644 --- a/ibc-testkit/tests/core/ics04_channel/chan_close_confirm.rs +++ b/ibc-testkit/tests/core/ics04_channel/chan_close_confirm.rs @@ -11,19 +11,20 @@ use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::ConnectionId; use ibc::core::host::ValidationContext; use ibc::core::primitives::*; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_chan_close_confirm; use ibc_testkit::fixtures::core::connection::dummy_raw_counterparty_conn; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::clients::mock::client_state::client_type as mock_client_type; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; #[test] fn test_chan_close_confirm_validate() { let client_id = mock_client_type().build_client_id(24); let conn_id = ConnectionId::new(2); let default_context = MockContext::::default(); - let client_consensus_state_height = default_context.host_height().unwrap(); + let client_consensus_state_height = default_context.ibc_store.host_height().unwrap(); let conn_end = ConnectionEnd::new( ConnectionState::Open, @@ -61,13 +62,13 @@ fn test_chan_close_confirm_validate() { .with_connection(conn_id, conn_end) .with_channel( msg_chan_close_confirm.port_id_on_b.clone(), - msg_chan_close_confirm.chan_id_on_b.clone(), + msg_chan_close_confirm.chan_id_on_b, chan_end, ); let router = MockRouter::new_with_transfer(); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_ok(), @@ -80,7 +81,7 @@ fn test_chan_close_confirm_execute() { let client_id = mock_client_type().build_client_id(24); let conn_id = ConnectionId::new(2); let default_context = MockContext::::default(); - let client_consensus_state_height = default_context.host_height().unwrap(); + let client_consensus_state_height = default_context.ibc_store.host_height().unwrap(); let conn_end = ConnectionEnd::new( ConnectionState::Open, @@ -118,13 +119,13 @@ fn test_chan_close_confirm_execute() { .with_connection(conn_id, conn_end) .with_channel( msg_chan_close_confirm.port_id_on_b.clone(), - msg_chan_close_confirm.chan_id_on_b.clone(), + msg_chan_close_confirm.chan_id_on_b, chan_end, ); let mut router = MockRouter::new_with_transfer(); - let res = execute(&mut context, &mut router, msg_envelope); + let res = execute(&mut context.ibc_store, &mut router, msg_envelope); assert!(res.is_ok(), "Execution success: happy path"); diff --git a/ibc-testkit/tests/core/ics04_channel/chan_close_init.rs b/ibc-testkit/tests/core/ics04_channel/chan_close_init.rs index 49394f6dd..c6f102c9c 100644 --- a/ibc-testkit/tests/core/ics04_channel/chan_close_init.rs +++ b/ibc-testkit/tests/core/ics04_channel/chan_close_init.rs @@ -11,12 +11,13 @@ use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::ConnectionId; use ibc::core::host::ValidationContext; use ibc::core::primitives::*; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_chan_close_init; use ibc_testkit::fixtures::core::connection::dummy_raw_counterparty_conn; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::clients::mock::client_state::client_type as mock_client_type; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; #[test] fn test_chan_close_init_validate() { @@ -51,7 +52,7 @@ fn test_chan_close_init_validate() { let context = { let default_context = MockContext::::default(); - let client_consensus_state_height = default_context.host_height().unwrap(); + let client_consensus_state_height = default_context.ibc_store.host_height().unwrap(); default_context .with_light_client( @@ -61,14 +62,14 @@ fn test_chan_close_init_validate() { .with_connection(conn_id, conn_end) .with_channel( msg_chan_close_init.port_id_on_a.clone(), - msg_chan_close_init.chan_id_on_a.clone(), + msg_chan_close_init.chan_id_on_a, chan_end, ) }; let router = MockRouter::new_with_transfer(); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_ok(), @@ -109,7 +110,7 @@ fn test_chan_close_init_execute() { let mut context = { let default_context = MockContext::::default(); - let client_consensus_state_height = default_context.host_height().unwrap(); + let client_consensus_state_height = default_context.ibc_store.host_height().unwrap(); default_context .with_light_client( @@ -119,14 +120,14 @@ fn test_chan_close_init_execute() { .with_connection(conn_id, conn_end) .with_channel( msg_chan_close_init.port_id_on_a.clone(), - msg_chan_close_init.chan_id_on_a.clone(), + msg_chan_close_init.chan_id_on_a, chan_end, ) }; let mut router = MockRouter::new_with_transfer(); - let res = execute(&mut context, &mut router, msg_envelope); + let res = execute(&mut context.ibc_store, &mut router, msg_envelope); assert!(res.is_ok(), "Execution happy path"); diff --git a/ibc-testkit/tests/core/ics04_channel/chan_open_ack.rs b/ibc-testkit/tests/core/ics04_channel/chan_open_ack.rs index 70fa5d077..608624558 100644 --- a/ibc-testkit/tests/core/ics04_channel/chan_open_ack.rs +++ b/ibc-testkit/tests/core/ics04_channel/chan_open_ack.rs @@ -12,12 +12,13 @@ use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::{ClientId, ConnectionId}; use ibc::core::primitives::*; use ibc::core::router::types::module::ModuleId; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_chan_open_ack; use ibc_testkit::fixtures::core::connection::dummy_raw_counterparty_conn; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::clients::mock::client_state::client_type as mock_client_type; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; use rstest::*; use test_log::test; @@ -104,7 +105,7 @@ fn chan_open_ack_happy_path(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!(res.is_ok(), "Validation happy path") } @@ -135,9 +136,9 @@ fn chan_open_ack_execute_happy_path(fixture: Fixture) { chan_end_on_a, ); - let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg.clone())); + let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); - let res = execute(&mut context, &mut router, msg_envelope); + let res = execute(&mut context.ibc_store, &mut router, msg_envelope); assert!(res.is_ok(), "Execution happy path"); @@ -176,7 +177,7 @@ fn chan_open_ack_fail_no_connection(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_err(), @@ -205,7 +206,7 @@ fn chan_open_ack_fail_no_channel(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_err(), @@ -248,7 +249,7 @@ fn chan_open_ack_fail_channel_wrong_state(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_err(), diff --git a/ibc-testkit/tests/core/ics04_channel/chan_open_confirm.rs b/ibc-testkit/tests/core/ics04_channel/chan_open_confirm.rs index e65b10036..441abae22 100644 --- a/ibc-testkit/tests/core/ics04_channel/chan_open_confirm.rs +++ b/ibc-testkit/tests/core/ics04_channel/chan_open_confirm.rs @@ -11,12 +11,13 @@ use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::{ChannelId, ClientId, ConnectionId}; use ibc::core::primitives::*; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_chan_open_confirm; use ibc_testkit::fixtures::core::connection::dummy_raw_counterparty_conn; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::clients::mock::client_state::client_type as mock_client_type; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; use rstest::*; use test_log::test; @@ -97,7 +98,7 @@ fn chan_open_confirm_validate_happy_path(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!(res.is_ok(), "Validation happy path") } @@ -126,7 +127,7 @@ fn chan_open_confirm_execute_happy_path(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); - let res = execute(&mut context, &mut router, msg_envelope); + let res = execute(&mut context.ibc_store, &mut router, msg_envelope); assert!(res.is_ok(), "Execution happy path"); @@ -163,7 +164,7 @@ fn chan_open_confirm_fail_no_channel(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_err(), @@ -194,7 +195,7 @@ fn chan_open_confirm_fail_channel_wrong_state(fixture: Fixture) { .unwrap(); let context = context .with_light_client( - &client_id_on_b.clone(), + &client_id_on_b, LightClientState::::with_latest_height(Height::new(0, proof_height).unwrap()), ) .with_connection(conn_id_on_b, conn_end_on_b) @@ -202,7 +203,7 @@ fn chan_open_confirm_fail_channel_wrong_state(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_err(), diff --git a/ibc-testkit/tests/core/ics04_channel/chan_open_init.rs b/ibc-testkit/tests/core/ics04_channel/chan_open_init.rs index 0ec6b619a..67ec6c479 100644 --- a/ibc-testkit/tests/core/ics04_channel/chan_open_init.rs +++ b/ibc-testkit/tests/core/ics04_channel/chan_open_init.rs @@ -8,11 +8,12 @@ use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::ConnectionId; use ibc::core::host::ValidationContext; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_chan_open_init; use ibc_testkit::fixtures::core::connection::dummy_msg_conn_open_init; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::{DefaultIbcStore, LightClientState}; use rstest::*; use test_log::test; @@ -62,7 +63,7 @@ fn chan_open_init_validate_happy_path(fixture: Fixture) { ctx, router, msg, .. } = fixture; - let res = validate(&ctx, &router, msg); + let res = validate(&ctx.ibc_store, &router, msg); assert!(res.is_ok(), "Validation succeeds; good parameters") } @@ -75,7 +76,7 @@ fn chan_open_init_validate_counterparty_chan_id_set(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!( res.is_ok(), @@ -92,11 +93,11 @@ fn chan_open_init_execute_happy_path(fixture: Fixture) { .. } = fixture; - let res = execute(&mut ctx, &mut router, msg); + let res = execute(&mut ctx.ibc_store, &mut router, msg); assert!(res.is_ok(), "Execution succeeds; good parameters"); - assert_eq!(ctx.channel_counter().unwrap(), 1); + assert_eq!(ctx.ibc_store.channel_counter().unwrap(), 1); let ibc_events = ctx.get_events(); @@ -113,7 +114,7 @@ fn chan_open_init_execute_happy_path(fixture: Fixture) { fn chan_open_init_fail_no_connection(fixture: Fixture) { let Fixture { router, msg, .. } = fixture; - let res = validate(&MockContext::::default(), &router, msg); + let res = validate(&DefaultIbcStore::default(), &router, msg); assert!( res.is_err(), diff --git a/ibc-testkit/tests/core/ics04_channel/chan_open_try.rs b/ibc-testkit/tests/core/ics04_channel/chan_open_try.rs index c9b7c54f6..5d6034c49 100644 --- a/ibc-testkit/tests/core/ics04_channel/chan_open_try.rs +++ b/ibc-testkit/tests/core/ics04_channel/chan_open_try.rs @@ -10,12 +10,13 @@ use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::{ClientId, ConnectionId}; use ibc::core::host::ValidationContext; use ibc::core::primitives::*; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_chan_open_try; use ibc_testkit::fixtures::core::connection::dummy_raw_counterparty_conn; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::clients::mock::client_state::client_type as mock_client_type; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; use rstest::*; use test_log::test; @@ -90,7 +91,7 @@ fn chan_open_try_validate_happy_path(fixture: Fixture) { ) .with_connection(conn_id_on_b, conn_end_on_b); - let res = validate(&ctx, &router, msg); + let res = validate(&ctx.ibc_store, &router, msg); assert!(res.is_ok(), "Validation success: happy path") } @@ -115,11 +116,11 @@ fn chan_open_try_execute_happy_path(fixture: Fixture) { ) .with_connection(conn_id_on_b, conn_end_on_b); - let res = execute(&mut ctx, &mut router, msg); + let res = execute(&mut ctx.ibc_store, &mut router, msg); assert!(res.is_ok(), "Execution success: happy path"); - assert_eq!(ctx.channel_counter().unwrap(), 1); + assert_eq!(ctx.ibc_store.channel_counter().unwrap(), 1); let ibc_events = ctx.get_events(); @@ -138,7 +139,7 @@ fn chan_open_try_fail_no_connection(fixture: Fixture) { ctx, router, msg, .. } = fixture; - let res = validate(&ctx, &router, msg); + let res = validate(&ctx.ibc_store, &router, msg); assert!( res.is_err(), @@ -158,7 +159,7 @@ fn chan_open_try_fail_no_client_state(fixture: Fixture) { } = fixture; let ctx = ctx.with_connection(conn_id_on_b, conn_end_on_b); - let res = validate(&ctx, &router, msg); + let res = validate(&ctx.ibc_store, &router, msg); assert!( res.is_err(), diff --git a/ibc-testkit/tests/core/ics04_channel/recv_packet.rs b/ibc-testkit/tests/core/ics04_channel/recv_packet.rs index 84e1496d0..52c8e0f59 100644 --- a/ibc-testkit/tests/core/ics04_channel/recv_packet.rs +++ b/ibc-testkit/tests/core/ics04_channel/recv_packet.rs @@ -2,7 +2,6 @@ use ibc::core::channel::types::channel::{ChannelEnd, Counterparty, Order, State} use ibc::core::channel::types::msgs::{MsgRecvPacket, PacketMsg}; use ibc::core::channel::types::packet::Packet; use ibc::core::channel::types::Version; -use ibc::core::client::context::ClientExecutionContext; use ibc::core::client::types::Height; use ibc::core::commitment_types::commitment::CommitmentPrefix; use ibc::core::connection::types::version::Version as ConnectionVersion; @@ -13,14 +12,14 @@ use ibc::core::entrypoint::{execute, validate}; use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::{ChannelId, ClientId, ConnectionId, PortId}; -use ibc::core::host::ExecutionContext; use ibc::core::primitives::*; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::{dummy_msg_recv_packet, dummy_raw_msg_recv_packet}; use ibc_testkit::fixtures::core::signer::dummy_account_id; use ibc_testkit::hosts::MockHost; use ibc_testkit::relayer::context::RelayerContext; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; use rstest::*; use test_log::test; @@ -97,7 +96,7 @@ fn recv_packet_fail_no_channel(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_err(), @@ -115,12 +114,11 @@ fn recv_packet_validate_happy_path(fixture: Fixture) { chan_end_on_b, client_height, host_height, - client_id, .. } = fixture; let packet = &msg.packet; - let mut context = context + let context = context .with_light_client( &ClientId::new("07-tendermint", 0).expect("no error"), LightClientState::::with_latest_height(client_height), @@ -136,7 +134,7 @@ fn recv_packet_validate_happy_path(fixture: Fixture) { packet.chan_id_on_b.clone(), 1.into(), ) - .with_height(host_height) + .advance_block_up_to(host_height) // This `with_recv_sequence` is required for ordered channels .with_recv_sequence( packet.port_id_on_b.clone(), @@ -144,19 +142,9 @@ fn recv_packet_validate_happy_path(fixture: Fixture) { packet.seq_on_a, ); - context - .get_client_execution_context() - .store_update_meta( - client_id, - client_height, - Timestamp::from_nanoseconds(1000).unwrap(), - Height::new(0, 5).unwrap(), - ) - .unwrap(); - let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_ok(), @@ -205,9 +193,9 @@ fn recv_packet_timeout_expired(fixture: Fixture) { .with_connection(ConnectionId::zero(), conn_end_on_b) .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_b) .with_send_sequence(PortId::transfer(), ChannelId::zero(), 1.into()) - .with_height(host_height); + .advance_block_up_to(host_height); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_err(), @@ -236,7 +224,7 @@ fn recv_packet_execute_happy_path(fixture: Fixture) { let msg_env = MsgEnvelope::from(PacketMsg::from(msg)); - let res = execute(&mut ctx, &mut router, msg_env); + let res = execute(&mut ctx.ibc_store, &mut router, msg_env); assert!(res.is_ok()); diff --git a/ibc-testkit/tests/core/ics04_channel/send_packet.rs b/ibc-testkit/tests/core/ics04_channel/send_packet.rs index 65286a6ce..7263f5310 100644 --- a/ibc-testkit/tests/core/ics04_channel/send_packet.rs +++ b/ibc-testkit/tests/core/ics04_channel/send_packet.rs @@ -14,9 +14,10 @@ use ibc::core::connection::types::{ use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::host::types::identifiers::{ChannelId, ClientId, ConnectionId, PortId}; use ibc::core::primitives::*; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_packet; use ibc_testkit::hosts::MockHost; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; use test_log::test; #[test] @@ -43,7 +44,7 @@ fn send_packet_processing() { ConnectionState::Open, default_client_id.clone(), ConnectionCounterparty::new( - default_client_id.clone(), + default_client_id, Some(ConnectionId::zero()), CommitmentPrefix::try_from(vec![0]).expect("no error"), ), @@ -147,7 +148,7 @@ fn send_packet_processing() { .collect(); for mut test in tests { - let res = send_packet(&mut test.ctx, test.packet.clone()); + let res = send_packet(&mut test.ctx.ibc_store, test.packet.clone()); // Additionally check the events and the output objects in the result. match res { Ok(()) => { diff --git a/ibc-testkit/tests/core/ics04_channel/timeout.rs b/ibc-testkit/tests/core/ics04_channel/timeout.rs index 7d2a5d2f3..315c6300b 100644 --- a/ibc-testkit/tests/core/ics04_channel/timeout.rs +++ b/ibc-testkit/tests/core/ics04_channel/timeout.rs @@ -13,24 +13,25 @@ use ibc::core::entrypoint::{execute, validate}; use ibc::core::handler::types::events::{IbcEvent, MessageEvent}; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::{ChannelId, ClientId, ConnectionId, PortId}; -use ibc::core::host::ExecutionContext; +use ibc::core::host::types::path::ClientConsensusStatePath; use ibc::core::primitives::*; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_timeout; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; use rstest::*; struct Fixture { ctx: MockContext, pub router: MockRouter, + client_id: ClientId, client_height: Height, msg: MsgTimeout, packet_commitment: PacketCommitment, conn_end_on_a: ConnectionEnd, chan_end_on_a_ordered: ChannelEnd, chan_end_on_a_unordered: ChannelEnd, - client_id: ClientId, } #[fixture] @@ -95,13 +96,13 @@ fn fixture() -> Fixture { Fixture { ctx, router, + client_id, client_height, msg, packet_commitment, conn_end_on_a, chan_end_on_a_ordered, chan_end_on_a_unordered, - client_id, } } @@ -119,7 +120,7 @@ fn timeout_fail_no_channel(fixture: Fixture) { LightClientState::::with_latest_height(client_height), ); let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!( res.is_err(), @@ -136,12 +137,13 @@ fn timeout_fail_no_consensus_state_for_height(fixture: Fixture) { chan_end_on_a_unordered, conn_end_on_a, packet_commitment, + client_id, .. } = fixture; let packet = msg.packet.clone(); - let ctx = ctx + let mut ctx = ctx .with_channel( PortId::transfer(), ChannelId::zero(), @@ -155,9 +157,19 @@ fn timeout_fail_no_consensus_state_for_height(fixture: Fixture) { packet_commitment, ); + let consensus_state_path = ClientConsensusStatePath::new( + client_id, + msg.proof_height_on_b.revision_number(), + msg.proof_height_on_b.revision_height(), + ); + + ctx.ibc_store + .delete_consensus_state(consensus_state_path) + .expect("consensus state exists"); + let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!( res.is_err(), @@ -174,7 +186,6 @@ fn timeout_fail_proof_timeout_not_reached(fixture: Fixture) { chan_end_on_a_unordered, conn_end_on_a, client_height, - client_id, .. } = fixture; @@ -190,7 +201,7 @@ fn timeout_fail_proof_timeout_not_reached(fixture: Fixture) { let packet = msg.packet.clone(); - let mut ctx = ctx + let ctx = ctx .with_light_client( &ClientId::new("07-tendermint", 0).expect("no error"), LightClientState::::with_latest_height(client_height), @@ -208,17 +219,9 @@ fn timeout_fail_proof_timeout_not_reached(fixture: Fixture) { packet_commitment, ); - ctx.store_update_meta( - client_id, - client_height, - Timestamp::from_nanoseconds(5).unwrap(), - Height::new(0, 4).unwrap(), - ) - .unwrap(); - let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!( res.is_err(), @@ -247,7 +250,7 @@ fn timeout_success_no_packet_commitment(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!( res.is_ok(), @@ -265,13 +268,12 @@ fn timeout_unordered_channel_validate(fixture: Fixture) { conn_end_on_a, packet_commitment, client_height, - client_id, .. } = fixture; let packet = msg.packet.clone(); - let mut ctx = ctx + let ctx = ctx .with_light_client( &ClientId::new("07-tendermint", 0).expect("no error"), LightClientState::::with_latest_height(client_height), @@ -289,18 +291,9 @@ fn timeout_unordered_channel_validate(fixture: Fixture) { packet_commitment, ); - ctx.get_client_execution_context() - .store_update_meta( - client_id, - client_height, - Timestamp::from_nanoseconds(1000).unwrap(), - Height::new(0, 5).unwrap(), - ) - .unwrap(); - let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!(res.is_ok(), "Good parameters for unordered channels") } @@ -315,13 +308,12 @@ fn timeout_ordered_channel_validate(fixture: Fixture) { conn_end_on_a, packet_commitment, client_height, - client_id, .. } = fixture; let packet = msg.packet.clone(); - let mut ctx = ctx + let ctx = ctx .with_light_client( &ClientId::new("07-tendermint", 0).expect("no error"), LightClientState::::with_latest_height(client_height), @@ -335,17 +327,9 @@ fn timeout_ordered_channel_validate(fixture: Fixture) { packet_commitment, ); - ctx.store_update_meta( - client_id, - client_height, - Timestamp::from_nanoseconds(1000).unwrap(), - Height::new(0, 4).unwrap(), - ) - .unwrap(); - let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&ctx, &router, msg_envelope); + let res = validate(&ctx.ibc_store, &router, msg_envelope); assert!(res.is_ok(), "Good parameters for unordered channels") } @@ -377,7 +361,7 @@ fn timeout_unordered_chan_execute(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = execute(&mut ctx, &mut router, msg_envelope); + let res = execute(&mut ctx.ibc_store, &mut router, msg_envelope); assert!(res.is_ok()); @@ -415,7 +399,7 @@ fn timeout_ordered_chan_execute(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = execute(&mut ctx, &mut router, msg_envelope); + let res = execute(&mut ctx.ibc_store, &mut router, msg_envelope); assert!(res.is_ok()); diff --git a/ibc-testkit/tests/core/ics04_channel/timeout_on_close.rs b/ibc-testkit/tests/core/ics04_channel/timeout_on_close.rs index d9ed62a2c..62468bbbc 100644 --- a/ibc-testkit/tests/core/ics04_channel/timeout_on_close.rs +++ b/ibc-testkit/tests/core/ics04_channel/timeout_on_close.rs @@ -2,7 +2,6 @@ use ibc::core::channel::types::channel::{ChannelEnd, Counterparty, Order, State} use ibc::core::channel::types::commitment::{compute_packet_commitment, PacketCommitment}; use ibc::core::channel::types::msgs::{MsgTimeoutOnClose, PacketMsg}; use ibc::core::channel::types::Version; -use ibc::core::client::context::ClientExecutionContext; use ibc::core::client::types::Height; use ibc::core::commitment_types::commitment::CommitmentPrefix; use ibc::core::connection::types::version::Version as ConnectionVersion; @@ -12,12 +11,12 @@ use ibc::core::connection::types::{ use ibc::core::entrypoint::validate; use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::{ChannelId, ClientId, ConnectionId, PortId}; -use ibc::core::host::ExecutionContext; use ibc::core::primitives::*; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_timeout_on_close; use ibc_testkit::hosts::MockHost; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::{LightClientState, MockContext}; +use ibc_testkit::testapp::ibc::core::types::LightClientState; use rstest::*; pub struct Fixture { @@ -68,7 +67,7 @@ fn fixture() -> Fixture { ConnectionState::Open, default_client_id.clone(), ConnectionCounterparty::new( - default_client_id.clone(), + default_client_id, Some(ConnectionId::zero()), CommitmentPrefix::try_from(vec![0]).expect("no error"), ), @@ -98,7 +97,7 @@ fn timeout_on_close_fail_no_channel(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_err(), @@ -123,7 +122,7 @@ fn timeout_on_close_success_no_packet_commitment(fixture: Fixture) { let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_ok(), @@ -133,8 +132,6 @@ fn timeout_on_close_success_no_packet_commitment(fixture: Fixture) { #[rstest] fn timeout_on_close_success_happy_path(fixture: Fixture) { - let default_client_id = ClientId::new("07-tendermint", 0).expect("no error"); - let Fixture { context, router, @@ -144,7 +141,7 @@ fn timeout_on_close_success_happy_path(fixture: Fixture) { chan_end_on_a, .. } = fixture; - let mut context = context + let context = context .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a) .with_connection(ConnectionId::zero(), conn_end_on_a) .with_packet_commitment( @@ -154,19 +151,9 @@ fn timeout_on_close_success_happy_path(fixture: Fixture) { packet_commitment, ); - context - .get_client_execution_context() - .store_update_meta( - default_client_id, - Height::new(0, 2).unwrap(), - Timestamp::from_nanoseconds(5000).unwrap(), - Height::new(0, 5).unwrap(), - ) - .unwrap(); - let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); - let res = validate(&context, &router, msg_envelope); + let res = validate(&context.ibc_store, &router, msg_envelope); assert!( res.is_ok(), diff --git a/ibc-testkit/tests/core/router.rs b/ibc-testkit/tests/core/router.rs index 95991a434..20344b6c5 100644 --- a/ibc-testkit/tests/core/router.rs +++ b/ibc-testkit/tests/core/router.rs @@ -1,4 +1,4 @@ -use std::ops::Add; +use core::ops::Add; use ibc::apps::transfer::handler::send_transfer; use ibc::apps::transfer::types::error::TokenTransferError; @@ -22,6 +22,7 @@ use ibc::core::host::types::path::CommitmentPath; use ibc::core::host::ValidationContext; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Timestamp; +use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::applications::transfer::{ extract_transfer_packet, MsgTransferConfig, PacketDataConfig, }; @@ -43,7 +44,6 @@ use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientState; use ibc_testkit::testapp::ibc::clients::mock::consensus_state::MockConsensusState; use ibc_testkit::testapp::ibc::clients::mock::header::MockHeader; use ibc_testkit::testapp::ibc::core::router::MockRouter; -use ibc_testkit::testapp::ibc::core::types::MockContext; use test_log::test; #[test] @@ -169,7 +169,7 @@ fn routing_module_and_keepers() { .build(); let msg_transfer_no_timeout_or_timestamp = MsgTransferConfig::builder() - .packet_data(packet_data.clone()) + .packet_data(packet_data) .timeout_timestamp_on_b(Timestamp::from_nanoseconds(0).unwrap()) .build(); @@ -193,7 +193,7 @@ fn routing_module_and_keepers() { // First, create a client.. let res = dispatch( - &mut ctx, + &mut ctx.ibc_store, &mut router, MsgEnvelope::Client(ClientMsg::CreateClient(create_client_msg.clone())), ); @@ -330,12 +330,13 @@ fn routing_module_and_keepers() { msg: MsgEnvelope::Packet(PacketMsg::Ack(msg_ack_packet.clone())).into(), want_pass: true, state_check: Some(Box::new(move |ctx| { - ctx.get_packet_commitment(&CommitmentPath::new( - &msg_ack_packet.packet.port_id_on_a, - &msg_ack_packet.packet.chan_id_on_a, - msg_ack_packet.packet.seq_on_a, - )) - .is_err() + ctx.ibc_store + .get_packet_commitment(&CommitmentPath::new( + &msg_ack_packet.packet.port_id_on_a, + &msg_ack_packet.packet.chan_id_on_a, + msg_ack_packet.packet.seq_on_a, + )) + .is_err() })), }, Test { @@ -416,8 +417,8 @@ fn routing_module_and_keepers() { for test in tests { let res = match test.msg.clone() { - TestMsg::Ics26(msg) => dispatch(&mut ctx, &mut router, msg).map(|_| ()), - TestMsg::Ics20(msg) => send_transfer(&mut ctx, &mut DummyTransferModule, msg) + TestMsg::Ics26(msg) => dispatch(&mut ctx.ibc_store, &mut router, msg), + TestMsg::Ics20(msg) => send_transfer(&mut ctx.ibc_store, &mut DummyTransferModule, msg) .map_err(|e: TokenTransferError| ChannelError::AppModule { description: e.to_string(), })