github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/perf/intkey_workload/src/main.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  
    18  extern crate cbor;
    19  extern crate clap;
    20  extern crate crypto;
    21  extern crate protobuf;
    22  extern crate rand;
    23  extern crate sawtooth_perf;
    24  extern crate sawtooth_sdk;
    25  extern crate simplelog;
    26  
    27  mod intkey_addresser;
    28  mod intkey_iterator;
    29  mod intkey_transformer;
    30  
    31  use std::convert::From;
    32  use std::error::Error;
    33  use std::fmt;
    34  use std::fs::File;
    35  use std::io::Read;
    36  use std::num::ParseFloatError;
    37  use std::num::ParseIntError;
    38  use std::str::Split;
    39  
    40  use clap::{App, Arg, ArgMatches};
    41  
    42  use rand::{Rng, StdRng};
    43  
    44  use sawtooth_perf::batch_gen::SignedBatchIterator;
    45  use sawtooth_perf::batch_submit::run_workload;
    46  use sawtooth_perf::batch_submit::InfiniteBatchListIterator;
    47  
    48  use sawtooth_sdk::signing;
    49  use sawtooth_sdk::signing::secp256k1::Secp256k1PrivateKey;
    50  
    51  use simplelog::{Config, LevelFilter, SimpleLogger};
    52  
    53  use intkey_iterator::IntKeyIterator;
    54  use intkey_transformer::IntKeyTransformer;
    55  
    56  const APP_NAME: &str = env!("CARGO_PKG_NAME");
    57  const VERSION: &str = env!("CARGO_PKG_VERSION");
    58  
    59  fn main() {
    60      match SimpleLogger::init(LevelFilter::Warn, Config::default()) {
    61          Ok(_) => (),
    62          Err(err) => println!("Failed to load logger: {}", err.description()),
    63      }
    64  
    65      let arg_matches = get_arg_matches();
    66  
    67      match run_load_command(&arg_matches) {
    68          Ok(_) => (),
    69          Err(err) => println!("{}", err.description()),
    70      }
    71  }
    72  
    73  fn get_arg_matches<'a>() -> ArgMatches<'a> {
    74      App::new(APP_NAME)
    75          .version(VERSION)
    76          .about("Submit intkey workload at a continuous rate")
    77          .arg(
    78              Arg::with_name("display")
    79                  .long("display")
    80                  .takes_value(true)
    81                  .number_of_values(1)
    82                  .default_value("30")
    83                  .value_name("TIME_BETWEEN_DISPLAYS")
    84                  .help("Seconds between statistics displays"),
    85          )
    86          .arg(
    87              Arg::with_name("key")
    88                  .short("k")
    89                  .long("key-file")
    90                  .value_name("KEY_FILE")
    91                  .help("File containing a private key to sign transactions and batches"),
    92          )
    93          .arg(
    94              Arg::with_name("batch-size")
    95                  .short("n")
    96                  .long("batch-size")
    97                  .takes_value(true)
    98                  .default_value("1")
    99                  .number_of_values(1)
   100                  .value_name("BATCH_SIZE")
   101                  .help("Transactions in a batch"),
   102          )
   103          .arg(
   104              Arg::with_name("names")
   105                  .long("num-names")
   106                  .takes_value(true)
   107                  .default_value("100")
   108                  .number_of_values(1)
   109                  .value_name("NUM_NAMES")
   110                  .help("Number of IntKey Names to set"),
   111          )
   112          .arg(
   113              Arg::with_name("rate")
   114                  .short("r")
   115                  .long("rate")
   116                  .takes_value(true)
   117                  .number_of_values(1)
   118                  .default_value("10")
   119                  .value_name("RATE")
   120                  .help("Batches per second to send to a Sawtooth REST Api"),
   121          )
   122          .arg(
   123              Arg::with_name("seed")
   124                  .short("s")
   125                  .long("seed")
   126                  .takes_value(true)
   127                  .number_of_values(1)
   128                  .value_name("SEED")
   129                  .help("Comma separated list of u8 to make the workload reproduceable"),
   130          )
   131          .arg(
   132              Arg::with_name("unnecessary")
   133                  .long("unnecessary")
   134                  .takes_value(true)
   135                  .number_of_values(1)
   136                  .default_value("0.0")
   137                  .value_name("UNNECESSARY")
   138                  .help("Probability of a transaction having a satisfiable but unnecessary depedendency"),
   139          )
   140          .arg(
   141              Arg::with_name("unsatisfiable")
   142                  .long("unsatisfiable")
   143                  .takes_value(true)
   144                  .number_of_values(1)
   145                  .default_value("0.0")
   146                  .value_name("UNSATISFIABLE")
   147                  .help("Probability of a transaction having an unsatisfiable dependency"),
   148          )
   149          .arg(
   150              Arg::with_name("urls")
   151                  .short("u")
   152                  .long("urls")
   153                  .value_name("URLS")
   154                  .takes_value(true)
   155                  .number_of_values(1)
   156                  .default_value("http://127.0.0.1:8008")
   157                  .help("Comma separated list of Sawtooth REST Apis"),
   158          )
   159          .arg(
   160              Arg::with_name("invalid")
   161                  .long("invalid")
   162                  .value_name("INVALID")
   163                  .takes_value(true)
   164                  .number_of_values(1)
   165                  .default_value("0.0")
   166                  .help("Probability of a transaction being invalid"),
   167          )
   168          .arg(
   169              Arg::with_name("wildcard")
   170                  .long("wildcard")
   171                  .value_name("WILDCARD")
   172                  .takes_value(true)
   173                  .number_of_values(1)
   174                  .default_value("0.0")
   175                  .help("Probability of a transaction having a wildcarded input/output"),
   176          )
   177          .arg(
   178              Arg::with_name("username")
   179                  .long("auth-username")
   180                  .value_name("BASIC_AUTH_USERNAME")
   181                  .help("Basic auth username to authenticate with the Sawtooth REST Api"),
   182          )
   183          .arg(
   184              Arg::with_name("password")
   185                  .long("auth-password")
   186                  .value_name("BASIC_AUTH_PASSWORD")
   187                  .help("Basic auth password to authenticate with the Sawtooth REST Api"),
   188          )
   189          .get_matches()
   190  }
   191  
   192  fn err_if_out_of_range(val: f32) -> Result<f32, IntKeyCliError> {
   193      if val < 0.0 || val > 1.0 {
   194          return Err(IntKeyCliError {
   195              msg: "Value must be between 0.0 and 1.0, inclusively".to_string(),
   196          });
   197      }
   198      Ok(val)
   199  }
   200  
   201  fn greater_than_zero32(val: u32) -> Result<u32, IntKeyCliError> {
   202      if val == 0 {
   203          return Err(IntKeyCliError {
   204              msg: "Value must be greater than zero".to_string(),
   205          });
   206      }
   207      Ok(val)
   208  }
   209  
   210  fn greater_than_zero(val: usize) -> Result<usize, IntKeyCliError> {
   211      if val == 0 {
   212          return Err(IntKeyCliError {
   213              msg: "Value must be greater than zero".to_string(),
   214          });
   215      }
   216      Ok(val)
   217  }
   218  
   219  fn run_load_command(args: &ArgMatches) -> Result<(), Box<Error>> {
   220      let batch_size: usize = args.value_of("batch-size")
   221          .unwrap_or("1")
   222          .parse()
   223          .map_err(IntKeyCliError::from)
   224          .and_then(greater_than_zero)?;
   225  
   226      let num_names: usize = args.value_of("names")
   227          .unwrap_or("100")
   228          .parse()
   229          .map_err(IntKeyCliError::from)
   230          .and_then(greater_than_zero)?;
   231  
   232      let urls: Vec<String> = args.value_of("urls")
   233          .unwrap_or("http://127.0.0.1:8008")
   234          .parse()
   235          .map_err(|_| String::from("urls are a comma separated list of strings"))
   236          .and_then(|st| {
   237              let s: String = st;
   238              let split: Split<char> = s.split(',');
   239              Ok(split.map(|s| s.to_string()).collect())
   240          })?;
   241  
   242      let rate: usize = args.value_of("rate")
   243          .unwrap_or("10")
   244          .parse()
   245          .map_err(IntKeyCliError::from)
   246          .and_then(greater_than_zero)?;
   247  
   248      let unsatisfiable: f32 = args.value_of("unsatisfiable")
   249          .unwrap_or("0.0")
   250          .parse()
   251          .map_err(IntKeyCliError::from)
   252          .and_then(err_if_out_of_range)?;
   253  
   254      let unnecessary: f32 = args.value_of("unnecessary")
   255          .unwrap_or("0.0")
   256          .parse()
   257          .map_err(IntKeyCliError::from)
   258          .and_then(err_if_out_of_range)?;
   259  
   260      let wildcard: f32 = args.value_of("wildcard")
   261          .unwrap_or("0.0")
   262          .parse()
   263          .map_err(IntKeyCliError::from)
   264          .and_then(err_if_out_of_range)?;
   265  
   266      let invalid: f32 = args.value_of("invalid")
   267          .unwrap_or("0.0")
   268          .parse()
   269          .map_err(IntKeyCliError::from)
   270          .and_then(err_if_out_of_range)?;
   271  
   272      let display: u32 = args.value_of("display")
   273          .unwrap_or("30")
   274          .parse()
   275          .map_err(IntKeyCliError::from)
   276          .and_then(greater_than_zero32)?;
   277  
   278      let username = args.value_of("username");
   279      let password = args.value_of("password");
   280  
   281      let basic_auth = {
   282          match username {
   283              Some(username) => match password {
   284                  None => Some(String::from(username)),
   285                  Some(password) => Some([username, password].join(":")),
   286              },
   287              None => None,
   288          }
   289      };
   290      let s: Result<Vec<usize>, std::num::ParseIntError> = match args.value_of("seed") {
   291          Some(s) => {
   292              let split: Split<char> = s.split(',');
   293              split.map(|s| s.parse()).collect()
   294          }
   295          None => {
   296              let mut rng = StdRng::new()?;
   297  
   298              Ok(rng.gen_iter().take(10).collect())
   299          }
   300      };
   301  
   302      let seed = s?;
   303  
   304      let context = signing::create_context("secp256k1")?;
   305  
   306      let private_key: Result<Box<signing::PrivateKey>, Box<Error>> = match args.value_of("key") {
   307          Some(file) => {
   308              let mut key_file = File::open(file)?;
   309              let mut buf = String::new();
   310              key_file.read_to_string(&mut buf)?;
   311              buf.pop(); // remove the new line
   312              let private_key = Secp256k1PrivateKey::from_hex(&buf)?;
   313              Ok(Box::new(private_key))
   314          }
   315          None => {
   316              let private_key = context.new_random_private_key()?;
   317              Ok(private_key)
   318          }
   319      };
   320  
   321      let priv_key = private_key?;
   322  
   323      let signer = signing::Signer::new(context.as_ref(), priv_key.as_ref());
   324  
   325      let signer_ref = &signer;
   326  
   327      let mut transformer = IntKeyTransformer::new(
   328          signer_ref,
   329          &seed,
   330          unsatisfiable,
   331          wildcard,
   332          num_names,
   333          unnecessary,
   334      );
   335  
   336      let mut transaction_iterator = IntKeyIterator::new(num_names, invalid, &seed)
   337          .map(|payload| transformer.intkey_payload_to_transaction(&payload))
   338          .filter_map(|payload| payload.ok());
   339      let mut batch_iter =
   340          SignedBatchIterator::new(&mut transaction_iterator, batch_size, signer_ref);
   341      let mut batchlist_iter = InfiniteBatchListIterator::new(&mut batch_iter);
   342  
   343      let time_to_wait: u32 = 1_000_000_000 / rate as u32;
   344  
   345      println!("--invalid {} --batch-size {} --rate {} --wildcard {} --urls {:?} --unsatisfiable {} --seed {:?} --num-names {} --display {}",
   346          invalid,
   347          batch_size,
   348          rate,
   349          wildcard,
   350          urls,
   351          unsatisfiable,
   352          seed,
   353          num_names,
   354          display);
   355  
   356      match run_workload(
   357          &mut batchlist_iter,
   358          time_to_wait,
   359          display,
   360          urls,
   361          &basic_auth,
   362      ) {
   363          Ok(_) => Ok(()),
   364          Err(err) => Err(Box::new(err)),
   365      }
   366  }
   367  
   368  #[derive(Debug)]
   369  struct IntKeyCliError {
   370      msg: String,
   371  }
   372  
   373  impl Error for IntKeyCliError {
   374      fn description(&self) -> &str {
   375          self.msg.as_str()
   376      }
   377  }
   378  
   379  impl fmt::Display for IntKeyCliError {
   380      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   381          write!(f, "{}", format!("IntKeyCliError {}", self.msg))
   382      }
   383  }
   384  
   385  impl From<ParseIntError> for IntKeyCliError {
   386      fn from(error: ParseIntError) -> Self {
   387          IntKeyCliError {
   388              msg: error.description().to_string(),
   389          }
   390      }
   391  }
   392  
   393  impl From<ParseFloatError> for IntKeyCliError {
   394      fn from(error: ParseFloatError) -> Self {
   395          IntKeyCliError {
   396              msg: error.description().to_string(),
   397          }
   398      }
   399  }