sawtooth_intkey/
handler.rs

1/*
2 * Copyright 2017 Bitwise IO, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 * -----------------------------------------------------------------------------
16 */
17
18use 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}