Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

imp(ibc-testkit): Tendermint proof verifications via integration test #1146

Merged
merged 55 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
012403e
test tmclient proof verification
rnbguy Mar 20, 2024
dd010fe
use ClientStateConfig directly
rnbguy Mar 20, 2024
f3dd05e
rm MockClientConfig
rnbguy Mar 20, 2024
e19c085
use basecoin store proofspec as default
rnbguy Mar 20, 2024
14201ee
update tests
rnbguy Mar 20, 2024
8a15b70
use merkle storage in MockContext
rnbguy Mar 20, 2024
edbc25c
fix ProofSpecs size
rnbguy Mar 20, 2024
2ef512c
refactor MockIbcStore to perform begin_block and end_block
rnbguy Mar 20, 2024
50c304f
simpler proof verification test
rnbguy Mar 20, 2024
50d4ac7
use ValidationContext::commitment_prefix()
rnbguy Mar 20, 2024
d6e9dbf
nits
rnbguy Mar 20, 2024
230e79a
refactor host related trait method
rnbguy Mar 21, 2024
ef369be
tendermint host client integration test with proof verification
rnbguy Mar 21, 2024
60b8271
rm raw test
rnbguy Mar 21, 2024
8a9cab4
use typed relayer
rnbguy Mar 21, 2024
1883016
add todo for channel integration test
rnbguy Mar 21, 2024
3735db1
core over std
rnbguy Mar 21, 2024
3b88e29
be semantically correct
rnbguy Mar 21, 2024
2f638b9
add comment for TypedRelayer
rnbguy Mar 21, 2024
27695c9
integration test for all pairs
rnbguy Mar 21, 2024
e370bcf
fix semantic bug
rnbguy Mar 21, 2024
135188a
renames
rnbguy Mar 21, 2024
5739e23
add channel management
rnbguy Mar 25, 2024
ccd4063
channel creation in RelayerContext
rnbguy Mar 25, 2024
b74263a
add channel creation in integration test
rnbguy Mar 25, 2024
aa99304
add test for channel close
rnbguy Mar 25, 2024
1869094
query client_id from connection and channel
rnbguy Mar 25, 2024
c67cf62
ibc_store_mut
rnbguy Mar 26, 2024
2b9ea76
utils functions for packet relay
rnbguy Mar 26, 2024
acbb3bd
add packet relay integration test
rnbguy Mar 26, 2024
555a4b5
add comments
rnbguy Mar 26, 2024
6f4d13b
optimize integration utils functions
rnbguy Mar 26, 2024
a8b7a98
serde feature for integration tests
rnbguy Mar 26, 2024
393462d
rm redundant chain_id
rnbguy Mar 29, 2024
98a4b7f
sync clock only on a
rnbguy Mar 29, 2024
fd8e08b
add comment
rnbguy Mar 29, 2024
3e3c9ac
imp: place router under MockGenericContext
Farhad-Shabani Mar 29, 2024
d2e4ba5
nit: add docstring for router
Farhad-Shabani Mar 29, 2024
ef23ac1
nits
rnbguy Mar 29, 2024
3538f26
rm redundant lint filters
rnbguy Mar 29, 2024
e645b70
imp: ditch RelayerContext
Farhad-Shabani Mar 29, 2024
6f3d328
nit: simplify build_client_update_datagram
Farhad-Shabani Mar 29, 2024
8150c80
refactor integration tests
rnbguy Apr 3, 2024
5a047f5
add doc strings for TypedRelayerOps
rnbguy Apr 3, 2024
5c1229a
doc strings for RelayerContext
rnbguy Apr 3, 2024
72a0353
Merge branch 'feat/refactor-testkit' into rano/testkit/integration-test
rnbguy Apr 3, 2024
66ad234
mv client_update_ping_pong to tests dir
rnbguy Apr 4, 2024
def992d
rename main_store to multi_store
rnbguy Apr 4, 2024
53a8db2
update TestHost trait
rnbguy Apr 4, 2024
e711fce
update mock and tendermint hosts
rnbguy Apr 4, 2024
a19c925
update relayer functions
rnbguy Apr 4, 2024
cfdf142
nits
rnbguy Apr 4, 2024
320805e
renames and comments
rnbguy Apr 4, 2024
6693800
add comments for return values in relayer ops
rnbguy Apr 4, 2024
410b8ad
imp: simplify into_header
Farhad-Shabani Apr 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 87 additions & 52 deletions ibc-testkit/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
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::context::{ClientExecutionContext, ClientValidationContext};
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;
Expand All @@ -20,16 +18,15 @@ use ibc::core::host::types::path::{
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::router::MockRouter;
use crate::testapp::ibc::core::types::DEFAULT_BLOCK_TIME_SECS;

/// A context implementing the dependencies necessary for testing any IBC module.
Expand All @@ -40,34 +37,23 @@ where
H: TestHost,
HostClientState<H>: ClientStateValidation<MockIbcStore<S>>,
{
/// The multi store of the context.
/// This is where the IBC store root is stored at IBC commitment prefix.
pub multi_store: S,

/// The type of host chain underlying this mock context.
pub host: H,

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

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

pub type MockStore = RevertibleStore<GrowingStore<InMemoryStore>>;
pub type MockContext<H> = MockGenericContext<MockStore, 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,
#[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.
Expand All @@ -94,6 +80,10 @@ where
&self.ibc_store
}

pub fn ibc_store_mut(&mut self) -> &mut MockIbcStore<S> {
&mut self.ibc_store
}

pub fn host_block(&self, target_height: &Height) -> Option<H::Block> {
self.host.get_block(target_height)
}
Expand All @@ -102,6 +92,13 @@ where
self.host.get_block(&self.latest_height())
}

