github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/perf/sawtooth_workload/src/main.rs (about) 1 /* 2 * Copyright 2017 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 extern crate clap; 18 extern crate protobuf; 19 extern crate sawtooth_perf; 20 extern crate sawtooth_sdk; 21 22 use std::error::Error; 23 use std::fs::File; 24 use std::io::Read; 25 26 use batch_gen::generate_signed_batches; 27 use batch_submit::submit_signed_batches; 28 use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; 29 30 use sawtooth_perf::batch_gen; 31 use sawtooth_perf::batch_submit; 32 33 use sawtooth_sdk::signing; 34 use sawtooth_sdk::signing::secp256k1::Secp256k1PrivateKey; 35 36 const APP_NAME: &str = env!("CARGO_PKG_NAME"); 37 const VERSION: &str = env!("CARGO_PKG_VERSION"); 38 39 fn main() { 40 let arg_matches = App::new(APP_NAME) 41 .version(VERSION) 42 .setting(AppSettings::SubcommandRequiredElseHelp) 43 .subcommand(create_batch_subcommand_args()) 44 .subcommand(create_submit_subcommand_args()) 45 .get_matches(); 46 47 let result = match arg_matches.subcommand() { 48 ("batch", Some(args)) => run_batch_command(args), 49 ("submit", Some(args)) => run_submit_command(args), 50 _ => panic!("Should have processed a subcommand or exited before here"), 51 }; 52 53 std::process::exit(match result { 54 Ok(_) => 0, 55 Err(err) => { 56 eprintln!("Error: {}", err); 57 1 58 } 59 }); 60 } 61 62 #[inline] 63 fn arg_error(msg: &str) -> Result<(), Box<Error>> { 64 Err(Box::new(CliError::ArgumentError(String::from(msg)))) 65 } 66 67 fn create_batch_subcommand_args<'a, 'b>() -> App<'a, 'b> { 68 SubCommand::with_name("batch") 69 .about( 70 "Generates signed batches from transaction input.\n \ 71 The transaction input is expected to be length-delimited protobuf \ 72 Transaction messages, which should also be pre-signed for \ 73 submission to the validator.", 74 ) 75 .arg( 76 Arg::with_name("input") 77 .short("i") 78 .long("input") 79 .value_name("FILE") 80 .required(true) 81 .help("The source of input transactions"), 82 ) 83 .arg( 84 Arg::with_name("output") 85 .short("o") 86 .long("output") 87 .value_name("FILE") 88 .required(true) 89 .help("The target for the signed batches"), 90 ) 91 .arg( 92 Arg::with_name("key") 93 .short("k") 94 .long("key") 95 .value_name("FILE") 96 .required(true) 97 .help("The signing key for the transactions"), 98 ) 99 .arg( 100 Arg::with_name("max-batch-size") 101 .short("n") 102 .long("max-batch-size") 103 .value_name("NUMBER") 104 .help( 105 "The maximum number of transactions to include in a batch; \ 106 Defaults to 100.", 107 ), 108 ) 109 } 110 111 fn run_batch_command(args: &ArgMatches) -> Result<(), Box<Error>> { 112 let max_txns: usize = match args.value_of("max-batch-size").unwrap_or("100").parse() { 113 Ok(n) => n, 114 Err(_) => 0, 115 }; 116 117 if max_txns == 0 { 118 return arg_error("max-batch-size must be a number greater than 0"); 119 } 120 121 let mut in_file = File::open(args.value_of("input").unwrap())?; 122 let mut out_file = File::create(args.value_of("output").unwrap())?; 123 124 let mut key_file = try!(File::open(args.value_of("key").unwrap())); 125 126 let mut buf = String::new(); 127 try!(key_file.read_to_string(&mut buf)); 128 buf.pop(); // remove the new line 129 130 let private_key = try!(Secp256k1PrivateKey::from_hex(&buf)); 131 let context = try!(signing::create_context("secp256k1")); 132 133 if let Err(err) = generate_signed_batches( 134 &mut in_file, 135 &mut out_file, 136 max_txns, 137 context.as_ref(), 138 &private_key, 139 ) { 140 return Err(Box::new(err)); 141 } 142 143 Ok(()) 144 } 145 146 fn create_submit_subcommand_args<'a, 'b>() -> App<'a, 'b> { 147 SubCommand::with_name("submit") 148 .about( 149 "Submits signed batches to one or more targets from batch input.\n \ 150 The batch input is expected to be length-delimited protobuf \ 151 Batch messages, which should also be pre-signed for \ 152 submission to the validator.", 153 ) 154 .arg( 155 Arg::with_name("input") 156 .short("i") 157 .long("input") 158 .value_name("FILE") 159 .help("The source of batch transactions"), 160 ) 161 .arg( 162 Arg::with_name("target") 163 .short("t") 164 .long("target") 165 .value_name("TARGET") 166 .help("A Sawtooth REST API endpoint"), 167 ) 168 .arg( 169 Arg::with_name("rate") 170 .short("r") 171 .long("rate") 172 .value_name("RATE") 173 .help("The number of batches per second to submit to the target"), 174 ) 175 } 176 177 fn run_submit_command(args: &ArgMatches) -> Result<(), Box<Error>> { 178 let rate: usize = match args.value_of("rate").unwrap_or("1").parse() { 179 Ok(n) => n, 180 Err(_) => 0, 181 }; 182 183 if rate == 0 { 184 return arg_error("rate must be a number greater than 0"); 185 } 186 187 let target: String = match args.value_of("target") 188 .unwrap_or("http://localhost:8008") 189 .parse() 190 { 191 Ok(s) => s, 192 Err(_) => String::new(), 193 }; 194 195 if target == "" { 196 return arg_error("target must be a valid http uri"); 197 } 198 199 let input: String = match args.value_of("input").unwrap_or("").parse() { 200 Ok(s) => s, 201 Err(_) => String::new(), 202 }; 203 204 if input == "" { 205 return arg_error("an input file must be specified"); 206 } 207 208 let mut in_file = File::open(args.value_of("input").unwrap())?; 209 210 println!("Input: {} Target: {} Rate: {}", input, target, rate); 211 212 if let Err(err) = submit_signed_batches(&mut in_file, target, rate) { 213 return Err(Box::new(err)); 214 } 215 216 Ok(()) 217 } 218 219 #[derive(Debug)] 220 enum CliError { 221 ArgumentError(String), 222 } 223 224 impl std::fmt::Display for CliError { 225 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 226 match *self { 227 CliError::ArgumentError(ref msg) => write!(f, "ArgumentError: {}", msg), 228 } 229 } 230 } 231 232 impl std::error::Error for CliError { 233 fn description(&self) -> &str { 234 match *self { 235 CliError::ArgumentError(ref msg) => msg, 236 } 237 } 238 239 fn cause(&self) -> Option<&Error> { 240 match *self { 241 CliError::ArgumentError(_) => None, 242 } 243 } 244 }