nym_mixnet_contract_common/
key_rotation.rs1use crate::EpochId;
5use cosmwasm_schema::cw_serde;
6
7pub type KeyRotationId = u32;
8
9#[cw_serde]
10#[derive(Copy)]
11#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
12pub struct KeyRotationState {
13 pub validity_epochs: u32,
15
16 #[cfg_attr(feature = "utoipa", schema(value_type = u32))]
19 pub initial_epoch_id: EpochId,
20}
21
22impl KeyRotationState {
23 pub fn key_rotation_id(&self, current_epoch_id: EpochId) -> KeyRotationId {
24 let diff = current_epoch_id.saturating_sub(self.initial_epoch_id);
25 diff / self.validity_epochs
26 }
27
28 pub fn next_rotation_starting_epoch_id(&self, current_epoch_id: EpochId) -> EpochId {
29 self.current_rotation_starting_epoch_id(current_epoch_id) + self.validity_epochs
30 }
31
32 pub fn current_rotation_starting_epoch_id(&self, current_epoch_id: EpochId) -> EpochId {
33 let current_rotation_id = self.key_rotation_id(current_epoch_id);
34
35 self.initial_epoch_id + self.validity_epochs * current_rotation_id
36 }
37}
38
39#[cw_serde]
40pub struct KeyRotationIdResponse {
41 pub rotation_id: KeyRotationId,
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
49 fn key_rotation_id() {
50 let state = KeyRotationState {
51 validity_epochs: 24,
52 initial_epoch_id: 0,
53 };
54 assert_eq!(0, state.key_rotation_id(0));
55 assert_eq!(0, state.key_rotation_id(23));
56 assert_eq!(1, state.key_rotation_id(24));
57 assert_eq!(1, state.key_rotation_id(47));
58 assert_eq!(2, state.key_rotation_id(48));
59
60 let state = KeyRotationState {
61 validity_epochs: 12,
62 initial_epoch_id: 0,
63 };
64 assert_eq!(0, state.key_rotation_id(0));
65 assert_eq!(0, state.key_rotation_id(11));
66 assert_eq!(1, state.key_rotation_id(12));
67 assert_eq!(1, state.key_rotation_id(23));
68 assert_eq!(2, state.key_rotation_id(24));
69
70 let state = KeyRotationState {
71 validity_epochs: 24,
72 initial_epoch_id: 10000,
73 };
74 assert_eq!(0, state.key_rotation_id(123));
75 assert_eq!(0, state.key_rotation_id(10000));
76 assert_eq!(0, state.key_rotation_id(10001));
77 assert_eq!(0, state.key_rotation_id(10023));
78 assert_eq!(1, state.key_rotation_id(10024));
79 assert_eq!(1, state.key_rotation_id(10047));
80 assert_eq!(2, state.key_rotation_id(10048));
81 assert_eq!(2, state.key_rotation_id(10060));
82 }
83
84 #[test]
85 fn next_rotation_starting_epoch_id() {
86 let state = KeyRotationState {
87 validity_epochs: 24,
88 initial_epoch_id: 0,
89 };
90 assert_eq!(24, state.next_rotation_starting_epoch_id(0));
91 assert_eq!(24, state.next_rotation_starting_epoch_id(23));
92 assert_eq!(48, state.next_rotation_starting_epoch_id(24));
93 assert_eq!(48, state.next_rotation_starting_epoch_id(47));
94 assert_eq!(72, state.next_rotation_starting_epoch_id(48));
95
96 let state = KeyRotationState {
97 validity_epochs: 12,
98 initial_epoch_id: 0,
99 };
100 assert_eq!(12, state.next_rotation_starting_epoch_id(0));
101 assert_eq!(12, state.next_rotation_starting_epoch_id(11));
102 assert_eq!(24, state.next_rotation_starting_epoch_id(12));
103 assert_eq!(24, state.next_rotation_starting_epoch_id(23));
104 assert_eq!(36, state.next_rotation_starting_epoch_id(24));
105
106 let state = KeyRotationState {
107 validity_epochs: 24,
108 initial_epoch_id: 10000,
109 };
110 assert_eq!(10024, state.next_rotation_starting_epoch_id(123));
111 assert_eq!(10024, state.next_rotation_starting_epoch_id(10000));
112 assert_eq!(10024, state.next_rotation_starting_epoch_id(10001));
113 assert_eq!(10024, state.next_rotation_starting_epoch_id(10023));
114 assert_eq!(10048, state.next_rotation_starting_epoch_id(10024));
115 assert_eq!(10048, state.next_rotation_starting_epoch_id(10047));
116 assert_eq!(10072, state.next_rotation_starting_epoch_id(10048));
117 assert_eq!(10072, state.next_rotation_starting_epoch_id(10060));
118 }
119
120 #[test]
121 fn current_rotation_starting_epoch_id() {
122 let state = KeyRotationState {
123 validity_epochs: 24,
124 initial_epoch_id: 0,
125 };
126 assert_eq!(0, state.current_rotation_starting_epoch_id(0));
127 assert_eq!(0, state.current_rotation_starting_epoch_id(23));
128 assert_eq!(24, state.current_rotation_starting_epoch_id(24));
129 assert_eq!(24, state.current_rotation_starting_epoch_id(47));
130 assert_eq!(48, state.current_rotation_starting_epoch_id(48));
131
132 let state = KeyRotationState {
133 validity_epochs: 12,
134 initial_epoch_id: 0,
135 };
136 assert_eq!(0, state.current_rotation_starting_epoch_id(0));
137 assert_eq!(0, state.current_rotation_starting_epoch_id(11));
138 assert_eq!(12, state.current_rotation_starting_epoch_id(12));
139 assert_eq!(12, state.current_rotation_starting_epoch_id(23));
140 assert_eq!(24, state.current_rotation_starting_epoch_id(24));
141
142 let state = KeyRotationState {
143 validity_epochs: 24,
144 initial_epoch_id: 10000,
145 };
146 assert_eq!(10000, state.current_rotation_starting_epoch_id(123));
147 assert_eq!(10000, state.current_rotation_starting_epoch_id(10000));
148 assert_eq!(10000, state.current_rotation_starting_epoch_id(10001));
149 assert_eq!(10000, state.current_rotation_starting_epoch_id(10023));
150 assert_eq!(10024, state.current_rotation_starting_epoch_id(10024));
151 assert_eq!(10024, state.current_rotation_starting_epoch_id(10047));
152 assert_eq!(10048, state.current_rotation_starting_epoch_id(10048));
153 assert_eq!(10048, state.current_rotation_starting_epoch_id(10060));
154 }
155}