Skip to content

Commit

Permalink
Allow ChainEndpoint implementations to fetch any types of clients a…
Browse files Browse the repository at this point in the history
…nd consensus states (#1625)
  • Loading branch information
romac authored Jan 20, 2022
1 parent 268c372 commit ba43f88
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Allow `ChainEndpoint` implementations to fetch any types of clients
and consensus states ([#1481](https://github.com/informalsystems/ibc-
rs/issues/1481))
41 changes: 29 additions & 12 deletions modules/src/clients/ics07_tendermint/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,18 +139,6 @@ impl ClientState {
})
}

/// Helper function to verify the upgrade client procedure.
/// Resets all fields except the blockchain-specific ones.
pub fn zero_custom_fields(mut client_state: Self) -> Self {
client_state.trusting_period = ZERO_DURATION;
client_state.trust_level = TrustThreshold::ZERO;
client_state.allow_update.after_expiry = false;
client_state.allow_update.after_misbehaviour = false;
client_state.frozen_height = None;
client_state.max_clock_drift = ZERO_DURATION;
client_state
}

/// Get the refresh time to ensure the state does not expire
pub fn refresh_time(&self) -> Option<Duration> {
Some(2 * self.trusting_period / 3)
Expand Down Expand Up @@ -217,7 +205,14 @@ impl ClientState {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct UpgradeOptions {
pub unbonding_period: Duration,
}

impl crate::core::ics02_client::client_state::ClientState for ClientState {
type UpgradeOptions = UpgradeOptions;

fn chain_id(&self) -> ChainId {
self.chain_id.clone()
}
Expand All @@ -234,6 +229,28 @@ impl crate::core::ics02_client::client_state::ClientState for ClientState {
self.frozen_height
}

fn upgrade(
mut self,
upgrade_height: Height,
upgrade_options: UpgradeOptions,
chain_id: ChainId,
) -> Self {
// Reset custom fields to zero values
self.trusting_period = ZERO_DURATION;
self.trust_level = TrustThreshold::ZERO;
self.allow_update.after_expiry = false;
self.allow_update.after_misbehaviour = false;
self.frozen_height = None;
self.max_clock_drift = ZERO_DURATION;

// Upgrade the client state
self.latest_height = upgrade_height;
self.unbonding_period = upgrade_options.unbonding_period;
self.chain_id = chain_id;

self
}

fn wrap_any(self) -> AnyClientState {
AnyClientState::Tendermint(self)
}
Expand Down
4 changes: 0 additions & 4 deletions modules/src/clients/ics07_tendermint/consensus_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ impl crate::core::ics02_client::client_consensus::ConsensusState for ConsensusSt
&self.root
}

fn validate_basic(&self) -> Result<(), Infallible> {
unimplemented!()
}

fn wrap_any(self) -> AnyConsensusState {
AnyConsensusState::Tendermint(self)
}
Expand Down
12 changes: 0 additions & 12 deletions modules/src/core/ics02_client/client_consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ pub trait ConsensusState: Clone + core::fmt::Debug + Send + Sync {
/// Commitment root of the consensus state, which is used for key-value pair verification.
fn root(&self) -> &CommitmentRoot;

/// Performs basic validation of the consensus state
fn validate_basic(&self) -> Result<(), Self::Error>;

/// Wrap into an `AnyConsensusState`
fn wrap_any(self) -> AnyConsensusState;
}
Expand Down Expand Up @@ -165,15 +162,6 @@ impl ConsensusState for AnyConsensusState {
}
}

fn validate_basic(&self) -> Result<(), Infallible> {
match self {
Self::Tendermint(cs_state) => cs_state.validate_basic(),

#[cfg(any(test, feature = "mocks"))]
Self::Mock(mock_state) => mock_state.validate_basic(),
}
}

fn wrap_any(self) -> AnyConsensusState {
self
}
Expand Down
55 changes: 55 additions & 0 deletions modules/src/core/ics02_client/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ pub const TENDERMINT_CLIENT_STATE_TYPE_URL: &str = "/ibc.lightclients.tendermint
pub const MOCK_CLIENT_STATE_TYPE_URL: &str = "/ibc.mock.ClientState";

pub trait ClientState: Clone + core::fmt::Debug + Send + Sync {
/// Client-specific options for upgrading the client
type UpgradeOptions;

/// Return the chain identifier which this client is serving (i.e., the client is verifying
/// consensus states from this chain).
fn chain_id(&self) -> ChainId;
Expand All @@ -40,10 +43,42 @@ pub trait ClientState: Clone + core::fmt::Debug + Send + Sync {
/// Frozen height of the client
fn frozen_height(&self) -> Option<Height>;

/// Helper function to verify the upgrade client procedure.
/// Resets all fields except the blockchain-specific ones,
/// and updates the given fields.
fn upgrade(
self,
upgrade_height: Height,
upgrade_options: Self::UpgradeOptions,
chain_id: ChainId,
) -> Self;

/// Wrap into an `AnyClientState`
fn wrap_any(self) -> AnyClientState;
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AnyUpgradeOptions {
Tendermint(client_state::UpgradeOptions),

#[cfg(any(test, feature = "mocks"))]
Mock(()),
}

impl AnyUpgradeOptions {
fn into_tendermint(self) -> client_state::UpgradeOptions {
match self {
Self::Tendermint(options) => options,

#[cfg(any(test, feature = "mocks"))]
Self::Mock(_) => {
panic!("cannot downcast AnyUpgradeOptions::Mock to Tendermint::UpgradeOptions")
}
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AnyClientState {
Expand Down Expand Up @@ -163,6 +198,8 @@ impl From<AnyClientState> for Any {
}

impl ClientState for AnyClientState {
type UpgradeOptions = AnyUpgradeOptions;

fn chain_id(&self) -> ChainId {
match self {
AnyClientState::Tendermint(tm_state) => tm_state.chain_id(),
Expand All @@ -184,6 +221,24 @@ impl ClientState for AnyClientState {
self.frozen_height()
}

fn upgrade(
self,
upgrade_height: Height,
upgrade_options: Self::UpgradeOptions,
chain_id: ChainId,
) -> Self {
match self {
AnyClientState::Tendermint(tm_state) => tm_state
.upgrade(upgrade_height, upgrade_options.into_tendermint(), chain_id)
.wrap_any(),

#[cfg(any(test, feature = "mocks"))]
AnyClientState::Mock(mock_state) => {
mock_state.upgrade(upgrade_height, (), chain_id).wrap_any()
}
}
}

fn wrap_any(self) -> AnyClientState {
self
}
Expand Down
10 changes: 6 additions & 4 deletions modules/src/mock/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ impl From<MockClientState> for RawMockClientState {
}

impl ClientState for MockClientState {
type UpgradeOptions = ();

fn chain_id(&self) -> ChainId {
todo!()
}
Expand All @@ -108,6 +110,10 @@ impl ClientState for MockClientState {
self.frozen_height
}

fn upgrade(self, _upgrade_height: Height, _upgrade_options: (), _chain_id: ChainId) -> Self {
todo!()
}

fn wrap_any(self) -> AnyClientState {
AnyClientState::Mock(self)
}
Expand Down Expand Up @@ -181,10 +187,6 @@ impl ConsensusState for MockConsensusState {
&self.root
}

fn validate_basic(&self) -> Result<(), Infallible> {
Ok(())
}

fn wrap_any(self) -> AnyConsensusState {
AnyConsensusState::Mock(self)
}
Expand Down
12 changes: 6 additions & 6 deletions relayer/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ pub trait ChainEndpoint: Sized {
&self,
client_id: &ClientId,
height: ICSHeight,
) -> Result<Self::ClientState, Error>;
) -> Result<AnyClientState, Error>;

fn query_consensus_states(
&self,
Expand All @@ -188,12 +188,12 @@ pub trait ChainEndpoint: Sized {
fn query_upgraded_client_state(
&self,
height: ICSHeight,
) -> Result<(Self::ClientState, MerkleProof), Error>;
) -> Result<(AnyClientState, MerkleProof), Error>;

fn query_upgraded_consensus_state(
&self,
height: ICSHeight,
) -> Result<(Self::ConsensusState, MerkleProof), Error>;
) -> Result<(AnyConsensusState, MerkleProof), Error>;

/// Performs a query to retrieve the identifiers of all connections.
fn query_connections(
Expand Down Expand Up @@ -276,7 +276,7 @@ pub trait ChainEndpoint: Sized {
&self,
client_id: &ClientId,
height: ICSHeight,
) -> Result<(Self::ClientState, MerkleProof), Error>;
) -> Result<(AnyClientState, MerkleProof), Error>;

fn proven_connection(
&self,
Expand All @@ -289,7 +289,7 @@ pub trait ChainEndpoint: Sized {
client_id: &ClientId,
consensus_height: ICSHeight,
height: ICSHeight,
) -> Result<(Self::ConsensusState, MerkleProof), Error>;
) -> Result<(AnyConsensusState, MerkleProof), Error>;

fn proven_channel(
&self,
Expand Down Expand Up @@ -339,7 +339,7 @@ pub trait ChainEndpoint: Sized {
connection_id: &ConnectionId,
client_id: &ClientId,
height: ICSHeight,
) -> Result<(Option<Self::ClientState>, Proofs), Error> {
) -> Result<(Option<AnyClientState>, Proofs), Error> {
let (connection_end, connection_proof) = self.proven_connection(connection_id, height)?;

// Check that the connection state is compatible with the message
Expand Down
Loading

0 comments on commit ba43f88

Please sign in to comment.