Skip to content

Commit

Permalink
Merge pull request #606 from CosmWasm/add-scheduled
Browse files Browse the repository at this point in the history
Implement Expired variant, Scheduled
  • Loading branch information
ethanfrey authored Dec 28, 2021
2 parents 37af252 + 37a2fe2 commit b872e22
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod expiration;
mod pagination;
mod parse_reply;
mod payment;
mod scheduled;
mod threshold;

pub use pagination::{
Expand All @@ -20,3 +21,4 @@ pub use threshold::{Threshold, ThresholdError, ThresholdResponse};
pub use crate::balance::NativeBalance;
pub use crate::event::Event;
pub use crate::expiration::{Duration, Expiration, DAY, HOUR, WEEK};
pub use crate::scheduled::Scheduled;
117 changes: 117 additions & 0 deletions packages/utils/src/scheduled.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::Duration;
use cosmwasm_std::{BlockInfo, StdError, StdResult, Timestamp};
use std::cmp::Ordering;
use std::fmt;
use std::ops::Add;

#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, JsonSchema, Debug)]
#[serde(rename_all = "snake_case")]
/// Scheduled represents a point in time when an event happens.
/// It can compare with a BlockInfo and will return is_triggered() == true
/// once the condition is hit (and for every block in the future)
pub enum Scheduled {
/// AtHeight will schedule when `env.block.height` >= height
AtHeight(u64),
/// AtTime will schedule when `env.block.time` >= time
AtTime(Timestamp),
}

impl fmt::Display for Scheduled {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Scheduled::AtHeight(height) => write!(f, "scheduled height: {}", height),
Scheduled::AtTime(time) => write!(f, "scheduled time: {}", time),
}
}
}

impl Scheduled {
#[allow(dead_code)]
pub fn is_triggered(&self, block: &BlockInfo) -> bool {
match self {
Scheduled::AtHeight(height) => block.height >= *height,
Scheduled::AtTime(time) => block.time >= *time,
}
}
}

impl Add<Duration> for Scheduled {
type Output = StdResult<Scheduled>;

fn add(self, duration: Duration) -> StdResult<Scheduled> {
match (self, duration) {
(Scheduled::AtTime(t), Duration::Time(delta)) => {
Ok(Scheduled::AtTime(t.plus_seconds(delta)))
}
(Scheduled::AtHeight(h), Duration::Height(delta)) => Ok(Scheduled::AtHeight(h + delta)),
_ => Err(StdError::generic_err("Cannot add height and time")),
}
}
}

impl PartialOrd for Scheduled {
fn partial_cmp(&self, other: &Scheduled) -> Option<Ordering> {
match (self, other) {
// compare if both height or both time
(Scheduled::AtHeight(h1), Scheduled::AtHeight(h2)) => Some(h1.cmp(h2)),
(Scheduled::AtTime(t1), Scheduled::AtTime(t2)) => Some(t1.cmp(t2)),
_ => None,
}
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn compare_schedules() {
// matching pairs
assert!(Scheduled::AtHeight(5) < Scheduled::AtHeight(10));
assert!(Scheduled::AtHeight(8) > Scheduled::AtHeight(7));
assert!(
Scheduled::AtTime(Timestamp::from_seconds(555))
< Scheduled::AtTime(Timestamp::from_seconds(777))
);
assert!(
Scheduled::AtTime(Timestamp::from_seconds(86))
< Scheduled::AtTime(Timestamp::from_seconds(100))
);

// what happens for the uncomparables?? all compares are false
assert_eq!(
None,
Scheduled::AtTime(Timestamp::from_seconds(1000)).partial_cmp(&Scheduled::AtHeight(230))
);
assert_eq!(
Scheduled::AtTime(Timestamp::from_seconds(1000)).partial_cmp(&Scheduled::AtHeight(230)),
None
);
assert_eq!(
Scheduled::AtTime(Timestamp::from_seconds(1000)).partial_cmp(&Scheduled::AtHeight(230)),
None
);
assert!(!(Scheduled::AtTime(Timestamp::from_seconds(1000)) == Scheduled::AtHeight(230)));
}

#[test]
fn schedule_addition() {
// height
let end = Scheduled::AtHeight(12345) + Duration::Height(400);
assert_eq!(end.unwrap(), Scheduled::AtHeight(12745));

// time
let end = Scheduled::AtTime(Timestamp::from_seconds(55544433)) + Duration::Time(40300);
assert_eq!(
end.unwrap(),
Scheduled::AtTime(Timestamp::from_seconds(55584733))
);

// mismatched
let end = Scheduled::AtHeight(12345) + Duration::Time(1500);
end.unwrap_err();
}
}

0 comments on commit b872e22

Please sign in to comment.