github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/adm/src/commands/genesis.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  use std::fs::{File, OpenOptions};
    19  use std::io::{Read, Write};
    20  use std::os::unix::fs::OpenOptionsExt;
    21  use std::path::Path;
    22  
    23  use clap::ArgMatches;
    24  use protobuf;
    25  use protobuf::Message;
    26  
    27  use sawtooth_sdk::messages::batch::{Batch, BatchList};
    28  use sawtooth_sdk::messages::genesis::GenesisData;
    29  use sawtooth_sdk::messages::transaction::TransactionHeader;
    30  
    31  use config;
    32  use err::CliError;
    33  
    34  pub fn run<'a>(args: &ArgMatches<'a>) -> Result<(), CliError> {
    35      let genesis_file_path = if args.is_present("output") {
    36          args.value_of("output")
    37              .ok_or_else(|| CliError::ArgumentError(format!("Failed to read `output` arg")))
    38              .map(|pathstr| Path::new(pathstr).to_path_buf())
    39      } else {
    40          Ok(config::get_path_config().data_dir.join("genesis.batch"))
    41      }?;
    42  
    43      if genesis_file_path.exists() {
    44          return Err(CliError::EnvironmentError(format!(
    45              "File already exists: {:?}",
    46              genesis_file_path
    47          )));
    48      }
    49  
    50      let input_files = args.values_of("input_file")
    51          .ok_or_else(|| CliError::ArgumentError("No input files passed".into()))?;
    52  
    53      let batch_lists = input_files
    54          .map(|filepath| {
    55              let mut file = File::open(filepath).map_err(|err| {
    56                  CliError::EnvironmentError(format!("Failed to open file: {}", err))
    57              })?;
    58              let mut packed = Vec::new();
    59              file.read_to_end(&mut packed).map_err(|err| {
    60                  CliError::EnvironmentError(format!("Failed to read file: {}", err))
    61              })?;
    62              let batch_list: BatchList = protobuf::parse_from_bytes(&packed).map_err(|err| {
    63                  CliError::ArgumentError(format!("Unable to read {}: {}", filepath, err))
    64              })?;
    65              Ok(batch_list)
    66          })
    67          .collect::<Result<Vec<BatchList>, CliError>>()?;
    68  
    69      let batches = batch_lists
    70          .into_iter()
    71          .fold(Vec::new(), |mut batches, batch_list| {
    72              batches.extend(batch_list.batches.into_iter());
    73              batches
    74          });
    75  
    76      validate_depedencies(&batches)?;
    77  
    78      let mut genesis_data = GenesisData::new();
    79      genesis_data.set_batches(protobuf::RepeatedField::from_vec(batches));
    80  
    81      let buf = genesis_data.write_to_bytes().map_err(|err| {
    82          CliError::ArgumentError(format!(
    83              "Failed to convert BatchLists to GenesisData: {}",
    84              err
    85          ))
    86      })?;
    87  
    88      let mut genesis_data_file = OpenOptions::new()
    89          .write(true)
    90          .create(true)
    91          .mode(0o640)
    92          .open(genesis_file_path.as_path())
    93          .map_err(|err| CliError::EnvironmentError(format!("{}", err)))?;
    94  
    95      genesis_data_file
    96          .write(&buf)
    97          .map_err(|err| CliError::EnvironmentError(format!("{}", err)))?;
    98  
    99      Ok(())
   100  }
   101  
   102  fn validate_depedencies(batches: &[Batch]) -> Result<(), CliError> {
   103      let mut txn_ids: Vec<String> = Vec::new();
   104      for batch in batches.iter() {
   105          for txn in batch.transactions.iter() {
   106              let header: TransactionHeader =
   107                  protobuf::parse_from_bytes(&txn.header).map_err(|err| {
   108                      CliError::ArgumentError(format!(
   109                          "Invalid transaction header for txn {}: {}",
   110                          &txn.header_signature, err
   111                      ))
   112                  })?;
   113              for dep in header.dependencies.iter() {
   114                  if !txn_ids.contains(dep) {
   115                      return Err(CliError::ArgumentError(format!(
   116                          "Unsatisfied dependency in given transaction {}: {}",
   117                          &txn.header_signature, dep
   118                      )));
   119                  }
   120                  txn_ids.push(dep.clone())
   121              }
   122          }
   123      }
   124      Ok(())
   125  }