1use std::{num::NonZeroU64, time::Duration};
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
7#[serde(rename_all = "kebab-case")]
8pub enum Epoch {
9 TimeClock(TimeClockConfig),
10 BlockClock(BlockClockConfig),
11}
12
13impl Default for Epoch {
14 fn default() -> Self {
15 Self::BlockClock(BlockClockConfig::default())
16 }
17}
18
19#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
20#[serde(rename_all = "kebab-case")]
21pub struct BlockClockConfig {
22 #[serde(default = "default_block_epoch_duration")]
23 pub epoch_duration: NonZeroU64,
24
25 #[serde(default = "default_genesis_block")]
26 pub genesis_block: u64,
27}
28
29impl Default for BlockClockConfig {
30 fn default() -> Self {
31 Self {
32 epoch_duration: default_block_epoch_duration(),
33 genesis_block: default_genesis_block(),
34 }
35 }
36}
37
38#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
39#[serde(rename_all = "kebab-case")]
40pub struct TimeClockConfig {
41 #[serde(
42 default = "default_epoch_duration",
43 with = "crate::with::HumanDuration",
44 alias = "EpochDuration"
45 )]
46 pub epoch_duration: Duration,
47}
48
49impl Default for TimeClockConfig {
50 fn default() -> Self {
51 Self {
52 epoch_duration: default_epoch_duration(),
53 }
54 }
55}
56
57fn default_block_epoch_duration() -> NonZeroU64 {
61 NonZeroU64::new(6).unwrap()
62}
63
64const fn default_genesis_block() -> u64 {
65 0
66}
67
68fn default_epoch_duration() -> Duration {
69 Duration::from_secs(60)
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn serialize_epoch() {
78 let epoch = Epoch::TimeClock(TimeClockConfig::default());
79 let serialized = serde_json::to_string(&epoch).unwrap();
80
81 assert_eq!(serialized, r#"{"time-clock":{"epoch-duration":"1m"}}"#);
82 }
83
84 #[test]
85 fn deserialize_epoch() {
86 let config = r#"{"time-clock":{"epoch-duration":3600}}"#;
87
88 let expected_duration = Duration::from_secs(3600);
89 let epoch: Epoch = serde_json::from_str(config).unwrap();
90
91 assert!(
92 matches!(epoch, Epoch::TimeClock(TimeClockConfig { epoch_duration }) if epoch_duration == expected_duration)
93 );
94 }
95}