1use std::collections::HashMap;
4
5use borsh::{BorshDeserialize, BorshSerialize};
6
7use crate::{
8 engine::GameHandler,
9 error::{Error, HandleError, Result},
10 random::RandomSpec,
11 types::{DecisionId, RandomId, Settle, Transfer},
12};
13
14#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq)]
15pub struct Ask {
16 pub player_addr: String,
17}
18
19#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq)]
20pub struct Assign {
21 pub random_id: RandomId,
22 pub player_addr: String,
23 pub indexes: Vec<usize>,
24}
25
26#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq)]
27pub struct Reveal {
28 pub random_id: RandomId,
29 pub indexes: Vec<usize>,
30}
31
32#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq)]
33pub struct Release {
34 pub decision_id: DecisionId,
35}
36
37#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq)]
38pub struct ActionTimeout {
39 pub player_addr: String,
40 pub timeout: u64,
41}
42
43#[cfg_attr(test, derive(PartialEq, Eq))]
132#[derive(Default, BorshSerialize, BorshDeserialize, Debug)]
133pub struct Effect {
134 pub action_timeout: Option<ActionTimeout>,
135 pub wait_timeout: Option<u64>,
136 pub start_game: bool,
137 pub stop_game: bool,
138 pub cancel_dispatch: bool,
139 pub timestamp: u64,
140 pub curr_random_id: RandomId,
141 pub curr_decision_id: DecisionId,
142 pub players_count: u16,
143 pub servers_count: u16,
144 pub asks: Vec<Ask>,
145 pub assigns: Vec<Assign>,
146 pub reveals: Vec<Reveal>,
147 pub releases: Vec<Release>,
148 pub init_random_states: Vec<RandomSpec>,
149 pub revealed: HashMap<RandomId, HashMap<usize, String>>,
150 pub answered: HashMap<DecisionId, String>,
151 pub is_checkpoint: bool,
152 pub checkpoint: Option<Vec<u8>>,
153 pub settles: Vec<Settle>,
154 pub handler_state: Option<Vec<u8>>,
155 pub error: Option<HandleError>,
156 pub allow_exit: bool,
157 pub transfers: Vec<Transfer>,
158}
159
160impl Effect {
161 pub fn count_players(&self) -> usize {
163 self.players_count as usize
164 }
165
166 pub fn count_servers(&self) -> usize {
168 self.servers_count as usize
169 }
170
171 pub fn init_random_state(&mut self, spec: RandomSpec) -> RandomId {
173 self.init_random_states.push(spec);
174 let random_id = self.curr_random_id;
175 self.curr_random_id += 1;
176 random_id
177 }
178
179 pub fn assign<S: Into<String>>(
181 &mut self,
182 random_id: RandomId,
183 player_addr: S,
184 indexes: Vec<usize>,
185 ) {
186 self.assigns.push(Assign {
187 random_id,
188 player_addr: player_addr.into(),
189 indexes,
190 })
191 }
192
193 pub fn reveal(&mut self, random_id: RandomId, indexes: Vec<usize>) {
195 self.reveals.push(Reveal { random_id, indexes })
196 }
197
198 pub fn get_revealed(&self, random_id: RandomId) -> Result<&HashMap<usize, String>> {
202 self.revealed
203 .get(&random_id)
204 .ok_or(Error::RandomnessNotRevealed)
205 }
206
207 pub fn get_answer(&self, decision_id: DecisionId) -> Result<&str> {
212 if let Some(a) = self.answered.get(&decision_id) {
213 Ok(a.as_ref())
214 } else {
215 Err(Error::AnswerNotAvailable)
216 }
217 }
218
219 pub fn ask<S: Into<String>>(&mut self, player_addr: S) -> DecisionId {
221 self.asks.push(Ask {
222 player_addr: player_addr.into(),
223 });
224 let decision_id = self.curr_decision_id;
225 self.curr_decision_id += 1;
226 decision_id
227 }
228
229 pub fn release(&mut self, decision_id: DecisionId) {
230 self.releases.push(Release { decision_id })
231 }
232
233 pub fn action_timeout<S: Into<String>>(&mut self, player_addr: S, timeout: u64) {
235 self.action_timeout = Some(ActionTimeout {
236 player_addr: player_addr.into(),
237 timeout,
238 });
239 }
240
241 pub fn timestamp(&self) -> u64 {
246 self.timestamp
247 }
248
249 pub fn wait_timeout(&mut self, timeout: u64) {
251 self.wait_timeout = Some(timeout);
252 }
253
254 pub fn start_game(&mut self) {
256 self.start_game = true;
257 }
258
259 pub fn stop_game(&mut self) {
261 self.stop_game = true;
262 }
263
264 pub fn allow_exit(&mut self, allow_exit: bool) {
266 self.allow_exit = allow_exit
267 }
268
269
270 pub fn checkpoint(&mut self) {
271 self.is_checkpoint = true;
272 }
273
274 pub fn settle(&mut self, settle: Settle) {
276 self.settles.push(settle);
277 }
278
279 pub fn transfer(&mut self, slot_id: u8, amount: u64) {
281 self.transfers.push(Transfer { slot_id, amount });
282 }
283
284 pub fn __handler_state<S>(&self) -> S
288 where
289 S: GameHandler,
290 {
291 S::try_from_slice(self.handler_state.as_ref().unwrap()).unwrap()
292 }
293
294 pub fn __set_handler_state<S: BorshSerialize>(&mut self, handler_state: S) {
298 if let Ok(state) = handler_state.try_to_vec() {
299 self.handler_state = Some(state);
300 } else {
301 self.error = Some(HandleError::SerializationError);
302 }
303 }
304
305 pub fn __set_checkpoint<S: BorshSerialize>(&mut self, checkpoint_state: S) {
309 if let Ok(state) = checkpoint_state.try_to_vec() {
310 self.checkpoint = Some(state);
311 } else {
312 self.error = Some(HandleError::SerializationError);
313 }
314 }
315
316 pub fn __set_checkpoint_raw(&mut self, raw: Vec<u8>) {
317 self.checkpoint = Some(raw);
318 }
319
320 pub fn __checkpoint(&mut self) -> Option<Vec<u8>> {
321 std::mem::replace(&mut self.checkpoint, None)
322 }
323
324 pub fn __set_error(&mut self, error: HandleError) {
328 self.error = Some(error);
329 }
330
331 pub fn __take_error(&mut self) -> Option<HandleError> {
335 std::mem::replace(&mut self.error, None)
336 }
337}
338
339#[cfg(test)]
340mod tests {
341
342 use super::*;
343
344 #[test]
345 fn abc() {
346 let data = vec![0,0,0,0,0,195,133,107,4,139,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,103,0,0,0,0,0,0,0,0,0,0,0,16,39,0,0,0,0,0,0,32,78,0,0,0,0,0,0,32,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,1,0,43,0,0,0,70,97,105,108,101,100,32,116,111,32,102,105,110,100,32,97,32,112,108,97,121,101,114,32,102,111,114,32,116,104,101,32,110,101,120,116,32,98,117,116,116,111,110,1,0,0,0,0];
347 let effect = Effect::try_from_slice(&data);
348 println!("{:?}", effect);
349 }
350
351 #[test]
352 fn test_serialization() -> anyhow::Result<()> {
353 let mut answered = HashMap::new();
354 answered.insert(33, "A".into());
355
356 let mut revealed = HashMap::new();
357 {
358 let mut m = HashMap::new();
359 m.insert(11, "B".into());
360 revealed.insert(22, m);
361 }
362
363 let effect = Effect {
364 action_timeout: Some(ActionTimeout {
365 player_addr: "alice".into(),
366 timeout: 100,
367 }),
368 wait_timeout: Some(200),
369 start_game: true,
370 stop_game: true,
371 cancel_dispatch: true,
372 timestamp: 300_000,
373 curr_random_id: 1,
374 curr_decision_id: 1,
375 players_count: 4,
376 servers_count: 4,
377 asks: vec![Ask {
378 player_addr: "bob".into(),
379 }],
380 assigns: vec![Assign {
381 player_addr: "bob".into(),
382 random_id: 5,
383 indexes: vec![0, 1, 2],
384 }],
385 reveals: vec![Reveal {
386 random_id: 6,
387 indexes: vec![0, 1, 2],
388 }],
389 releases: vec![Release { decision_id: 7 }],
390 init_random_states: vec![RandomSpec::shuffled_list(vec!["a".into(), "b".into()])],
391 revealed,
392 answered,
393 settles: vec![Settle::add("alice", 200), Settle::sub("bob", 200)],
394 handler_state: Some(vec![1, 2, 3, 4]),
395 error: Some(HandleError::NoEnoughPlayers),
396 allow_exit: true,
397 transfers: vec![],
398 is_checkpoint: false,
399 checkpoint: None,
400 };
401 let bs = effect.try_to_vec()?;
402
403 let parsed = Effect::try_from_slice(&bs)?;
404
405 assert_eq!(effect, parsed);
406 Ok(())
407 }
408}