1use borsh::{BorshDeserialize, BorshSerialize};
7
8use crate::{
9 error::{Error, Result},
10 types::{Ciphertext, DecisionId, SecretDigest, SecretKey},
11};
12
13#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
14pub enum DecisionStatus {
15 Asked,
16 Answered,
17 Releasing,
18 Released,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
22pub struct Answer {
23 pub digest: SecretDigest,
24 pub ciphertext: Ciphertext,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
28pub struct DecisionState {
29 pub id: DecisionId,
30 owner: String,
31 status: DecisionStatus,
32 answer: Option<Answer>,
33 secret: Option<SecretKey>,
34 value: Option<String>,
35}
36
37impl DecisionState {
38 pub fn new(id: DecisionId, owner: String) -> Self {
39 Self {
40 id,
41 owner,
42 status: DecisionStatus::Asked,
43 answer: None,
44 secret: None,
45 value: None,
46 }
47 }
48
49 pub fn answer(
50 &mut self,
51 owner: &str,
52 ciphertext: Ciphertext,
53 digest: SecretDigest,
54 ) -> Result<()> {
55 if self.owner.ne(owner) {
56 return Err(Error::InvalidDecisionOwner);
57 }
58 if self.status.ne(&DecisionStatus::Asked) {
59 return Err(Error::InvalidDecisionStatus);
60 }
61 self.answer = Some(Answer { ciphertext, digest });
62 self.status = DecisionStatus::Answered;
63 Ok(())
64 }
65
66 pub fn release(&mut self) -> Result<()> {
67 if self.status != DecisionStatus::Answered {
68 Err(Error::InvalidDecisionStatus)
69 } else {
70 self.status = DecisionStatus::Releasing;
71 Ok(())
72 }
73 }
74
75 pub fn add_released(&mut self, value: String) -> Result<()> {
79 if self.status != DecisionStatus::Released {
80 Err(Error::InvalidDecisionStatus)
81 } else {
82 self.value = Some(value);
83 Ok(())
84 }
85 }
86
87 pub fn add_secret(&mut self, owner: &str, secret: SecretKey) -> Result<()> {
91 if self.status != DecisionStatus::Releasing {
92 Err(Error::InvalidDecisionStatus)
93 } else if self.owner.ne(owner) {
94 Err(Error::InvalidDecisionOwner)
95 } else {
96 self.secret = Some(secret);
97 self.status = DecisionStatus::Released;
98 Ok(())
99 }
100 }
101
102 pub fn get_secret(&self) -> Result<&SecretKey> {
103 match self.secret.as_ref() {
104 Some(secret) => Ok(secret),
105 None => Err(Error::InvalidDecisionStatus),
106 }
107 }
108
109 pub fn is_answered(&self) -> bool {
110 self.status == DecisionStatus::Answered
111 }
112
113 pub fn is_prompted(&self) -> bool {
114 self.status == DecisionStatus::Asked
115 }
116
117 pub fn is_revealed(&self) -> bool {
118 self.status == DecisionStatus::Released
119 }
120
121 pub fn is_revealing(&self) -> bool {
122 self.status == DecisionStatus::Releasing
123 }
124
125 pub fn get_answer(&self) -> Option<&Answer> {
126 self.answer.as_ref()
127 }
128
129 pub fn get_revealed(&self) -> Option<&String> {
130 self.value.as_ref()
131 }
132
133 pub fn get_owner(&self) -> &str {
134 self.owner.as_ref()
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn test_prompt() {
144 let st = DecisionState::new(1, "Alice".into());
145 assert!(st.is_prompted());
146 }
147
148 #[test]
149 fn test_answer() -> anyhow::Result<()> {
150 let mut st = DecisionState::new(1, "Alice".into());
151 st.answer("Alice", vec![1], vec![2])?;
152 assert_eq!(
153 st.answer,
154 Some(Answer {
155 digest: vec![2],
156 ciphertext: vec![1]
157 })
158 );
159 assert!(st.is_answered());
160 Ok(())
161 }
162
163 #[test]
164 fn test_reveal() -> anyhow::Result<()> {
165 let mut st = DecisionState::new(1, "Alice".into());
166 st.answer("Alice", vec![1], vec![2])?;
167 st.release()?;
168 assert!(st.is_revealing());
169 assert_eq!(st.release(), Err(Error::InvalidDecisionStatus));
170 Ok(())
171 }
172
173 #[test]
174 fn test_add_secret() -> anyhow::Result<()> {
175 let mut st = DecisionState::new(1, "Alice".into());
176 st.answer("Alice", vec![1], vec![2])?;
177 assert_eq!(
178 st.add_secret("Alice", vec![0]),
179 Err(Error::InvalidDecisionStatus)
180 );
181 st.release()?;
182 assert_eq!(
183 st.add_secret("Bob", vec![0]),
184 Err(Error::InvalidDecisionOwner)
185 );
186 st.add_secret("Alice", vec![0])?;
187 assert!(st.is_revealed());
188 Ok(())
189 }
190}