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

Deterministic host timestamp #1771

Merged
merged 14 commits into from
Feb 8, 2022
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- IBC handlers now retrieve the host timestamp from the latest host consensus
state ([#1770](https://github.com/informalsystems/ibc-rs/issues/1770))
11 changes: 6 additions & 5 deletions modules/src/clients/ics07_tendermint/client_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use core::convert::TryInto;

use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof;
use prost::Message;
use tendermint::Time;
use tendermint_light_client_verifier::types::{TrustedBlockState, UntrustedBlockState};
use tendermint_light_client_verifier::{ProdVerifier, Verdict, Verifier};
use tendermint_proto::Protobuf;
Expand Down Expand Up @@ -50,7 +49,6 @@ impl ClientDef for TendermintClient {

fn check_header_and_update_state(
&self,
now: Time,
ctx: &dyn ClientReader,
client_id: ClientId,
client_state: Self::ClientState,
Expand Down Expand Up @@ -113,9 +111,12 @@ impl ClientDef for TendermintClient {

let options = client_state.as_light_client_options()?;

let verdict = self
.verifier
.verify(untrusted_state, trusted_state, &options, now);
let verdict = self.verifier.verify(
untrusted_state,
trusted_state,
&options,
ctx.host_timestamp().into_tm_time().unwrap(),
);

match verdict {
Verdict::Success => {}
Expand Down
21 changes: 4 additions & 17 deletions modules/src/core/ics02_client/client_def.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use ibc_proto::ibc::core::commitment::v1::MerkleProof;
use tendermint::Time;

use crate::clients::ics07_tendermint::client_def::TendermintClient;
use crate::core::ics02_client::client_consensus::{AnyConsensusState, ConsensusState};
Expand Down Expand Up @@ -30,7 +29,6 @@ pub trait ClientDef: Clone {

fn check_header_and_update_state(
&self,
now: Time,
ctx: &dyn ClientReader,
client_id: ClientId,
client_state: Self::ClientState,
Expand Down Expand Up @@ -197,7 +195,6 @@ impl ClientDef for AnyClient {
/// Validates an incoming `header` against the latest consensus state of this client.
fn check_header_and_update_state(
&self,
now: Time,
ctx: &dyn ClientReader,
client_id: ClientId,
client_state: AnyClientState,
Expand All @@ -211,13 +208,8 @@ impl ClientDef for AnyClient {
)
.ok_or_else(|| Error::client_args_type_mismatch(ClientType::Tendermint))?;

let (new_state, new_consensus) = client.check_header_and_update_state(
now,
ctx,
client_id,
client_state,
header,
)?;
let (new_state, new_consensus) =
client.check_header_and_update_state(ctx, client_id, client_state, header)?;

Ok((
AnyClientState::Tendermint(new_state),
Expand All @@ -233,13 +225,8 @@ impl ClientDef for AnyClient {
)
.ok_or_else(|| Error::client_args_type_mismatch(ClientType::Mock))?;

let (new_state, new_consensus) = client.check_header_and_update_state(
now,
ctx,
client_id,
client_state,
header,
)?;
let (new_state, new_consensus) =
client.check_header_and_update_state(ctx, client_id, client_state, header)?;

Ok((
AnyClientState::Mock(new_state),
Expand Down
59 changes: 50 additions & 9 deletions modules/src/core/ics02_client/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::core::ics02_client::client_type::ClientType;
use crate::core::ics02_client::error::{Error, ErrorDetail};
use crate::core::ics02_client::handler::ClientResult::{self, Create, Update, Upgrade};
use crate::core::ics24_host::identifier::ClientId;
use crate::timestamp::Timestamp;
use crate::Height;

/// Defines the read-only part of ICS2 (client functions) context.
Expand Down Expand Up @@ -58,6 +59,20 @@ pub trait ClientReader {
/// Returns the current height of the local chain.
fn host_height(&self) -> Height;

/// Returns the current timestamp of the local chain.
fn host_timestamp(&self) -> Timestamp {
let pending_consensus_state = self
.pending_host_consensus_state()
.expect("host must have pending consensus state");
pending_consensus_state.timestamp()
}

/// Returns the `ConsensusState` of the host (local) chain at a specific height.
fn host_consensus_state(&self, height: Height) -> Result<AnyConsensusState, Error>;

/// Returns the pending `ConsensusState` of the host (local) chain.
fn pending_host_consensus_state(&self) -> Result<AnyConsensusState, Error>;

/// Returns a natural number, counting how many clients have been created thus far.
/// The value of this counter should increase only via method `ClientKeeper::increase_client_counter`.
fn client_counter(&self) -> Result<u64, Error>;
Expand All @@ -78,8 +93,16 @@ pub trait ClientKeeper {
res.consensus_state,
)?;
self.increase_client_counter();
self.store_update_time(res.client_id.clone(), res.client_state.latest_height())?;
self.store_update_height(res.client_id, res.client_state.latest_height())?;
self.store_update_time(
res.client_id.clone(),
res.client_state.latest_height(),
res.processed_time,
)?;
self.store_update_height(
res.client_id,
res.client_state.latest_height(),
res.processed_height,
)?;
Ok(())
}
Update(res) => {
Expand All @@ -89,8 +112,16 @@ pub trait ClientKeeper {
res.client_state.latest_height(),
res.consensus_state,
)?;
self.store_update_time(res.client_id.clone(), res.client_state.latest_height())?;
self.store_update_height(res.client_id, res.client_state.latest_height())?;
self.store_update_time(
res.client_id.clone(),
res.client_state.latest_height(),
res.processed_time,
)?;
self.store_update_height(
res.client_id,
res.client_state.latest_height(),
res.processed_height,
)?;
Ok(())
}
Upgrade(res) => {
Expand Down Expand Up @@ -133,12 +164,22 @@ pub trait ClientKeeper {
fn increase_client_counter(&mut self);

/// Called upon successful client update.
/// Implementations are expected to use this to record the current (host) time as the time at
/// which this update (or header) was processed.
fn store_update_time(&mut self, client_id: ClientId, height: Height) -> Result<(), Error>;
/// Implementations are expected to use this to record the specified time as the time at which
/// this update (or header) was processed.
fn store_update_time(
&mut self,
client_id: ClientId,
height: Height,
timestamp: Timestamp,
) -> Result<(), Error>;

/// Called upon successful client update.
/// Implementations are expected to use this to record the current (host) height as the height
/// Implementations are expected to use this to record the specified height as the height at
/// at which this update (or header) was processed.
fn store_update_height(&mut self, client_id: ClientId, height: Height) -> Result<(), Error>;
fn store_update_height(
&mut self,
client_id: ClientId,
height: Height,
host_height: Height,
) -> Result<(), Error>;
}
4 changes: 4 additions & 0 deletions modules/src/core/ics02_client/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ define_error! {
[ Ics07Error ]
| _ | { format_args!("Tendermint-specific handler error") },

MissingLocalConsensusState
{ height: Height }
| e | { format_args!("the local consensus state could not be retrieved for height {}", e.height) },

}
}

Expand Down
12 changes: 3 additions & 9 deletions modules/src/core/ics02_client/handler.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! This module implements the processing logic for ICS2 (client abstractions and functions) msgs.

use tendermint::Time;

use crate::core::ics02_client::context::ClientReader;
use crate::core::ics02_client::error::Error;
use crate::core::ics02_client::msgs::ClientMsg;
Expand All @@ -19,17 +17,13 @@ pub enum ClientResult {
}

/// General entry point for processing any message related to ICS2 (client functions) protocols.
pub fn dispatch<Ctx>(
now: Time,
ctx: &Ctx,
msg: ClientMsg,
) -> Result<HandlerOutput<ClientResult>, Error>
pub fn dispatch<Ctx>(ctx: &Ctx, msg: ClientMsg) -> Result<HandlerOutput<ClientResult>, Error>
where
Ctx: ClientReader,
{
match msg {
ClientMsg::CreateClient(msg) => create_client::process(now, ctx, msg),
ClientMsg::UpdateClient(msg) => update_client::process(now, ctx, msg),
ClientMsg::CreateClient(msg) => create_client::process(ctx, msg),
ClientMsg::UpdateClient(msg) => update_client::process(ctx, msg),
ClientMsg::UpgradeClient(msg) => upgrade_client::process(ctx, msg),
_ => {
unimplemented!()
Expand Down
13 changes: 5 additions & 8 deletions modules/src/core/ics02_client/handler/create_client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! Protocol logic specific to processing ICS2 messages of type `MsgCreateAnyClient`.

use tendermint::Time;

use crate::prelude::*;

use crate::core::ics02_client::client_consensus::AnyConsensusState;
Expand All @@ -17,6 +15,7 @@ use crate::core::ics24_host::identifier::ClientId;
use crate::events::IbcEvent;
use crate::handler::{HandlerOutput, HandlerResult};
use crate::timestamp::Timestamp;

/// The result following the successful processing of a `MsgCreateAnyClient` message. Preferably
/// this data type should be used with a qualified name `create_client::Result` to avoid ambiguity.
#[derive(Clone, Debug, PartialEq, Eq)]
Expand All @@ -30,7 +29,6 @@ pub struct Result {
}

pub fn process(
now: Time,
ctx: &dyn ClientReader,
msg: MsgCreateAnyClient,
) -> HandlerResult<ClientResult, Error> {
Expand All @@ -52,7 +50,7 @@ pub fn process(
client_type: msg.client_state().client_type(),
client_state: msg.client_state(),
consensus_state: msg.consensus_state(),
processed_time: now.into(),
processed_time: ctx.host_timestamp(),
processed_height: ctx.host_height(),
});

Expand All @@ -70,7 +68,6 @@ mod tests {
use crate::prelude::*;

use core::time::Duration;
use tendermint::Time;
use test_log::test;

use crate::clients::ics07_tendermint::client_state::{
Expand Down Expand Up @@ -107,7 +104,7 @@ mod tests {
)
.unwrap();

let output = dispatch(Time::now(), &ctx, ClientMsg::CreateClient(msg.clone()));
let output = dispatch(&ctx, ClientMsg::CreateClient(msg.clone()));

match output {
Ok(HandlerOutput {
Expand Down Expand Up @@ -198,7 +195,7 @@ mod tests {
let expected_client_id = ClientId::new(ClientType::Mock, 0).unwrap();

for msg in create_client_msgs {
let output = dispatch(Time::now(), &ctx, ClientMsg::CreateClient(msg.clone()));
let output = dispatch(&ctx, ClientMsg::CreateClient(msg.clone()));

match output {
Ok(HandlerOutput {
Expand Down Expand Up @@ -260,7 +257,7 @@ mod tests {
)
.unwrap();

let output = dispatch(Time::now(), &ctx, ClientMsg::CreateClient(msg.clone()));
let output = dispatch(&ctx, ClientMsg::CreateClient(msg.clone()));

match output {
Ok(HandlerOutput {
Expand Down
Loading