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)!: refactor Timestamp type and distinguish timeout timestamp #1307

Merged
merged 15 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ lint: ## Lint the code using rustfmt, clippy and whitespace lints.
$(MAKE) fmt
$(MAKE) clippy
$(MAKE) lint-toml
$(MAKE) -C ./cosmwasm lint $@
$(MAKE) -C ./cosmwasm lint
bash ./ci/code-quality/whitespace-lints.sh

fmt: ## Format the code using nightly rustfmt.
Expand Down
1 change: 0 additions & 1 deletion ci/no-std-check/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions cosmwasm/ibc-clients/cw-context/src/context/client_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,7 @@ where
description: "time key cannot be converted to u64".to_string(),
})?);

let timestamp = Timestamp::from_nanoseconds(time).map_err(|e| ClientError::Other {
description: e.to_string(),
})?;
let timestamp = Timestamp::from_nanoseconds(time);

let height_key = self.client_update_height_key(height);

Expand Down
5 changes: 1 addition & 4 deletions cosmwasm/ibc-clients/cw-context/src/context/custom_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ where
fn host_timestamp(&self) -> Result<Timestamp, ContextError> {
let time = self.env().block.time;

let host_timestamp =
Timestamp::from_nanoseconds(time.nanos()).map_err(|e| ClientError::Other {
description: e.to_string(),
})?;
let host_timestamp = Timestamp::from_nanoseconds(time.nanos());

Ok(host_timestamp)
}
Expand Down
2 changes: 1 addition & 1 deletion cosmwasm/ibc-clients/ics07-tendermint/src/tests/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub fn dummy_checksum() -> Binary {
pub fn dummy_sov_consensus_state(timestamp: IbcTimestamp) -> ConsensusState {
ConsensusState::new(
vec![0].into(),
timestamp.into_tm_time().expect("Time exists"),
timestamp.into_tm_time(),
// Hash of default validator set
Hash::from_str("D6B93922C33AAEBEC9043566CB4B1B48365B1358B67C7DEF986D9EE1861BC143")
.expect("Never fails"),
Expand Down
11 changes: 4 additions & 7 deletions ibc-apps/ics20-transfer/types/src/msgs/transfer.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
//! Defines the token transfer message type

use ibc_core::channel::types::error::PacketError;
use ibc_core::channel::types::timeout::TimeoutHeight;
use ibc_core::channel::types::timeout::{TimeoutHeight, TimeoutTimestamp};
use ibc_core::handler::types::error::ContextError;
use ibc_core::host::types::identifiers::{ChannelId, PortId};
use ibc_core::primitives::prelude::*;
use ibc_core::primitives::Timestamp;
use ibc_proto::google::protobuf::Any;
use ibc_proto::ibc::applications::transfer::v1::MsgTransfer as RawMsgTransfer;
use ibc_proto::Protobuf;
Expand Down Expand Up @@ -45,22 +44,20 @@
pub timeout_height_on_b: TimeoutHeight,
/// Timeout timestamp relative to the current block timestamp.
/// The timeout is disabled when set to 0.
pub timeout_timestamp_on_b: Timestamp,
pub timeout_timestamp_on_b: TimeoutTimestamp,
}

impl TryFrom<RawMsgTransfer> for MsgTransfer {
type Error = TokenTransferError;

fn try_from(raw_msg: RawMsgTransfer) -> Result<Self, Self::Error> {
let timeout_timestamp_on_b = Timestamp::from_nanoseconds(raw_msg.timeout_timestamp)
.map_err(PacketError::InvalidPacketTimestamp)
.map_err(ContextError::from)?;

let timeout_height_on_b: TimeoutHeight = raw_msg
.timeout_height
.try_into()
.map_err(ContextError::from)?;

let timeout_timestamp_on_b: TimeoutTimestamp = raw_msg.timeout_timestamp.into();

Check warning on line 60 in ibc-apps/ics20-transfer/types/src/msgs/transfer.rs

View check run for this annotation

Codecov / codecov/patch

ibc-apps/ics20-transfer/types/src/msgs/transfer.rs#L59-L60

Added lines #L59 - L60 were not covered by tests
// Packet timeout height and packet timeout timestamp cannot both be unset.
if !timeout_height_on_b.is_set() && !timeout_timestamp_on_b.is_set() {
return Err(ContextError::from(PacketError::MissingTimeout))?;
Expand Down
11 changes: 4 additions & 7 deletions ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
//! Defines the Non-Fungible Token Transfer message type

use ibc_core::channel::types::error::PacketError;
use ibc_core::channel::types::timeout::TimeoutHeight;
use ibc_core::channel::types::timeout::{TimeoutHeight, TimeoutTimestamp};
use ibc_core::handler::types::error::ContextError;
use ibc_core::host::types::identifiers::{ChannelId, PortId};
use ibc_core::primitives::prelude::*;
use ibc_core::primitives::Timestamp;
use ibc_proto::google::protobuf::Any;
use ibc_proto::ibc::applications::nft_transfer::v1::MsgTransfer as RawMsgTransfer;
use ibc_proto::Protobuf;
Expand Down Expand Up @@ -45,22 +44,20 @@
pub timeout_height_on_b: TimeoutHeight,
/// Timeout timestamp relative to the current block timestamp.
/// The timeout is disabled when set to 0.
pub timeout_timestamp_on_b: Timestamp,
pub timeout_timestamp_on_b: TimeoutTimestamp,
}

impl TryFrom<RawMsgTransfer> for MsgTransfer {
type Error = NftTransferError;

fn try_from(raw_msg: RawMsgTransfer) -> Result<Self, Self::Error> {
let timeout_timestamp_on_b = Timestamp::from_nanoseconds(raw_msg.timeout_timestamp)
.map_err(PacketError::InvalidPacketTimestamp)
.map_err(ContextError::from)?;

let timeout_height_on_b: TimeoutHeight = raw_msg
.timeout_height
.try_into()
.map_err(ContextError::from)?;

let timeout_timestamp_on_b: TimeoutTimestamp = raw_msg.timeout_timestamp.into();

Check warning on line 60 in ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs

View check run for this annotation

Codecov / codecov/patch

ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs#L59-L60

Added lines #L59 - L60 were not covered by tests
// Packet timeout height and packet timeout timestamp cannot both be unset.
if !timeout_height_on_b.is_set() && !timeout_timestamp_on_b.is_set() {
return Err(ContextError::from(PacketError::MissingTimeout))?;
Expand Down
6 changes: 0 additions & 6 deletions ibc-clients/ics07-tendermint/src/client_state/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,6 @@ pub fn consensus_state_status<CS: ConsensusState>(
host_timestamp: &Timestamp,
trusting_period: Duration,
) -> Result<Status, ClientError> {
if !host_timestamp.is_set() {
return Err(ClientError::Other {
description: "host timestamp is none".into(),
});
}

// Note: if the `duration_since()` is `None`, indicating that the latest
// consensus state is in the future, then we don't consider the client
// to be expired.
Expand Down
7 changes: 1 addition & 6 deletions ibc-clients/ics07-tendermint/src/client_state/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,12 +336,7 @@ where
let tm_consensus_state: ConsensusStateType =
consensus_state.try_into().map_err(Into::into)?;

let host_timestamp =
ctx.host_timestamp()?
.into_tm_time()
.ok_or_else(|| ClientError::Other {
description: String::from("host timestamp is not a valid TM timestamp"),
})?;
let host_timestamp = ctx.host_timestamp()?.into_tm_time();

let tm_consensus_state_timestamp = tm_consensus_state.timestamp();
let tm_consensus_state_expiry = (tm_consensus_state_timestamp
Expand Down
28 changes: 13 additions & 15 deletions ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub fn verify_misbehaviour_header<H>(
header: &TmHeader,
chain_id: &ChainId,
options: &Options,
trusted_timestamp: Time,
trusted_time: Time,
trusted_next_validator_hash: Hash,
current_timestamp: Timestamp,
verifier: &impl Verifier,
Expand All @@ -97,12 +97,15 @@ where

// ensure trusted consensus state is within trusting period
{
let duration_since_consensus_state = current_timestamp
.duration_since(&trusted_timestamp.into())
.ok_or_else(|| ClientError::InvalidConsensusStateTimestamp {
time1: trusted_timestamp.into(),
time2: current_timestamp,
})?;
let trusted_timestamp = trusted_time.try_into().expect("time conversion failed");

let duration_since_consensus_state =
current_timestamp.duration_since(&trusted_timestamp).ok_or(
ClientError::InvalidConsensusStateTimestamp {
time1: trusted_timestamp,
time2: current_timestamp,
},
)?;

if duration_since_consensus_state >= options.trusting_period {
return Err(Error::ConsensusStateTimestampGteTrustingPeriod {
Expand All @@ -123,15 +126,10 @@ where
description: format!("failed to parse chain id: {e}"),
})?;

let trusted_state = header.as_trusted_block_state(
tm_chain_id,
trusted_timestamp,
trusted_next_validator_hash,
)?;
let trusted_state =
header.as_trusted_block_state(tm_chain_id, trusted_time, trusted_next_validator_hash)?;

let current_timestamp = current_timestamp.into_tm_time().ok_or(ClientError::Other {
description: "host timestamp must not be zero".to_string(),
})?;
let current_timestamp = current_timestamp.into_tm_time();

verifier
.verify_misbehaviour_header(untrusted_state, trusted_state, options, current_timestamp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,7 @@ where
next_validators: None,
};

let now =
ctx.host_timestamp()?
.into_tm_time()
.ok_or_else(|| ClientError::ClientSpecific {
description: "host timestamp is not a valid TM timestamp".to_string(),
})?;
let now = ctx.host_timestamp()?.into_tm_time();

// main header verification, delegated to the tendermint-light-client crate.
verifier
Expand Down
5 changes: 4 additions & 1 deletion ibc-clients/ics07-tendermint/src/consensus_state.rs
seanchen1991 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ impl ConsensusStateTrait for ConsensusState {
}

fn timestamp(&self) -> Timestamp {
self.0.timestamp.into()
self.0
.timestamp
.try_into()
.expect("UNIX Timestamp can't be negative")
}
}
7 changes: 3 additions & 4 deletions ibc-clients/ics07-tendermint/types/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use ibc_core_commitment_types::error::CommitmentError;
use ibc_core_host_types::error::IdentifierError;
use ibc_core_host_types::identifiers::ClientId;
use ibc_primitives::prelude::*;
use ibc_primitives::TimestampError;
use tendermint::{Error as TendermintError, Hash};
use tendermint_light_client_verifier::errors::VerificationErrorDetail as LightClientErrorDetail;
use tendermint_light_client_verifier::operations::VotingPowerTally;
Expand Down Expand Up @@ -58,10 +59,8 @@ pub enum Error {
InvalidRawHeader(TendermintError),
/// invalid raw misbehaviour: `{reason}`
InvalidRawMisbehaviour { reason: String },
/// given other previous updates, header timestamp should be at most `{max}`, but was `{actual}`
HeaderTimestampTooHigh { actual: String, max: String },
/// given other previous updates, header timestamp should be at least `{min}`, but was `{actual}`
HeaderTimestampTooLow { actual: String, min: String },
/// invalid header timestamp: `{0}`
InvalidHeaderTimestamp(TimestampError),
/// header revision height = `{height}` is invalid
InvalidHeaderHeight { height: u64 },
/// frozen height is missing
Expand Down
8 changes: 6 additions & 2 deletions ibc-clients/ics07-tendermint/types/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,12 @@
}

impl Header {
pub fn timestamp(&self) -> Timestamp {
self.signed_header.header.time.into()
pub fn timestamp(&self) -> Result<Timestamp, Error> {
self.signed_header
.header
.time
.try_into()
.map_err(Error::InvalidHeaderTimestamp)

Check warning on line 55 in ibc-clients/ics07-tendermint/types/src/header.rs

View check run for this annotation

Codecov / codecov/patch

ibc-clients/ics07-tendermint/types/src/header.rs#L50-L55

Added lines #L50 - L55 were not covered by tests
}

pub fn height(&self) -> Height {
Expand Down
3 changes: 0 additions & 3 deletions ibc-core/ics02-client/types/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ pub enum ClientError {
},
/// invalid commitment proof bytes error: `{0}`
InvalidCommitmentProof(CommitmentError),
/// invalid packet timeout timestamp value error: `{0}`
InvalidPacketTimestamp(ibc_primitives::ParseTimestampError),
/// mismatch between client and arguments types
ClientArgsTypeMismatch { client_type: ClientType },
/// timestamp is invalid or missing, timestamp=`{time1}`, now=`{time2}`
Expand Down Expand Up @@ -133,7 +131,6 @@ impl std::error::Error for ClientError {
| Self::InvalidClientIdentifier(e)
| Self::InvalidRawMisbehaviour(e) => Some(e),
Self::InvalidCommitmentProof(e) | Self::Ics23Verification(e) => Some(e),
Self::InvalidPacketTimestamp(e) => Some(e),
_ => None,
}
}
Expand Down
4 changes: 2 additions & 2 deletions ibc-core/ics03-connection/types/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use ibc_core_client_types::{error as client_error, Height};
use ibc_core_host_types::error::IdentifierError;
use ibc_core_host_types::identifiers::{ClientId, ConnectionId};
use ibc_primitives::prelude::*;
use ibc_primitives::{Timestamp, TimestampOverflowError};
use ibc_primitives::{Timestamp, TimestampError};

use crate::version::Version;

Expand Down Expand Up @@ -80,7 +80,7 @@ pub enum ConnectionError {
earliest_valid_time: Timestamp,
},
/// timestamp overflowed error: `{0}`
TimestampOverflow(TimestampOverflowError),
TimestampOverflow(TimestampError),
/// connection counter overflow error
CounterOverflow,
/// other error: `{description}`
Expand Down
7 changes: 5 additions & 2 deletions ibc-core/ics04-channel/src/handler/recv_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use ibc_core_host::types::path::{
use ibc_core_host::{ExecutionContext, ValidationContext};
use ibc_core_router::module::Module;
use ibc_primitives::prelude::*;
use ibc_primitives::Expiry;

pub fn recv_packet_validate<ValCtx>(ctx_b: &ValCtx, msg: MsgRecvPacket) -> Result<(), ContextError>
where
Expand Down Expand Up @@ -171,7 +170,11 @@ where
}

let latest_timestamp = ctx_b.host_timestamp()?;
if let Expiry::Expired = latest_timestamp.check_expiry(&msg.packet.timeout_timestamp_on_b) {
if msg
.packet
.timeout_timestamp_on_b
.has_expired(&latest_timestamp)
{
return Err(PacketError::LowPacketTimestamp.into());
}

Expand Down
3 changes: 1 addition & 2 deletions ibc-core/ics04-channel/src/handler/send_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use ibc_core_host::types::path::{
ChannelEndPath, ClientConsensusStatePath, CommitmentPath, SeqSendPath,
};
use ibc_primitives::prelude::*;
use ibc_primitives::Expiry;

use crate::context::{SendPacketExecutionContext, SendPacketValidationContext};

Expand Down Expand Up @@ -81,7 +80,7 @@ pub fn send_packet_validate(
client_val_ctx_a.consensus_state(&client_cons_state_path_on_a)?;
let latest_timestamp = consensus_state_of_b_on_a.timestamp();
let packet_timestamp = packet.timeout_timestamp_on_b;
if let Expiry::Expired = latest_timestamp.check_expiry(&packet_timestamp) {
if packet_timestamp.has_expired(&latest_timestamp) {
return Err(PacketError::LowPacketTimestamp.into());
}

Expand Down
4 changes: 4 additions & 0 deletions ibc-core/ics04-channel/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ tendermint = { workspace = true }
parity-scale-codec = { workspace = true, optional = true }
scale-info = { workspace = true, optional = true }

[dev-dependencies]
rstest = { workspace = true }
serde-json = { workspace = true }

[features]
default = [ "std" ]
std = [
Expand Down
7 changes: 3 additions & 4 deletions ibc-core/ics04-channel/types/src/commitment.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
//! Types and utilities related to packet commitments.

use ibc_primitives::prelude::*;
use ibc_primitives::Timestamp;

use super::acknowledgement::Acknowledgement;
use crate::timeout::TimeoutHeight;
use crate::timeout::{TimeoutHeight, TimeoutTimestamp};

/// Packet commitment
#[cfg_attr(
Expand Down Expand Up @@ -87,7 +86,7 @@ impl From<Vec<u8>> for AcknowledgementCommitment {
pub fn compute_packet_commitment(
packet_data: &[u8],
timeout_height: &TimeoutHeight,
timeout_timestamp: &Timestamp,
timeout_timestamp: &TimeoutTimestamp,
) -> PacketCommitment {
let mut hash_input = [0; 8 * 3 + 32];

Expand Down Expand Up @@ -128,7 +127,7 @@ mod test {
let actual = compute_packet_commitment(
b"packet data",
&TimeoutHeight::At(ibc_core_client_types::Height::new(42, 24).unwrap()),
&Timestamp::from_nanoseconds(0x42).unwrap(),
&TimeoutTimestamp::from(0x42),
);
assert_eq!(&expected[..], actual.as_ref());
}
Expand Down
Loading
Loading