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  }