Skip to content

Commit a6e629f

Browse files
apskhemMr-Leshiy
andauthored
chore(rust/signed-doc): Replace system::time with chrono (#612)
* initial * fix: correct time delta --------- Co-authored-by: Alex Pozhylenkov <leshiy12345678@gmail.com>
1 parent aa36054 commit a6e629f

File tree

5 files changed

+100
-104
lines changed

5 files changed

+100
-104
lines changed

rust/signed_doc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ futures = "0.3.31"
3333
ed25519-bip32 = "0.4.1" # used by the `mk_signed_doc` cli tool
3434
tracing = "0.1.40"
3535
thiserror = "2.0.11"
36+
chrono = "0.4.42"
3637

3738
[dev-dependencies]
3839
base64-url = "3.0.0"

rust/signed_doc/src/validator/rules/chain/tests.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,17 @@ use crate::{
88
};
99

1010
mod helper {
11-
use std::time::{Duration, SystemTime, UNIX_EPOCH};
12-
1311
use catalyst_types::uuid::UuidV7;
12+
use chrono::{Duration, Utc};
1413
use uuid::{Timestamp, Uuid};
1514

16-
pub(super) fn get_now_plus_uuidv7(secs: u64) -> UuidV7 {
17-
let future_time = SystemTime::now()
18-
.checked_add(Duration::from_secs(secs))
19-
.unwrap();
20-
let duration_since_epoch = future_time.duration_since(UNIX_EPOCH).unwrap();
15+
pub(super) fn get_now_plus_uuidv7(secs: i64) -> UuidV7 {
16+
let future_time = Utc::now()
17+
.checked_add_signed(Duration::seconds(secs))
18+
.expect("time overflow in future_time calculation");
2119

22-
let unix_secs = duration_since_epoch.as_secs();
23-
let nanos = duration_since_epoch.subsec_nanos();
20+
let unix_secs = u64::try_from(future_time.timestamp()).unwrap_or(0);
21+
let nanos = future_time.timestamp_subsec_nanos();
2422

2523
let ts = Timestamp::from_unix(uuid::NoContext, unix_secs, nanos);
2624
let uuid = Uuid::new_v7(ts);

rust/signed_doc/src/validator/rules/id/mod.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
#[cfg(test)]
44
mod tests;
55

6-
use std::time::{Duration, SystemTime};
7-
86
use anyhow::Context;
7+
use chrono::{DateTime, Utc};
98

109
use crate::{providers::CatalystSignedDocumentProvider, CatalystSignedDocument};
1110

@@ -16,11 +15,10 @@ pub(crate) struct IdRule;
1615
impl IdRule {
1716
/// Validates document `id` field on the timestamps:
1817
/// 1. If `provider.future_threshold()` not `None`, document `id` cannot be too far in
19-
/// the future (`future_threshold` arg) from `SystemTime::now()` based on the
20-
/// provide threshold
21-
/// 2. If `provider.future_threshold()` not `None`, document `id` cannot be too far
22-
/// behind (`past_threshold` arg) from `SystemTime::now()` based on the provide
18+
/// the future (`future_threshold` arg) from `Utc::now()` based on the provided
2319
/// threshold
20+
/// 2. If `provider.past_threshold()` not `None`, document `id` cannot be too far
21+
/// behind (`past_threshold` arg) from `Utc::now()` based on the provided threshold
2422
#[allow(clippy::unused_async)]
2523
pub(crate) async fn check<Provider>(
2624
&self,
@@ -46,37 +44,40 @@ impl IdRule {
4644
.ok_or(anyhow::anyhow!("Document `id` field must be a UUIDv7"))?
4745
.to_unix();
4846

49-
let Some(id_time) =
50-
SystemTime::UNIX_EPOCH.checked_add(Duration::new(id_time_secs, id_time_nanos))
47+
let Some(id_time) = i64::try_from(id_time_secs)
48+
.ok()
49+
.and_then(|id_time_secs| DateTime::from_timestamp(id_time_secs, id_time_nanos))
5150
else {
5251
doc.report().invalid_value(
5352
"id",
5453
&id.to_string(),
55-
"Must a valid duration since `UNIX_EPOCH`",
56-
"Cannot instantiate a valid `SystemTime` value from the provided `id` field timestamp.",
54+
"Must a valid UTC date time since `UNIX_EPOCH`",
55+
"Cannot instantiate a valid `DateTime<Utc>` value from the provided `id` field timestamp.",
5756
);
5857
return Ok(false);
5958
};
6059

61-
let now = SystemTime::now();
60+
let now = Utc::now();
61+
let time_delta = id_time.signed_duration_since(now);
6262

63-
if let Ok(id_age) = id_time.duration_since(now) {
63+
if let Ok(id_age) = time_delta.to_std() {
6464
// `now` is earlier than `id_time`
6565
if let Some(future_threshold) = provider.future_threshold() {
6666
if id_age > future_threshold {
6767
doc.report().invalid_value(
6868
"id",
6969
&id.to_string(),
7070
"id < now + future_threshold",
71-
&format!("Document Version timestamp {id} cannot be too far in future (threshold: {future_threshold:?}) from now: {now:?}"),
71+
&format!("Document ID timestamp {id} cannot be too far in future (threshold: {future_threshold:?}) from now: {now}"),
7272
);
7373
is_valid = false;
7474
}
7575
}
7676
} else {
7777
// `id_time` is earlier than `now`
78-
let id_age = now
79-
.duration_since(id_time)
78+
let id_age = time_delta
79+
.abs()
80+
.to_std()
8081
.context("BUG! `id_time` must be earlier than `now` at this place")?;
8182

8283
if let Some(past_threshold) = provider.past_threshold() {
@@ -85,7 +86,7 @@ impl IdRule {
8586
"id",
8687
&id.to_string(),
8788
"id > now - past_threshold",
88-
&format!("Document Version timestamp {id} cannot be too far behind (threshold: {past_threshold:?}) from now: {now:?}",),
89+
&format!("Document ID timestamp {id} cannot be too far behind (threshold: {past_threshold:?}) from now: {now:?}",),
8990
);
9091
is_valid = false;
9192
}

rust/signed_doc/src/validator/rules/id/tests.rs

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use std::time::SystemTime;
2-
1+
use chrono::Utc;
32
use test_case::test_case;
43
use uuid::{Timestamp, Uuid};
54

@@ -22,46 +21,46 @@ use crate::{
2221
#[test_case(
2322
#[allow(clippy::arithmetic_side_effects)]
2423
|provider| {
25-
let now = SystemTime::now()
26-
.duration_since(SystemTime::UNIX_EPOCH)
27-
.unwrap()
28-
.as_secs();
29-
let to_far_in_past = Uuid::new_v7(Timestamp::from_unix_time(
30-
now - provider.past_threshold().unwrap().as_secs() - 1,
31-
0,
32-
0,
33-
0,
34-
))
35-
.try_into()
36-
.unwrap();
24+
let now = Utc::now().timestamp();
25+
let past_threshold_secs = i64::try_from(provider.past_threshold().unwrap().as_secs()).unwrap_or(0);
26+
27+
let too_far_in_past = Uuid::new_v7(Timestamp::from_unix_time(
28+
u64::try_from(now - past_threshold_secs - 1).unwrap_or(0),
29+
0,
30+
0,
31+
0,
32+
))
33+
.try_into()
34+
.unwrap();
35+
3736
Builder::new()
38-
.with_metadata_field(SupportedField::Id(to_far_in_past))
37+
.with_metadata_field(SupportedField::Id(too_far_in_past))
3938
.build()
4039
}
4140
=> false;
42-
"`id` to far in past"
41+
"`id` too far in past"
4342
)]
4443
#[test_case(
4544
#[allow(clippy::arithmetic_side_effects)]
4645
|provider| {
47-
let now = SystemTime::now()
48-
.duration_since(SystemTime::UNIX_EPOCH)
49-
.unwrap()
50-
.as_secs();
51-
let to_far_in_future = Uuid::new_v7(Timestamp::from_unix_time(
52-
now + provider.future_threshold().unwrap().as_secs() + 1,
53-
0,
54-
0,
55-
0,
56-
))
57-
.try_into()
58-
.unwrap();
46+
let now = Utc::now().timestamp();
47+
let future_threshold_secs = i64::try_from(provider.future_threshold().unwrap().as_secs()).unwrap_or(0);
48+
49+
let too_far_in_future = Uuid::new_v7(Timestamp::from_unix_time(
50+
u64::try_from(now + future_threshold_secs + 1).unwrap_or(0),
51+
0,
52+
0,
53+
0,
54+
))
55+
.try_into()
56+
.unwrap();
57+
5958
Builder::new()
60-
.with_metadata_field(SupportedField::Id(to_far_in_future))
59+
.with_metadata_field(SupportedField::Id(too_far_in_future))
6160
.build()
6261
}
6362
=> false;
64-
"`id` to far in future"
63+
"`id` too far in future"
6564
)]
6665
#[test_case(
6766
|_| {

0 commit comments

Comments
 (0)