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 }