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 }