1use cbor;
19
20use sha2::{Digest, Sha512};
21
22use std::collections::BTreeMap;
23use std::collections::HashMap;
24use std::fmt;
25use std::io::Cursor;
26
27use cbor::encoder::GenericEncoder;
28use cbor::value::Key;
29use cbor::value::Text;
30use cbor::value::Value;
31
32use sawtooth_sdk::messages::processor::TpProcessRequest;
33use sawtooth_sdk::processor::handler::ApplyError;
34use sawtooth_sdk::processor::handler::TransactionContext;
35use sawtooth_sdk::processor::handler::TransactionHandler;
36
37const MAX_VALUE: u32 = 4_294_967_295;
38const MAX_NAME_LEN: usize = 20;
39
40#[derive(Copy, Clone)]
41enum Verb {
42 Set,
43 Increment,
44 Decrement,
45}
46
47impl fmt::Display for Verb {
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 write!(
50 f,
51 "{}",
52 match *self {
53 Verb::Set => "Verb::Set",
54 Verb::Increment => "Verb::Increment",
55 Verb::Decrement => "Verb::Decrement",
56 }
57 )
58 }
59}
60
61fn get_intkey_prefix() -> String {
62 hex::encode(Sha512::digest(b"intkey"))[..6].to_string()
63}
64
65struct IntkeyPayload {
66 verb: Verb,
67 name: String,
68 value: u32,
69}
70
71impl IntkeyPayload {
72 pub fn new(payload_data: &[u8]) -> Result<Option<IntkeyPayload>, ApplyError> {
73 let input = Cursor::new(payload_data);
74
75 let mut decoder = cbor::GenericDecoder::new(cbor::Config::default(), input);
76 let decoder_value = decoder
77 .value()
78 .map_err(|err| ApplyError::InternalError(format!("{}", err)))?;
79
80 let c = cbor::value::Cursor::new(&decoder_value);
81
82 let verb_raw: String = match c.field("Verb").text_plain() {
83 None => {
84 return Err(ApplyError::InvalidTransaction(String::from(
85 "Verb must be 'set', 'inc', or 'dec'",
86 )));
87 }
88 Some(verb_raw) => verb_raw.clone(),
89 };
90
91 let verb = match verb_raw.as_str() {
92 "set" => Verb::Set,
93 "inc" => Verb::Increment,
94 "dec" => Verb::Decrement,
95 _ => {
96 return Err(ApplyError::InvalidTransaction(String::from(
97 "Verb must be 'set', 'inc', or 'dec'",
98 )));
99 }
100 };
101
102 let value_raw = c.field("Value");
103 let value_raw = match value_raw.value() {
104 Some(x) => x,
105 None => {
106 return Err(ApplyError::InvalidTransaction(String::from(
107 "Must have a value",
108 )));
109 }
110 };
111
112 let value: u32 = match *value_raw {
113 cbor::value::Value::U8(x) => u32::from(x),
114 cbor::value::Value::U16(x) => u32::from(x),
115 cbor::value::Value::U32(x) => x,
116 _ => {
117 return Err(ApplyError::InvalidTransaction(String::from(
118 "Value must be an integer",
119 )));
120 }
121 };
122
123 let name_raw: String = match c.field("Name").text_plain() {
124 None => {
125 return Err(ApplyError::InvalidTransaction(String::from(
126 "Name must be a string",
127 )));
128 }
129 Some(name_raw) => name_raw.clone(),
130 };
131
132 if name_raw.len() > MAX_NAME_LEN {
133 return Err(ApplyError::InvalidTransaction(String::from(
134 "Name must be equal to or less than 20 characters",
135 )));
136 }
137
138 let intkey_payload = IntkeyPayload {
139 verb,
140 name: name_raw,
141 value,
142 };
143 Ok(Some(intkey_payload))
144 }
145
146 pub fn get_verb(&self) -> Verb {
147 self.verb
148 }
149
150 pub fn get_name(&self) -> &String {
151 &self.name
152 }
153
154 pub fn get_value(&self) -> u32 {
155 self.value
156 }
157}
158
159pub struct IntkeyState<'a> {
160 context: &'a mut dyn TransactionContext,
161 get_cache: HashMap<String, BTreeMap<Key, Value>>,
162}
163
164impl<'a> IntkeyState<'a> {
165 pub fn new(context: &'a mut dyn TransactionContext) -> IntkeyState {
166 IntkeyState {
167 context,
168 get_cache: HashMap::new(),
169 }
170 }
171
172 fn calculate_address(name: &str) -> String {
173 let sha = hex::encode(Sha512::digest(name.as_bytes()))[64..].to_string();
174 get_intkey_prefix() + &sha
175 }
176
177 pub fn get(&mut self, name: &str) -> Result<Option<u32>, ApplyError> {
178 let address = IntkeyState::calculate_address(name);
179 let d = self.context.get_state_entry(&address)?;
180 match d {
181 Some(packed) => {
182 let input = Cursor::new(packed);
183 let mut decoder = cbor::GenericDecoder::new(cbor::Config::default(), input);
184 let map_value = decoder
185 .value()
186 .map_err(|err| ApplyError::InternalError(format!("{}", err)))?;
187 let map = match map_value {
188 Value::Map(m) => m,
189 _ => {
190 return Err(ApplyError::InternalError(String::from(
191 "No map returned from state",
192 )));
193 }
194 };
195
196 let status = match map.get(&Key::Text(Text::Text(String::from(name)))) {
197 Some(v) => match *v {
198 Value::U32(x) => Ok(Some(x)),
199 Value::U16(x) => Ok(Some(u32::from(x))),
200 Value::U8(x) => Ok(Some(u32::from(x))),
201 _ => Err(ApplyError::InternalError(String::from(
202 "Value returned from state is the wrong type.",
203 ))),
204 },
205 None => Ok(None),
206 };
207 self.get_cache.insert(address, map);
208 status
209 }
210 None => Ok(None),
211 }
212 }
213
214 pub fn set(&mut self, name: &str, value: u32) -> Result<(), ApplyError> {
215 let mut map: BTreeMap<Key, Value> = match self
216 .get_cache
217 .get_mut(&IntkeyState::calculate_address(name))
218 {
219 Some(m) => m.clone(),
220 None => BTreeMap::new(),
221 };
222 map.insert(Key::Text(Text::Text(String::from(name))), Value::U32(value));
223
224 let mut e = GenericEncoder::new(Cursor::new(Vec::new()));
225 e.value(&Value::Map(map))
226 .map_err(|err| ApplyError::InternalError(format!("{}", err)))?;
227
228 let packed = e.into_inner().into_writer().into_inner();
229 self.context
230 .set_state_entry(IntkeyState::calculate_address(name), packed)
231 .map_err(|err| ApplyError::InternalError(format!("{}", err)))?;
232
233 Ok(())
234 }
235}
236
237pub struct IntkeyTransactionHandler {
238 family_name: String,
239 family_versions: Vec<String>,
240 namespaces: Vec<String>,
241}
242
243impl Default for IntkeyTransactionHandler {
244 fn default() -> Self {
245 IntkeyTransactionHandler {
246 family_name: "intkey".to_string(),
247 family_versions: vec!["1.0".to_string()],
248 namespaces: vec![get_intkey_prefix()],
249 }
250 }
251}
252
253impl IntkeyTransactionHandler {
254 pub fn new() -> IntkeyTransactionHandler {
255 Self::default()
256 }
257}
258
259impl TransactionHandler for IntkeyTransactionHandler {
260 fn family_name(&self) -> String {
261 self.family_name.clone()
262 }
263
264 fn family_versions(&self) -> Vec<String> {
265 self.family_versions.clone()
266 }
267
268 fn namespaces(&self) -> Vec<String> {
269 self.namespaces.clone()
270 }
271
272 fn apply(
273 &self,
274 request: &TpProcessRequest,
275 context: &mut dyn TransactionContext,
276 ) -> Result<(), ApplyError> {
277 let payload = IntkeyPayload::new(request.get_payload());
278 let payload = match payload {
279 Err(e) => return Err(e),
280 Ok(payload) => payload,
281 };
282 let payload = match payload {
283 Some(x) => x,
284 None => {
285 return Err(ApplyError::InvalidTransaction(String::from(
286 "Request must contain a payload",
287 )));
288 }
289 };
290
291 let mut state = IntkeyState::new(context);
292
293 info!(
294 "payload: {} {} {} {} {}",
295 payload.get_verb(),
296 payload.get_name(),
297 payload.get_value(),
298 request.get_header().get_inputs()[0],
299 request.get_header().get_outputs()[0]
300 );
301
302 match payload.get_verb() {
303 Verb::Set => {
304 match state.get(payload.get_name()) {
305 Ok(Some(_)) => {
306 return Err(ApplyError::InvalidTransaction(format!(
307 "{} already set",
308 payload.get_name()
309 )));
310 }
311 Ok(None) => (),
312 Err(err) => return Err(err),
313 };
314 state.set(payload.get_name(), payload.get_value())
315 }
316 Verb::Increment => {
317 let orig_value: u32 = match state.get(payload.get_name()) {
318 Ok(Some(v)) => v,
319 Ok(None) => {
320 return Err(ApplyError::InvalidTransaction(String::from(
321 "inc requires a set value",
322 )));
323 }
324 Err(err) => return Err(err),
325 };
326 let diff = MAX_VALUE - orig_value;
327 if diff < payload.get_value() {
328 return Err(ApplyError::InvalidTransaction(String::from(
329 "Value is too large to inc",
330 )));
331 };
332
333 state.set(payload.get_name(), orig_value + payload.get_value())
334 }
335 Verb::Decrement => {
336 let orig_value: u32 = match state.get(payload.get_name()) {
337 Ok(Some(v)) => v,
338 Ok(None) => {
339 return Err(ApplyError::InvalidTransaction(String::from(
340 "dec requires a set value",
341 )));
342 }
343 Err(err) => return Err(err),
344 };
345 if payload.get_value() > orig_value {
346 return Err(ApplyError::InvalidTransaction(String::from(
347 "Value is too large to dec",
348 )));
349 };
350 state.set(payload.get_name(), orig_value - payload.get_value())
351 }
352 }
353 }
354}