github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/validator/src/state/settings_view.rs (about) 1 /* 2 * Copyright 2018 Intel Corporation 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 use std::iter::repeat; 18 use std::num::ParseIntError; 19 20 use crypto::digest::Digest; 21 use crypto::sha2::Sha256; 22 use protobuf; 23 24 use state::StateDatabaseError; 25 use state::StateReader; 26 27 use proto::setting::Setting; 28 29 const CONFIG_STATE_NAMESPACE: &str = "000000"; 30 const MAX_KEY_PARTS: usize = 4; 31 const ADDRESS_PART_SIZE: usize = 16; 32 33 #[derive(Debug)] 34 pub enum SettingsViewError { 35 StateDatabaseError(StateDatabaseError), 36 EncodingError(protobuf::ProtobufError), 37 38 ParseError(String), 39 ParseIntError(ParseIntError), 40 UnknownError, 41 } 42 43 impl From<StateDatabaseError> for SettingsViewError { 44 fn from(err: StateDatabaseError) -> Self { 45 SettingsViewError::StateDatabaseError(err) 46 } 47 } 48 49 impl From<protobuf::ProtobufError> for SettingsViewError { 50 fn from(err: protobuf::ProtobufError) -> Self { 51 SettingsViewError::EncodingError(err) 52 } 53 } 54 55 impl From<ParseIntError> for SettingsViewError { 56 fn from(err: ParseIntError) -> Self { 57 SettingsViewError::ParseIntError(err) 58 } 59 } 60 61 pub struct SettingsView<R> 62 where 63 R: StateReader, 64 { 65 state_reader: R, 66 } 67 68 impl<R> SettingsView<R> 69 where 70 R: StateReader, 71 { 72 /// Creates a new SettingsView with a given StateReader 73 pub fn new(state_reader: R) -> Self { 74 SettingsView { state_reader } 75 } 76 77 pub fn get_setting_str( 78 &self, 79 key: &str, 80 default_value: Option<String>, 81 ) -> Result<Option<String>, SettingsViewError> { 82 self.get_setting(key, default_value, |s: &str| Ok(s.to_string())) 83 } 84 85 pub fn get_setting_u32( 86 &self, 87 key: &str, 88 default_value: Option<u32>, 89 ) -> Result<Option<u32>, SettingsViewError> { 90 self.get_setting(key, default_value, |value| { 91 value.parse().map_err(SettingsViewError::ParseIntError) 92 }) 93 } 94 95 pub fn get_setting<T, F>( 96 &self, 97 key: &str, 98 default_value: Option<T>, 99 value_parser: F, 100 ) -> Result<Option<T>, SettingsViewError> 101 where 102 F: FnOnce(&str) -> Result<T, SettingsViewError>, 103 { 104 self.state_reader 105 .get(&setting_address(key)) 106 .map_err(SettingsViewError::from) 107 .and_then(|bytes_opt: Option<Vec<u8>>| { 108 Ok(if let Some(bytes) = bytes_opt { 109 Some(protobuf::parse_from_bytes::<Setting>(&bytes)?) 110 } else { 111 None 112 }) 113 }) 114 .and_then(|setting_opt: Option<Setting>| { 115 if let Some(setting) = setting_opt { 116 for setting_entry in setting.get_entries() { 117 if setting_entry.get_key() == key { 118 let parsed_value = value_parser(&setting_entry.get_value())?; 119 return Ok(Some(parsed_value)); 120 } 121 } 122 } 123 Ok(default_value) 124 }) 125 } 126 } 127 128 fn setting_address(key: &str) -> String { 129 let mut address = String::new(); 130 address.push_str(CONFIG_STATE_NAMESPACE); 131 address.push_str(&key.splitn(MAX_KEY_PARTS, ".") 132 .chain(repeat("")) 133 .map(short_hash) 134 .take(MAX_KEY_PARTS) 135 .collect::<Vec<_>>() 136 .join("")); 137 138 address 139 } 140 141 fn short_hash(s: &str) -> String { 142 let mut sha = Sha256::new(); 143 sha.input(s.as_bytes()); 144 sha.result_str()[..ADDRESS_PART_SIZE].to_string() 145 } 146 147 #[cfg(test)] 148 mod tests { 149 use super::*; 150 use proto::setting::Setting; 151 use proto::setting::Setting_Entry; 152 use protobuf; 153 use protobuf::Message; 154 use state::StateDatabaseError; 155 use state::StateReader; 156 use std::collections::HashMap; 157 158 #[test] 159 fn addresses() { 160 // These addresses were generated via the python implementation 161 assert_eq!( 162 "000000ca978112ca1bbdca3e23e8160039594a2e7d2c03a9507ae2e3b0c44298fc1c14", 163 setting_address("a.b.c") 164 ); 165 assert_eq!( 166 "000000ca978112ca1bbdca3e23e8160039594a2e7d2c03a9507ae2e67adc8234459dc2", 167 setting_address("a.b.c.d.e") 168 ); 169 assert_eq!( 170 "000000a87cb5eafdcca6a8c983c585ac3c40d9b1eb2ec8ac9f31ffe3b0c44298fc1c14", 171 setting_address("sawtooth.consensus.algorithm") 172 ); 173 } 174 175 #[test] 176 fn basics() { 177 let mock_reader = MockStateReader::new(vec![ 178 setting_entry("my.setting", "10"), 179 setting_entry("my.setting.list", "10,11,12"), 180 setting_entry("my.other.list", "13;14;15"), 181 ]); 182 183 let settings_view = SettingsView::new(mock_reader); 184 185 // Test not founds 186 assert_eq!( 187 None, 188 settings_view 189 .get_setting_str("some.nonexistent.setting", None) 190 .unwrap() 191 ); 192 assert_eq!( 193 Some("default".to_string()), 194 settings_view 195 .get_setting_str("some.nonexistent.setting", Some("default".to_string())) 196 .unwrap() 197 ); 198 199 // return setting values 200 assert_eq!( 201 Some("10".to_string()), 202 settings_view.get_setting_str("my.setting", None).unwrap() 203 ); 204 assert_eq!( 205 Some(10), 206 settings_view.get_setting_u32("my.setting", None).unwrap() 207 ); 208 209 // Test with advanced parsing 210 assert_eq!( 211 Some(vec![10, 11, 12]), 212 settings_view 213 .get_setting("my.setting.list", None, |value| { 214 value 215 .split(',') 216 .map(|s| s.parse().map_err(SettingsViewError::ParseIntError)) 217 .collect::<Result<Vec<u32>, SettingsViewError>>() 218 }) 219 .unwrap() 220 ); 221 222 assert_eq!( 223 Some(vec![13, 14, 15]), 224 settings_view 225 .get_setting("my.other.list", None, |value| { 226 value 227 .split(';') 228 .map(|s| s.parse().map_err(SettingsViewError::ParseIntError)) 229 .collect::<Result<Vec<u32>, SettingsViewError>>() 230 }) 231 .unwrap() 232 ); 233 234 // Verify that we still return the default 235 assert_eq!( 236 Some(vec![]), 237 settings_view 238 .get_setting("some.nonexistent.setting", Some(vec![]), |value| { 239 value 240 .split(',') 241 .map(|s| s.parse().map_err(SettingsViewError::ParseIntError)) 242 .collect::<Result<Vec<u32>, SettingsViewError>>() 243 }) 244 .unwrap() 245 ); 246 } 247 248 fn setting_entry(key: &str, value: &str) -> (String, Vec<u8>) { 249 let mut setting = Setting::new(); 250 let mut setting_entry = Setting_Entry::new(); 251 setting_entry.set_key(key.into()); 252 setting_entry.set_value(value.into()); 253 254 setting.set_entries(protobuf::RepeatedField::from_vec(vec![setting_entry])); 255 256 ( 257 setting_address(key), 258 setting 259 .write_to_bytes() 260 .expect("Unable to serialize setting"), 261 ) 262 } 263 264 struct MockStateReader { 265 state: HashMap<String, Vec<u8>>, 266 } 267 268 impl MockStateReader { 269 fn new(values: Vec<(String, Vec<u8>)>) -> Self { 270 MockStateReader { 271 state: values.into_iter().collect(), 272 } 273 } 274 } 275 276 impl StateReader for MockStateReader { 277 fn get(&self, address: &str) -> Result<Option<Vec<u8>>, StateDatabaseError> { 278 Ok(self.state.get(address).cloned()) 279 } 280 281 fn contains(&self, address: &str) -> Result<bool, StateDatabaseError> { 282 Ok(self.state.contains_key(address)) 283 } 284 285 fn leaves( 286 &self, 287 prefix: Option<&str>, 288 ) -> Result< 289 Box<Iterator<Item = Result<(String, Vec<u8>), StateDatabaseError>>>, 290 StateDatabaseError, 291 > { 292 let iterable: Vec<_> = self.state 293 .iter() 294 .filter(|(key, _)| key.starts_with(prefix.unwrap_or(""))) 295 .map(|(key, value)| Ok((key.clone().to_string(), value.clone()))) 296 .collect(); 297 298 Ok(Box::new(iterable.into_iter())) 299 } 300 } 301 302 }