github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/perf/sawtooth_perf/src/batch_gen.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 18 //! Tools for generating signed batches from a stream of transactions 19 20 extern crate protobuf; 21 22 use std::error; 23 use std::fmt; 24 use std::io::Read; 25 use std::io::Write; 26 27 use self::protobuf::Message; 28 use sawtooth_sdk::messages::batch::Batch; 29 use sawtooth_sdk::messages::batch::BatchHeader; 30 use sawtooth_sdk::messages::transaction::Transaction; 31 32 use sawtooth_sdk::signing; 33 34 use source::LengthDelimitedMessageSource; 35 36 /// Generates signed batches from a stream of length-delimited transactions. 37 /// Constrains the batches to `max_batch_size` number of transactions per 38 /// batch. The resulting batches are written in a length-delimited fashion to 39 /// the given writer. 40 pub fn generate_signed_batches<'a>( 41 reader: &'a mut Read, 42 writer: &'a mut Write, 43 max_batch_size: usize, 44 signing_context: &signing::Context, 45 signing_key: &signing::PrivateKey, 46 ) -> Result<(), BatchingError> { 47 let crypto_factory = signing::CryptoFactory::new(signing_context); 48 let signer = crypto_factory.new_signer(signing_key); 49 50 let mut producer = SignedBatchProducer::new(reader, max_batch_size, &signer); 51 loop { 52 match producer.next() { 53 Some(Ok(batch)) => { 54 if let Err(err) = batch.write_length_delimited_to_writer(writer) { 55 return Err(BatchingError::MessageError(err)); 56 } 57 } 58 None => break, 59 Some(Err(err)) => return Err(err), 60 } 61 } 62 63 Ok(()) 64 } 65 66 type TransactionSource<'a> = LengthDelimitedMessageSource<'a, Transaction>; 67 68 /// Errors that may occur during the generation of batches. 69 #[derive(Debug)] 70 pub enum BatchingError { 71 MessageError(protobuf::ProtobufError), 72 SigningError(signing::Error), 73 } 74 75 impl From<signing::Error> for BatchingError { 76 fn from(err: signing::Error) -> Self { 77 BatchingError::SigningError(err) 78 } 79 } 80 81 impl From<protobuf::ProtobufError> for BatchingError { 82 fn from(err: protobuf::ProtobufError) -> Self { 83 BatchingError::MessageError(err) 84 } 85 } 86 87 impl fmt::Display for BatchingError { 88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 89 match *self { 90 BatchingError::MessageError(ref err) => { 91 write!(f, "Error occurred reading messages: {}", err) 92 } 93 BatchingError::SigningError(ref err) => write!(f, "Unable to sign batch: {}", err), 94 } 95 } 96 } 97 98 impl error::Error for BatchingError { 99 fn description(&self) -> &str { 100 match *self { 101 BatchingError::MessageError(ref err) => err.description(), 102 BatchingError::SigningError(ref err) => err.description(), 103 } 104 } 105 106 fn cause(&self) -> Option<&error::Error> { 107 match *self { 108 BatchingError::MessageError(ref err) => Some(err), 109 BatchingError::SigningError(ref err) => Some(err), 110 } 111 } 112 } 113 114 /// Produces signed batches from a length-delimited source of Transactions. 115 pub struct SignedBatchProducer<'a> { 116 transaction_source: TransactionSource<'a>, 117 max_batch_size: usize, 118 signer: &'a signing::Signer<'a>, 119 } 120 121 /// Resulting batch or error. 122 pub type BatchResult = Result<Batch, BatchingError>; 123 124 impl<'a> SignedBatchProducer<'a> { 125 /// Creates a new `SignedBatchProducer` with a given Transaction source and 126 /// a max number of transactions per batch. 127 pub fn new(source: &'a mut Read, max_batch_size: usize, signer: &'a signing::Signer) -> Self { 128 let transaction_source = LengthDelimitedMessageSource::new(source); 129 SignedBatchProducer { 130 transaction_source, 131 max_batch_size, 132 signer: signer, 133 } 134 } 135 } 136 137 impl<'a> Iterator for SignedBatchProducer<'a> { 138 type Item = BatchResult; 139 140 /// Gets the next BatchResult. 141 /// `Ok(None)` indicates that the underlying source has been consumed. 142 fn next(&mut self) -> Option<BatchResult> { 143 let txns = match self.transaction_source.next(self.max_batch_size) { 144 Ok(txns) => txns, 145 Err(err) => return Some(Err(BatchingError::MessageError(err))), 146 }; 147 if txns.is_empty() { 148 None 149 } else { 150 Some(batch_transactions(txns, self.signer)) 151 } 152 } 153 } 154 155 fn batch_transactions(txns: Vec<Transaction>, signer: &signing::Signer) -> BatchResult { 156 let mut batch_header = BatchHeader::new(); 157 158 // set signer_public_key 159 let pk = match signer.get_public_key() { 160 Ok(pk) => pk, 161 Err(err) => return Err(BatchingError::SigningError(err)), 162 }; 163 let public_key = pk.as_hex(); 164 165 let txn_ids = txns.iter() 166 .map(|txn| String::from(txn.get_header_signature())) 167 .collect(); 168 batch_header.set_transaction_ids(protobuf::RepeatedField::from_vec(txn_ids)); 169 batch_header.set_signer_public_key(public_key); 170 171 let header_bytes = batch_header.write_to_bytes()?; 172 let signature = signer 173 .sign(&header_bytes) 174 .map_err(BatchingError::SigningError); 175 match signature { 176 Ok(signature) => { 177 let mut batch = Batch::new(); 178 batch.set_header_signature(signature); 179 batch.set_header(header_bytes); 180 batch.set_transactions(protobuf::RepeatedField::from_vec(txns)); 181 182 Ok(batch) 183 } 184 Err(err) => Err(err), 185 } 186 } 187 188 pub struct SignedBatchIterator<'a> { 189 transaction_iterator: &'a mut Iterator<Item = Transaction>, 190 max_batch_size: usize, 191 signer: &'a signing::Signer<'a>, 192 } 193 194 impl<'a> SignedBatchIterator<'a> { 195 pub fn new( 196 iterator: &'a mut Iterator<Item = Transaction>, 197 max_batch_size: usize, 198 signer: &'a signing::Signer, 199 ) -> Self { 200 SignedBatchIterator { 201 transaction_iterator: iterator, 202 max_batch_size: max_batch_size, 203 signer: signer, 204 } 205 } 206 } 207 208 impl<'a> Iterator for SignedBatchIterator<'a> { 209 type Item = BatchResult; 210 211 fn next(&mut self) -> Option<Self::Item> { 212 let txns = self.transaction_iterator 213 .take(self.max_batch_size) 214 .collect(); 215 216 Some(batch_transactions(txns, self.signer)) 217 } 218 } 219 220 #[cfg(test)] 221 mod tests { 222 use super::protobuf; 223 use super::protobuf::Message; 224 use super::LengthDelimitedMessageSource; 225 use super::SignedBatchProducer; 226 use super::TransactionSource; 227 use sawtooth_sdk::messages::batch::{Batch, BatchHeader}; 228 use sawtooth_sdk::messages::transaction::{Transaction, TransactionHeader}; 229 use sawtooth_sdk::signing; 230 use std::io::{Cursor, Write}; 231 232 type BatchSource<'a> = LengthDelimitedMessageSource<'a, Batch>; 233 234 #[test] 235 fn empty_transaction_source() { 236 let encoded_bytes: Vec<u8> = Vec::new(); 237 let mut source = Cursor::new(encoded_bytes); 238 239 let mut txn_stream: TransactionSource = LengthDelimitedMessageSource::new(&mut source); 240 let txns = txn_stream.next(2).unwrap(); 241 assert_eq!(txns.len(), 0); 242 } 243 244 #[test] 245 fn next_transactions() { 246 let mut encoded_bytes: Vec<u8> = Vec::new(); 247 248 write_txn_with_sig("sig1", &mut encoded_bytes); 249 write_txn_with_sig("sig2", &mut encoded_bytes); 250 write_txn_with_sig("sig3", &mut encoded_bytes); 251 252 let mut source = Cursor::new(encoded_bytes); 253 254 let mut txn_stream: TransactionSource = LengthDelimitedMessageSource::new(&mut source); 255 256 let mut txns = txn_stream.next(2).unwrap(); 257 assert_eq!(txns.len(), 2); 258 259 // ensure that it is exhausted, even when more are requested 260 txns = txn_stream.next(2).unwrap(); 261 assert_eq!(txns.len(), 1); 262 } 263 264 #[test] 265 fn signed_batches_empty_transactions() { 266 let encoded_bytes: Vec<u8> = Vec::new(); 267 let mut source = Cursor::new(encoded_bytes); 268 269 let context = MockContext; 270 let crypto_factory = signing::CryptoFactory::new(&context); 271 let private_key = MockPrivateKey; 272 let signer = crypto_factory.new_signer(&private_key); 273 274 let mut producer = SignedBatchProducer::new(&mut source, 2, &signer); 275 let batch_result = producer.next(); 276 277 assert!(batch_result.is_none()); 278 } 279 280 #[test] 281 fn signed_batches_single_transaction() { 282 let mut encoded_bytes: Vec<u8> = Vec::new(); 283 write_txn_with_sig("sig1", &mut encoded_bytes); 284 285 let mut source = Cursor::new(encoded_bytes); 286 287 let context = MockContext; 288 let crypto_factory = signing::CryptoFactory::new(&context); 289 let private_key = MockPrivateKey; 290 let signer = crypto_factory.new_signer(&private_key); 291 292 let mut producer = SignedBatchProducer::new(&mut source, 2, &signer); 293 let mut batch_result = producer.next(); 294 assert!(batch_result.is_some()); 295 296 let batch = batch_result.unwrap().unwrap(); 297 298 let batch_header: BatchHeader = protobuf::parse_from_bytes(&batch.header).unwrap(); 299 assert_eq!(batch_header.transaction_ids.len(), 1); 300 assert_eq!(batch_header.transaction_ids[0], String::from("sig1")); 301 302 // test exhaustion 303 batch_result = producer.next(); 304 assert!(batch_result.is_none()); 305 } 306 307 #[test] 308 fn signed_batches_multiple_batches() { 309 let mut encoded_bytes: Vec<u8> = Vec::new(); 310 311 write_txn_with_sig("sig1", &mut encoded_bytes); 312 write_txn_with_sig("sig2", &mut encoded_bytes); 313 write_txn_with_sig("sig3", &mut encoded_bytes); 314 315 let mut source = Cursor::new(encoded_bytes); 316 317 let context = MockContext; 318 let crypto_factory = signing::CryptoFactory::new(&context); 319 let private_key = MockPrivateKey; 320 let signer = crypto_factory.new_signer(&private_key); 321 322 let mut producer = SignedBatchProducer::new(&mut source, 2, &signer); 323 let mut batch_result = producer.next(); 324 assert!(batch_result.is_some()); 325 326 let batch = batch_result.unwrap().unwrap(); 327 328 let batch_header: BatchHeader = protobuf::parse_from_bytes(&batch.header).unwrap(); 329 assert_eq!(batch_header.transaction_ids.len(), 2); 330 assert_eq!(batch_header.transaction_ids[0], String::from("sig1")); 331 assert_eq!(batch_header.transaction_ids[1], String::from("sig2")); 332 assert_eq!( 333 batch.header_signature, 334 String::from("signed by mock_algorithm") 335 ); 336 337 // pull the next batch 338 batch_result = producer.next(); 339 assert!(batch_result.is_some()); 340 341 let batch = batch_result.unwrap().unwrap(); 342 343 let batch_header: BatchHeader = protobuf::parse_from_bytes(&batch.header).unwrap(); 344 assert_eq!(batch_header.transaction_ids.len(), 1); 345 assert_eq!(batch_header.transaction_ids[0], String::from("sig3")); 346 347 // test exhaustion 348 batch_result = producer.next(); 349 assert!(batch_result.is_none()); 350 } 351 352 #[test] 353 fn generate_signed_batches() { 354 let mut encoded_bytes: Vec<u8> = Vec::new(); 355 356 write_txn_with_sig("sig1", &mut encoded_bytes); 357 write_txn_with_sig("sig2", &mut encoded_bytes); 358 write_txn_with_sig("sig3", &mut encoded_bytes); 359 360 let mut source = Cursor::new(encoded_bytes); 361 let output_bytes: Vec<u8> = Vec::new(); 362 let mut output = Cursor::new(output_bytes); 363 364 let context = MockContext; 365 let private_key = MockPrivateKey; 366 367 super::generate_signed_batches(&mut source, &mut output, 2, &context, &private_key) 368 .expect("Should have generated batches!"); 369 370 // reset for reading 371 output.set_position(0); 372 let mut batch_source: BatchSource = LengthDelimitedMessageSource::new(&mut output); 373 374 let batch = &(batch_source.next(1).unwrap())[0]; 375 let batch_header: BatchHeader = protobuf::parse_from_bytes(&batch.header).unwrap(); 376 assert_eq!(batch_header.transaction_ids.len(), 2); 377 assert_eq!(batch_header.transaction_ids[0], String::from("sig1")); 378 assert_eq!(batch_header.transaction_ids[1], String::from("sig2")); 379 380 let batch = &(batch_source.next(1).unwrap())[0]; 381 let batch_header: BatchHeader = protobuf::parse_from_bytes(&batch.header).unwrap(); 382 assert_eq!(batch_header.transaction_ids.len(), 1); 383 assert_eq!(batch_header.transaction_ids[0], String::from("sig3")); 384 } 385 386 fn make_txn(sig: &str) -> Transaction { 387 let mut txn_header = TransactionHeader::new(); 388 389 txn_header.set_batcher_public_key(String::from("some_public_key")); 390 txn_header.set_family_name(String::from("test_family")); 391 txn_header.set_family_version(String::from("1.0")); 392 txn_header.set_signer_public_key(String::from("some_public_key")); 393 txn_header.set_payload_sha512(String::from("some_sha512_hash")); 394 395 let mut txn = Transaction::new(); 396 txn.set_header(txn_header.write_to_bytes().unwrap()); 397 txn.set_header_signature(String::from(sig)); 398 txn.set_payload(sig.as_bytes().to_vec()); 399 400 txn 401 } 402 403 fn write_txn_with_sig(sig: &str, out: &mut Write) { 404 let txn = make_txn(sig); 405 txn.write_length_delimited_to_writer(out) 406 .expect("Unable to write delimiter"); 407 } 408 409 struct MockContext; 410 411 impl signing::Context for MockContext { 412 fn get_algorithm_name(&self) -> &str { 413 "mock_algorithm" 414 } 415 416 fn sign( 417 &self, 418 _message: &[u8], 419 _key: &signing::PrivateKey, 420 ) -> Result<String, signing::Error> { 421 Ok(String::from("signed by mock_algorithm")) 422 } 423 424 fn verify( 425 &self, 426 _signature: &str, 427 _message: &[u8], 428 _key: &signing::PublicKey, 429 ) -> Result<bool, signing::Error> { 430 Ok(true) 431 } 432 433 fn get_public_key( 434 &self, 435 _private_key: &signing::PrivateKey, 436 ) -> Result<Box<signing::PublicKey>, signing::Error> { 437 Ok(Box::new(MockPublicKey)) 438 } 439 440 fn new_random_private_key(&self) -> Result<Box<signing::PrivateKey>, signing::Error> { 441 Ok(Box::new(MockPrivateKey)) 442 } 443 } 444 445 struct MockPublicKey; 446 447 impl signing::PublicKey for MockPublicKey { 448 fn get_algorithm_name(&self) -> &str { 449 "mock_algorithm" 450 } 451 452 fn as_hex(&self) -> String { 453 String::from("123456789abcdef") 454 } 455 456 fn as_slice(&self) -> &[u8] { 457 "123456789abcdef".as_bytes() 458 } 459 } 460 461 struct MockPrivateKey; 462 463 impl signing::PrivateKey for MockPrivateKey { 464 fn get_algorithm_name(&self) -> &str { 465 "mock_algorithm" 466 } 467 468 fn as_hex(&self) -> String { 469 String::from("123456789abcdef123456789abcdef") 470 } 471 472 fn as_slice(&self) -> &[u8] { 473 "123456789abcdef123456789abcdef".as_bytes() 474 } 475 } 476 }