Skip to content

Commit 8edd876

Browse files
authored
Voyager timeouts (#4217)
2 parents e9e31ab + 3b89493 commit 8edd876

File tree

45 files changed

+985
-220
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+985
-220
lines changed

Cargo.lock

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ members = [
188188

189189
"voyager/plugins/packet-filter",
190190
"voyager/plugins/transaction-batch",
191+
"voyager/plugins/packet-timeout",
191192

192193
"drip",
193194

cosmwasm/ibc-union/app/ucs00-pingpong/src/contract.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use cosmwasm_schema::cw_serde;
33
use cosmwasm_std::entry_point;
44
use cosmwasm_std::{wasm_execute, DepsMut, Env, MessageInfo, Response, StdError};
55
use ibc_union_msg::{module::IbcUnionMsg, msg::MsgWriteAcknowledgement};
6+
use ibc_union_spec::Timestamp;
67

78
use crate::{
89
msg::{ExecuteMsg, InitMsg, UCS00PingPong},
@@ -33,7 +34,11 @@ pub fn execute(
3334
match msg {
3435
ExecuteMsg::Initiate { channel_id, packet } => {
3536
let config = CONFIG.load(deps.storage)?;
36-
let msg = packet.reverse(&config, env.block.time.nanos(), channel_id);
37+
let msg = packet.reverse(
38+
&config,
39+
Timestamp::from_nanos(env.block.time.nanos()),
40+
channel_id,
41+
);
3742

3843
Ok(Response::default().add_message(wasm_execute(config.ibc_host, &msg, vec![])?))
3944
}
@@ -54,7 +59,7 @@ pub fn execute(
5459
let config = CONFIG.load(deps.storage)?;
5560
let msg = ping_packet.reverse(
5661
&config,
57-
env.block.time.nanos(),
62+
Timestamp::from_nanos(env.block.time.nanos()),
5863
packet.destination_channel_id,
5964
);
6065

cosmwasm/ibc-union/app/ucs00-pingpong/src/msg.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use cosmwasm_schema::cw_serde;
22
use ethabi::{ParamType, Token};
33
use ibc_union_msg::msg::MsgSendPacket;
4-
use ibc_union_spec::ChannelId;
4+
use ibc_union_spec::{ChannelId, Timestamp};
55

66
use crate::{state::Config, ContractError};
77

@@ -37,7 +37,7 @@ impl UCS00PingPong {
3737
pub fn reverse(
3838
&self,
3939
config: &Config,
40-
current_timestamp: u64,
40+
current_timestamp: Timestamp,
4141
source_channel: ChannelId,
4242
) -> ibc_union_msg::msg::ExecuteMsg {
4343
let counterparty_packet = UCS00PingPong {
@@ -47,7 +47,8 @@ impl UCS00PingPong {
4747
ibc_union_msg::msg::ExecuteMsg::PacketSend(MsgSendPacket {
4848
source_channel_id: source_channel,
4949
timeout_height: 0,
50-
timeout_timestamp: current_timestamp + config.seconds_before_timeout * 1_000_000_000,
50+
timeout_timestamp: current_timestamp
51+
+ Timestamp::from_secs(config.seconds_before_timeout),
5152
data: counterparty_packet.encode().into(),
5253
})
5354
}

cosmwasm/ibc-union/app/ucs03-zkgm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ ibc-union-msg = { workspace = true }
2929
ibc-union-spec = { workspace = true, features = ["serde", "ethabi"] }
3030
serde = { workspace = true, features = ["derive"] }
3131
serde-json-wasm = "1.0"
32+
serde-utils.workspace = true
3233
thiserror = { workspace = true }
3334
token-factory-api = { workspace = true }
3435
ucs03-zkgm-token-minter-api = { workspace = true }

cosmwasm/ibc-union/app/ucs03-zkgm/src/contract.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use ibc_union_msg::{
1313
module::IbcUnionMsg,
1414
msg::{MsgSendPacket, MsgWriteAcknowledgement},
1515
};
16-
use ibc_union_spec::{path::BatchPacketsPath, ChannelId, Packet};
16+
use ibc_union_spec::{path::BatchPacketsPath, ChannelId, Packet, Timestamp};
1717
use ucs03_zkgm_token_minter_api::{LocalTokenMsg, Metadata, MetadataResponse, WrappedTokenMsg};
1818
use unionlabs::{
1919
ethereum::keccak256,
@@ -228,7 +228,7 @@ pub fn execute(
228228
info,
229229
channel_id,
230230
timeout_height.u64(),
231-
timeout_timestamp.u64(),
231+
timeout_timestamp,
232232
salt,
233233
Instruction::abi_decode_params(&instruction, true)?,
234234
),
@@ -1008,7 +1008,7 @@ fn execute_forward(
10081008
let next_packet = MsgSendPacket {
10091009
source_channel_id: next_source_channel_id,
10101010
timeout_height: forward.timeout_height,
1011-
timeout_timestamp: forward.timeout_timestamp,
1011+
timeout_timestamp: Timestamp::from_nanos(forward.timeout_timestamp),
10121012
data: ZkgmPacket {
10131013
salt: derive_forward_salt(salt).into(),
10141014
path: next_path,
@@ -1856,7 +1856,7 @@ pub fn send(
18561856
info: MessageInfo,
18571857
channel_id: ChannelId,
18581858
timeout_height: u64,
1859-
timeout_timestamp: u64,
1859+
timeout_timestamp: Timestamp,
18601860
salt: H256,
18611861
instruction: Instruction,
18621862
) -> Result<Response, ContractError> {

cosmwasm/ibc-union/app/ucs03-zkgm/src/msg.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use cosmwasm_std::{Addr, CosmosMsg, Uint256, Uint64};
2-
use ibc_union_spec::{ChannelId, Packet};
2+
use ibc_union_spec::{ChannelId, Packet, Timestamp};
33
use serde::{Deserialize, Serialize};
44
use unionlabs::primitives::{Bytes, H256};
55

@@ -64,7 +64,8 @@ pub enum ExecuteMsg {
6464
Send {
6565
channel_id: ChannelId,
6666
timeout_height: Uint64,
67-
timeout_timestamp: Uint64,
67+
#[serde(with = "serde_utils::string")]
68+
timeout_timestamp: Timestamp,
6869
salt: H256,
6970
instruction: Bytes,
7071
},
@@ -142,7 +143,7 @@ mod tests {
142143
ExecuteMsg::Send {
143144
channel_id: ChannelId!(9),
144145
timeout_height: Uint64::new(0),
145-
timeout_timestamp: Uint64::new(1744248392563000000),
146+
timeout_timestamp: Timestamp::from_nanos(1744248392563000000),
146147
salt: hex!("fd0ff5488c14b15c03d8958b25261c22a42b049894aeb1f33926a1f7ccadaf98").into(),
147148
instruction: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000012d450000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000012d450000000000000000000000000000000000000000000000000000000000000002a307832633664373366343061636535313263343330343032646362646339343839343134333035303438000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014bd1b743615f903a630393f78234b4500fbe5691a000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e62626e316e7a6e6c377372676d7478396a7565766e72617372327372736c717a7a6533303833673330773875673936663936726a7065757167386636757700000000000000000000000000000000000000000000000000000000000000000007756e6942544364000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006756e6942544300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014717dA936440d811EbBF98515EB4a8Db2443BeFf5000000000000000000000000".parse().unwrap()
148149
}

cosmwasm/ibc-union/core/msg/src/msg.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ibc_union_spec::{Channel, ChannelId, ClientId, ConnectionId, Packet};
1+
use ibc_union_spec::{Channel, ChannelId, ClientId, ConnectionId, Packet, Timestamp};
22
use serde::{Deserialize, Serialize};
33
use unionlabs_primitives::Bytes;
44

@@ -225,6 +225,6 @@ pub struct MsgWriteAcknowledgement {
225225
pub struct MsgSendPacket {
226226
pub source_channel_id: ChannelId,
227227
pub timeout_height: u64,
228-
pub timeout_timestamp: u64,
228+
pub timeout_timestamp: Timestamp,
229229
pub data: Bytes,
230230
}

cosmwasm/ibc-union/core/src/contract.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use ibc_union_spec::{
3131
ConnectionPath, ConsensusStatePath, COMMITMENT_MAGIC, COMMITMENT_MAGIC_ACK,
3232
},
3333
Channel, ChannelId, ChannelState, ClientId, Connection, ConnectionId, ConnectionState, Packet,
34+
Timestamp,
3435
};
3536
use serde::{de::DeserializeOwned, Deserialize, Serialize};
3637
use unionlabs::{
@@ -666,7 +667,7 @@ fn timeout_packet(
666667

667668
let proof_timestamp =
668669
get_timestamp_at_height(deps.as_ref(), connection.client_id, proof_height)?;
669-
if proof_timestamp == 0 {
670+
if proof_timestamp.is_zero() {
670671
return Err(ContractError::TimeoutProofTimestampNotFound);
671672
}
672673

@@ -685,15 +686,15 @@ fn timeout_packet(
685686
)?;
686687
mark_packet_as_acknowledged(deps.branch(), &packet)?;
687688

688-
if packet.timeout_timestamp == 0 && packet.timeout_height == 0 {
689+
if packet.timeout_timestamp.is_zero() && packet.timeout_height == 0 {
689690
return Err(ContractError::TimeoutMustBeSet);
690691
}
691692

692-
if packet.timeout_timestamp > 0 && packet.timeout_timestamp > proof_timestamp {
693+
if !packet.timeout_timestamp.is_zero() && packet.timeout_timestamp > proof_timestamp {
693694
return Err(ContractError::TimeoutTimestampNotReached);
694695
}
695696

696-
if packet.timeout_height > 0 && packet.timeout_height > proof_height {
697+
if !packet.timeout_timestamp.is_zero() && packet.timeout_height > proof_height {
697698
return Err(ContractError::TimeoutHeightNotReached);
698699
}
699700

@@ -1636,8 +1637,8 @@ fn process_receive(
16361637
});
16371638
}
16381639

1639-
let current_timestamp = env.block.time.nanos();
1640-
if packet.timeout_timestamp != 0 && (current_timestamp >= packet.timeout_timestamp) {
1640+
let current_timestamp = Timestamp::from_nanos(env.block.time.nanos());
1641+
if !packet.timeout_timestamp.is_zero() && (current_timestamp >= packet.timeout_timestamp) {
16411642
return Err(ContractError::ReceivedTimedOutPacketTimestamp {
16421643
timeout_timestamp: packet.timeout_timestamp,
16431644
current_timestamp,
@@ -1750,10 +1751,10 @@ fn send_packet(
17501751
sender: Addr,
17511752
source_channel_id: ChannelId,
17521753
timeout_height: u64,
1753-
timeout_timestamp: u64,
1754+
timeout_timestamp: Timestamp,
17541755
data: Vec<u8>,
17551756
) -> ContractResult {
1756-
if timeout_timestamp == 0 && timeout_height == 0 {
1757+
if timeout_timestamp.is_zero() && timeout_height == 0 {
17571758
return Err(ContractError::TimeoutMustBeSet);
17581759
}
17591760

@@ -1975,7 +1976,7 @@ fn get_timestamp_at_height(
19751976
deps: Deps,
19761977
client_id: ClientId,
19771978
height: u64,
1978-
) -> Result<u64, ContractError> {
1979+
) -> Result<Timestamp, ContractError> {
19791980
let client_impl = client_impl(deps, client_id)?;
19801981
let timestamp = query_light_client(
19811982
deps,

cosmwasm/ibc-union/core/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod tests;
99
use cosmwasm_std::{Addr, StdError};
1010
use frissitheto::UpgradeError;
1111
use ibc_union_msg::lightclient::Status;
12-
use ibc_union_spec::{ChannelId, ChannelState, ClientId, ConnectionState};
12+
use ibc_union_spec::{ChannelId, ChannelState, ClientId, ConnectionState, Timestamp};
1313
use thiserror::Error;
1414
use unionlabs::primitives::Bytes;
1515

@@ -72,8 +72,8 @@ pub enum ContractError {
7272
ContractErrorKind::from(self)
7373
)]
7474
ReceivedTimedOutPacketTimestamp {
75-
timeout_timestamp: u64,
76-
current_timestamp: u64,
75+
timeout_timestamp: Timestamp,
76+
current_timestamp: Timestamp,
7777
},
7878
#[error(
7979
"{} caller ({caller}) is not the owner ({owner}) of the channel ({channel_id})",

lib/consensus-primitives/src/lib.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![warn(clippy::pedantic, missing_docs, clippy::missing_const_for_fn)]
44
#![cfg_attr(not(feature = "std"), no_std)]
55

6-
use core::fmt;
6+
use core::{fmt, ops::Add, str::FromStr};
77

88
/// Represents a timestamp, normalized to nanoseconds.
99
///
@@ -19,7 +19,7 @@ use core::fmt;
1919
/// This type can represent timestamps between **January 1, 1970 12:00:00 AM** and **July 21, 2554
2020
/// 11:34:33.709 PM** (about 529 years from the time of writing this). If this code is still in use
2121
/// at this time, good luck.
22-
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
22+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
2323
#[cfg_attr(
2424
feature = "serde",
2525
derive(serde::Serialize, serde::Deserialize),
@@ -30,6 +30,9 @@ use core::fmt;
3030
pub struct Timestamp(u64);
3131

3232
impl Timestamp {
33+
/// Zero timestamp.
34+
pub const ZERO: Self = Timestamp(0);
35+
3336
/// Construct a [`Timestamp`] from the given ***nanoseconds*** value.
3437
///
3538
/// ```rust
@@ -73,10 +76,42 @@ impl Timestamp {
7376
pub const fn as_secs(&self) -> u64 {
7477
self.0 / 1_000_000_000
7578
}
79+
80+
/// Check if the timestamp is zero.
81+
///
82+
/// Note that this checks against the ***nanos***. If the value is sub-second, this will return *false*, whereas [`Timestamp::as_secs()`] will return 0:
83+
///
84+
/// ```rust
85+
/// # use consensus_primitives::Timestamp;
86+
/// let ts = Timestamp::from_nanos(123);
87+
/// assert_eq!(ts.as_secs(), 0);
88+
/// assert!(!ts.is_zero());
89+
/// ```
90+
#[must_use = "accessing the inner value has no effect"]
91+
pub const fn is_zero(&self) -> bool {
92+
self.0 == 0
93+
}
94+
}
95+
96+
impl FromStr for Timestamp {
97+
type Err = <u64 as FromStr>::Err;
98+
99+
fn from_str(s: &str) -> Result<Self, Self::Err> {
100+
s.parse().map(Self)
101+
}
76102
}
77103

78104
impl fmt::Display for Timestamp {
79105
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80106
write!(f, "{}", self.0)
81107
}
82108
}
109+
110+
impl Add for Timestamp {
111+
type Output = Self;
112+
113+
#[track_caller]
114+
fn add(self, rhs: Self) -> Self::Output {
115+
Self(self.0 + rhs.0)
116+
}
117+
}

lib/ibc-union-spec/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ ibc-union-spec = { workspace = true, features = ["ethabi", "schemars", "serde",
3232
[features]
3333
default = []
3434

35-
bincode = ["dep:bincode", "unionlabs/bincode"]
35+
bincode = ["dep:bincode", "voyager-primitives/bincode", "unionlabs/bincode"]
3636
ethabi = ["dep:alloy-sol-types", "unionlabs/ethabi"]
3737
ibc-solidity-compat = ["dep:ibc-solidity"]
3838
schemars = ["dep:schemars", "voyager-primitives/schemars", "unionlabs/schemars"]

lib/ibc-union-spec/src/datagram.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,12 @@ pub struct MsgPacketAcknowledgement {
275275
derive(serde::Serialize, serde::Deserialize),
276276
serde(rename_all = "snake_case", deny_unknown_fields)
277277
)]
278-
pub struct MsgPacketTimeout {}
278+
pub struct MsgPacketTimeout {
279+
pub packet: Packet,
280+
/// TODO: Should this be proof_unreceived?
281+
pub proof: Bytes,
282+
pub proof_height: u64,
283+
}
279284

280285
#[derive(Debug, Clone, PartialEq, Eq)]
281286
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]

lib/ibc-union-spec/src/event.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use enumorph::Enumorph;
22
use unionlabs::primitives::Bytes;
3-
use voyager_primitives::ClientType;
3+
use voyager_primitives::{ClientType, Timestamp};
44

55
use crate::{
66
types::{ChannelId, ClientId, ConnectionId},
@@ -389,7 +389,7 @@ pub struct PacketMetadata {
389389
pub destination_channel: ChannelMetadata,
390390

391391
pub timeout_height: u64,
392-
pub timeout_timestamp: u64,
392+
pub timeout_timestamp: Timestamp,
393393
}
394394

395395
/// All metadata associated with a Channel.

0 commit comments

Comments
 (0)