river_core/room_state/
version.rs1use super::{ChatRoomParametersV1, ChatRoomStateV1};
9use freenet_scaffold::ComposableState;
10use serde::{Deserialize, Serialize};
11
12pub const CURRENT_STATE_VERSION: u32 = 1;
14
15#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Debug)]
21pub struct StateVersion(pub u32);
22
23impl ComposableState for StateVersion {
24 type ParentState = ChatRoomStateV1;
25 type Summary = u32;
26 type Delta = ();
27 type Parameters = ChatRoomParametersV1;
28
29 fn verify(
30 &self,
31 _parent_state: &Self::ParentState,
32 _parameters: &Self::Parameters,
33 ) -> Result<(), String> {
34 if self.0 > CURRENT_STATE_VERSION {
37 return Err(format!(
38 "Unknown state version {}. This contract supports versions 0-{}. \
39 Please upgrade your client.",
40 self.0, CURRENT_STATE_VERSION
41 ));
42 }
43 Ok(())
44 }
45
46 fn summarize(
47 &self,
48 _parent_state: &Self::ParentState,
49 _parameters: &Self::Parameters,
50 ) -> Self::Summary {
51 self.0
52 }
53
54 fn delta(
55 &self,
56 _parent_state: &Self::ParentState,
57 _parameters: &Self::Parameters,
58 _old_state_summary: &Self::Summary,
59 ) -> Option<Self::Delta> {
60 None
62 }
63
64 fn apply_delta(
65 &mut self,
66 _parent_state: &Self::ParentState,
67 _parameters: &Self::Parameters,
68 _delta: &Option<Self::Delta>,
69 ) -> Result<(), String> {
70 Ok(())
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use freenet_stdlib::prelude::serde_json;
80
81 #[test]
82 fn test_version_default_is_zero() {
83 let v = StateVersion::default();
84 assert_eq!(v.0, 0);
85 }
86
87 #[test]
88 fn test_version_verify_accepts_current() {
89 let v = StateVersion(CURRENT_STATE_VERSION);
90 let parent = ChatRoomStateV1::default();
91 let params = ChatRoomParametersV1 {
92 owner: ed25519_dalek::SigningKey::generate(&mut rand::rngs::OsRng).verifying_key(),
93 };
94 assert!(v.verify(&parent, ¶ms).is_ok());
95 }
96
97 #[test]
98 fn test_version_verify_accepts_legacy() {
99 let v = StateVersion(0);
100 let parent = ChatRoomStateV1::default();
101 let params = ChatRoomParametersV1 {
102 owner: ed25519_dalek::SigningKey::generate(&mut rand::rngs::OsRng).verifying_key(),
103 };
104 assert!(v.verify(&parent, ¶ms).is_ok());
105 }
106
107 #[test]
108 fn test_version_verify_rejects_future() {
109 let v = StateVersion(CURRENT_STATE_VERSION + 1);
110 let parent = ChatRoomStateV1::default();
111 let params = ChatRoomParametersV1 {
112 owner: ed25519_dalek::SigningKey::generate(&mut rand::rngs::OsRng).verifying_key(),
113 };
114 assert!(v.verify(&parent, ¶ms).is_err());
115 }
116
117 #[test]
118 fn test_version_serialization_roundtrip() {
119 let v = StateVersion(CURRENT_STATE_VERSION);
121 let serialized = serde_json::to_string(&v).unwrap();
122 let deserialized: StateVersion = serde_json::from_str(&serialized).unwrap();
123 assert_eq!(v, deserialized);
124 }
125
126 #[test]
127 fn test_state_without_version_field_deserializes_with_default() {
128 use crate::room_state::configuration::{AuthorizedConfigurationV1, Configuration};
131
132 let owner_sk = ed25519_dalek::SigningKey::generate(&mut rand::rngs::OsRng);
133 let owner_vk = owner_sk.verifying_key();
134
135 let mut state = ChatRoomStateV1::default();
137 let config = Configuration {
138 owner_member_id: owner_vk.into(),
139 ..Default::default()
140 };
141 state.configuration = AuthorizedConfigurationV1::new(config, &owner_sk);
142
143 let mut json_value: serde_json::Value = serde_json::to_value(&state).unwrap();
145 if let serde_json::Value::Object(ref mut map) = json_value {
146 map.remove("version");
147 }
148 let legacy_json = serde_json::to_string(&json_value).unwrap();
149
150 let deserialized: ChatRoomStateV1 = serde_json::from_str(&legacy_json).unwrap();
152 assert_eq!(
153 deserialized.version.0, 0,
154 "Legacy state without version field should deserialize with version=0"
155 );
156 }
157
158 #[test]
159 fn test_state_with_version_field_roundtrips() {
160 use crate::room_state::configuration::{AuthorizedConfigurationV1, Configuration};
161
162 let owner_sk = ed25519_dalek::SigningKey::generate(&mut rand::rngs::OsRng);
163 let owner_vk = owner_sk.verifying_key();
164
165 let mut state = ChatRoomStateV1::default();
166 let config = Configuration {
167 owner_member_id: owner_vk.into(),
168 ..Default::default()
169 };
170 state.configuration = AuthorizedConfigurationV1::new(config, &owner_sk);
171 state.version = StateVersion(CURRENT_STATE_VERSION);
172
173 let json = serde_json::to_string(&state).unwrap();
175 let deserialized: ChatRoomStateV1 = serde_json::from_str(&json).unwrap();
176
177 assert_eq!(deserialized.version.0, CURRENT_STATE_VERSION);
178 }
179}