pub fn light_client_latest_height(&self, client_id: &ClientId) -> Height {
self.ibc_store
.client_state(client_id)
.expect("client state exists")
.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() {
Expand All @@ -118,38 +115,79 @@ where
}

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");
self.end_block();

// generate and push genesis block
let genesis_block = self.host.generate_block(app_hash, 1, genesis_time, params);
self.host.push_block(genesis_block);
// commit multi store
let multi_store_commitment = self.multi_store.commit().expect("no error");

// store it in ibc context as host consensus state
self.ibc_store.store_host_consensus_state(
// generate a genesis block
let genesis_block =
self.host
.latest_block()
.into_header()
.into_consensus_state()
.into(),
.generate_block(multi_store_commitment, 1, genesis_time, params);

// push the genesis block to the host
self.host.push_block(genesis_block);

self.begin_block();
}

pub fn begin_block(&mut self) {
let consensus_state = self
.host
.latest_block()
.into_header()
.into_consensus_state()
.into();

let ibc_commitment_proof = self
.multi_store
.get_proof(
self.host.latest_height().revision_height().into(),
&self
.ibc_store
.commitment_prefix()
.as_bytes()
.try_into()
.expect("valid utf8 prefix"),
)
.expect("no error");

self.ibc_store.begin_block(
self.host.latest_height().revision_height(),
consensus_state,
ibc_commitment_proof,
);
}

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");
pub fn end_block(&mut self) {
// commit ibc store
let ibc_store_commitment = self.ibc_store.end_block().expect("no error");

// commit ibc store commitment in multi store
self.multi_store
.set(
self.ibc_store
.commitment_prefix()
.as_bytes()
.try_into()
.expect("valid utf8 prefix"),
ibc_store_commitment,
)
.expect("no error");
}

pub fn produce_block(&mut self, block_time: Duration, params: &H::BlockParams) {
// commit the multi store
let multi_store_commitment = self.multi_store.commit().expect("no error");
// generate a new block
self.host.advance_block(app_hash, block_time, params);
self.host
.advance_block(multi_store_commitment, 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_with_block_params(&mut self, block_time: Duration, params: &H::BlockParams) {
self.end_block();
self.produce_block(block_time, params);
self.begin_block();
}

pub fn advance_block(&mut self) {
Expand Down Expand Up @@ -355,12 +393,9 @@ where
/// 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)?;
pub fn deliver(&mut self, msg: MsgEnvelope) -> Result<(), RelayerError> {
dispatch(&mut self.ibc_store, &mut self.ibc_router, msg)
.map_err(RelayerError::TransactionFailed)?;
// Create a new block.
self.advance_block();
Ok(())
Expand Down
51 changes: 29 additions & 22 deletions ibc-testkit/src/fixtures/clients/tendermint.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::str::FromStr;
use core::time::Duration;

use basecoin_store::avl::get_proof_spec as basecoin_proof_spec;
use ibc::clients::tendermint::client_state::ClientState as TmClientState;
use ibc::clients::tendermint::types::error::{Error as ClientError, Error};
use ibc::clients::tendermint::types::proto::v1::{ClientState as RawTmClientState, Fraction};
Expand All @@ -15,6 +16,7 @@ use ibc::core::commitment_types::specs::ProofSpecs;
use ibc::core::host::types::identifiers::ChainId;
use ibc::core::primitives::prelude::*;
use tendermint::block::Header as TmHeader;
use typed_builder::TypedBuilder;

/// Returns a dummy tendermint `ClientState` by given `frozen_height`, for testing purposes only!
pub fn dummy_tm_client_state_from_raw(frozen_height: RawHeight) -> Result<TmClientState, Error> {
Expand Down Expand Up @@ -64,43 +66,48 @@ pub fn dummy_raw_tm_client_state(frozen_height: RawHeight) -> RawTmClientState {
}
}

#[derive(typed_builder::TypedBuilder, Debug)]
#[derive(TypedBuilder, Debug)]
pub struct ClientStateConfig {
pub chain_id: ChainId,
#[builder(default = TrustThreshold::ONE_THIRD)]
pub trust_level: TrustThreshold,
#[builder(default = Duration::from_secs(64000))]
pub trusting_period: Duration,
#[builder(default = Duration::from_secs(128_000))]
pub unbonding_period: Duration,
#[builder(default = Duration::from_millis(3000))]
max_clock_drift: Duration,
pub latest_height: Height,
#[builder(default = ProofSpecs::cosmos())]
pub max_clock_drift: Duration,
#[builder(default = vec![basecoin_proof_spec(); 2].into())]
pub proof_specs: ProofSpecs,
#[builder(default)]
pub upgrade_path: Vec<String>,
#[builder(default = AllowUpdate { after_expiry: false, after_misbehaviour: false })]
allow_update: AllowUpdate,
}

impl TryFrom<ClientStateConfig> for TmClientState {
type Error = ClientError;

fn try_from(config: ClientStateConfig) -> Result<Self, Self::Error> {
let client_state = ClientStateType::new(
config.chain_id,
config.trust_level,
config.trusting_period,
config.unbonding_period,
config.max_clock_drift,
config.latest_height,
config.proof_specs,
config.upgrade_path,
config.allow_update,
)?;

Ok(client_state.into())
impl Default for ClientStateConfig {
fn default() -> Self {
Self::builder().build()
}
}

impl ClientStateConfig {
pub fn into_client_state(
self,
chain_id: ChainId,
latest_height: Height,
) -> Result<TmClientState, ClientError> {
Ok(ClientStateType::new(
chain_id,
self.trust_level,
self.trusting_period,
self.unbonding_period,
self.max_clock_drift,
latest_height,
self.proof_specs,
self.upgrade_path,
self.allow_update,
)?
.into())
}
}

Expand Down
7 changes: 5 additions & 2 deletions ibc-testkit/src/fixtures/core/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use typed_builder::TypedBuilder;

use crate::context::MockGenericContext;
use crate::hosts::{HostClientState, TestBlock, TestHost};
use crate::testapp::ibc::core::router::MockRouter;
use crate::testapp::ibc::core::types::{MockIbcStore, DEFAULT_BLOCK_TIME_SECS};
use crate::utils::year_2023;

Expand All @@ -21,7 +22,7 @@ where
H: TestHost,
{
#[builder(default)]
pub host: H,
host: H,

#[builder(default = Duration::from_secs(DEFAULT_BLOCK_TIME_SECS))]
block_time: Duration,
Expand Down Expand Up @@ -56,11 +57,13 @@ where
.expect("no underflow");

let mut context = Self {
multi_store: Default::default(),
host: params.host,
ibc_store: MockIbcStore::new(
params.latest_height.revision_number(),
Default::default(),
),
host: params.host,
ibc_router: MockRouter::new_with_transfer(),
};

// store is a height 0; no block
Expand Down
4 changes: 4 additions & 0 deletions ibc-testkit/src/hosts/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ impl TestBlock for MockHeader {
fn timestamp(&self) -> Timestamp {
self.timestamp
}

fn into_header_with_trusted(self, _: &Self) -> Self::Header {
self
}
}

impl From<MockHeader> for MockConsensusState {
Expand Down
10 changes: 7 additions & 3 deletions ibc-testkit/src/hosts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,17 +124,21 @@ pub trait TestHost: Default + Debug + Sized {
/// TestBlock is a trait that defines the interface for a block produced by a host blockchain.
pub trait TestBlock: Clone + Debug {
/// The type of header can be extracted from the block.
type Header: TestHeader + From<Self>;
type Header: TestHeader;

/// The height of the block.
fn height(&self) -> Height;

/// The timestamp of the block.
fn timestamp(&self) -> Timestamp;

/// Extract the header from the block.
/// Extract the IBC header using the target and trusted blocks.
fn into_header_with_trusted(self, trusted_block: &Self) -> Self::Header;

/// Extract the IBC header only using the target block (sets the trusted
/// block to itself).
fn into_header(self) -> Self::Header {
self.into()
self.clone().into_header_with_trusted(&self)
}
}

Expand Down
Loading
Loading