From c5404d6e02fe5cca9b81f8d7b6e6559a4c569a3a Mon Sep 17 00:00:00 2001 From: Aleksandr Petrosyan Date: Fri, 15 Apr 2022 15:42:09 +0400 Subject: [PATCH] [fix] #2081: Fix role registration. Signed-off-by: Aleksandr Petrosyan --- Cargo.lock | 3 + client/tests/integration/roles.rs | 32 ++++- config/derive/src/lib.rs | 2 +- config/src/lib.rs | 8 +- config/src/runtime_upgrades.rs | 2 +- core/src/block.rs | 14 +- core/src/genesis.rs | 10 +- core/src/smartcontracts/wasm.rs | 22 +-- core/src/sumeragi/message.rs | 4 +- core/src/sumeragi/network_topology.rs | 12 +- core/src/triggers.rs | 4 +- crypto/src/signature.rs | 8 +- data_model/src/domain.rs | 4 +- data_model/src/merkle.rs | 18 +-- schema/derive/src/lib.rs | 4 +- tools/crypto_cli/src/main.rs | 107 --------------- tools/generator/Cargo.toml | 9 +- tools/generator/src/main.rs | 186 +++++++++++++++++++++----- version/src/lib.rs | 2 +- 19 files changed, 253 insertions(+), 198 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 660280e5041..8b11f99a548 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1938,10 +1938,13 @@ dependencies = [ name = "iroha_gen" version = "2.0.0-pre-rc.3" dependencies = [ + "clap 2.34.0", "color-eyre", + "hex", "iroha", "iroha_config", "iroha_core", + "iroha_crypto", "iroha_data_model", "iroha_schema_bin", "serde_json", diff --git a/client/tests/integration/roles.rs b/client/tests/integration/roles.rs index 8fbd54d9a3c..c300f65b6a6 100644 --- a/client/tests/integration/roles.rs +++ b/client/tests/integration/roles.rs @@ -6,7 +6,10 @@ use eyre::{eyre, Result}; use iroha_client::client::{self, Client}; use iroha_core::{prelude::AllowAll, smartcontracts::permissions::ValidatorBuilder}; use iroha_data_model::{permissions::Permissions, prelude::*}; -use iroha_permissions_validators::public_blockchain::transfer; +use iroha_permissions_validators::public_blockchain::{ + key_value::{CAN_REMOVE_KEY_VALUE_IN_USER_METADATA, CAN_SET_KEY_VALUE_IN_USER_METADATA}, + transfer, +}; use test_network::{Peer as TestPeer, *}; use tokio::runtime::Runtime; @@ -126,3 +129,30 @@ fn register_role_with_empty_token_params() -> Result<()> { // TODO: When we have more sane default permissions, see if we can // test more about whether or not roles actually work. + +#[test] +fn register_and_grant_metadata_role_to_account() -> Result<()> { + let (_rt, _peer, mut test_client) = ::start_test_with_runtime(); + wait_for_genesis_committed(&vec![test_client.clone()], 0); + + let bob_id = ::Id::from_str("bob@wonderland")?; + let register_bob = RegisterBox::new(Account::new(bob_id.clone(), [])); + test_client.submit_blocking(register_bob)?; + + let role_id = iroha_data_model::role::Id::new("USER_METADATA_ACCESS".parse::()?); + let mut permissions = Permissions::new(); + let mut params = BTreeMap::new(); + params.insert(Name::from_str("account_id")?, bob_id.into()); + permissions.insert(PermissionToken { + name: CAN_SET_KEY_VALUE_IN_USER_METADATA.clone(), + params: params.clone(), + }); + permissions.insert(PermissionToken { + name: CAN_REMOVE_KEY_VALUE_IN_USER_METADATA.clone(), + params, + }); + let register_role = RegisterBox::new(Role::new(role_id, permissions)); + + test_client.submit(register_role)?; + Ok(()) +} diff --git a/config/derive/src/lib.rs b/config/derive/src/lib.rs index 0c1a9dd7b10..72588f03ea2 100644 --- a/config/derive/src/lib.rs +++ b/config/derive/src/lib.rs @@ -22,7 +22,7 @@ mod attrs { pub const INNER: &str = "inner"; } -fn get_type_argument<'a, 'b>(s: &'a str, ty: &'b Type) -> Option<&'b GenericArgument> { +fn get_type_argument<'st, 'ty>(s: &'st str, ty: &'ty Type) -> Option<&'ty GenericArgument> { let path = if let Type::Path(r#type) = ty { r#type } else { diff --git a/config/src/lib.rs b/config/src/lib.rs index 1ce41d754e3..d37a15e1b8a 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -172,9 +172,9 @@ pub trait Configurable: Serialize + DeserializeOwned { /// Gets inner field of arbitrary inner depth and returns as json-value /// # Errors /// Fails if field was unknown - fn get_recursive<'a, T>(&self, inner_field: T) -> Result + fn get_recursive<'fld, T>(&self, inner_field: T) -> Result where - T: AsRef<[&'a str]> + Send + 'a; + T: AsRef<[&'fld str]> + Send + 'fld; /// Fails if fails to deserialize from environment /// # Errors @@ -184,8 +184,8 @@ pub trait Configurable: Serialize + DeserializeOwned { /// Gets docs of inner field of arbitrary depth /// # Errors /// Fails if field was unknown - fn get_doc_recursive<'a>( - field: impl AsRef<[&'a str]>, + fn get_doc_recursive<'fld>( + field: impl AsRef<[&'fld str]>, ) -> Result, Self::Error>; /// Gets docs of field diff --git a/config/src/runtime_upgrades.rs b/config/src/runtime_upgrades.rs index 08b662bc4ad..87dba2d436e 100644 --- a/config/src/runtime_upgrades.rs +++ b/config/src/runtime_upgrades.rs @@ -30,7 +30,7 @@ pub enum ReloadError { Other, } -type PoisonErr<'a, T> = PoisonError + Send + Sync)>>>>; +type PoisonErr<'mutex, T> = PoisonError + Send + Sync)>>>>; impl From> for ReloadError { fn from(_: PoisonErr<'_, T>) -> Self { diff --git a/core/src/block.rs b/core/src/block.rs index fbec7f30214..950a5830329 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -98,14 +98,14 @@ impl Chain { } /// Chain iterator -pub struct ChainIterator<'a> { - chain: &'a Chain, +pub struct ChainIterator<'ch> { + chain: &'ch Chain, pos_front: u64, pos_back: u64, } -impl<'a> ChainIterator<'a> { - fn new(chain: &'a Chain) -> Self { +impl<'ch> ChainIterator<'ch> { + fn new(chain: &'ch Chain) -> Self { ChainIterator { chain, pos_front: 1, @@ -118,8 +118,8 @@ impl<'a> ChainIterator<'a> { } } -impl<'a> Iterator for ChainIterator<'a> { - type Item = MapRef<'a, u64, VersionedCommittedBlock>; +impl<'ch> Iterator for ChainIterator<'ch> { + type Item = MapRef<'ch, u64, VersionedCommittedBlock>; fn next(&mut self) -> Option { if !self.is_exhausted() { let val = self.chain.blocks.get(&self.pos_front); @@ -152,7 +152,7 @@ impl<'a> Iterator for ChainIterator<'a> { } } -impl<'a> DoubleEndedIterator for ChainIterator<'a> { +impl<'de> DoubleEndedIterator for ChainIterator<'de> { fn next_back(&mut self) -> Option { if !self.is_exhausted() { let val = self.chain.blocks.get(&self.pos_back); diff --git a/core/src/genesis.rs b/core/src/genesis.rs index 41cc4271824..36846620a05 100644 --- a/core/src/genesis.rs +++ b/core/src/genesis.rs @@ -8,7 +8,7 @@ use std::{collections::HashSet, fmt::Debug, fs::File, io::BufReader, ops::Deref, use eyre::{eyre, Result, WrapErr}; use iroha_actor::Addr; use iroha_crypto::{KeyPair, PublicKey}; -use iroha_data_model::{asset::AssetDefinition, domain::NewDomain, prelude::*}; +use iroha_data_model::{asset::AssetDefinition, prelude::*}; use iroha_schema::prelude::*; use serde::{Deserialize, Serialize}; use small::SmallVec; @@ -398,7 +398,7 @@ impl RawGenesisBlockBuilder { /// be used to create assets and accounts. pub fn domain(mut self, domain_name: Name) -> RawGenesisDomainBuilder { let domain_id = DomainId::new(domain_name); - let new_domain = NewDomain::new(domain_id.clone()); + let new_domain = Domain::new(domain_id.clone()); self.transaction .isi .push(Instruction::from(RegisterBox::new(new_domain))); @@ -505,7 +505,7 @@ mod tests { let domain_id: DomainId = "wonderland".parse().unwrap(); assert_eq!( finished_genesis_block.transactions[0].isi[0], - Instruction::from(RegisterBox::new(NewDomain::new(domain_id.clone()))) + Instruction::from(RegisterBox::new(Domain::new(domain_id.clone()))) ); assert_eq!( finished_genesis_block.transactions[0].isi[1], @@ -521,7 +521,7 @@ mod tests { let domain_id: DomainId = "tulgey_wood".parse().unwrap(); assert_eq!( finished_genesis_block.transactions[0].isi[3], - Instruction::from(RegisterBox::new(NewDomain::new(domain_id.clone()))) + Instruction::from(RegisterBox::new(Domain::new(domain_id.clone()))) ); assert_eq!( finished_genesis_block.transactions[0].isi[4], @@ -532,7 +532,7 @@ mod tests { let domain_id: DomainId = "meadow".parse().unwrap(); assert_eq!( finished_genesis_block.transactions[0].isi[5], - Instruction::from(RegisterBox::new(NewDomain::new(domain_id.clone()))) + Instruction::from(RegisterBox::new(Domain::new(domain_id.clone()))) ); assert_eq!( finished_genesis_block.transactions[0].isi[6], diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index f0193dafef4..5c0009abf9a 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -68,7 +68,7 @@ impl From for Error { } } -struct Validator<'a, W: WorldTrait> { +struct Validator<'va, W: WorldTrait> { /// Number of instructions in the smartcontract instruction_count: u64, /// Max allowed number of instructions in the smartcontract @@ -78,7 +78,7 @@ struct Validator<'a, W: WorldTrait> { /// If this particular query is allowed is_query_allowed: Arc>, /// Current [`WorldStateview`] - wsv: &'a WorldStateView, + wsv: &'va WorldStateView, } impl Validator<'_, W> { @@ -125,16 +125,16 @@ impl Validator<'_, W> { } } -struct State<'a, W: WorldTrait> { +struct State<'wrld, W: WorldTrait> { account_id: AccountId, /// Ensures smartcontract adheres to limits - validator: Option>, + validator: Option>, store_limits: StoreLimits, - wsv: &'a WorldStateView, + wsv: &'wrld WorldStateView, } -impl<'a, W: WorldTrait> State<'a, W> { - fn new(wsv: &'a WorldStateView, account_id: AccountId, config: Configuration) -> Self { +impl<'wrld, W: WorldTrait> State<'wrld, W> { + fn new(wsv: &'wrld WorldStateView, account_id: AccountId, config: Configuration) -> Self { Self { wsv, account_id, @@ -171,13 +171,13 @@ impl<'a, W: WorldTrait> State<'a, W> { } /// `WebAssembly` virtual machine -pub struct Runtime<'a, W: WorldTrait> { +pub struct Runtime<'wrld, W: WorldTrait> { engine: Engine, - linker: Linker>, + linker: Linker>, config: Configuration, } -impl<'a, W: WorldTrait> Runtime<'a, W> { +impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { /// `Runtime` constructor with default configuration. /// /// # Errors @@ -344,7 +344,7 @@ impl<'a, W: WorldTrait> Runtime<'a, W> { Ok(()) } - fn create_linker(engine: &Engine) -> Result>, Error> { + fn create_linker(engine: &Engine) -> Result>, Error> { let mut linker = Linker::new(engine); linker diff --git a/core/src/sumeragi/message.rs b/core/src/sumeragi/message.rs index b41983bfe58..61455e8fd03 100644 --- a/core/src/sumeragi/message.rs +++ b/core/src/sumeragi/message.rs @@ -145,9 +145,9 @@ impl VersionedMessage { /// Send this message over the network to multiple `peers`. /// # Errors /// Fails if network sending fails - pub async fn send_to_multiple<'a, I>(self, broker: &Broker, peers: I) + pub async fn send_to_multiple<'itm, I>(self, broker: &Broker, peers: I) where - I: IntoIterator + Send, + I: IntoIterator + Send, { let futures = peers .into_iter() diff --git a/core/src/sumeragi/network_topology.rs b/core/src/sumeragi/network_topology.rs index e03864c49fa..415d3931be3 100644 --- a/core/src/sumeragi/network_topology.rs +++ b/core/src/sumeragi/network_topology.rs @@ -366,10 +366,10 @@ impl Topology { } /// Returns signatures of the peers with the specified `roles` from all `signatures`. - pub fn filter_signatures_by_roles<'a>( - &'a self, - roles: &'a [Role], - signatures: impl IntoIterator> + 'a, + pub fn filter_signatures_by_roles<'slf>( + &'slf self, + roles: &'slf [Role], + signatures: impl IntoIterator> + 'slf, ) -> Vec> { let roles: HashSet = roles.iter().copied().collect(); let public_keys: HashSet<_> = roles @@ -481,8 +481,8 @@ mod tests { fn correct_number_of_peers_genesis() { let peers = topology_test_peers(); // set_a.len() = 2, is wrong as it is not possible to get integer f in: 2f + 1 = 2 - let set_a: HashSet<_> = topology_test_peers().iter().cloned().take(3).collect(); - let set_b: HashSet<_> = topology_test_peers().iter().cloned().skip(3).collect(); + let set_a: HashSet<_> = topology_test_peers().iter().take(3).cloned().collect(); + let set_b: HashSet<_> = topology_test_peers().iter().skip(3).cloned().collect(); let _network_topology = GenesisBuilder::new() .with_leader(peers.iter().next().unwrap().clone()) .with_set_a(set_a) diff --git a/core/src/triggers.rs b/core/src/triggers.rs index 0f4bd3db443..fb217baf21f 100644 --- a/core/src/triggers.rs +++ b/core/src/triggers.rs @@ -105,9 +105,9 @@ impl TriggerSet { /// /// Users should not try to modify [`TriggerSet`] before dropping actions, /// returned by the current function - pub fn find_matching<'e, E>(&self, events: E) -> Vec + pub fn find_matching<'evnt, E>(&self, events: E) -> Vec where - E: IntoIterator, + E: IntoIterator, { let mut result = Vec::new(); diff --git a/crypto/src/signature.rs b/crypto/src/signature.rs index f39fc596155..22ee049ba5d 100644 --- a/crypto/src/signature.rs +++ b/crypto/src/signature.rs @@ -305,9 +305,9 @@ impl IntoIterator for SignaturesOf { } } -impl<'a, T> IntoIterator for &'a SignaturesOf { - type Item = &'a SignatureOf; - type IntoIter = btree_map::Values<'a, PublicKey, SignatureOf>; +impl<'sig, T> IntoIterator for &'sig SignaturesOf { + type Item = &'sig SignatureOf; + type IntoIter = btree_map::Values<'sig, PublicKey, SignatureOf>; fn into_iter(self) -> Self::IntoIter { self.signatures.values() } @@ -363,7 +363,7 @@ impl SignaturesOf { /// # Warning: /// /// This method uses [`core::mem::transmute`] internally - #[allow(unsafe_code)] + #[allow(unsafe_code, clippy::transmute_undefined_repr)] pub fn transmute(self) -> SignaturesOf { // SAFETY: Safe because we are transmuting to a pointer of // type `` which is related to type ``. diff --git a/data_model/src/domain.rs b/data_model/src/domain.rs index 7f4ba484825..ea8768a113b 100644 --- a/data_model/src/domain.rs +++ b/data_model/src/domain.rs @@ -74,7 +74,7 @@ pub struct NewDomain { /// The (IPFS) link to the logo of this domain. logo: Option, /// metadata associated to the domain builder. - pub metadata: Metadata, + metadata: Metadata, } impl PartialOrd for NewDomain { @@ -94,7 +94,7 @@ impl Ord for NewDomain { impl NewDomain { /// Create a [`NewDomain`], reserved for internal use. #[must_use] - pub fn new(id: ::Id) -> Self { + fn new(id: ::Id) -> Self { Self { id, logo: None, diff --git a/data_model/src/merkle.rs b/data_model/src/merkle.rs index 4bb58e75b1f..de3ec6f975e 100644 --- a/data_model/src/merkle.rs +++ b/data_model/src/merkle.rs @@ -48,8 +48,8 @@ pub enum Node { #[derive(Debug)] /// BFS iterator over the Merkle tree -pub struct BreadthFirstIter<'a, T> { - queue: Vec<&'a Node>, +pub struct BreadthFirstIter<'itm, T> { + queue: Vec<&'itm Node>, } #[cfg(feature = "std")] @@ -184,8 +184,8 @@ impl Node { } } -impl<'a, T> BreadthFirstIter<'a, T> { - fn new(root_node: &'a Node) -> Self { +impl<'itm, T> BreadthFirstIter<'itm, T> { + fn new(root_node: &'itm Node) -> Self { BreadthFirstIter { queue: vec![root_node], } @@ -196,8 +196,8 @@ impl<'a, T> BreadthFirstIter<'a, T> { /// `'a` lifetime specified for `Node`. Because `Node` is recursive data structure with self /// composition in case of `Node::Subtree` we use `Box` to know size of each `Node` object in /// memory. -impl<'a, T> Iterator for BreadthFirstIter<'a, T> { - type Item = &'a Node; +impl<'itm, T> Iterator for BreadthFirstIter<'itm, T> { + type Item = &'itm Node; fn next(&mut self) -> Option { match &self.queue.pop() { @@ -213,9 +213,9 @@ impl<'a, T> Iterator for BreadthFirstIter<'a, T> { } } -impl<'a, T> IntoIterator for &'a MerkleTree { - type Item = &'a Node; - type IntoIter = BreadthFirstIter<'a, T>; +impl<'itm, T> IntoIterator for &'itm MerkleTree { + type Item = &'itm Node; + type IntoIter = BreadthFirstIter<'itm, T>; fn into_iter(self) -> Self::IntoIter { BreadthFirstIter::new(&self.root_node) diff --git a/schema/derive/src/lib.rs b/schema/derive/src/lib.rs index a5c04de7682..c380a073941 100644 --- a/schema/derive/src/lib.rs +++ b/schema/derive/src/lib.rs @@ -299,10 +299,10 @@ fn variant_index(v: &Variant, i: usize) -> TokenStream2 { } /// Finds specific attribute with codec ident satisfying predicate -fn find_meta_item<'a, F, R, I, M>(mut itr: I, mut pred: F) -> Option +fn find_meta_item<'attr, F, R, I, M>(mut itr: I, mut pred: F) -> Option where F: FnMut(M) -> Option + Clone, - I: Iterator, + I: Iterator, M: Parse, { itr.find_map(|attr| { diff --git a/tools/crypto_cli/src/main.rs b/tools/crypto_cli/src/main.rs index 15d42b9bdc8..8b137891791 100644 --- a/tools/crypto_cli/src/main.rs +++ b/tools/crypto_cli/src/main.rs @@ -1,108 +1 @@ -//! `iroha_crypto_cli` is a command line tool used to generate keys for Iroha peers and clients. -use clap::{App, Arg, ArgGroup}; -use color_eyre::{ - eyre::{self, eyre, WrapErr}, - Report, Result, -}; -use iroha_crypto::{Algorithm, KeyGenConfiguration, KeyPair, PrivateKey}; - -fn main() -> Result<(), Report> { - color_eyre::install()?; - let default_algorithm = Algorithm::default().to_string(); - let matches = App::new("iroha_crypto_cli") - .version("0.1") - .author("Soramitsu") - .about("iroha_crypto_cli is a command line tool used to generate keys for Iroha peers and clients.") - .arg( - Arg::with_name("seed") - .long("seed") - .value_name("seed") - .help("Sets a seed for random number generator. Should be used separately from `private_key`.") - .required(false) - .takes_value(true) - ) - .arg( - Arg::with_name("private_key") - .long("private_key") - .value_name("private_key") - .help("Sets a private key. Should be used separately from `seed`.") - .required(false) - .takes_value(true) - ) - .arg( - Arg::with_name("algorithm") - .long("algorithm") - .value_name("algorithm") - .help("Function used to generate the key pair.") - .takes_value(true) - .possible_value(iroha_crypto::ED_25519) - .possible_value(iroha_crypto::SECP_256_K1) - .possible_value(iroha_crypto::BLS_NORMAL) - .possible_value(iroha_crypto::BLS_SMALL) - .default_value(&default_algorithm) - ) - .arg( - Arg::with_name("json") - .long("json") - .help("If specified the output will be formatted as json.") - .takes_value(false) - .multiple(false) - ) - .group( - ArgGroup::with_name("key_gen_options") - .args(&["seed", "private_key"]) - .required(false) - .multiple(false) - ) - .get_matches(); - let seed_option = matches.value_of("seed"); - let private_key_option = matches.value_of("private_key"); - let algorithm = matches - .value_of("algorithm") - .ok_or_else(|| eyre!("Failed to get algorithm name."))? - .parse::() - .wrap_err("Failed to parse algorithm.")?; - let key_gen_configuration = KeyGenConfiguration::default().with_algorithm(algorithm); - let keypair: KeyPair = seed_option.map_or_else( - || -> eyre::Result<_> { - private_key_option.map_or_else( - || { - KeyPair::generate_with_configuration(key_gen_configuration.clone()) - .wrap_err("failed to generate key pair") - }, - |private_key| { - KeyPair::generate_with_configuration( - key_gen_configuration.clone().use_private_key(PrivateKey { - digest_function: algorithm.to_string(), - payload: hex::decode(private_key) - .wrap_err("Failed to decode private key.")?, - }), - ) - .wrap_err("Failed to generate key pair") - }, - ) - }, - |seed| -> eyre::Result<_> { - KeyPair::generate_with_configuration( - key_gen_configuration - .clone() - .use_seed(seed.as_bytes().into()), - ) - .wrap_err("Failed to generate key pair") - }, - )?; - - #[allow(clippy::print_stdout)] - if matches.is_present("json") { - let json = - serde_json::to_string_pretty(&keypair).wrap_err("Failed to serialize to json.")?; - println!("{}", json); - } else { - println!("Public key (multihash): {}", &keypair.public_key); - println!("Private key: {}", &keypair.private_key); - println!("Digest function: {}", &keypair.public_key.digest_function); - } - - Ok(()) -} diff --git a/tools/generator/Cargo.toml b/tools/generator/Cargo.toml index c0da4eea7d2..f2aeed5ad5f 100644 --- a/tools/generator/Cargo.toml +++ b/tools/generator/Cargo.toml @@ -6,7 +6,11 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -# Explanation: You want the option to remove configuration docs if you distribute e.g. a `deb`, but want the person who just cloned the repo to be able to see at a glance what kinds of features are accessible to them, what they do and how to use them. #1975 should be fixed soon. +# Explanation: You want the option to remove configuration docs if you +# distribute e.g. a `deb`, but want the person who just cloned the +# repo to be able to see at a glance what kinds of features are +# accessible to them, what they do and how to use them. #1975 should +# be fixed soon. [features] roles = ["iroha_core/roles"] dex = ["iroha_core/dex"] @@ -17,10 +21,13 @@ default = ["roles", "dex", "telemetry", "dev-telemetry"] [dependencies] iroha_core = { version = "=2.0.0-pre-rc.3", path = "../../core" } +iroha_crypto = { version = "=2.0.0-pre-rc.3", path = "../../crypto" } iroha_config = { version = "=2.0.0-pre-rc.3", path = "../../config" } iroha_data_model = { version = "=2.0.0-pre-rc.3", path = "../../data_model" } iroha_schema_bin = { version = "=2.0.0-pre-rc.3", path = "../../schema/bin" } iroha = { path = "../../cli" } color-eyre = "0.5.11" +hex = "0.4.0" +clap = "2.33.0" serde_json = "1" diff --git a/tools/generator/src/main.rs b/tools/generator/src/main.rs index 3ce17232fcf..11eb6d31ad3 100644 --- a/tools/generator/src/main.rs +++ b/tools/generator/src/main.rs @@ -1,60 +1,181 @@ -//! CLI for generating iroha sample configuration and genesis, as well -//! as their documentation. - -#![allow(clippy::restriction)] +//! CLI for generating iroha sample configuration, genesis and +//! cryptographic key pairs. To be used with all compliant Iroha +//! installations. use std::io::{stdout, BufWriter, Write}; +use clap::{App, Arg, ArgGroup}; use color_eyre::eyre::WrapErr as _; +use docs::PrintDocs as _; use iroha::config::Configuration; -// TODO: if we merge #2077 first, we should change this to sync up with the default in docs. +// The reason for hard-coding this default is to ensure that the +// algorithm is matched to the public key. If you need to change +// either, you should definitely change both. static DEFAULT_PUBLIC_KEY: &str = "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"; +static DEFAULT_ALGORITHM: &str = iroha_crypto::ED_25519; fn main() -> color_eyre::Result<()> { - use docs::PrintDocs as _; - color_eyre::install().unwrap(); + color_eyre::install()?; + let matches = arg_parse(); + let keypair = crypto::key_pair(&matches)?; let mut output = BufWriter::new(stdout()); - if std::env::args().any(|a| cli::is_genesis(&a)) { + + if matches.is_present("genesis") { writeln!( output, "{}", serde_json::to_string_pretty(&genesis::generate_default()?)? )?; - Ok(()) - } else if std::env::args().any(|a| cli::is_schema(&a)) { + } else if matches.is_present("docs") { + Configuration::get_markdown(&mut BufWriter::new(stdout())) + .wrap_err("Failed to generate documentation")?; + } else if matches.is_present("schema") { let schemas = iroha_schema_bin::build_schemas(); writeln!(output, "{}", serde_json::to_string_pretty(&schemas)?)?; - Ok(()) - } else if std::env::args().any(|a| cli::is_docs(&a)) { - Configuration::get_markdown(&mut BufWriter::new(stdout())) - .wrap_err("Failed to generate documentation") } else { - cli::print_help(); - Ok(()) + #[allow(clippy::print_stdout)] + if matches.is_present("json") { + let json = + serde_json::to_string_pretty(&keypair).wrap_err("Failed to serialize to json.")?; + writeln!(output, "{}", json)?; + } else { + writeln!(output, "Public key (multihash): {}", &keypair.public_key)?; + writeln!(output, "Private key: {}", &keypair.private_key)?; + writeln!( + output, + "Digest function: {}", + &keypair.public_key.digest_function + )?; + } } + Ok(()) } -mod cli { - pub fn print_help() { - println!("Tool for generating iroha-related data."); - println!(); - println!("pass `--docs` or `-d` to generate sample config and its documentation."); - println!("pass `--schema` or `-s` to generate the schema."); - println!("pass `--genesis` or `-g` to generate the genesis block."); - } +fn arg_parse() -> clap::ArgMatches<'static> { + let matches = App::new("iroha_crypto_cli") + .version("0.1") + .author("Soramitsu") + .about("iroha_crypto_cli is a command line tool used to generate keys for Iroha peers and clients.") + .arg( + Arg::with_name("seed") + .long("seed") + .value_name("seed") + .help("Sets a seed for random number generator. Should be used separately from `private_key`.") + .required(false) + .takes_value(true) + ) + .arg( + Arg::with_name("private_key") + .long("private_key") + .value_name("private_key") + .help("Sets a private key. Should be used separately from `seed`.") + .required(false) + .takes_value(true) + ) + .arg( + Arg::with_name("algorithm") + .long("algorithm") + .value_name("algorithm") + .help("Function used to generate the key pair.") + .takes_value(true) + .possible_value(iroha_crypto::ED_25519) + .possible_value(iroha_crypto::SECP_256_K1) + .possible_value(iroha_crypto::BLS_NORMAL) + .possible_value(iroha_crypto::BLS_SMALL) + .default_value(DEFAULT_ALGORITHM) + ) + .arg( + Arg::with_name("json") + .long("json") + .help("If specified the output will be formatted as json.") + .takes_value(false) + .multiple(false) + ) + .arg( + Arg::with_name("genesis") + .long("genesis") + .short("g") + .help("If specified, print the Genesis") + .takes_value(false) + .multiple(false) + ) + .arg( + Arg::with_name("schema") + .long("schema") + .short("s") + .help("If specified, print Schema") + .takes_value(false) + .multiple(false) + ) + .arg( + Arg::with_name("docs") + .long("docs") + .short("d") + .help("If specified, print configuration docs") + .takes_value(false) + .multiple(false) + ) + .group( + ArgGroup::with_name("other_gen_options") + .args(&["docs", "schema", "genesis"]) + .required(false) + .multiple(false) + ) + .group( + ArgGroup::with_name("key_gen_options") + .args(&["seed", "private_key"]) + .required(false) + .multiple(false) + ) + .get_matches(); + matches +} - pub fn is_docs(arg: &str) -> bool { - ["--docs", "-d"].contains(&arg) - } +mod crypto { - pub fn is_schema(arg: &str) -> bool { - ["--schema", "-s"].contains(&arg) - } + use color_eyre::eyre::{eyre, WrapErr as _}; + use iroha_crypto::{Algorithm, KeyGenConfiguration, KeyPair, PrivateKey}; - pub fn is_genesis(arg: &str) -> bool { - ["--genesis", "-g"].contains(&arg) + pub fn key_pair(matches: &clap::ArgMatches) -> color_eyre::Result { + let seed_option = matches.value_of("seed"); + let private_key_option = matches.value_of("private_key"); + let algorithm = matches + .value_of("algorithm") + .ok_or_else(|| eyre!("Failed to get algorithm name."))? + .parse::() + .wrap_err("Failed to parse algorithm.")?; + let key_gen_configuration = KeyGenConfiguration::default().with_algorithm(algorithm); + let keypair: KeyPair = seed_option.map_or_else( + || -> color_eyre::Result<_> { + private_key_option.map_or_else( + || { + KeyPair::generate_with_configuration(key_gen_configuration.clone()) + .wrap_err("failed to generate key pair") + }, + |private_key| { + KeyPair::generate_with_configuration( + key_gen_configuration.clone().use_private_key(PrivateKey { + digest_function: algorithm.to_string(), + payload: hex::decode(private_key) + .wrap_err("Failed to decode private key.")?, + }), + ) + .wrap_err("Failed to generate key pair") + }, + ) + }, + |seed| -> color_eyre::Result<_> { + KeyPair::generate_with_configuration( + key_gen_configuration + .clone() + .use_seed(seed.as_bytes().into()), + ) + .wrap_err("Failed to generate key pair") + }, + )?; + Ok(keypair) } } @@ -85,6 +206,7 @@ mod genesis { } mod docs { + #![allow(clippy::panic_in_result_fn, clippy::expect_used)] use std::{fmt::Debug, io::Write}; use iroha_config::Configurable; diff --git a/version/src/lib.rs b/version/src/lib.rs index d03895eef0f..576c9bcf3c4 100644 --- a/version/src/lib.rs +++ b/version/src/lib.rs @@ -217,7 +217,7 @@ pub mod json { use super::{error::Result, Version}; /// [`Serialize`] versioned analog, specifically for JSON. - pub trait DeserializeVersioned<'a>: Deserialize<'a> + Version { + pub trait DeserializeVersioned<'de>: Deserialize<'de> + Version { /// Use this function for versioned objects instead of [`serde_json::from_str`]. /// /// # Errors