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  }