diff --git a/Cargo.lock b/Cargo.lock index 6dc6867f5bb..62c5ba799d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1669,6 +1669,7 @@ checksum = "ec58677acfea8a15352d42fc87d11d63596ade9239e0a7c9352914417515dbe6" name = "iroha" version = "2.0.0-pre-rc.3" dependencies = [ + "async-trait", "color-eyre", "eyre", "futures", @@ -1680,6 +1681,7 @@ dependencies = [ "iroha_data_model", "iroha_futures", "iroha_logger", + "iroha_macro", "iroha_p2p", "iroha_permissions_validators", "iroha_schema_bin", @@ -1829,7 +1831,6 @@ dependencies = [ "tokio", "tokio-stream", "unique_port", - "warp", "wasmtime", ] @@ -1838,9 +1839,11 @@ name = "iroha_crypto" version = "2.0.0-pre-rc.3" dependencies = [ "derive_more", + "getset", "hex", "hex-literal", "iroha_schema", + "openssl-sys", "parity-scale-codec", "serde", "serde_json", @@ -1865,7 +1868,6 @@ dependencies = [ "criterion", "derive_more", "getset", - "hex-literal", "iroha", "iroha_client", "iroha_core", @@ -2015,6 +2017,7 @@ name = "iroha_schema_bin" version = "2.0.0-pre-rc.3" dependencies = [ "iroha_core", + "iroha_crypto", "iroha_data_model", "iroha_schema", "serde_json", @@ -2484,6 +2487,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "111.18.0+1.1.1n" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7897a926e1e8d00219127dc020130eca4292e5ca666dd592480d72c3eca2ff6c" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.72" @@ -2493,6 +2505,7 @@ dependencies = [ "autocfg 1.1.0", "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -3520,7 +3533,6 @@ dependencies = [ "async-trait", "eyre", "futures", - "hex-literal", "iroha", "iroha_actor", "iroha_client", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 7178d440551..605599551a4 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -12,16 +12,17 @@ keywords = ["crypto", "blockchain", "ledger"] categories = ["cryptography::cryptocurrencies"] [features] +default = ["bridge", "telemetry", "schema-endpoint"] + bridge = ["iroha_core/bridge"] dex = ["iroha_core/dex"] +# Include support for account roles roles = ["iroha_core/roles", "iroha_permissions_validators/roles"] telemetry = ["iroha_telemetry", "iroha_core/telemetry"] dev-telemetry = ["iroha_core/dev-telemetry", "iroha_telemetry"] schema-endpoint = ["iroha_schema_bin"] test-network = [] -default = ["bridge", "telemetry", "schema-endpoint"] - [badges] is-it-maintained-issue-resolution = { repository = "https://github.com/hyperledger/iroha" } is-it-maintained-open-issues = { repository = "https://github.com/hyperledger/iroha" } @@ -29,6 +30,7 @@ maintenance = { status = "actively-developed" } [dependencies] iroha_core = { version = "=2.0.0-pre-rc.3", path = "../core" } +iroha_macro = { version = "=2.0.0-pre-rc.3", path = "../macro" } iroha_permissions_validators = { version = "=2.0.0-pre-rc.3", path = "../permissions_validators" } iroha_logger = { version = "=2.0.0-pre-rc.3", path = "../logger" } iroha_futures = { version = "=2.0.0-pre-rc.3", path = "../futures" } @@ -46,6 +48,7 @@ futures = { version = "0.3.17", default-features = false, features = ["std", "as parity-scale-codec = { version = "2.3.1", default-features = false, features = ["derive"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +async-trait = "0.1" tokio = { version = "1.6.0", features = ["sync", "time", "rt", "io-util", "rt-multi-thread", "macros", "fs"] } warp = "0.3" thiserror = "1.0.28" @@ -53,5 +56,4 @@ color-eyre = "0.5.11" [dev-dependencies] unique_port = "0.1.0" -iroha_core = { version = "=2.0.0-pre-rc.3", path = "../core", features = ["cross_crate_testing"] } hex = "0.4.0" diff --git a/cli/src/config.rs b/cli/src/config.rs index 111ddd96cf0..d47b5ae1ff7 100644 --- a/cli/src/config.rs +++ b/cli/src/config.rs @@ -9,7 +9,7 @@ use iroha_core::{ sumeragi::config::SumeragiConfiguration, wsv::config::Configuration as WorldStateViewConfiguration, }; -use iroha_crypto::{PrivateKey, PublicKey}; +use iroha_crypto::prelude::*; use iroha_data_model::prelude::*; use iroha_logger::Configuration as LoggerConfiguration; use serde::{Deserialize, Serialize}; @@ -17,7 +17,7 @@ use serde::{Deserialize, Serialize}; use super::torii::config::ToriiConfiguration; /// Configuration parameters container. -#[derive(Clone, Deserialize, Serialize, Debug, Configurable, Default)] +#[derive(Debug, Clone, Deserialize, Serialize, Configurable)] #[serde(default)] #[serde(rename_all = "UPPERCASE")] #[config(env_prefix = "IROHA_")] @@ -53,17 +53,41 @@ pub struct Configuration { /// Configuration for `WorldStateView`. #[config(inner)] pub wsv: WorldStateViewConfiguration, - #[cfg(feature = "telemetry")] - /// Configuration for telemetry - #[config(inner)] - pub telemetry: iroha_telemetry::Configuration, /// Network configuration #[config(inner)] pub network: NetworkConfiguration, + /// Configuration for telemetry + #[config(inner)] + #[cfg(feature = "telemetry")] + pub telemetry: iroha_telemetry::Configuration, +} + +impl Default for Configuration { + fn default() -> Self { + let sumeragi_configuration = SumeragiConfiguration::default(); + let (public_key, private_key) = sumeragi_configuration.key_pair.clone().into(); + + Self { + public_key, + private_key, + disable_panic_terminal_colors: bool::default(), + kura: KuraConfiguration::default(), + sumeragi: sumeragi_configuration, + torii: ToriiConfiguration::default(), + block_sync: BlockSyncConfiguration::default(), + queue: QueueConfiguration::default(), + logger: LoggerConfiguration::default(), + genesis: GenesisConfiguration::default(), + wsv: WorldStateViewConfiguration::default(), + network: NetworkConfiguration::default(), + #[cfg(feature = "telemetry")] + telemetry: iroha_telemetry::Configuration::default(), + } + } } /// Network Configuration parameters container. -#[derive(Clone, Copy, Deserialize, Serialize, Debug, Configurable, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Configurable)] #[serde(default)] #[serde(rename_all = "UPPERCASE")] #[config(env_prefix = "IROHA_NETWORK_")] @@ -104,7 +128,7 @@ impl Configuration { } fn finalize(&mut self) { - self.sumeragi.key_pair = self.key_pair().into(); + self.sumeragi.key_pair = self.key_pair(); self.sumeragi.peer_id = PeerId::new(&self.torii.p2p_addr, &self.public_key.clone()); } @@ -120,8 +144,8 @@ impl Configuration { } /// Get `public_key` and `private_key` configuration parameters. - pub fn key_pair(&self) -> (PublicKey, PrivateKey) { - (self.public_key.clone(), self.private_key.clone()) + pub fn key_pair(&self) -> iroha_crypto::KeyPair { + iroha_crypto::KeyPair::new(self.public_key.clone(), self.private_key.clone()) } } @@ -129,8 +153,6 @@ impl Configuration { mod tests { #![allow(clippy::restriction)] - use std::collections::HashSet; - use iroha_core::sumeragi::config::TrustedPeers; use super::*; @@ -146,99 +168,10 @@ mod tests { Ok(()) } - #[test] - fn parse_example_trusted_peers_json() -> Result<(), String> { - let configuration = Configuration::from_path(CONFIGURATION_PATH) - .map_err(|e| format!("Failed to read configuration from example config: {}", e))?; - let public_key1 = PublicKey { - digest_function: iroha_crypto::ED_25519.to_string(), - payload: hex::decode( - "7233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0", - ) - .expect("Failed to decode"), - }; - let public_key2 = PublicKey { - digest_function: iroha_crypto::ED_25519.to_string(), - payload: hex::decode( - "CC25624D62896D3A0BFD8940F928DC2ABF27CC57CEFEB442AA96D9081AAE58A1", - ) - .expect("Failed to decode"), - }; - let public_key3 = PublicKey { - digest_function: iroha_crypto::ED_25519.to_string(), - payload: hex::decode( - "FACA9E8AA83225CB4D16D67F27DD4F93FC30FFA11ADC1F5C88FD5495ECC91020", - ) - .expect("Failed to decode"), - }; - let public_key4 = PublicKey { - digest_function: iroha_crypto::ED_25519.to_string(), - payload: hex::decode( - "8E351A70B6A603ED285D666B8D689B680865913BA03CE29FB7D13A166C4E7F1F", - ) - .expect("Failed to decode"), - }; - let expected_trusted_peers = vec![ - PeerId { - address: "127.0.0.1:1337".to_owned(), - public_key: public_key1, - }, - PeerId { - address: "127.0.0.1:1338".to_owned(), - public_key: public_key2, - }, - PeerId { - address: "127.0.0.1:1339".to_owned(), - public_key: public_key3, - }, - PeerId { - address: "127.0.0.1:1340".to_owned(), - public_key: public_key4, - }, - ] - .into_iter() - .collect::>(); - assert_eq!(1000, configuration.sumeragi.block_time_ms); - assert_eq!( - expected_trusted_peers, - configuration.sumeragi.trusted_peers.peers - ); - Ok(()) - } - - #[test] - fn parse_trusted_peers_success() { - let trusted_peers_string = r#"[{"address":"127.0.0.1:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address":"localhost:1338", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address": "195.162.0.1:23", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}]"#; - let public_key = PublicKey { - digest_function: iroha_crypto::ED_25519.to_string(), - payload: hex::decode( - "7233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0", - ) - .expect("Failed to decode"), - }; - let expected_trusted_peers = vec![ - PeerId { - address: "127.0.0.1:1337".to_string(), - public_key: public_key.clone(), - }, - PeerId { - address: "localhost:1338".to_string(), - public_key: public_key.clone(), - }, - PeerId { - address: "195.162.0.1:23".to_string(), - public_key, - }, - ]; - let result: Vec = - serde_json::from_str(trusted_peers_string).expect("Failed to parse Trusted Peers."); - assert_eq!(expected_trusted_peers, result); - } - #[test] #[should_panic] fn parse_trusted_peers_fail_duplicate_peer_id() { - let trusted_peers_string = r#"[{"address":"127.0.0.1:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address":"127.0.0.1:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address":"localhost:1338", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address": "195.162.0.1:23", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}]"#; + let trusted_peers_string = r#"[{"address":"127.0.0.1:1337", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}, {"address":"127.0.0.1:1337", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}, {"address":"localhost:1338", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}, {"address": "195.162.0.1:23", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}]"#; let _result: TrustedPeers = serde_json::from_str(trusted_peers_string).expect("Failed to parse Trusted Peers"); } diff --git a/core/src/event.rs b/cli/src/event.rs similarity index 92% rename from core/src/event.rs rename to cli/src/event.rs index 1719e562c5f..875225b0c37 100644 --- a/core/src/event.rs +++ b/cli/src/event.rs @@ -5,15 +5,10 @@ use futures::TryStreamExt; use iroha_data_model::events::prelude::*; use iroha_macro::error::ErrorTryFromEnum; -use tokio::sync::broadcast; use warp::ws::WebSocket; use crate::stream::{self, Sink, Stream}; -/// Type of `Sender` which should be used for channels of `Event` messages. -pub type EventsSender = broadcast::Sender; -/// Type of `Receiver` which should be used for channels of `Event` messages. -pub type EventsReceiver = broadcast::Receiver; /// Type of Stream error pub type StreamError = stream::Error<>::Err>; diff --git a/cli/src/lib.rs b/cli/src/lib.rs index ef2aa9daada..dc85199ec9a 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -26,7 +26,9 @@ use tokio::sync::broadcast; use torii::Torii; pub mod config; +mod event; pub mod samples; +mod stream; pub mod torii; /// Arguments for Iroha2 - usually parsed from cli. @@ -163,7 +165,7 @@ where WorldStateView::from_configuration( config.wsv, W::with( - domains(&config).wrap_err("Failed to get initial domains")?, + domains(&config), config.sumeragi.trusted_peers.peers.clone(), ), ) @@ -305,12 +307,7 @@ where /// /// # Errors /// - Genesis account public key not specified. -fn domains(configuration: &config::Configuration) -> Result> { - let key = configuration - .genesis - .account_public_key - .clone() - .ok_or_else(|| eyre!("Genesis account public key is not specified."))?; - - Ok([Domain::from(GenesisDomain::new(key))].into_iter()) +fn domains(configuration: &config::Configuration) -> impl Iterator { + let key = configuration.genesis.account_public_key.clone(); + [Domain::from(GenesisDomain::new(key))].into_iter() } diff --git a/cli/src/samples.rs b/cli/src/samples.rs index b8b263dab43..a1d6bda4384 100644 --- a/cli/src/samples.rs +++ b/cli/src/samples.rs @@ -75,10 +75,7 @@ pub fn get_config(trusted_peers: HashSet, key_pair: Option) -> ..KuraConfiguration::default() }, sumeragi: SumeragiConfiguration { - key_pair: KeyPair { - public_key: public_key.clone(), - private_key: private_key.clone(), - }, + key_pair: KeyPair::new(public_key.clone(), private_key.clone()), peer_id: PeerId::new(DEFAULT_TORII_P2P_ADDR, &public_key), trusted_peers: TrustedPeers { peers: trusted_peers, @@ -100,7 +97,7 @@ pub fn get_config(trusted_peers: HashSet, key_pair: Option) -> ..QueueConfiguration::default() }, genesis: GenesisConfiguration { - account_public_key: Some(public_key), + account_public_key: public_key, account_private_key: Some(private_key), ..GenesisConfiguration::default() }, diff --git a/core/src/stream.rs b/cli/src/stream.rs similarity index 99% rename from core/src/stream.rs rename to cli/src/stream.rs index 5ba37600286..15c96287551 100644 --- a/core/src/stream.rs +++ b/cli/src/stream.rs @@ -151,7 +151,7 @@ impl Stream for warp::ws::WebSocket { type Message = warp::ws::Message; } -#[cfg(feature = "cross_crate_testing")] +#[cfg(test)] mod ws_client { use warp::test::WsClient; diff --git a/cli/src/torii/mod.rs b/cli/src/torii/mod.rs index f803b1d4998..28c967324e8 100644 --- a/cli/src/torii/mod.rs +++ b/cli/src/torii/mod.rs @@ -3,20 +3,15 @@ use std::{convert::Infallible, fmt::Debug, net::ToSocketAddrs, sync::Arc}; -use eyre::{eyre, Context}; +use eyre::eyre; use futures::{stream::FuturesUnordered, StreamExt}; use iroha_core::{ - event::{Consumer, EventsSender}, prelude::*, queue::{self, Queue}, - smartcontracts::{ - isi::query::{self, VerifiedQueryRequest}, - permissions::IsQueryAllowedBoxed, - }, + smartcontracts::{isi::query, permissions::IsQueryAllowedBoxed}, wsv::WorldTrait, - IrohaNetwork, + EventsSender, IrohaNetwork, }; -use iroha_data_model::prelude::*; use thiserror::Error; use utils::*; use warp::{ @@ -86,12 +81,23 @@ pub enum Error { Prometheus(#[source] eyre::Report), } +/// Status code for query error response. +pub(crate) const fn query_status_code(query_error: &query::Error) -> StatusCode { + use query::Error::*; + match query_error { + Decode(_) | Version(_) | Evaluate(_) | Conversion(_) => StatusCode::BAD_REQUEST, + Signature(_) => StatusCode::UNAUTHORIZED, + Permission(_) => StatusCode::FORBIDDEN, + Find(_) => StatusCode::NOT_FOUND, + } +} + impl Reply for Error { fn into_response(self) -> Response { const fn status_code(err: &Error) -> StatusCode { use Error::*; match err { - Query(e) => e.status_code(), + Query(e) => query_status_code(e), VersionedTransaction(_) | AcceptTransaction(_) | RequestPendingTransactions(_) diff --git a/cli/src/torii/routing.rs b/cli/src/torii/routing.rs index 02cb5d63d10..d72a55eeaf7 100644 --- a/cli/src/torii/routing.rs +++ b/cli/src/torii/routing.rs @@ -1,6 +1,8 @@ //! Routing functions for Torii. If you want to add an endpoint to //! Iroha you should add it here by creating a `handle_*` function, -//! and add it to impl Torii. +//! and add it to impl Torii. This module also defines the `VerifiedQueryRequest`, +//! which is the only kind of query that is permitted to execute. +use eyre::WrapErr; use iroha_actor::Addr; use iroha_config::{Configurable, GetConfiguration, PostConfiguration}; use iroha_core::{ @@ -8,14 +10,75 @@ use iroha_core::{ BlockPublisherMessage, BlockSubscriberMessage, VersionedBlockPublisherMessage, VersionedBlockSubscriberMessage, }, - stream::{Sink, Stream}, + smartcontracts::isi::{ + permissions::IsQueryAllowedBoxed, + query::{Error as QueryError, ValidQueryRequest}, + }, wsv::WorldTrait, }; +use iroha_crypto::SignatureOf; +use iroha_data_model::{prelude::*, query}; #[cfg(feature = "telemetry")] use iroha_telemetry::metrics::Status; +use parity_scale_codec::{Decode, Encode}; use super::*; -use crate::Configuration; +use crate::{ + stream::{Sink, Stream}, + Configuration, +}; + +/// Query Request verified on the Iroha node side. +#[derive(Debug, Decode, Encode)] +pub struct VerifiedQueryRequest { + /// Payload. + payload: query::Payload, + /// Signature of the client who sends this query. + signature: SignatureOf, +} + +impl VerifiedQueryRequest { + /// Validate query. + /// + /// # Errors + /// if: + /// - Account doesn't exist. + /// - Account doesn't have the correct public key. + /// - Account has incorrect permissions. + pub fn validate( + self, + wsv: &WorldStateView, + query_validator: &IsQueryAllowedBoxed, + ) -> Result { + let account_has_public_key = wsv.map_account(&self.payload.account_id, |account| { + account.contains_signatory(self.signature.public_key()) + })?; + if !account_has_public_key { + return Err(QueryError::Signature(String::from( + "Signature public key doesn't correspond to the account.", + ))); + } + query_validator + .check(&self.payload.account_id, &self.payload.query, wsv) + .map_err(QueryError::Permission)?; + Ok(ValidQueryRequest::new(self.payload.query)) + } +} + +impl TryFrom for VerifiedQueryRequest { + type Error = QueryError; + + fn try_from(query: SignedQueryRequest) -> Result { + query + .signature + .verify(&query.payload) + .map(|_| Self { + payload: query.payload, + signature: query.signature, + }) + .map_err(|e| Self::Error::Signature(e.to_string())) + } +} #[iroha_futures::telemetry_future] pub(crate) async fn handle_instructions( @@ -60,8 +123,8 @@ pub(crate) async fn handle_queries( } #[allow(clippy::needless_pass_by_value)] // Required for `map_err`. -fn into_reply(error: query::Error) -> warp::http::Response { - reply::with_status(Scale(&error), error.status_code()).into_response() +fn into_reply(error: QueryError) -> warp::http::Response { + reply::with_status(Scale(&error), super::query_status_code(&error)).into_response() } #[derive(serde::Serialize)] @@ -108,9 +171,7 @@ async fn handle_get_configuration( Docs(field) => { Configuration::get_doc_recursive(field.iter().map(AsRef::as_ref).collect::>()) .wrap_err("Failed to get docs {:?field}") - .and_then(|doc| { - Context::wrap_err(serde_json::to_value(doc), "Failed to serialize docs") - }) + .and_then(|doc| serde_json::to_value(doc).wrap_err("Failed to serialize docs")) } Value => serde_json::to_value(iroha_cfg).wrap_err("Failed to serialize value"), } @@ -190,9 +251,8 @@ async fn stream_blocks( mod subscription { //! Contains the `handle_subscription` functions and used for general routing. - use iroha_core::event; - use super::*; + use crate::event; /// Type for any error during subscription handling #[derive(thiserror::Error, Debug)] @@ -233,7 +293,7 @@ mod subscription { /// There should be a [`warp::filters::ws::Message::close()`] message to end subscription #[iroha_futures::telemetry_future] pub async fn handle_subscription(events: EventsSender, stream: WebSocket) -> eyre::Result<()> { - let mut consumer = Consumer::new(stream).await?; + let mut consumer = event::Consumer::new(stream).await?; match subscribe_forever(events, &mut consumer).await { Ok(()) | Err(Error::CloseMessage) => consumer.close_stream().await.map_err(Into::into), @@ -244,7 +304,7 @@ mod subscription { /// Make endless `consumer` subscription for `events` /// /// Ideally should return `Result` cause it either runs forever either returns `Err` variant - async fn subscribe_forever(events: EventsSender, consumer: &mut Consumer) -> Result<()> { + async fn subscribe_forever(events: EventsSender, consumer: &mut event::Consumer) -> Result<()> { let mut events = events.subscribe(); loop { @@ -335,7 +395,9 @@ pub(crate) async fn handle_rejection(rejection: Rejection) -> Result reply::with_status(utils::Scale(err), err.status_code()).into_response(), + Query(err) => { + reply::with_status(utils::Scale(err), super::query_status_code(err)).into_response() + } VersionedTransaction(err) => { reply::with_status(err.to_string(), err.status_code()).into_response() } diff --git a/cli/src/torii/tests.rs b/cli/src/torii/tests.rs index cbb07b04ba6..74b186fbb58 100644 --- a/cli/src/torii/tests.rs +++ b/cli/src/torii/tests.rs @@ -14,18 +14,20 @@ use iroha_core::{ }, queue::Queue, smartcontracts::{isi::error::FindError, permissions::DenyAll}, - stream::{Sink, Stream}, sumeragi::view_change::ProofChain, tx::TransactionValidator, wsv::World, }; -use iroha_data_model::account::GENESIS_ACCOUNT_NAME; +use iroha_data_model::{account::GENESIS_ACCOUNT_NAME, prelude::*}; use iroha_version::prelude::*; use tokio::time; use warp::test::WsClient; use super::{routing::*, *}; -use crate::samples::{get_config, get_trusted_peers}; +use crate::{ + samples::{get_config, get_trusted_peers}, + stream::{Sink, Stream}, +}; async fn create_torii() -> (Torii, KeyPair) { let mut config = crate::samples::get_config(crate::samples::get_trusted_peers(None), None); @@ -47,7 +49,7 @@ async fn create_torii() -> (Torii, KeyPair) { .add_account( Account::new( AccountId::from_str("alice@wonderland").expect("Valid"), - [keys.public_key.clone()], + [keys.public_key().clone()], ) .build() ) @@ -250,9 +252,10 @@ fn register_domain() -> Instruction { } fn register_account(name: &str) -> Instruction { + let (public_key, _) = KeyPair::generate().unwrap().into(); RegisterBox::new(Account::new( AccountId::new(name.parse().expect("Valid"), DOMAIN.parse().expect("Valid")), - [KeyPair::generate().unwrap().public_key], + [public_key], )) .into() } @@ -690,11 +693,7 @@ async fn blocks_stream() { fn domains( configuration: &crate::config::Configuration, ) -> eyre::Result> { - let key = configuration - .genesis - .account_public_key - .clone() - .ok_or_else(|| eyre!("Genesis account public key is not specified."))?; + let key = configuration.genesis.account_public_key.clone(); Ok([Domain::from(GenesisDomain::new(key))].into_iter()) } @@ -702,11 +701,11 @@ fn domains( fn hash_should_be_the_same() { let key_pair = KeyPair::generate().expect("Failed to generate key pair."); let mut config = get_config( - get_trusted_peers(Some(&key_pair.public_key)), + get_trusted_peers(Some(key_pair.public_key())), Some(key_pair.clone()), ); - config.genesis.account_private_key = Some(key_pair.private_key.clone()); - config.genesis.account_public_key = Some(key_pair.public_key.clone()); + config.genesis.account_private_key = Some(key_pair.private_key().clone()); + config.genesis.account_public_key = key_pair.public_key().clone(); let tx = Transaction::new( AccountId::new( @@ -742,10 +741,11 @@ fn hash_should_be_the_same() { #[tokio::test] async fn test_subscription_websocket_clean_closing() { - use iroha_core::stream::{Sink, Stream}; use iroha_data_model::events::{pipeline, EventFilter}; use warp::filters::ws; + use crate::stream::{Sink, Stream}; + let (torii, _) = create_torii().await; let router = torii.create_api_router(); diff --git a/cli/src/torii/utils.rs b/cli/src/torii/utils.rs index 5fe30b346b7..a4e72d4862e 100644 --- a/cli/src/torii/utils.rs +++ b/cli/src/torii/utils.rs @@ -4,7 +4,7 @@ use iroha_version::scale::DecodeVersioned; use parity_scale_codec::Encode; use warp::{hyper::body::Bytes, reply::Response, Filter, Rejection, Reply}; -use super::VerifiedQueryRequest; +use super::routing::VerifiedQueryRequest; /// Structure for empty response body #[derive(Clone, Copy)] @@ -36,8 +36,33 @@ macro_rules! add_state { } pub mod body { + use iroha_core::smartcontracts::query::Error as QueryError; + use iroha_data_model::query::VersionedSignedQueryRequest; + use super::*; + #[derive(Debug)] + pub struct WarpQueryError(QueryError); + + impl From for WarpQueryError { + fn from(source: QueryError) -> Self { + Self(source) + } + } + + impl warp::reject::Reject for WarpQueryError {} + + impl TryFrom<&Bytes> for super::VerifiedQueryRequest { + type Error = WarpQueryError; + + fn try_from(body: &Bytes) -> Result { + let query = VersionedSignedQueryRequest::decode_versioned(body.as_ref()) + .map_err(|e| WarpQueryError(QueryError::Decode(Box::new(e))))?; + let VersionedSignedQueryRequest::V1(query) = query; + Ok(Self::try_from(query)?) + } + } + /// Decode query request pub fn query() -> impl Filter + Copy { warp::body::bytes() diff --git a/client/Cargo.toml b/client/Cargo.toml index c4bc799856c..7a47e504b83 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -40,7 +40,6 @@ base64 = "0.13.0" iroha_core = { version = "=2.0.0-pre-rc.3", path = "../core", features = ["dev-telemetry", "telemetry"] } iroha_permissions_validators = { version = "=2.0.0-pre-rc.3", path = "../permissions_validators" } iroha = { path = "../cli", features = ["dev-telemetry", "telemetry"] } -iroha_data_model = { version = "=2.0.0-pre-rc.3", path = "../data_model", features = ["warp", "cross_crate_testing", "roles"] } test_network = { version = "=2.0.0-pre-rc.3", path = "../core/test_network" } diff --git a/client/benches/torii.rs b/client/benches/torii.rs index a829a1e6f92..1008e200dd4 100644 --- a/client/benches/torii.rs +++ b/client/benches/torii.rs @@ -30,7 +30,7 @@ fn query_requests(criterion: &mut Criterion) { RawGenesisBlock::new( "alice".parse().expect("Valid"), "wonderland".parse().expect("Valid"), - get_key_pair().public_key, + get_key_pair().public_key().clone(), ), &configuration.genesis, &configuration.sumeragi.transaction_limits, @@ -52,12 +52,10 @@ fn query_requests(criterion: &mut Criterion) { let domain_id: DomainId = "domain".parse().expect("Valid"); let create_domain = RegisterBox::new(Domain::new(domain_id.clone())); let account_id = AccountId::new("account".parse().expect("Valid"), domain_id.clone()); - let create_account = RegisterBox::new(Account::new( - account_id.clone(), - [KeyPair::generate() - .expect("Failed to generate KeyPair.") - .public_key], - )); + let (public_key, _) = KeyPair::generate() + .expect("Failed to generate KeyPair") + .into(); + let create_account = RegisterBox::new(Account::new(account_id.clone(), [public_key])); let asset_definition_id = AssetDefinitionId::new("xor".parse().expect("Valid"), domain_id); let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); @@ -144,12 +142,10 @@ fn instruction_submits(criterion: &mut Criterion) { let domain_id: DomainId = "domain".parse().expect("Valid"); let create_domain = RegisterBox::new(Domain::new(domain_id.clone())); let account_id = AccountId::new("account".parse().expect("Valid"), domain_id.clone()); - let create_account = RegisterBox::new(Account::new( - account_id.clone(), - [KeyPair::generate() - .expect("Failed to generate Key-pair.") - .public_key], - )); + let (public_key, _) = KeyPair::generate() + .expect("Failed to generate Key-pair.") + .into(); + let create_account = RegisterBox::new(Account::new(account_id.clone(), [public_key])); let asset_definition_id = AssetDefinitionId::new("xor".parse().expect("Valid"), domain_id); let mut client_config = iroha_client::samples::get_client_config(&get_key_pair()); client_config.torii_api_url = small::SmallStr::from_string(peer.api_address.clone()); diff --git a/client/benches/tps/lib.rs b/client/benches/tps/lib.rs index e0ef911786e..4ee7611a421 100644 --- a/client/benches/tps/lib.rs +++ b/client/benches/tps/lib.rs @@ -117,12 +117,11 @@ impl MeasurerUnit { /// Submit initial transactions for measurement #[allow(clippy::expect_used, clippy::unwrap_in_result)] fn ready(mut self) -> Result { - let register_me = RegisterBox::new(Account::new( - account_id(self.name), - [iroha_core::prelude::KeyPair::generate() - .expect("Failed to generate KeyPair.") - .public_key], - )); + let (public_key, _) = iroha_core::prelude::KeyPair::generate() + .expect("Failed to generate KeyPair.") + .into(); + + let register_me = RegisterBox::new(Account::new(account_id(self.name), [public_key])); let mint_a_rose = MintBox::new(1_u32, asset_id(self.name)); let _ = self.client.submit_blocking(register_me)?; diff --git a/client/examples/million_accounts_genesis.rs b/client/examples/million_accounts_genesis.rs index e7b7ce34a81..6c432aaa965 100644 --- a/client/examples/million_accounts_genesis.rs +++ b/client/examples/million_accounts_genesis.rs @@ -1,9 +1,8 @@ #![allow(missing_docs, clippy::pedantic, clippy::restriction)] use iroha::samples::get_config; -use iroha_core::{ - genesis::{GenesisNetwork, GenesisNetworkTrait, RawGenesisBlock, RawGenesisBlockBuilder}, - prelude::*, +use iroha_core::genesis::{ + GenesisNetwork, GenesisNetworkTrait, RawGenesisBlock, RawGenesisBlockBuilder, }; use iroha_data_model::prelude::*; use test_network::{get_key_pair, Peer as TestPeer, TestRuntime}; @@ -12,12 +11,14 @@ use tokio::runtime::Runtime; fn main() { fn generate_genesis(num_domains: u32) -> RawGenesisBlock { let mut builder = RawGenesisBlockBuilder::new(); + + let key_pair = get_key_pair(); for i in 0_u32..num_domains { builder = builder .domain(format!("wonderland-{}", i).parse().expect("Valid")) .with_account( format!("Alice-{}", i).parse().expect("Valid"), - PublicKey::default(), + key_pair.public_key().clone(), ) .with_asset( AssetDefinition::quantity( @@ -29,6 +30,7 @@ fn main() { ) .finish_domain(); } + builder.build() } let mut peer = ::new().expect("Failed to create peer"); diff --git a/client/src/client.rs b/client/src/client.rs index 0194d2a7489..ed29cd1c0b8 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -73,10 +73,10 @@ impl Client { torii_url: configuration.torii_api_url.clone(), telemetry_url: configuration.torii_telemetry_url.clone(), transaction_limits: configuration.transaction_limits, - key_pair: KeyPair { - public_key: configuration.public_key.clone(), - private_key: configuration.private_key.clone(), - }, + key_pair: KeyPair::new( + configuration.public_key.clone(), + configuration.private_key.clone(), + ), proposed_transaction_ttl_ms: configuration.transaction_time_to_live_ms, transaction_status_timeout: Duration::from_millis( configuration.transaction_status_timeout_ms, @@ -632,7 +632,7 @@ impl Drop for EventIterator { impl Debug for Client { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("Client") - .field("public_key", &self.key_pair.public_key) + .field("public_key", self.key_pair.public_key()) .field("torii_url", &self.torii_url) .field("telemetry_url", &self.telemetry_url) .finish() @@ -728,10 +728,11 @@ mod tests { #[test] fn txs_same_except_for_nonce_have_different_hashes() { - let keys = KeyPair::generate().unwrap(); + let (public_key, private_key) = KeyPair::generate().unwrap().into(); + let cfg = Configuration { - public_key: keys.public_key, - private_key: keys.private_key, + public_key, + private_key, add_transaction_nonce: true, ..Configuration::default() }; diff --git a/client/src/config.rs b/client/src/config.rs index 2c707ecc523..ac2794ba5ed 100644 --- a/client/src/config.rs +++ b/client/src/config.rs @@ -2,7 +2,7 @@ use std::{fmt, fs::File, io::BufReader, path::Path, str::FromStr}; use eyre::{eyre, Result, WrapErr}; use iroha_config::derive::Configurable; -use iroha_crypto::{PrivateKey, PublicKey}; +use iroha_crypto::prelude::*; use iroha_data_model::{prelude::*, transaction}; use iroha_logger::Configuration as LoggerConfiguration; use serde::{Deserialize, Serialize}; @@ -98,11 +98,12 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { - #[allow(clippy::expect_used)] + let (public_key, private_key) = Self::placeholder_keypair().into(); + Self { - public_key: PublicKey::default(), - private_key: PrivateKey::default(), - account_id: AccountId::from_str("").expect("Empty strings are valid"), + public_key, + private_key, + account_id: Self::placeholder_account(), basic_auth: None, torii_api_url: small::SmallStr::from_str(uri::DEFAULT_API_URL), torii_telemetry_url: small::SmallStr::from_str(DEFAULT_TORII_TELEMETRY_URL), @@ -119,6 +120,26 @@ impl Default for Configuration { } impl Configuration { + /// Key-pair used by default for demo purposes + #[allow(clippy::expect_used)] + fn placeholder_keypair() -> KeyPair { + let public_key = "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0" + .parse() + .expect("Public key not in mulithash format"); + let private_key = PrivateKey::from_hex( + Algorithm::Ed25519, + "9ac47abf59b356e0bd7dcbbbb4dec080e302156a48ca907e47cb6aea1d32719e7233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0" + ).expect("Private key not hex encoded"); + + KeyPair::new(public_key, private_key) + } + + /// Account ID used by default for demo purposes + #[allow(clippy::expect_used)] + fn placeholder_account() -> ::Id { + AccountId::from_str("alice@wonderland").expect("Account ID not valid") + } + /// This method will build `Configuration` from a json *pretty* formatted file (without `:` in /// key names). /// diff --git a/client/tests/integration/asset_propagation.rs b/client/tests/integration/asset_propagation.rs index a3944bed10d..fbe6601c818 100644 --- a/client/tests/integration/asset_propagation.rs +++ b/client/tests/integration/asset_propagation.rs @@ -20,10 +20,8 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount_on_a let create_domain = RegisterBox::new(Domain::new(DomainId::from_str("domain")?)); let account_id = AccountId::from_str("account@domain")?; - let create_account = RegisterBox::new(Account::new( - account_id.clone(), - [KeyPair::generate()?.public_key], - )); + let (public_key, _) = KeyPair::generate()?.into(); + let create_account = RegisterBox::new(Account::new(account_id.clone(), [public_key])); let asset_definition_id = AssetDefinitionId::from_str("xor#domain")?; let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); diff --git a/client/tests/integration/burn_public_keys.rs b/client/tests/integration/burn_public_keys.rs index 7dfdbcdb234..81bf0fd4322 100644 --- a/client/tests/integration/burn_public_keys.rs +++ b/client/tests/integration/burn_public_keys.rs @@ -40,8 +40,10 @@ fn public_keys_cannot_be_burned_to_nothing() { let mut keys_count = bob_keys_count(&mut client); assert_eq!(keys_count, 0); - let mint_keys = (0..KEYS_COUNT) - .map(|_| MintBox::new(KeyPair::generate().unwrap().public_key, bob_id.clone()).into()); + let mint_keys = (0..KEYS_COUNT).map(|_| { + let (public_key, _) = KeyPair::generate().unwrap().into(); + MintBox::new(public_key, bob_id.clone()).into() + }); let _ = submit_and_get(&mut client, mint_keys); keys_count = bob_keys_count(&mut client); diff --git a/client/tests/integration/multiple_blocks_created.rs b/client/tests/integration/multiple_blocks_created.rs index 092e4ab7a65..04955de425f 100644 --- a/client/tests/integration/multiple_blocks_created.rs +++ b/client/tests/integration/multiple_blocks_created.rs @@ -21,12 +21,10 @@ fn long_multiple_blocks_created() { let create_domain = RegisterBox::new(Domain::new("domain".parse().expect("Valid"))); let account_id: AccountId = "account@domain".parse().expect("Valid"); - let create_account = RegisterBox::new(Account::new( - account_id.clone(), - [KeyPair::generate() - .expect("Failed to generate KeyPair.") - .public_key], - )); + let (public_key, _) = KeyPair::generate() + .expect("Failed to generate KeyPair") + .into(); + let create_account = RegisterBox::new(Account::new(account_id.clone(), [public_key])); let asset_definition_id: AssetDefinitionId = "xor#domain".parse().expect("Valid"); let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); diff --git a/client/tests/integration/multisignature_account.rs b/client/tests/integration/multisignature_account.rs index 914939244c4..24372f416cd 100644 --- a/client/tests/integration/multisignature_account.rs +++ b/client/tests/integration/multisignature_account.rs @@ -23,7 +23,7 @@ fn transaction_signed_by_new_signatory_of_account_should_pass() -> Result<()> { RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); let key_pair = KeyPair::generate()?; let add_signatory = MintBox::new( - key_pair.public_key.clone(), + key_pair.public_key().clone(), IdBox::AccountId(account_id.clone()), ); diff --git a/client/tests/integration/multisignature_transaction.rs b/client/tests/integration/multisignature_transaction.rs index 09f26e31139..a0926e9c8f8 100644 --- a/client/tests/integration/multisignature_transaction.rs +++ b/client/tests/integration/multisignature_transaction.rs @@ -25,7 +25,7 @@ fn multisignature_transactions_should_wait_for_all_signatures() { let key_pair_2 = KeyPair::generate().expect("Failed to generate KeyPair."); let create_account = RegisterBox::new(Account::new( account_id.clone(), - [key_pair_1.public_key.clone()], + [key_pair_1.public_key().clone()], )); let asset_definition_id = AssetDefinitionId::from_str("xor#domain").expect("Valid"); let create_asset = @@ -34,7 +34,10 @@ fn multisignature_transactions_should_wait_for_all_signatures() { SignatureCheckCondition( ContainsAll::new( ContextValue::new(TRANSACTION_SIGNATORIES_VALUE), - vec![key_pair_1.public_key.clone(), key_pair_2.public_key.clone()], + vec![ + key_pair_1.public_key().clone(), + key_pair_2.public_key().clone(), + ], ) .into(), ), @@ -62,9 +65,11 @@ fn multisignature_transactions_should_wait_for_all_signatures() { Value::U32(quantity), IdBox::AssetId(AssetId::new(asset_definition_id, account_id.clone())), ); + + let (public_key1, private_key1) = key_pair_1.into(); client_configuration.account_id = account_id.clone(); - client_configuration.public_key = key_pair_1.public_key; - client_configuration.private_key = key_pair_1.private_key; + client_configuration.public_key = public_key1; + client_configuration.private_key = private_key1; let iroha_client = Client::new(&client_configuration); let instructions: Vec = vec![mint_asset.clone().into()]; let transaction = iroha_client @@ -89,8 +94,9 @@ fn multisignature_transactions_should_wait_for_all_signatures() { .request(request.clone()) .expect("Query failed.") .is_empty()); - client_configuration.public_key = key_pair_2.public_key; - client_configuration.private_key = key_pair_2.private_key; + let (public_key2, private_key2) = key_pair_2.into(); + client_configuration.public_key = public_key2; + client_configuration.private_key = private_key2; let iroha_client_2 = Client::new(&client_configuration); let instructions: Vec = vec![mint_asset.into()]; let transaction = iroha_client_2 diff --git a/client/tests/integration/roles.rs b/client/tests/integration/roles.rs index 8fbd54d9a3c..b30a8b89f5a 100644 --- a/client/tests/integration/roles.rs +++ b/client/tests/integration/roles.rs @@ -1,6 +1,6 @@ #![allow(clippy::restriction)] -use std::{collections::BTreeMap, str::FromStr as _, time::Duration}; +use std::{str::FromStr as _, time::Duration}; use eyre::{eyre, Result}; use iroha_client::client::{self, Client}; @@ -44,16 +44,15 @@ fn add_role_to_limit_transfer_count() -> Result<()> { // Registering new role which sets `Transfer` execution count limit to // `COUNT` for every `PERIOD_MS` milliseconds - let permission_token = PermissionToken::new( - transfer::CAN_TRANSFER_ONLY_FIXED_NUMBER_OF_TIMES_PER_PERIOD.clone(), - [ - ( - transfer::PERIOD_PARAM_NAME.clone(), - Value::U128(PERIOD_MS.into()), - ), - (transfer::COUNT_PARAM_NAME.clone(), Value::U32(COUNT)), - ], - ); + let permission_token = + PermissionToken::new(transfer::CAN_TRANSFER_ONLY_FIXED_NUMBER_OF_TIMES_PER_PERIOD.clone()) + .with_params([ + ( + transfer::PERIOD_PARAM_NAME.clone(), + Value::U128(PERIOD_MS.into()), + ), + (transfer::COUNT_PARAM_NAME.clone(), Value::U32(COUNT)), + ]); let permissions = Permissions::from([permission_token]); let register_role = RegisterBox::new(Role::new(role_id.clone(), permissions)); test_client.submit_blocking(register_role)?; @@ -114,10 +113,7 @@ fn register_role_with_empty_token_params() -> Result<()> { let role_id = iroha_data_model::role::Id::new("root".parse::().expect("Valid")); let mut permissions = Permissions::new(); - permissions.insert(PermissionToken { - name: "token".parse().expect("Valid"), - params: BTreeMap::new(), - }); + permissions.insert(PermissionToken::new("token".parse().expect("Valid"))); let register_role = RegisterBox::new(Role::new(role_id, permissions)); test_client.submit(register_role)?; diff --git a/client/tests/integration/transfer_asset.rs b/client/tests/integration/transfer_asset.rs index f3f4db463ad..b64ed04ba76 100644 --- a/client/tests/integration/transfer_asset.rs +++ b/client/tests/integration/transfer_asset.rs @@ -18,18 +18,14 @@ fn client_can_transfer_asset_to_another_account() { let create_domain = RegisterBox::new(Domain::new("domain".parse().expect("Valid"))); let account1_id: AccountId = "account1@domain".parse().expect("Valid"); let account2_id: AccountId = "account2@domain".parse().expect("Valid"); - let create_account1 = RegisterBox::new(Account::new( - account1_id.clone(), - [KeyPair::generate() - .expect("Failed to generate KeyPair.") - .public_key], - )); - let create_account2 = RegisterBox::new(Account::new( - account2_id.clone(), - [KeyPair::generate() - .expect("Failed to generate KeyPair.") - .public_key], - )); + let (public_key1, _) = KeyPair::generate() + .expect("Failed to generate KeyPair") + .into(); + let (public_key2, _) = KeyPair::generate() + .expect("Failed to generate KeyPair") + .into(); + let create_account1 = RegisterBox::new(Account::new(account1_id.clone(), [public_key1])); + let create_account2 = RegisterBox::new(Account::new(account2_id.clone(), [public_key2])); let asset_definition_id: AssetDefinitionId = "xor#domain".parse().expect("Valid"); let quantity: u32 = 200; let create_asset = diff --git a/client/tests/integration/unregister_peer.rs b/client/tests/integration/unregister_peer.rs index 7288cf0f838..6650540355d 100644 --- a/client/tests/integration/unregister_peer.rs +++ b/client/tests/integration/unregister_peer.rs @@ -102,10 +102,8 @@ fn init() -> Result<( iroha_logger::info!("Started"); let create_domain = RegisterBox::new(Domain::new("domain".parse().expect("Valid"))); let account_id: AccountId = "account@domain".parse().expect("Valid"); - let create_account = RegisterBox::new(Account::new( - account_id.clone(), - [KeyPair::generate()?.public_key], - )); + let (public_key, _) = KeyPair::generate()?.into(); + let create_account = RegisterBox::new(Account::new(account_id.clone(), [public_key])); let asset_definition_id: AssetDefinitionId = "xor#domain".parse().expect("Valid"); let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).build()); diff --git a/configs/peer/config.json b/configs/peer/config.json index 4efaa56d190..8f5ee24946e 100644 --- a/configs/peer/config.json +++ b/configs/peer/config.json @@ -7,7 +7,7 @@ "TRUSTED_PEERS": [ { "address": "127.0.0.1:1337", - "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0" + "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" }, { "address": "127.0.0.1:1338", @@ -31,16 +31,16 @@ "GOSSIP_PERIOD_MS": 10000, "BATCH_SIZE": 4 }, - "PUBLIC_KEY": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0", + "PUBLIC_KEY": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b", "PRIVATE_KEY": { "digest_function": "ed25519", - "payload": "9ac47abf59b356e0bd7dcbbbb4dec080e302156a48ca907e47cb6aea1d32719e7233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0" + "payload": "282ed9f3cf92811c3818dbc4ae594ed59dc1a2f78e4241e31924e101d6b1fb831c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" }, "GENESIS": { - "ACCOUNT_PUBLIC_KEY": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0", + "ACCOUNT_PUBLIC_KEY": "ed01204cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf", "ACCOUNT_PRIVATE_KEY": { "digest_function": "ed25519", - "payload": "9ac47abf59b356e0bd7dcbbbb4dec080e302156a48ca907e47cb6aea1d32719e7233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0" + "payload": "d748e18ce60cb30dea3e73c9019b7af45a8d465e3d71bcc9a5ef99a008205e534cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf" } } } diff --git a/configs/peer/genesis.json b/configs/peer/genesis.json index 3c0f7cbf670..b0b8523644b 100644 --- a/configs/peer/genesis.json +++ b/configs/peer/genesis.json @@ -11,6 +11,7 @@ "id": { "name": "wonderland" }, + "logo": null, "metadata": {} } } @@ -53,8 +54,8 @@ } }, "value_type": "Quantity", - "metadata": {}, - "mintable": true + "mintable": "Infinitely", + "metadata": {} } } } diff --git a/core/Cargo.toml b/core/Cargo.toml index 06b0c081288..1caad3de504 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -12,15 +12,16 @@ keywords = ["crypto", "blockchain", "ledger"] categories = ["cryptography::cryptocurrencies"] [features] +default = ["bridge", "cli", "telemetry", "roles"] + bridge = [] -dex = [] +# Include support for account roles roles = ["iroha_data_model/roles"] telemetry = [] cli = [] -cross_crate_testing = [] +dex = [] dev-telemetry = ["telemetry", "iroha_telemetry/dev-telemetry"] expensive-telemetry = ["iroha_telemetry/metric-instrumentation"] -default = ["bridge", "cli", "telemetry", "roles"] [badges] is-it-maintained-issue-resolution = { repository = "https://github.com/hyperledger/iroha" } @@ -52,7 +53,6 @@ serde_json = "1.0" tokio = { version = "1.6.0", features = ["sync", "time", "rt", "io-util", "rt-multi-thread", "macros", "fs"]} tokio-stream = { version = "0.1.6", features = ["fs"]} crossbeam-queue = "0.3" -warp = "0.3" thiserror = "1.0.28" pin-project = "1" wasmtime = "0.35.1" @@ -66,7 +66,6 @@ anyhow = ">= 1.0" [dev-dependencies] tempfile = "3" criterion = "0.3" -iroha_data_model = { version = "=2.0.0-pre-rc.3", path = "../data_model", features = ["warp", "cross_crate_testing"] } hex = "0.4.0" byte-unit = "4.0.12" once_cell = "1.8.0" diff --git a/core/benches/sumeragi.rs b/core/benches/sumeragi.rs index 4750715db19..a0f1c34ae25 100644 --- a/core/benches/sumeragi.rs +++ b/core/benches/sumeragi.rs @@ -13,7 +13,8 @@ fn get_n_peers(n: usize) -> Vec { address: format!("127.0.0.{}", i), public_key: KeyPair::generate() .expect("Failed to generate KeyPair.") - .public_key, + .public_key() + .clone(), }) .collect() } @@ -21,7 +22,7 @@ fn get_n_peers(n: usize) -> Vec { fn sort_peers(criterion: &mut Criterion) { let peers = get_n_peers(N_PEERS); let _ = criterion.bench_function("sort_peers", |b| { - let hash = HashOf::from_hash(Hash([0_u8; 32])); + let hash = HashOf::new(&[1_u8; Hash::LENGTH]).transmute(); b.iter(|| network_topology::sort_peers_by_hash(peers.clone(), &hash)); }); } diff --git a/core/benches/validation.rs b/core/benches/validation.rs index 4b60884dbba..f68936d83ac 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -26,14 +26,15 @@ fn build_test_transaction(keys: KeyPair) -> Transaction { let domain_id = DomainId::from_str(domain_name).expect("does not panic"); let create_domain = RegisterBox::new(Domain::new(domain_id)); let account_name = "account"; + let (public_key, _) = KeyPair::generate() + .expect("Failed to generate KeyPair.") + .into(); let create_account = RegisterBox::new(Account::new( AccountId::new( account_name.parse().expect("Valid"), domain_name.parse().expect("Valid"), ), - [KeyPair::generate() - .expect("Failed to generate KeyPair.") - .public_key], + [public_key], )); let asset_definition_id = AssetDefinitionId::new( "xor".parse().expect("Valid"), @@ -58,6 +59,8 @@ fn build_test_transaction(keys: KeyPair) -> Transaction { } fn build_test_wsv(keys: KeyPair) -> WorldStateView { + let (public_key, _) = keys.into(); + WorldStateView::new({ let domain_id = DomainId::from_str(START_DOMAIN).expect("Valid"); let mut domain = Domain::new(domain_id).build(); @@ -65,7 +68,7 @@ fn build_test_wsv(keys: KeyPair) -> WorldStateView { START_ACCOUNT.parse().expect("Valid"), START_DOMAIN.parse().expect("Valid"), ); - let account = Account::new(account_id, [keys.public_key]).build(); + let account = Account::new(account_id, [public_key]).build(); assert!(domain.add_account(account).is_none()); World::with([domain], BTreeSet::new()) }) @@ -199,7 +202,8 @@ fn validate_blocks(criterion: &mut Criterion) { "root".parse().expect("Valid"), domain_name.parse().expect("Valid"), ); - let account = Account::new(account_id, [key_pair.public_key]).build(); + let (public_key, _) = key_pair.into(); + let account = Account::new(account_id, [public_key]).build(); let domain_id = DomainId::from_str(domain_name).expect("is valid"); let mut domain = Domain::new(domain_id).build(); assert!(domain.add_account(account).is_none()); diff --git a/core/docs/Cargo.toml b/core/docs/Cargo.toml index 7706f36cf9c..d53cb713a0d 100644 --- a/core/docs/Cargo.toml +++ b/core/docs/Cargo.toml @@ -6,13 +6,14 @@ 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] +default = ["roles", "dex", "telemetry", "dev-telemetry"] +# Include support for account roles roles = ["iroha_core/roles"] dex = ["iroha_core/dex"] telemetry = ["iroha_core/telemetry"] dev-telemetry = ["iroha_core/dev-telemetry"] -default = ["roles", "dex", "telemetry", "dev-telemetry"] [dependencies] diff --git a/core/src/block.rs b/core/src/block.rs index fbec7f30214..c22fa25f1b6 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -10,10 +10,8 @@ use std::{collections::BTreeSet, error::Error, iter, marker::PhantomData}; use dashmap::{mapref::one::Ref as MapRef, DashMap}; use eyre::{eyre, Context, Result}; -use iroha_crypto::{HashOf, KeyPair, SignatureOf, SignaturesOf}; -use iroha_data_model::{ - current_time, events::prelude::*, merkle::MerkleTree, transaction::prelude::*, -}; +use iroha_crypto::{HashOf, KeyPair, MerkleTree, SignatureOf, SignaturesOf}; +use iroha_data_model::{current_time, events::prelude::*, transaction::prelude::*}; use iroha_schema::IntoSchema; use iroha_version::{declare_versioned_with_scale, version_with_scale}; use parity_scale_codec::{Decode, Encode}; @@ -49,7 +47,7 @@ impl Default for EmptyChainHash { impl From> for HashOf { fn from(EmptyChainHash(PhantomData): EmptyChainHash) -> Self { - Self::from_hash(Hash([0_u8; 32])) + Hash::zeroed().typed() } } @@ -220,8 +218,8 @@ impl PendingBlock { consensus_estimation: DEFAULT_CONSENSUS_ESTIMATION_MS, height: height + 1, previous_block_hash, - transactions_hash: HashOf::from_hash(Hash([0_u8; 32])), - rejected_transactions_hash: HashOf::from_hash(Hash([0_u8; 32])), + transactions_hash: Hash::zeroed().typed(), + rejected_transactions_hash: Hash::zeroed().typed(), view_change_proofs, invalidated_blocks_hashes, genesis_topology: None, @@ -239,8 +237,8 @@ impl PendingBlock { consensus_estimation: DEFAULT_CONSENSUS_ESTIMATION_MS, height: 1, previous_block_hash: EmptyChainHash::default().into(), - transactions_hash: HashOf::from_hash(Hash([0_u8; 32])), - rejected_transactions_hash: HashOf::from_hash(Hash([0_u8; 32])), + transactions_hash: Hash::zeroed().typed(), + rejected_transactions_hash: Hash::zeroed().typed(), view_change_proofs: ViewChangeProofs::empty(), invalidated_blocks_hashes: Vec::new(), genesis_topology: Some(genesis_topology), @@ -258,8 +256,8 @@ impl PendingBlock { consensus_estimation: DEFAULT_CONSENSUS_ESTIMATION_MS, height: 1, previous_block_hash: EmptyChainHash::default().into(), - transactions_hash: HashOf::from_hash(Hash([0_u8; 32])), - rejected_transactions_hash: HashOf::from_hash(Hash([0_u8; 32])), + transactions_hash: Hash::zeroed().typed(), + rejected_transactions_hash: Hash::zeroed().typed(), view_change_proofs: ViewChangeProofs::empty(), invalidated_blocks_hashes: Vec::new(), genesis_topology: None, diff --git a/core/src/genesis.rs b/core/src/genesis.rs index e61b863e61a..3cc8650ce5c 100644 --- a/core/src/genesis.rs +++ b/core/src/genesis.rs @@ -184,16 +184,13 @@ impl GenesisNetworkTrait for GenesisNetwork { .transactions .iter() .map(|raw_transaction| { - let genesis_key_pair = KeyPair { - public_key: genesis_config - .account_public_key - .clone() - .ok_or_else(|| eyre!("Genesis account public key is empty."))?, - private_key: genesis_config + let genesis_key_pair = KeyPair::new( + genesis_config.account_public_key.clone(), + genesis_config .account_private_key .clone() .ok_or_else(|| eyre!("Genesis account private key is empty."))?, - }; + ); raw_transaction.sign_and_accept(genesis_key_pair, tx_limits) }) @@ -310,22 +307,22 @@ impl GenesisTransaction { /// Module with genesis configuration logic. pub mod config { use iroha_config::derive::Configurable; - use iroha_crypto::{PrivateKey, PublicKey}; + use iroha_crypto::{KeyPair, PrivateKey, PublicKey}; use serde::{Deserialize, Serialize}; const DEFAULT_WAIT_FOR_PEERS_RETRY_COUNT: u64 = 100; const DEFAULT_WAIT_FOR_PEERS_RETRY_PERIOD_MS: u64 = 500; const DEFAULT_GENESIS_SUBMISSION_DELAY_MS: u64 = 1000; - #[derive(Clone, Deserialize, Serialize, Debug, Configurable, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Configurable)] + #[serde(default)] #[serde(rename_all = "UPPERCASE")] #[config(env_prefix = "IROHA_GENESIS_")] /// Configuration of the genesis block and the process of its submission. pub struct GenesisConfiguration { /// The genesis account public key, should be supplied to all peers. - /// The type is `Option` just because it might be loaded from environment variables and not from `config.json`. #[config(serde_as_str)] - pub account_public_key: Option, + pub account_public_key: PublicKey, /// Genesis account private key, only needed on the peer that submits the genesis block. pub account_private_key: Option, /// Number of attempts to connect to peers, while waiting for them to submit genesis. @@ -340,11 +337,14 @@ pub mod config { pub genesis_submission_delay_ms: u64, } + #[allow(clippy::expect_used)] impl Default for GenesisConfiguration { fn default() -> Self { + let (public_key, private_key) = Self::placeholder_keypair().into(); + Self { - account_public_key: None, - account_private_key: None, + account_public_key: public_key, + account_private_key: Some(private_key), wait_for_peers_retry_count: DEFAULT_WAIT_FOR_PEERS_RETRY_COUNT, wait_for_peers_retry_period_ms: DEFAULT_WAIT_FOR_PEERS_RETRY_PERIOD_MS, genesis_submission_delay_ms: DEFAULT_GENESIS_SUBMISSION_DELAY_MS, @@ -352,6 +352,23 @@ pub mod config { } } + impl GenesisConfiguration { + /// Key-pair used by default for demo purposes + #[allow(clippy::expect_used)] + fn placeholder_keypair() -> KeyPair { + let public_key = + "ed01204cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf" + .parse() + .expect("Public key not in mulithash format"); + let private_key = PrivateKey::from_hex( + iroha_crypto::Algorithm::Ed25519, + "d748e18ce60cb30dea3e73c9019b7af45a8d465e3d71bcc9a5ef99a008205e534cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf" + ).expect("Private key not hex encoded"); + + KeyPair::new(public_key, private_key) + } + } + const fn default_wait_for_peers_retry_count() -> u64 { DEFAULT_WAIT_FOR_PEERS_RETRY_COUNT } @@ -458,7 +475,7 @@ mod tests { #[test] fn load_default_genesis_block() -> Result<()> { - let genesis_key_pair = KeyPair::generate()?; + let (public_key, private_key) = KeyPair::generate()?.into(); let tx_limits = TransactionLimits { max_instruction_number: 4096, max_wasm_size_bytes: 0, @@ -467,8 +484,8 @@ mod tests { true, RawGenesisBlock::default(), &GenesisConfiguration { - account_public_key: Some(genesis_key_pair.public_key), - account_private_key: Some(genesis_key_pair.private_key), + account_public_key: public_key, + account_private_key: Some(private_key), ..GenesisConfiguration::default() }, &tx_limits, diff --git a/core/src/kura.rs b/core/src/kura.rs index 898d7db5692..fd527afeb0d 100644 --- a/core/src/kura.rs +++ b/core/src/kura.rs @@ -14,8 +14,7 @@ use std::{ use async_trait::async_trait; use futures::{Stream, StreamExt, TryStreamExt}; use iroha_actor::{broker::*, prelude::*}; -use iroha_crypto::HashOf; -use iroha_data_model::merkle::MerkleTree; +use iroha_crypto::{HashOf, MerkleTree}; use iroha_logger::prelude::*; use iroha_version::scale::{DecodeVersioned, EncodeVersioned}; use pin_project::pin_project; diff --git a/core/src/lib.rs b/core/src/lib.rs index 244ebf58e96..3013930fb9a 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -2,13 +2,11 @@ pub mod block; pub mod block_sync; -pub mod event; pub mod genesis; pub mod kura; pub mod modules; pub mod queue; pub mod smartcontracts; -pub mod stream; pub mod sumeragi; pub mod triggers; pub mod tx; @@ -18,6 +16,7 @@ use std::time::Duration; use iroha_data_model::prelude::*; use parity_scale_codec::{Decode, Encode}; +use tokio::sync::broadcast; use crate::{ block_sync::message::VersionedMessage as BlockSyncMessage, prelude::*, @@ -40,6 +39,11 @@ pub type DomainsMap = dashmap::DashMap; #[cfg(feature = "roles")] pub type RolesMap = dashmap::DashMap; +/// Type of `Sender` which should be used for channels of `Event` messages. +pub type EventsSender = broadcast::Sender; +/// Type of `Receiver` which should be used for channels of `Event` messages. +pub type EventsReceiver = broadcast::Receiver; + /// The network message #[derive(Clone, Debug, Encode, Decode, iroha_actor::Message)] pub enum NetworkMessage { @@ -61,7 +65,7 @@ pub mod prelude { //! Re-exports important traits and types. Meant to be glob imported when using `Iroha`. #[doc(inline)] - pub use iroha_crypto::{Hash, KeyPair, PrivateKey, PublicKey}; + pub use iroha_crypto::{Algorithm, Hash, KeyPair, PrivateKey, PublicKey}; #[doc(inline)] pub use crate::{ diff --git a/core/src/queue.rs b/core/src/queue.rs index 2e43167874b..daee58b6f01 100644 --- a/core/src/queue.rs +++ b/core/src/queue.rs @@ -311,9 +311,8 @@ mod tests { #[test] fn push_tx() { - let wsv = Arc::new(WorldStateView::new(world_with_test_domains( - KeyPair::generate().unwrap().public_key, - ))); + let (public_key, _) = KeyPair::generate().unwrap().into(); + let wsv = Arc::new(WorldStateView::new(world_with_test_domains(public_key))); let queue = Queue::from_configuration( &Configuration { @@ -334,9 +333,8 @@ mod tests { fn push_tx_overflow() { let max_txs_in_queue = 10; - let wsv = Arc::new(WorldStateView::new(world_with_test_domains( - KeyPair::generate().unwrap().public_key, - ))); + let (public_key, _) = KeyPair::generate().unwrap().into(); + let wsv = Arc::new(WorldStateView::new(world_with_test_domains(public_key))); let queue = Queue::from_configuration( &Configuration { @@ -366,7 +364,7 @@ mod tests { let max_txs_in_queue = 10; let wsv = { - let public_key = KeyPair::generate().unwrap().public_key; + let (public_key, _) = KeyPair::generate().unwrap().into(); let domain_id = DomainId::from_str("wonderland").expect("Valid"); let mut domain = Domain::new(domain_id.clone()).build(); let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); @@ -395,9 +393,8 @@ mod tests { #[test] fn push_multisignature_tx() { - let wsv = Arc::new(WorldStateView::new(world_with_test_domains( - KeyPair::generate().unwrap().public_key, - ))); + let (public_key, _) = KeyPair::generate().unwrap().into(); + let wsv = Arc::new(WorldStateView::new(world_with_test_domains(public_key))); let queue = Queue::from_configuration( &Configuration { @@ -446,7 +443,7 @@ mod tests { let max_block_tx = 2; let alice_key = KeyPair::generate().expect("Failed to generate keypair."); let wsv = Arc::new(WorldStateView::new(world_with_test_domains( - alice_key.public_key.clone(), + alice_key.public_key().clone(), ))); let queue = Queue::from_configuration( &Configuration { @@ -473,7 +470,7 @@ mod tests { let max_block_tx = 2; let alice_key = KeyPair::generate().expect("Failed to generate keypair."); let wsv = Arc::new(WorldStateView::new(world_with_test_domains( - alice_key.public_key.clone(), + alice_key.public_key().clone(), ))); let tx = accepted_tx("alice@wonderland", 100_000, Some(&alice_key)); wsv.transactions.insert(tx.hash()); @@ -495,7 +492,7 @@ mod tests { let max_block_tx = 2; let alice_key = KeyPair::generate().expect("Failed to generate keypair."); let wsv = Arc::new(WorldStateView::new(world_with_test_domains( - alice_key.public_key.clone(), + alice_key.public_key().clone(), ))); let tx = accepted_tx("alice@wonderland", 100_000, Some(&alice_key)); let queue = Queue::from_configuration( @@ -518,7 +515,7 @@ mod tests { let max_block_tx = 6; let alice_key = KeyPair::generate().expect("Failed to generate keypair."); let wsv = Arc::new(WorldStateView::new(world_with_test_domains( - alice_key.public_key.clone(), + alice_key.public_key().clone(), ))); let queue = Queue::from_configuration( &Configuration { @@ -555,7 +552,7 @@ mod tests { fn transactions_available_after_pop() { let alice_key = KeyPair::generate().expect("Failed to generate keypair."); let wsv = Arc::new(WorldStateView::new(world_with_test_domains( - alice_key.public_key.clone(), + alice_key.public_key().clone(), ))); let queue = Queue::from_configuration( &Configuration { @@ -589,7 +586,7 @@ mod tests { let max_block_tx = 10; let alice_key = KeyPair::generate().expect("Failed to generate keypair."); let wsv = Arc::new(WorldStateView::new(world_with_test_domains( - alice_key.public_key.clone(), + alice_key.public_key().clone(), ))); let wsv_clone = Arc::clone(&wsv); let queue = Arc::new(Queue::from_configuration( @@ -655,7 +652,7 @@ mod tests { let alice_key = KeyPair::generate().expect("Failed to generate keypair."); let wsv = Arc::new(WorldStateView::new(world_with_test_domains( - alice_key.public_key.clone(), + alice_key.public_key().clone(), ))); let queue = Queue::from_configuration( diff --git a/core/src/smartcontracts/isi/expression.rs b/core/src/smartcontracts/isi/expression.rs index d7fc8bb6460..5bd2b7d9112 100644 --- a/core/src/smartcontracts/isi/expression.rs +++ b/core/src/smartcontracts/isi/expression.rs @@ -383,15 +383,15 @@ mod tests { fn conditional_multisignature_quorum() -> Result<()> { let asset_quantity_high = Value::U32(750); let asset_quantity_low = Value::U32(300); - let key_pair_teller_1 = KeyPair::generate()?; - let key_pair_teller_2 = KeyPair::generate()?; - let key_pair_manager = KeyPair::generate()?; + let (public_key_teller_1, _) = KeyPair::generate()?.into(); + let (public_key_teller_2, _) = KeyPair::generate()?.into(); + let (manager_public_key, _) = KeyPair::generate()?.into(); let teller_signatory_set = Value::Vec(vec![ - Value::PublicKey(key_pair_teller_1.clone().public_key), - Value::PublicKey(key_pair_teller_2.public_key), + Value::PublicKey(public_key_teller_1.clone()), + Value::PublicKey(public_key_teller_2), ]); - let one_teller_set = Value::Vec(vec![Value::PublicKey(key_pair_teller_1.public_key)]); - let manager_signatory = Value::PublicKey(key_pair_manager.public_key); + let one_teller_set = Value::Vec(vec![Value::PublicKey(public_key_teller_1)]); + let manager_signatory = Value::PublicKey(manager_public_key); let manager_signatory_set = Value::Vec(vec![manager_signatory.clone()]); let condition: ExpressionBox = IfBuilder::condition(And::new( Greater::new(ContextValue::new("usd_quantity"), 500_u32), diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index 6a8c4f2c7fa..adf5290f969 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -12,7 +12,6 @@ pub mod world; pub use error::*; use eyre::Result; -use iroha_crypto::HashOf; use iroha_data_model::{expression::prelude::*, isi::*, prelude::*}; use iroha_logger::prelude::*; @@ -637,8 +636,8 @@ mod tests { fn world_with_test_domains() -> Result { let mut domain = Domain::new(DomainId::from_str("wonderland")?).build(); let account_id = AccountId::from_str("alice@wonderland")?; - let key_pair = KeyPair::generate()?; - let account = Account::new(account_id.clone(), [key_pair.public_key]).build(); + let (public_key, _) = KeyPair::generate()?.into(); + let account = Account::new(account_id.clone(), [public_key]).build(); assert!(domain.add_account(account).is_none()); let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; assert!(domain diff --git a/core/src/smartcontracts/isi/permissions.rs b/core/src/smartcontracts/isi/permissions.rs index 765a350fb1c..ad78d158602 100644 --- a/core/src/smartcontracts/isi/permissions.rs +++ b/core/src/smartcontracts/isi/permissions.rs @@ -807,10 +807,7 @@ pub mod prelude { mod tests { #![allow(clippy::restriction)] - use std::{ - collections::{BTreeMap, BTreeSet}, - str::FromStr as _, - }; + use std::{collections::BTreeSet, str::FromStr as _}; use iroha_data_model::{expression::prelude::*, isi::*}; @@ -875,7 +872,6 @@ mod tests { ) -> Result { Ok(PermissionToken::new( Name::from_str("token").expect("Valid"), - BTreeMap::new(), )) } } @@ -963,8 +959,7 @@ mod tests { let mut domain = Domain::new(DomainId::from_str("test").expect("Valid")).build(); let mut bob_account = Account::new(bob_id.clone(), []).build(); assert!(bob_account.add_permission(PermissionToken::new( - Name::from_str("token").expect("Valid"), - BTreeMap::default(), + Name::from_str("token").expect("Valid") ))); assert!(domain.add_account(bob_account).is_none()); let wsv = WorldStateView::new(World::with([domain], BTreeSet::new())); diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index a30ce55e2e5..a3f3be0dbdc 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -1,76 +1,17 @@ -//! Query functionality. This module defines the -//! `VerifiedQueryRequest`, which is the only kind of query that is -//! permitted to execute. The common error type is also defined here, +//! Query functionality. The common error type is also defined here, //! alongside functions for converting them into HTTP responses. use std::{error::Error as StdError, fmt}; use eyre::Result; -use iroha_crypto::SignatureOf; -use iroha_data_model::{prelude::*, query}; +use iroha_data_model::prelude::*; use iroha_schema::IntoSchema; -use iroha_version::scale::DecodeVersioned; use parity_scale_codec::{Decode, Encode}; use thiserror::Error; -use warp::{http::StatusCode, hyper::body::Bytes}; -use super::{permissions::IsQueryAllowedBoxed, FindError}; +use super::FindError; use crate::{prelude::ValidQuery, WorldStateView, WorldTrait}; -/// Query Request verified on the Iroha node side. -#[derive(Debug, Decode, Encode)] -pub struct VerifiedQueryRequest { - /// Payload. - payload: query::Payload, - /// Signature of the client who sends this query. - signature: SignatureOf, -} - -impl VerifiedQueryRequest { - /// Validate query. - /// - /// # Errors - /// if: - /// - Account doesn't exist. - /// - Account doesn't have the correct public key. - /// - Account has the correct permissions. - pub fn validate( - self, - wsv: &WorldStateView, - query_validator: &IsQueryAllowedBoxed, - ) -> Result { - let account_has_public_key = wsv.map_account(&self.payload.account_id, |account| { - account.contains_signatory(&self.signature.public_key) - })?; - if !account_has_public_key { - return Err(Error::Signature(String::from( - "Signature public key doesn't correspond to the account.", - ))); - } - query_validator - .check(&self.payload.account_id, &self.payload.query, wsv) - .map_err(Error::Permission)?; - Ok(ValidQueryRequest { - query: self.payload.query, - }) - } -} - -impl TryFrom for VerifiedQueryRequest { - type Error = Error; - - fn try_from(query: SignedQueryRequest) -> Result { - query - .signature - .verify(&query.payload) - .map(|_| Self { - payload: query.payload, - signature: query.signature, - }) - .map_err(|e| Error::Signature(e.to_string())) - } -} - /// Query Request statefully validated on the Iroha node side. #[derive(Debug, Decode, Encode)] pub struct ValidQueryRequest { @@ -86,6 +27,12 @@ impl ValidQueryRequest { pub fn execute(&self, wsv: &WorldStateView) -> Result { self.query.execute(wsv) } + + /// Construct `ValidQueryRequest` from a validated query + #[must_use] + pub const fn new(query: QueryBox) -> Self { + Self { query } + } } /// Unsupported version error @@ -147,32 +94,6 @@ impl From for Error { } } -impl Error { - /// Status code for query error response. - pub const fn status_code(&self) -> StatusCode { - use Error::*; - match self { - Decode(_) | Version(_) | Evaluate(_) | Conversion(_) => StatusCode::BAD_REQUEST, - Signature(_) => StatusCode::UNAUTHORIZED, - Permission(_) => StatusCode::FORBIDDEN, - Find(_) => StatusCode::NOT_FOUND, - } - } -} - -impl warp::reject::Reject for Error {} - -impl TryFrom<&Bytes> for VerifiedQueryRequest { - type Error = Error; - - fn try_from(body: &Bytes) -> Result { - let query = VersionedSignedQueryRequest::decode_versioned(body.as_ref()) - .map_err(|e| Error::Decode(Box::new(e)))?; - let VersionedSignedQueryRequest::V1(query) = query; - VerifiedQueryRequest::try_from(query) - } -} - impl ValidQuery for QueryBox { fn execute(&self, wsv: &WorldStateView) -> Result { use QueryBox::*; @@ -215,7 +136,7 @@ mod tests { use std::{str::FromStr, sync::Arc}; - use iroha_crypto::{Hash, KeyPair}; + use iroha_crypto::{Hash, HashOf, KeyPair}; use iroha_data_model::transaction::TransactionLimits; use once_cell::sync::Lazy; @@ -231,7 +152,7 @@ mod tests { fn world_with_test_domains() -> World { let domain_id = DomainId::from_str("wonderland").expect("Valid"); let mut domain = Domain::new(domain_id).build(); - let account = Account::new(ALICE_ID.clone(), [ALICE_KEYS.public_key.clone()]).build(); + let account = Account::new(ALICE_ID.clone(), [ALICE_KEYS.public_key().clone()]).build(); assert!(domain.add_account(account).is_none()); let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland").expect("Valid"); assert!(domain @@ -246,7 +167,7 @@ mod tests { fn world_with_test_asset_with_metadata() -> World { let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland").expect("Valid"); let mut domain = Domain::new(DomainId::from_str("wonderland").expect("Valid")).build(); - let mut account = Account::new(ALICE_ID.clone(), [ALICE_KEYS.public_key.clone()]).build(); + let mut account = Account::new(ALICE_ID.clone(), [ALICE_KEYS.public_key().clone()]).build(); assert!(domain .add_asset_definition( AssetDefinition::quantity(asset_definition_id.clone()).build(), @@ -279,7 +200,7 @@ mod tests { )?; let mut domain = Domain::new(DomainId::from_str("wonderland")?).build(); - let account = Account::new(ALICE_ID.clone(), [ALICE_KEYS.public_key.clone()]) + let account = Account::new(ALICE_ID.clone(), [ALICE_KEYS.public_key().clone()]) .with_metadata(metadata) .build(); assert!(domain.add_account(account).is_none()); @@ -351,14 +272,14 @@ mod tests { .commit(); wsv.apply(vcb).await?; - let wrong_hash = Hash::new(&[2_u8]); + let wrong_hash: Hash = HashOf::new(&2_u8).into(); let not_found = FindTransactionByHash::new(wrong_hash).execute(&wsv); assert!(matches!(not_found, Err(_))); let found_accepted = FindTransactionByHash::new(Hash::from(va_tx.hash())).execute(&wsv)?; match found_accepted { TransactionValue::Transaction(tx) => { - assert_eq!(Hash::from(va_tx.hash()), Hash::from(tx.hash())) + assert_eq!(va_tx.hash().transmute(), tx.hash()) } TransactionValue::RejectedTransaction(_) => {} } @@ -377,7 +298,7 @@ mod tests { let mut domain = Domain::new(DomainId::from_str("wonderland")?) .with_metadata(metadata) .build(); - let account = Account::new(ALICE_ID.clone(), [ALICE_KEYS.public_key.clone()]).build(); + let account = Account::new(ALICE_ID.clone(), [ALICE_KEYS.public_key().clone()]).build(); assert!(domain.add_account(account).is_none()); let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; assert!(domain diff --git a/core/src/smartcontracts/isi/tx.rs b/core/src/smartcontracts/isi/tx.rs index 9f1a14cc294..adb183cb2fc 100644 --- a/core/src/smartcontracts/isi/tx.rs +++ b/core/src/smartcontracts/isi/tx.rs @@ -29,7 +29,7 @@ impl ValidQuery for FindTransactionByHash { .evaluate(wsv, &Context::default()) .wrap_err("Failed to get hash") .map_err(|e| query::Error::Evaluate(e.to_string()))?; - let hash = HashOf::from_hash(hash); + let hash = hash.typed(); if !wsv.has_transaction(&hash) { return Err(FindError::Transaction(hash).into()); }; diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index f0193dafef4..533227d6156 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -239,7 +239,7 @@ impl<'a, W: WorldTrait> Runtime<'a, W> { // Store length as byte array in front of encoding for (i, byte) in WasmUsize::try_from(r.len()) .map_err(|e| Trap::new(e.to_string()))? - .to_be_bytes() + .to_le_bytes() .into_iter() .enumerate() { @@ -535,7 +535,7 @@ mod tests { fn world_with_test_account(account_id: AccountId) -> World { let domain_id = account_id.domain_id.clone(); - let public_key = KeyPair::generate().unwrap().public_key; + let (public_key, _) = KeyPair::generate().unwrap().into(); let account = Account::new(account_id, [public_key]).build(); let mut domain = Domain::new(domain_id).build(); assert!(domain.add_account(account).is_none()); diff --git a/core/src/sumeragi/config.rs b/core/src/sumeragi/config.rs index 84b08920f3c..34bb8d58d07 100644 --- a/core/src/sumeragi/config.rs +++ b/core/src/sumeragi/config.rs @@ -54,9 +54,9 @@ pub struct SumeragiConfiguration { impl Default for SumeragiConfiguration { fn default() -> Self { Self { - key_pair: KeyPair::default(), - trusted_peers: TrustedPeers::default(), - peer_id: PeerId::default(), + key_pair: Self::placeholder_keypair(), + peer_id: Self::placeholder_peer_id(), + trusted_peers: Self::placeholder_trusted_peers(), block_time_ms: DEFAULT_BLOCK_TIME_MS, commit_time_ms: DEFAULT_COMMIT_TIME_MS, tx_receipt_time_ms: DEFAULT_TX_RECEIPT_TIME_MS, @@ -73,6 +73,35 @@ impl Default for SumeragiConfiguration { } impl SumeragiConfiguration { + /// Key-pair used by default for demo purposes + #[allow(clippy::expect_used)] + fn placeholder_keypair() -> KeyPair { + let public_key = "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" + .parse() + .expect("Public key not in mulithash format"); + let private_key = PrivateKey::from_hex( + Algorithm::Ed25519, + "282ed9f3cf92811c3818dbc4ae594ed59dc1a2f78e4241e31924e101d6b1fb831c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" + ).expect("Private key not hex encoded"); + + KeyPair::new(public_key, private_key) + } + + fn placeholder_peer_id() -> PeerId { + let (public_key, _) = Self::placeholder_keypair().into(); + + PeerId { + address: "127.0.0.1:1337".to_owned(), + public_key, + } + } + + fn placeholder_trusted_peers() -> TrustedPeers { + let mut peers = HashSet::new(); + peers.insert(Self::placeholder_peer_id()); + TrustedPeers { peers } + } + /// Set `trusted_peers` configuration parameter. Will overwrite /// existing `trusted_peers` but does not check for duplication. #[inline] diff --git a/core/src/sumeragi/fault.rs b/core/src/sumeragi/fault.rs index d175e921fd4..4c0194f7bb5 100644 --- a/core/src/sumeragi/fault.rs +++ b/core/src/sumeragi/fault.rs @@ -881,7 +881,7 @@ impl Deb { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("Sumeragi") - .field("public_key", &self.key_pair.public_key) + .field("public_key", &self.key_pair.public_key()) .field("network_topology", &self.topology) .field("peer_id", &self.peer_id) .field("voting_block", &self.voting_block) @@ -899,7 +899,7 @@ impl Con info!("Starting Sumeragi"); self.connect_peers().await; - if height != 0 && *last_block != Hash([0; 32]) { + if height != 0 && last_block != Hash::zeroed().typed() { self.init(last_block, height); } else if let Some(genesis_network) = self.genesis_network.take() { let addr = self.network.clone(); diff --git a/core/src/sumeragi/mod.rs b/core/src/sumeragi/mod.rs index e637fa2e4c2..d1dc65a6cfb 100644 --- a/core/src/sumeragi/mod.rs +++ b/core/src/sumeragi/mod.rs @@ -32,14 +32,13 @@ use self::{ }; use crate::{ block::{BlockHeader, ChainedBlock, EmptyChainHash, VersionedPendingBlock}, - event::EventsSender, genesis::GenesisNetworkTrait, kura::{GetBlockHash, KuraTrait, StoreBlock}, prelude::*, queue::Queue, tx::TransactionValidator, wsv::WorldTrait, - IrohaNetwork, NetworkMessage, VersionedValidBlock, + EventsSender, IrohaNetwork, NetworkMessage, VersionedValidBlock, }; trait Consensus { diff --git a/core/src/sumeragi/network_topology.rs b/core/src/sumeragi/network_topology.rs index e03864c49fa..3b3da51ffae 100644 --- a/core/src/sumeragi/network_topology.rs +++ b/core/src/sumeragi/network_topology.rs @@ -21,15 +21,15 @@ pub fn sort_peers_by_hash( } /// Sorts peers based on the `hash` and `counter` combined as a seed. -pub fn sort_peers_by_hash_and_counter( +fn sort_peers_by_hash_and_counter( mut peers: Vec, hash: &HashOf, counter: u64, ) -> Vec { peers.sort_by(|p1, p2| p1.address.cmp(&p2.address)); let mut bytes: Vec = counter.to_le_bytes().to_vec(); - bytes.append(hash.as_ref().to_vec().as_mut()); - let Hash(bytes) = Hash::new(&bytes); + bytes.extend(hash.as_ref()); + let bytes = Hash::new(&bytes).into(); let mut rng = StdRng::from_seed(bytes); peers.shuffle(&mut rng); peers @@ -352,7 +352,7 @@ impl Topology { if role .peers(self) .iter() - .any(|peer| peer.public_key == signature.public_key) + .any(|peer| peer.public_key == *signature.public_key()) { Ok(()) } else { @@ -379,7 +379,7 @@ impl Topology { .collect(); signatures .into_iter() - .filter(|signature| public_keys.contains(&signature.public_key)) + .filter(|signature| public_keys.contains(signature.public_key())) .cloned() .collect() } @@ -451,19 +451,22 @@ mod tests { address: "127.0.0.1".to_owned(), public_key: KeyPair::generate() .expect("Failed to generate KeyPair.") - .public_key, + .public_key() + .clone(), }; let peer_2: PeerId = PeerId { address: "127.0.0.2".to_owned(), public_key: KeyPair::generate() .expect("Failed to generate KeyPair.") - .public_key, + .public_key() + .clone(), }; let peer_3: PeerId = PeerId { address: "127.0.0.3".to_owned(), public_key: KeyPair::generate() .expect("Failed to generate KeyPair.") - .public_key, + .public_key() + .clone(), }; // set_a.len() = 2, is wrong as it is not possible to get integer f in: 2f + 1 = 2 let set_a: HashSet<_> = vec![peer_1.clone(), peer_2].into_iter().collect(); @@ -499,25 +502,29 @@ mod tests { address: "127.0.0.1:7878".to_owned(), public_key: KeyPair::generate() .expect("Failed to generate KeyPair.") - .public_key, + .public_key() + .clone(), }, PeerId { address: "127.0.0.1:7879".to_owned(), public_key: KeyPair::generate() .expect("Failed to generate KeyPair.") - .public_key, + .public_key() + .clone(), }, PeerId { address: "127.0.0.1:7880".to_owned(), public_key: KeyPair::generate() .expect("Failed to generate KeyPair.") - .public_key, + .public_key() + .clone(), }, PeerId { address: "127.0.0.1:7881".to_owned(), public_key: KeyPair::generate() .expect("Failed to generate KeyPair.") - .public_key, + .public_key() + .clone(), }, ] .into_iter() @@ -526,37 +533,42 @@ mod tests { #[test] fn different_order() { + let hash1 = Hash::prehashed([1_u8; Hash::LENGTH]).typed(); + let hash2 = Hash::prehashed([2_u8; Hash::LENGTH]).typed(); + let peers: Vec<_> = topology_test_peers().into_iter().collect(); - let peers_1 = sort_peers_by_hash(peers.clone(), &HashOf::from_hash(Hash([1_u8; 32]))); - let peers_2 = sort_peers_by_hash(peers, &HashOf::from_hash(Hash([2_u8; 32]))); + let peers_1 = sort_peers_by_hash(peers.clone(), &hash1); + let peers_2 = sort_peers_by_hash(peers, &hash2); assert_ne!(peers_1, peers_2); } #[test] fn same_order() { + let hash = Hash::prehashed([2_u8; Hash::LENGTH]).typed(); + let peers: Vec<_> = topology_test_peers().into_iter().collect(); - let peers_1 = sort_peers_by_hash(peers.clone(), &HashOf::from_hash(Hash([2_u8; 32]))); - let peers_2 = sort_peers_by_hash(peers, &HashOf::from_hash(Hash([2_u8; 32]))); + let peers_1 = sort_peers_by_hash(peers.clone(), &hash); + let peers_2 = sort_peers_by_hash(peers, &hash); assert_eq!(peers_1, peers_2); } #[test] fn same_order_by_hash_and_counter() { + let hash = Hash::prehashed([2_u8; Hash::LENGTH]).typed(); + let peers: Vec<_> = topology_test_peers().into_iter().collect(); - let peers_1 = - sort_peers_by_hash_and_counter(peers.clone(), &HashOf::from_hash(Hash([2_u8; 32])), 1); - let peers_2 = - sort_peers_by_hash_and_counter(peers, &HashOf::from_hash(Hash([2_u8; 32])), 1); + let peers_1 = sort_peers_by_hash_and_counter(peers.clone(), &hash, 1); + let peers_2 = sort_peers_by_hash_and_counter(peers, &hash, 1); assert_eq!(peers_1, peers_2); } #[test] fn different_order_by_hash_and_counter() { + let hash = Hash::prehashed([2_u8; Hash::LENGTH]).typed(); + let peers: Vec<_> = topology_test_peers().into_iter().collect(); - let peers_1 = - sort_peers_by_hash_and_counter(peers.clone(), &HashOf::from_hash(Hash([2_u8; 32])), 1); - let peers_2 = - sort_peers_by_hash_and_counter(peers, &HashOf::from_hash(Hash([2_u8; 32])), 2); + let peers_1 = sort_peers_by_hash_and_counter(peers.clone(), &hash, 1); + let peers_2 = sort_peers_by_hash_and_counter(peers, &hash, 2); assert_ne!(peers_1, peers_2); } } diff --git a/core/src/sumeragi/view_change.rs b/core/src/sumeragi/view_change.rs index 810c6c95da0..809605313c0 100644 --- a/core/src/sumeragi/view_change.rs +++ b/core/src/sumeragi/view_change.rs @@ -89,7 +89,7 @@ impl Proof { /// /// # Errors /// Can fail during creation of signature - pub fn sign(mut self, key_pair: KeyPair) -> Result { + pub fn sign(mut self, key_pair: KeyPair) -> Result { let signature = SignatureOf::new(key_pair, &self.payload)?.transmute(); self.signatures.insert(signature); Ok(self) @@ -98,7 +98,7 @@ impl Proof { /// Adds verified signatures of `other` to self. pub fn merge_signatures(&mut self, other: SignaturesOf) { self.signatures - .extend(other.into_verified_by_hash(self.hash())) + .extend(other.into_verified_by_hash(&self.hash())) } /// Verify if the proof is valid, given the peers in `topology`. @@ -110,7 +110,7 @@ impl Proof { let n_signatures = self .signatures .verified_by_hash(self.hash()) - .filter(|signature| peer_public_keys.contains(&signature.public_key)) + .filter(|signature| peer_public_keys.contains(signature.public_key())) .count(); // See Whitepaper for the information on this limit. #[allow(clippy::int_plus_one)] @@ -123,7 +123,7 @@ impl Proof { pub fn has_same_state( &self, latest_block: &HashOf, - latest_view_change: &HashOf, + latest_view_change: &HashOf, ) -> bool { &self.payload.latest_block == latest_block && &self.payload.previous_proof == latest_view_change @@ -195,7 +195,8 @@ pub struct ProofChain { impl ProofChain { /// Initialize an empty proof chain. - pub const fn empty() -> ProofChain { + #[must_use] + pub const fn empty() -> Self { Self { proofs: Vec::new() } } @@ -246,7 +247,7 @@ impl ProofChain { mod tests { #![allow(clippy::restriction)] - use iroha_crypto::{Hash, HashOf}; + use iroha_crypto::Hash; use super::*; @@ -254,15 +255,16 @@ mod tests { fn proof_is_valid() -> Result<()> { let key_pair_1 = KeyPair::generate()?; let key_pair_2 = KeyPair::generate()?; + let proof = Proof::commit_timeout( - HashOf::from_hash(Hash([1_u8; 32])), - HashOf::from_hash(Hash([2_u8; 32])), - HashOf::from_hash(Hash([3_u8; 32])), + Hash::prehashed([1_u8; Hash::LENGTH]).typed(), + Hash::prehashed([2_u8; Hash::LENGTH]).typed(), + Hash::prehashed([3_u8; Hash::LENGTH]).typed(), key_pair_1.clone(), )? .sign(key_pair_2.clone())?; - let peer_1 = PeerId::new("127.0.0.1:1001", &key_pair_1.public_key); - let peer_2 = PeerId::new("127.0.0.1:1002", &key_pair_2.public_key); + let peer_1 = PeerId::new("127.0.0.1:1001", key_pair_1.public_key()); + let peer_2 = PeerId::new("127.0.0.1:1002", key_pair_2.public_key()); let peers = [peer_1, peer_2].into(); assert!(proof.verify(&peers, 1)); Ok(()) @@ -272,14 +274,15 @@ mod tests { fn proof_has_not_enough_signatures() -> Result<()> { let key_pair_1 = KeyPair::generate()?; let key_pair_2 = KeyPair::generate()?; + let proof = Proof::commit_timeout( - HashOf::from_hash(Hash([1_u8; 32])), - HashOf::from_hash(Hash([2_u8; 32])), - HashOf::from_hash(Hash([3_u8; 32])), + Hash::prehashed([1_u8; Hash::LENGTH]).typed(), + Hash::prehashed([2_u8; Hash::LENGTH]).typed(), + Hash::prehashed([3_u8; Hash::LENGTH]).typed(), key_pair_1.clone(), )?; - let peer_1 = PeerId::new("127.0.0.1:1001", &key_pair_1.public_key); - let peer_2 = PeerId::new("127.0.0.1:1002", &key_pair_2.public_key); + let peer_1 = PeerId::new("127.0.0.1:1001", key_pair_1.public_key()); + let peer_2 = PeerId::new("127.0.0.1:1002", key_pair_2.public_key()); let peers = [peer_1, peer_2].into(); assert!(!proof.verify(&peers, 1)); Ok(()) @@ -290,15 +293,16 @@ mod tests { let key_pair_1 = KeyPair::generate()?; let key_pair_2 = KeyPair::generate()?; let key_pair_3 = KeyPair::generate()?; + let proof = Proof::commit_timeout( - HashOf::from_hash(Hash([1_u8; 32])), - HashOf::from_hash(Hash([2_u8; 32])), - HashOf::from_hash(Hash([3_u8; 32])), + Hash::prehashed([1_u8; Hash::LENGTH]).typed(), + Hash::prehashed([2_u8; Hash::LENGTH]).typed(), + Hash::prehashed([3_u8; Hash::LENGTH]).typed(), key_pair_1.clone(), )? .sign(key_pair_3)?; - let peer_1 = PeerId::new("127.0.0.1:1001", &key_pair_1.public_key); - let peer_2 = PeerId::new("127.0.0.1:1002", &key_pair_2.public_key); + let peer_1 = PeerId::new("127.0.0.1:1001", key_pair_1.public_key()); + let peer_2 = PeerId::new("127.0.0.1:1002", key_pair_2.public_key()); let peers = [peer_1, peer_2].into(); assert!(!proof.verify(&peers, 1)); Ok(()) @@ -309,12 +313,12 @@ mod tests { let mut proof_chain = ProofChain::empty(); let key_pair_1 = KeyPair::generate()?; let key_pair_2 = KeyPair::generate()?; - let peer_1 = PeerId::new("127.0.0.1:1001", &key_pair_1.public_key); - let peer_2 = PeerId::new("127.0.0.1:1002", &key_pair_2.public_key); - let latest_block = HashOf::from_hash(Hash([3_u8; 32])); + let peer_1 = PeerId::new("127.0.0.1:1001", key_pair_1.public_key()); + let peer_2 = PeerId::new("127.0.0.1:1002", key_pair_2.public_key()); + let latest_block = Hash::prehashed([3_u8; Hash::LENGTH]).typed(); for i in 0..10 { let proof = Proof::commit_timeout( - HashOf::from_hash(Hash([i; 32])), + Hash::prehashed([i; Hash::LENGTH]).typed(), proof_chain.latest_hash(), latest_block, key_pair_1.clone(), @@ -332,17 +336,17 @@ mod tests { let mut proof_chain = ProofChain::empty(); let key_pair_1 = KeyPair::generate()?; let key_pair_2 = KeyPair::generate()?; - let peer_1 = PeerId::new("127.0.0.1:1001", &key_pair_1.public_key); - let peer_2 = PeerId::new("127.0.0.1:1002", &key_pair_2.public_key); - let latest_block = HashOf::from_hash(Hash([3_u8; 32])); + let peer_1 = PeerId::new("127.0.0.1:1001", key_pair_1.public_key()); + let peer_2 = PeerId::new("127.0.0.1:1002", key_pair_2.public_key()); + let latest_block = Hash::prehashed([3_u8; Hash::LENGTH]).typed(); for i in 0..10 { let latest_proof_hash = if i == 2 { - HashOf::from_hash(Hash([0_u8; 32])) + Hash::prehashed([1_u8; Hash::LENGTH]).typed() } else { proof_chain.latest_hash() }; let proof = Proof::commit_timeout( - HashOf::from_hash(Hash([i; 32])), + Hash::prehashed([i; Hash::LENGTH]).typed(), latest_proof_hash, latest_block, key_pair_1.clone(), diff --git a/core/src/tx.rs b/core/src/tx.rs index b5ca53e9567..2d29f91b8b4 100644 --- a/core/src/tx.rs +++ b/core/src/tx.rs @@ -291,7 +291,7 @@ impl AcceptedTransaction { let signatories = self .signatures .iter() - .map(|signature| &signature.public_key) + .map(|signature| signature.public_key()) .cloned(); wsv.map_account(account_id, |account| { diff --git a/core/src/wsv.rs b/core/src/wsv.rs index 641bbc0e1c8..fcfb8589f19 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -24,11 +24,10 @@ use tokio::task; use crate::{ block::Chain, - event::EventsSender, prelude::*, smartcontracts::{isi::Error, wasm, Execute, FindError}, triggers::TriggerSet, - DomainsMap, PeersIds, + DomainsMap, EventsSender, PeersIds, }; /// Sender type of the new block notification channel @@ -629,9 +628,7 @@ impl WorldStateView { pub fn latest_block_hash(&self) -> HashOf { self.blocks .latest_block() - .map_or(HashOf::from_hash(Hash([0_u8; 32])), |block| { - block.value().hash() - }) + .map_or(Hash::zeroed().typed(), |block| block.value().hash()) } /// Get `Account` and pass it to closure. diff --git a/core/test_network/Cargo.toml b/core/test_network/Cargo.toml index f90a41065fe..67caf708752 100644 --- a/core/test_network/Cargo.toml +++ b/core/test_network/Cargo.toml @@ -19,7 +19,6 @@ iroha_p2p = { version = "=2.0.0-pre-rc.3", path = "../../p2p" } iroha_actor = { version = "=2.0.0-pre-rc.3", path = "../../actor" } iroha = { path = "../../cli", features = ["test-network"] } -hex-literal = "0.3.4" eyre = "0.6.5" tempfile = "3" unique_port = "0.1.0" diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index a338b8dbed0..4af7404ad2c 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -2,7 +2,7 @@ #![allow(clippy::restriction, clippy::future_not_send)] -use core::{fmt::Debug, str::FromStr, time::Duration}; +use core::{fmt::Debug, str::FromStr as _, time::Duration}; use std::{collections::HashMap, thread}; use eyre::{Error, Result}; @@ -101,20 +101,18 @@ impl std::cmp::Eq for Peer {} /// Get a standardised key-pair from the hard-coded literals. /// /// # Panics -/// Programmer error. The key must be given in Multihash format. +/// Programmer error. Given keys must be in proper format. pub fn get_key_pair() -> KeyPair { - KeyPair { - public_key: PublicKey::from_str( + KeyPair::new( + PublicKey::from_str( r#"ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"#, ) - .expect("Works"), - private_key: PrivateKey { - digest_function: "ed25519".to_string(), - payload: hex_literal::hex!("9AC47ABF 59B356E0 BD7DCBBB B4DEC080 E302156A 48CA907E 47CB6AEA 1D32719E 7233BFC8 9DCBD68C 19FDE6CE 61582252 98EC1131 B6A130D1 AEB454C1 AB5183C0" - ) - .into(), - }, - } + .expect("Public key not in mulithash format"), + PrivateKey::from_hex( + Algorithm::Ed25519, + "9AC47ABF 59B356E0 BD7DCBBB B4DEC080 E302156A 48CA907E 47CB6AEA 1D32719E 7233BFC8 9DCBD68C 19FDE6CE 61582252 98EC1131 B6A130D1 AEB454C1 AB5183C0", + ).expect("Private key not hex encoded") + ) } /// Trait used to differentiate a test instance of `genesis`. @@ -130,7 +128,7 @@ impl TestGenesis for G { let mut genesis = RawGenesisBlock::new( "alice".parse().expect("Valid"), "wonderland".parse().expect("Valid"), - get_key_pair().public_key, + get_key_pair().public_key().clone(), ); genesis.transactions[0].isi.push( RegisterBox::new( @@ -426,8 +424,8 @@ where logger: LoggerConfiguration { ..configuration.logger }, - public_key: self.key_pair.public_key.clone(), - private_key: self.key_pair.private_key.clone(), + public_key: self.key_pair.public_key().clone(), + private_key: self.key_pair.private_key().clone(), disable_panic_terminal_colors: true, ..configuration } @@ -565,7 +563,7 @@ where let telemetry_address = local_unique_port()?; let id = PeerId { address: p2p_address.clone(), - public_key: key_pair.public_key.clone(), + public_key: key_pair.public_key().clone(), }; let shutdown = None; Ok(Self { @@ -775,9 +773,9 @@ impl TestConfiguration for Configuration { configuration .load_environment() .expect("Failed to load configuration from environment"); - let keypair = KeyPair::generate().unwrap(); - configuration.public_key = keypair.public_key; - configuration.private_key = keypair.private_key; + let (public_key, private_key) = KeyPair::generate().unwrap().into(); + configuration.public_key = public_key; + configuration.private_key = private_key; configuration } @@ -814,8 +812,9 @@ impl TestClient for Client { fn test_with_key(api_url: &str, telemetry_url: &str, keys: KeyPair) -> Self { let mut configuration = ClientConfiguration::test(api_url, telemetry_url); - configuration.public_key = keys.public_key; - configuration.private_key = keys.private_key; + let (public_key, private_key) = keys.into(); + configuration.public_key = public_key; + configuration.private_key = private_key; Client::new(&configuration) } @@ -827,8 +826,9 @@ impl TestClient for Client { ) -> Self { let mut configuration = ClientConfiguration::test(api_url, telemetry_url); configuration.account_id = account_id.clone(); - configuration.public_key = keys.public_key; - configuration.private_key = keys.private_key; + let (public_key, private_key) = keys.into(); + configuration.public_key = public_key; + configuration.private_key = private_key; Client::new(&configuration) } diff --git a/core/test_network/tests/sumeragi_with_mock.rs b/core/test_network/tests/sumeragi_with_mock.rs index ade8b5af852..eaf875fbe2a 100644 --- a/core/test_network/tests/sumeragi_with_mock.rs +++ b/core/test_network/tests/sumeragi_with_mock.rs @@ -248,7 +248,7 @@ pub mod utils { pub static ALICE: Lazy = Lazy::new(|| { let account_id = AccountId::from_str("alice@wonderland").expect("valid account name."); let mut account = Account::new(account_id, []).build(); - assert!(account.add_signatory(ALICE_KEYS.public_key.clone())); + assert!(account.add_signatory(ALICE_KEYS.public_key().clone())); account }); pub static WONDERLAND: Lazy = Lazy::new(|| { diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 59c40b7a234..151ed7668a8 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -8,7 +8,11 @@ edition = "2021" [features] default = ["std"] +# Enable static linkage of the rust standard library. +# Please refer to https://docs.rust-embedded.org/book/intro/no-std.html std = ["ursa"] +# Force static linking +vendored = ["openssl-sys"] [dependencies] iroha_schema = { path = "../schema" } @@ -17,7 +21,9 @@ derive_more = { version = "0.99.16", default-features = false, features = ["dere parity-scale-codec = { version = "2.3.1", default-features = false, features = ["derive", "full"] } serde = { version = "1.0.130", default-features = false, features = ["derive"] } hex = { version = "0.4.0", default-features = false, features = ["alloc", "serde"] } +openssl-sys = { version = "0.9.72", features = ["vendored"], optional = true } ursa = { version = "=0.3.7", optional = true } +getset = "0.1.2" [dev-dependencies] hex-literal = "0.3.4" diff --git a/crypto/src/hash.rs b/crypto/src/hash.rs index f8df42f8cc5..63a6b7a7671 100644 --- a/crypto/src/hash.rs +++ b/crypto/src/hash.rs @@ -31,23 +31,44 @@ use ursa::blake2::{ Serialize, IntoSchema, )] -pub struct Hash(pub [u8; Self::LENGTH]); +pub struct Hash([u8; Self::LENGTH]); impl Hash { /// Length of hash pub const LENGTH: usize = 32; - /// new hash from bytes + /// Wrap the given bytes; they must be prehashed with `VarBlake2b` + pub const fn prehashed(bytes: [u8; Self::LENGTH]) -> Self { + Self(bytes) + } + + /// Construct zeroed hash + #[must_use] + // TODO: It would be best if all uses of zeroed hash could be replaced with Option + pub const fn zeroed() -> Self { + Hash::prehashed([0; Hash::LENGTH]) + } + + /// Hash the given bytes. #[cfg(feature = "std")] #[allow(clippy::expect_used)] - pub fn new(bytes: &[u8]) -> Self { + #[must_use] + pub fn new(bytes: impl AsRef<[u8]>) -> Self { let vec_hash = VarBlake2b::new(Self::LENGTH) .expect("Failed to initialize variable size hash") .chain(bytes) .finalize_boxed(); let mut hash = [0; Self::LENGTH]; hash.copy_from_slice(&vec_hash); - Hash(hash) + Hash::prehashed(hash) + } + + /// Adds type information to the hash. Be careful about using this function + /// since it is not possible to validate the correctness of the conversion. + /// Prefer creating new hashes with [`HashOf::new`] whenever possible + #[must_use] + pub const fn typed(self) -> HashOf { + HashOf(self, PhantomData) } } @@ -65,13 +86,26 @@ impl Debug for Hash { } } -impl AsRef<[u8]> for Hash { - fn as_ref(&self) -> &[u8] { - let Hash(bytes) = self; +impl From for [u8; Hash::LENGTH] { + #[inline] + fn from(Hash(bytes): Hash) -> Self { bytes } } +impl AsRef<[u8; Hash::LENGTH]> for Hash { + #[inline] + fn as_ref(&self) -> &[u8; Hash::LENGTH] { + &self.0 + } +} + +impl From> for Hash { + fn from(HashOf(hash, _): HashOf) -> Self { + hash + } +} + /// Represents hash of Iroha entities like `Block` or `Transaction`. Currently supports only blake2b-32. // Lint triggers when expanding #[codec(skip)] #[allow(clippy::default_trait_access)] @@ -124,35 +158,28 @@ impl hash::Hash for HashOf { } } -impl AsRef<[u8]> for HashOf { - fn as_ref(&self) -> &[u8] { - Hash::as_ref(&self.0) - } -} - -impl From> for Hash { - fn from(HashOf(hash, _): HashOf) -> Self { - hash +impl AsRef<[u8; Hash::LENGTH]> for HashOf { + fn as_ref(&self) -> &[u8; Hash::LENGTH] { + self.0.as_ref() } } impl HashOf { - /// Unsafe constructor for typed hash - pub const fn from_hash(hash: Hash) -> Self { - Self(hash, PhantomData) - } - - /// Transmutes hash to some specific type + /// Transmutes hash to some specific type. + /// Don't use this method if not required. + #[inline] + #[must_use] pub const fn transmute(self) -> HashOf { HashOf(self.0, PhantomData) } } impl HashOf { - /// Constructor for typed hash + /// Construct typed hash #[cfg(feature = "std")] + #[must_use] pub fn new(value: &T) -> Self { - Self(Hash::new(&value.encode()), PhantomData) + Self(Hash::new(value.encode()), PhantomData) } } diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index 5f49928b5ce..e4ae942e765 100644 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -6,7 +6,8 @@ extern crate alloc; mod hash; -pub mod multihash; +mod merkle; +mod multihash; mod signature; mod varint; @@ -17,10 +18,12 @@ use core::{fmt, str::FromStr}; #[cfg(feature = "base64")] pub use base64; use derive_more::Display; +use getset::Getters; pub use hash::*; use iroha_schema::IntoSchema; +pub use merkle::MerkleTree; use multihash::{DigestFunction as MultihashDigestFunction, Multihash}; -use parity_scale_codec::{Decode, Encode}; +use parity_scale_codec::{Decode, Encode, Error as ScaleError}; use serde::{Deserialize, Serialize}; pub use signature::*; #[cfg(feature = "std")] @@ -37,13 +40,13 @@ use ursa::{ }; /// ed25519 -pub const ED_25519: &str = "ed25519"; +const ED_25519: &str = "ed25519"; /// secp256k1 -pub const SECP_256_K1: &str = "secp256k1"; +const SECP_256_K1: &str = "secp256k1"; /// bls normal -pub const BLS_NORMAL: &str = "bls_normal"; +const BLS_NORMAL: &str = "bls_normal"; /// bls small -pub const BLS_SMALL: &str = "bls_small"; +const BLS_SMALL: &str = "bls_small"; /// Error indicating algorithm could not be found #[derive(Debug, Clone, Copy, Display, IntoSchema)] @@ -54,16 +57,20 @@ pub struct NoSuchAlgorithm; impl std::error::Error for NoSuchAlgorithm {} /// Algorithm for hashing -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)] pub enum Algorithm { /// Ed25519 + #[display(fmt = "{}", "ED_25519")] Ed25519, /// Secp256k1 + #[display(fmt = "{}", "SECP_256_K1")] Secp256k1, - /// BlsSmall - BlsSmall, /// BlsNormal + #[display(fmt = "{}", "BLS_NORMAL")] BlsNormal, + /// BlsSmall + #[display(fmt = "{}", "BLS_SMALL")] + BlsSmall, } impl Default for Algorithm { @@ -86,17 +93,6 @@ impl FromStr for Algorithm { } } -impl fmt::Display for Algorithm { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Algorithm::Ed25519 => write!(f, "{}", ED_25519), - Algorithm::Secp256k1 => write!(f, "{}", SECP_256_K1), - Algorithm::BlsSmall => write!(f, "{}", BLS_SMALL), - Algorithm::BlsNormal => write!(f, "{}", BLS_NORMAL), - } - } -} - /// Options for key generation #[derive(Debug, Clone)] pub enum KeyGenOption { @@ -114,7 +110,9 @@ impl TryFrom for UrsaKeyGenOption { match key_gen_option { KeyGenOption::UseSeed(seed) => Ok(UrsaKeyGenOption::UseSeed(seed)), KeyGenOption::FromPrivateKey(key) => { - if key.digest_function == ED_25519 || key.digest_function == SECP_256_K1 { + if key.digest_function() == Algorithm::Ed25519 + || key.digest_function() == Algorithm::Secp256k1 + { return Ok(Self::FromSecretKey(UrsaPrivateKey(key.payload))); } @@ -157,21 +155,13 @@ impl KeyGenConfiguration { } /// Pair of Public and Private keys. -#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, Getters, Deserialize, Serialize)] +#[getset(get = "pub")] pub struct KeyPair { /// Public Key. - pub public_key: PublicKey, + public_key: PublicKey, /// Private Key. - pub private_key: PrivateKey, -} - -impl From<(PublicKey, PrivateKey)> for KeyPair { - fn from((public_key, private_key): (PublicKey, PrivateKey)) -> Self { - Self { - public_key, - private_key, - } - } + private_key: PrivateKey, } /// Error when dealing with cryptographic functions @@ -214,12 +204,20 @@ impl From for Error { #[cfg(feature = "std")] impl std::error::Error for Error {} -#[cfg(feature = "std")] impl KeyPair { + /// Construct `KeyPair` + pub fn new(public_key: PublicKey, private_key: PrivateKey) -> Self { + Self { + public_key, + private_key, + } + } + /// Generates a pair of Public and Private key with [`Algorithm::default()`] selected as generation algorithm. /// /// # Errors /// Fails if decoding fails + #[cfg(feature = "std")] pub fn generate() -> Result { Self::generate_with_configuration(KeyGenConfiguration::default()) } @@ -228,6 +226,7 @@ impl KeyPair { /// /// # Errors /// Fails if decoding fails + #[cfg(feature = "std")] pub fn generate_with_configuration(configuration: KeyGenConfiguration) -> Result { let key_gen_option: Option = configuration .key_gen_option @@ -284,12 +283,22 @@ impl From for KeyParseError { impl std::error::Error for KeyParseError {} /// Public Key used in signatures. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Decode, Encode, IntoSchema)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters, Encode, IntoSchema)] +#[getset(get = "pub")] pub struct PublicKey { /// Digest function - pub digest_function: String, + #[getset(skip)] + digest_function: String, /// payload of key - pub payload: Vec, + payload: Vec, +} + +impl PublicKey { + /// Digest function + #[allow(clippy::expect_used)] + pub fn digest_function(&self) -> Algorithm { + self.digest_function.parse().expect("Valid") + } } impl FromStr for PublicKey { @@ -303,17 +312,10 @@ impl FromStr for PublicKey { } } -impl Default for PublicKey { - #[allow(clippy::unwrap_used)] - fn default() -> Self { - Multihash::default().try_into().unwrap() - } -} - impl fmt::Debug for PublicKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PublicKey") - .field("digest_function", &self.digest_function) + .field("digest_function", &self.digest_function()) .field("payload", &hex::encode_upper(self.payload.as_slice())) .finish() } @@ -335,36 +337,36 @@ impl fmt::Display for PublicKey { impl From for PublicKey { fn from(multihash: Multihash) -> Self { + #[cfg(not(feature = "std"))] + use alloc::string::ToString as _; + let digest_function = match multihash.digest_function { - MultihashDigestFunction::Ed25519Pub => ED_25519, - MultihashDigestFunction::Secp256k1Pub => SECP_256_K1, - MultihashDigestFunction::Bls12381G1Pub => BLS_NORMAL, - MultihashDigestFunction::Bls12381G2Pub => BLS_SMALL, + MultihashDigestFunction::Ed25519Pub => Algorithm::Ed25519, + MultihashDigestFunction::Secp256k1Pub => Algorithm::Secp256k1, + MultihashDigestFunction::Bls12381G1Pub => Algorithm::BlsNormal, + MultihashDigestFunction::Bls12381G2Pub => Algorithm::BlsSmall, }; Self { - digest_function: String::from(digest_function), + digest_function: digest_function.to_string(), payload: multihash.payload, } } } -impl TryFrom for Multihash { - type Error = NoSuchAlgorithm; - - fn try_from(public_key: PublicKey) -> Result { - let digest_function = match public_key.digest_function.as_str() { - ED_25519 => Ok(MultihashDigestFunction::Ed25519Pub), - SECP_256_K1 => Ok(MultihashDigestFunction::Secp256k1Pub), - BLS_NORMAL => Ok(MultihashDigestFunction::Bls12381G1Pub), - BLS_SMALL => Ok(MultihashDigestFunction::Bls12381G2Pub), - _ => Err(Self::Error {}), - }?; +impl From for Multihash { + fn from(public_key: PublicKey) -> Self { + let digest_function = match public_key.digest_function() { + Algorithm::Ed25519 => MultihashDigestFunction::Ed25519Pub, + Algorithm::Secp256k1 => MultihashDigestFunction::Secp256k1Pub, + Algorithm::BlsNormal => MultihashDigestFunction::Bls12381G1Pub, + Algorithm::BlsSmall => MultihashDigestFunction::Bls12381G2Pub, + }; - Ok(Self { + Self { digest_function, payload: public_key.payload, - }) + } } } @@ -394,20 +396,95 @@ impl<'de> Deserialize<'de> for PublicKey { } } +impl Decode for PublicKey { + fn decode(input: &mut I) -> Result { + let digest_function = String::decode(input)?; + + if Algorithm::from_str(&digest_function).is_err() { + return Err(ScaleError::from("Algorithm not supported")); + } + + Ok(Self { + digest_function, + payload: Decode::decode(input)?, + }) + } +} + /// Private Key used in signatures. -#[derive(Clone, Default, PartialEq, Eq, Deserialize, Serialize)] +#[derive(Clone, PartialEq, Eq, Getters, Serialize)] +#[getset(get = "pub")] pub struct PrivateKey { /// Digest function - pub digest_function: String, + #[getset(skip)] + digest_function: String, /// key payload. WARNING! Do not use `"string".as_bytes()` to obtain the key. #[serde(with = "hex::serde")] - pub payload: Vec, + payload: Vec, +} + +impl PrivateKey { + /// Construct `PrivateKey` from hex encoded string + /// + /// # Errors + /// + /// If given payload is not hex encoded + pub fn from_hex( + digest_function: Algorithm, + payload: &(impl AsRef<[u8]> + ?Sized), + ) -> Result { + #[cfg(not(feature = "std"))] + use alloc::string::ToString as _; + + let payload: Vec = payload + .as_ref() + .iter() + .filter(|&e| *e as char != ' ') + .copied() + .collect(); + + Ok(Self { + digest_function: digest_function.to_string(), + payload: hex::decode(payload)?, + }) + } + + /// Digest function + #[allow(clippy::expect_used)] + pub fn digest_function(&self) -> Algorithm { + self.digest_function.parse().expect("Valid") + } +} + +impl<'de> Deserialize<'de> for PrivateKey { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use serde::de::Error as _; + + #[derive(Deserialize)] + struct PrivateKey { + digest_function: String, + #[serde(with = "hex::serde")] + payload: Vec, + } + + let private_key = PrivateKey::deserialize(deserializer)?; + match Algorithm::from_str(&private_key.digest_function) { + Ok(_) => Ok(Self { + digest_function: private_key.digest_function, + payload: private_key.payload, + }), + Err(err) => Err(D::Error::custom(err)), + } + } } impl fmt::Debug for PrivateKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PrivateKey") - .field("digest_function", &self.digest_function) + .field("digest_function", &self.digest_function()) .field("payload", &format!("{:X?}", self.payload)) .finish() } @@ -421,7 +498,7 @@ impl fmt::Display for PrivateKey { /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { - pub use super::{Hash, KeyPair, PrivateKey, PublicKey, Signature}; + pub use super::{Algorithm, Hash, KeyPair, PrivateKey, PublicKey, Signature}; } #[cfg(test)] @@ -429,7 +506,7 @@ mod tests { #![allow(clippy::restriction)] #[cfg(not(feature = "std"))] - use alloc::borrow::ToOwned as _; + use alloc::borrow::ToString as _; use super::*; @@ -439,7 +516,7 @@ mod tests { format!( "{}", PublicKey { - digest_function: ED_25519.to_owned(), + digest_function: Algorithm::Ed25519.to_string(), payload: hex::decode( "1509a611ad6d97b01d871e58ed00c8fd7c3917b6ca61a8c2833a19e000aac2e4" ) @@ -452,7 +529,7 @@ mod tests { format!( "{}", PublicKey { - digest_function: SECP_256_K1.to_owned(), + digest_function: Algorithm::Secp256k1.to_string(), payload: hex::decode( "0312273e8810581e58948d3fb8f9e8ad53aaa21492ebb8703915bbb565a21b7fcc" ) @@ -465,7 +542,7 @@ mod tests { format!( "{}", PublicKey { - digest_function: BLS_NORMAL.to_owned(), + digest_function: Algorithm::BlsNormal.to_string(), payload: hex::decode( "04175b1e79b15e8a2d5893bf7f8933ca7d0863105d8bac3d6f976cb043378a0e4b885c57ed14eb85fc2fabc639adc7de7f0020c70c57acc38dee374af2c04a6f61c11de8df9034b12d849c7eb90099b0881267d0e1507d4365d838d7dcc31511e7" ) @@ -478,7 +555,7 @@ mod tests { format!( "{}", PublicKey { - digest_function: BLS_SMALL.to_owned(), + digest_function: Algorithm::BlsSmall.to_string(), payload: hex::decode( "040cb3231f601e7245a6ec9a647b450936f707ca7dc347ed258586c1924941d8bc38576473a8ba3bb2c37e3e121130ab67103498a96d0d27003e3ad960493da79209cf024e2aa2ae961300976aeee599a31a5e1b683eaa1bcffc47b09757d20f21123c594cf0ee0baf5e1bdd272346b7dc98a8f12c481a6b28174076a352da8eae881b90911013369d7fa960716a5abc5314307463fa2285a5bf2a5b5c6220d68c2d34101a91dbfc531c5b9bbfb2245ccc0c50051f79fc6714d16907b1fc40e0c0" ) @@ -507,14 +584,14 @@ mod tests { }").expect("Failed to deserialize."), TestJson { public_key: PublicKey { - digest_function: ED_25519.to_owned(), + digest_function: Algorithm::Ed25519.to_string(), payload: hex::decode( "1509a611ad6d97b01d871e58ed00c8fd7c3917b6ca61a8c2833a19e000aac2e4" ) .expect("Failed to decode public key.") }, private_key: PrivateKey { - digest_function: ED_25519.to_owned(), + digest_function: Algorithm::Ed25519.to_string(), payload: hex::decode("3a7991af1abb77f3fd27cc148404a6ae4439d095a63591b77c788d53f708a02a1509a611ad6d97b01d871e58ed00c8fd7c3917b6ca61a8c2833a19e000aac2e4") .expect("Failed to decode private key"), } @@ -530,14 +607,14 @@ mod tests { }").expect("Failed to deserialize."), TestJson { public_key: PublicKey { - digest_function: SECP_256_K1.to_owned(), + digest_function: Algorithm::Secp256k1.to_string(), payload: hex::decode( "0312273e8810581e58948d3fb8f9e8ad53aaa21492ebb8703915bbb565a21b7fcc" ) .expect("Failed to decode public key.") }, private_key: PrivateKey { - digest_function: SECP_256_K1.to_owned(), + digest_function: Algorithm::Secp256k1.to_string(), payload: hex::decode("4df4fca10762d4b529fe40a2188a60ca4469d2c50a825b5f33adc2cb78c69445") .expect("Failed to decode private key"), } @@ -553,14 +630,14 @@ mod tests { }").expect("Failed to deserialize."), TestJson { public_key: PublicKey { - digest_function: BLS_NORMAL.to_owned(), + digest_function: Algorithm::BlsNormal.to_string(), payload: hex::decode( "04175b1e79b15e8a2d5893bf7f8933ca7d0863105d8bac3d6f976cb043378a0e4b885c57ed14eb85fc2fabc639adc7de7f0020c70c57acc38dee374af2c04a6f61c11de8df9034b12d849c7eb90099b0881267d0e1507d4365d838d7dcc31511e7" ) .expect("Failed to decode public key.") }, private_key: PrivateKey { - digest_function: BLS_NORMAL.to_owned(), + digest_function: Algorithm::BlsNormal.to_string(), payload: hex::decode("000000000000000000000000000000002f57460183837efbac6aa6ab3b8dbb7cffcfc59e9448b7860a206d37d470cba3") .expect("Failed to decode private key"), } @@ -576,14 +653,14 @@ mod tests { }").expect("Failed to deserialize."), TestJson { public_key: PublicKey { - digest_function: BLS_SMALL.to_owned(), + digest_function: Algorithm::BlsSmall.to_string(), payload: hex::decode( "040cb3231f601e7245a6ec9a647b450936f707ca7dc347ed258586c1924941d8bc38576473a8ba3bb2c37e3e121130ab67103498a96d0d27003e3ad960493da79209cf024e2aa2ae961300976aeee599a31a5e1b683eaa1bcffc47b09757d20f21123c594cf0ee0baf5e1bdd272346b7dc98a8f12c481a6b28174076a352da8eae881b90911013369d7fa960716a5abc5314307463fa2285a5bf2a5b5c6220d68c2d34101a91dbfc531c5b9bbfb2245ccc0c50051f79fc6714d16907b1fc40e0c0" ) .expect("Failed to decode public key.") }, private_key: PrivateKey { - digest_function: BLS_SMALL.to_owned(), + digest_function: Algorithm::BlsSmall.to_string(), payload: hex::decode("0000000000000000000000000000000060f3c1ac9addbbed8db83bc1b2ef22139fb049eecb723a557a41ca1a4b1fed63") .expect("Failed to decode private key"), } diff --git a/data_model/src/merkle.rs b/crypto/src/merkle.rs similarity index 69% rename from data_model/src/merkle.rs rename to crypto/src/merkle.rs index 4bb58e75b1f..41bd03e1a5f 100644 --- a/data_model/src/merkle.rs +++ b/crypto/src/merkle.rs @@ -1,23 +1,36 @@ //! Merkle tree implementation. #[cfg(not(feature = "std"))] -use alloc::{boxed::Box, format, string::String, vec, vec::Vec}; +use alloc::{boxed::Box, vec, vec::Vec}; #[cfg(feature = "std")] use std::collections::VecDeque; -use iroha_crypto::{Hash, HashOf}; -use iroha_schema::IntoSchema; +use iroha_schema::prelude::*; + +use crate::HashOf; /// [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree) used to validate and prove data at /// each block height. /// Our implementation uses binary hash tree. -#[derive(Debug, IntoSchema)] +#[derive(Debug)] pub struct MerkleTree { root_node: Node, } +impl IntoSchema for MerkleTree { + fn schema(map: &mut MetaMap) { + map.entry(Self::type_name()).or_insert_with(|| { + // BFS ordered list of leaf nodes + Metadata::Vec(HashOf::::type_name()) + }); + if !map.contains_key(&HashOf::::type_name()) { + HashOf::::schema(map); + } + } +} + /// Represents subtree rooted by the current node -#[derive(Debug, IntoSchema)] +#[derive(Debug)] pub struct Subtree { /// Left subtree left: Box>, @@ -28,14 +41,14 @@ pub struct Subtree { } /// Represents leaf node -#[derive(Debug, IntoSchema)] +#[derive(Debug)] pub struct Leaf { /// Hash of the node hash: HashOf, } /// Binary Tree's node with possible variants: Subtree, Leaf (with data or links to data) and Empty. -#[derive(Debug, IntoSchema)] +#[derive(Debug)] #[allow(clippy::module_name_repetitions)] pub enum Node { /// Node is root of a subtree @@ -156,7 +169,7 @@ impl Node { match self { Node::Subtree(Subtree { hash, .. }) => *hash, Node::Leaf(Leaf { hash }) => (*hash).transmute(), - Node::Empty => HashOf::from_hash(Hash([0; 32])), + Node::Empty => crate::Hash::zeroed().typed(), } } @@ -178,9 +191,8 @@ impl Node { .iter() .zip(right_hash.as_ref().iter()) .map(|(l, r)| l.saturating_add(*r)) - .take(32) .collect(); - HashOf::from_hash(Hash::new(&sum)) + crate::Hash::new(sum).typed() } } @@ -225,31 +237,32 @@ impl<'a, T> IntoIterator for &'a MerkleTree { #[cfg(test)] mod tests { use super::*; + use crate::Hash; #[test] fn tree_with_two_layers_should_reach_all_nodes() { - let tree = MerkleTree { + let tree = MerkleTree::<()> { root_node: Node::Subtree(Subtree { left: Box::new(Node::Leaf(Leaf { - hash: HashOf::<()>::from_hash(Hash([0; 32])), + hash: Hash::prehashed([1; Hash::LENGTH]).typed(), })), right: Box::new(Node::Leaf(Leaf { - hash: HashOf::from_hash(Hash([0; 32])), + hash: Hash::prehashed([2; Hash::LENGTH]).typed(), })), - hash: HashOf::from_hash(Hash([0; 32])), + hash: Hash::prehashed([3; Hash::LENGTH]).typed(), }), }; assert_eq!(3, tree.into_iter().count()); } - fn get_hashes(hash: Hash) -> impl Iterator> { - let hash = HashOf::<()>::from_hash(hash); + fn get_hashes(hash: [u8; Hash::LENGTH]) -> impl Iterator> { + let hash = Hash::prehashed(hash).typed(); std::iter::repeat_with(move || hash) } #[test] fn four_hashes_should_built_seven_nodes() { - let merkle_tree = get_hashes(Hash([1_u8; 32])) + let merkle_tree = get_hashes([1_u8; Hash::LENGTH]) .take(4) .collect::>(); assert_eq!(7, merkle_tree.into_iter().count()); @@ -257,7 +270,7 @@ mod tests { #[test] fn three_hashes_should_built_seven_nodes() { - let merkle_tree = get_hashes(Hash([1_u8; 32])) + let merkle_tree = get_hashes([1_u8; Hash::LENGTH]) .take(3) .collect::>(); assert_eq!(7, merkle_tree.into_iter().count()); @@ -265,68 +278,78 @@ mod tests { #[test] fn same_root_hash_for_same_hashes() { - let merkle_tree_1 = vec![ - HashOf::<()>::from_hash(Hash([1_u8; 32])), - HashOf::from_hash(Hash([2_u8; 32])), - HashOf::from_hash(Hash([3_u8; 32])), + let merkle_tree_1 = [ + Hash::prehashed([1_u8; Hash::LENGTH]), + Hash::prehashed([2_u8; Hash::LENGTH]), + Hash::prehashed([3_u8; Hash::LENGTH]), ] .into_iter() - .collect::>(); - let merkle_tree_2 = vec![ - HashOf::<()>::from_hash(Hash([2_u8; 32])), - HashOf::from_hash(Hash([1_u8; 32])), - HashOf::from_hash(Hash([3_u8; 32])), + .map(Hash::typed) + .collect::>(); + let merkle_tree_2 = [ + Hash::prehashed([2_u8; Hash::LENGTH]), + Hash::prehashed([1_u8; Hash::LENGTH]), + Hash::prehashed([3_u8; Hash::LENGTH]), ] .into_iter() - .collect::>(); + .map(Hash::typed) + .collect::>(); assert_eq!(merkle_tree_1.root_hash(), merkle_tree_2.root_hash()); } #[test] fn different_root_hash_for_different_hashes() { - let merkle_tree_1 = vec![ - HashOf::<()>::from_hash(Hash([1_u8; 32])), - HashOf::from_hash(Hash([2_u8; 32])), - HashOf::from_hash(Hash([3_u8; 32])), + let merkle_tree_1 = [ + Hash::prehashed([1_u8; Hash::LENGTH]), + Hash::prehashed([2_u8; Hash::LENGTH]), + Hash::prehashed([3_u8; Hash::LENGTH]), ] .into_iter() - .collect::>(); - let merkle_tree_2 = vec![ - HashOf::<()>::from_hash(Hash([1_u8; 32])), - HashOf::from_hash(Hash([4_u8; 32])), - HashOf::from_hash(Hash([5_u8; 32])), + .map(Hash::typed) + .collect::>(); + let merkle_tree_2 = [ + Hash::prehashed([1_u8; Hash::LENGTH]), + Hash::prehashed([4_u8; Hash::LENGTH]), + Hash::prehashed([5_u8; Hash::LENGTH]), ] .into_iter() - .collect::>(); + .map(Hash::typed) + .collect::>(); assert_ne!(merkle_tree_1.root_hash(), merkle_tree_2.root_hash()); } #[test] fn get_leaf() { - let tree = vec![ - HashOf::<()>::from_hash(Hash([1; 32])), - HashOf::from_hash(Hash([2; 32])), - HashOf::from_hash(Hash([3; 32])), - ] - .into_iter() - .collect::>(); - assert_eq!(tree.get_leaf(0), Some(HashOf::from_hash(Hash([1; 32])))); - assert_eq!(tree.get_leaf(1), Some(HashOf::from_hash(Hash([2; 32])))); - assert_eq!(tree.get_leaf(2), Some(HashOf::from_hash(Hash([3; 32])))); + let hash1 = Hash::prehashed([1; Hash::LENGTH]).typed(); + let hash2 = Hash::prehashed([2; Hash::LENGTH]).typed(); + let hash3 = Hash::prehashed([3; Hash::LENGTH]).typed(); + assert!(hash1 < hash2 && hash2 < hash3); + + let tree = [hash1, hash2, hash3] + .into_iter() + .collect::>(); + assert_eq!(tree.get_leaf(0), Some(hash1)); + assert_eq!(tree.get_leaf(1), Some(hash2)); + assert_eq!(tree.get_leaf(2), Some(hash3)); assert_eq!(tree.get_leaf(3), None); } #[test] fn add() { - let tree = vec![Hash([1_u8; 32]), Hash([2_u8; 32]), Hash([4_u8; 32])] + let hash1 = Hash::prehashed([1; Hash::LENGTH]).typed(); + let hash2 = Hash::prehashed([2; Hash::LENGTH]).typed(); + let hash3 = Hash::prehashed([3; Hash::LENGTH]).typed(); + let hash4 = Hash::prehashed([4; Hash::LENGTH]).typed(); + assert!(hash1 < hash2 && hash2 < hash3 && hash3 < hash4); + + let tree = [hash1, hash2, hash4] .into_iter() - .map(HashOf::<()>::from_hash) - .collect::>(); - let tree = tree.add(HashOf::from_hash(Hash([3_u8; 32]))); - assert_eq!(tree.get_leaf(0), Some(HashOf::from_hash(Hash([1; 32])))); - assert_eq!(tree.get_leaf(1), Some(HashOf::from_hash(Hash([2; 32])))); - assert_eq!(tree.get_leaf(2), Some(HashOf::from_hash(Hash([3; 32])))); - assert_eq!(tree.get_leaf(3), Some(HashOf::from_hash(Hash([4; 32])))); + .collect::>(); + let tree = tree.add(hash3); + assert_eq!(tree.get_leaf(0), Some(hash1)); + assert_eq!(tree.get_leaf(1), Some(hash2)); + assert_eq!(tree.get_leaf(2), Some(hash3)); + assert_eq!(tree.get_leaf(3), Some(hash4)); assert_eq!(tree.get_leaf(4), None); } } diff --git a/crypto/src/multihash.rs b/crypto/src/multihash.rs index fc24b1c68e8..24399a28a24 100644 --- a/crypto/src/multihash.rs +++ b/crypto/src/multihash.rs @@ -112,7 +112,7 @@ impl From for ConvertError { } /// Multihash -#[derive(Debug, Default, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct Multihash { /// digest pub digest_function: DigestFunction, diff --git a/crypto/src/signature.rs b/crypto/src/signature.rs index f39fc596155..a1908203ff1 100644 --- a/crypto/src/signature.rs +++ b/crypto/src/signature.rs @@ -12,6 +12,7 @@ use core::{fmt, marker::PhantomData}; use std::collections::{btree_map, btree_set}; use derive_more::{Deref, DerefMut}; +use getset::Getters; use iroha_schema::prelude::*; use parity_scale_codec::{Decode, Encode, Input}; use serde::{Deserialize, Serialize}; @@ -30,32 +31,47 @@ use ursa::{ use crate::{Algorithm, HashOf, KeyPair}; use crate::{Error, PublicKey}; +/// Signature payload(i.e THE signature) +pub type Payload = Vec; + /// Represents signature of the data (`Block` or `Transaction` for example). #[derive( - Clone, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, Serialize, Deserialize, IntoSchema, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Getters, + Encode, + Decode, + Serialize, + Deserialize, + IntoSchema, )] +#[getset(get = "pub")] pub struct Signature { /// Public key that is used for verification. Payload is verified by algorithm /// that corresponds with the public key's digest function. - pub public_key: PublicKey, + public_key: PublicKey, /// Actual signature payload is placed here. - signature: Vec, + #[getset(skip)] + payload: Payload, } -#[cfg(feature = "std")] impl Signature { /// Creates new [`Signature`] by signing payload via [`KeyPair::private_key`]. /// /// # Errors - /// Fails if decoding digest of key pair fails - pub fn new( + /// Fails if signing fails + #[cfg(feature = "std")] + fn new( KeyPair { public_key, private_key, }: KeyPair, payload: &[u8], ) -> Result { - let algorithm: Algorithm = public_key.digest_function.parse()?; + let algorithm: Algorithm = public_key.digest_function(); let private_key = UrsaPrivateKey(private_key.payload); let signature = match algorithm { @@ -67,27 +83,35 @@ impl Signature { Ok(Self { public_key, - signature, + payload: signature, }) } + /// Adds type information to the signature. Be careful about using this function + /// since it is not possible to validate the correctness of the conversion. + /// Prefer creating new signatures with [`SignatureOf::new`] whenever possible + #[inline] + #[allow(dead_code)] + fn typed(self) -> SignatureOf { + SignatureOf(self, PhantomData) + } + /// Verify `message` using signed data and [`KeyPair::public_key`]. /// /// # Errors - /// Fails if decoding digest of key pair fails or if message didn't pass verification + /// Fails if message didn't pass verification + #[cfg(feature = "std")] pub fn verify(&self, payload: &[u8]) -> Result<(), Error> { - let algorithm: Algorithm = self.public_key.digest_function.parse()?; + let algorithm: Algorithm = self.public_key.digest_function(); let public_key = UrsaPublicKey(self.public_key.payload.clone()); match algorithm { - Algorithm::Ed25519 => { - Ed25519Sha512::new().verify(payload, &self.signature, &public_key) - } + Algorithm::Ed25519 => Ed25519Sha512::new().verify(payload, &self.payload, &public_key), Algorithm::Secp256k1 => { - EcdsaSecp256k1Sha256::new().verify(payload, &self.signature, &public_key) + EcdsaSecp256k1Sha256::new().verify(payload, &self.payload, &public_key) } - Algorithm::BlsSmall => BlsSmall::new().verify(payload, &self.signature, &public_key), - Algorithm::BlsNormal => BlsNormal::new().verify(payload, &self.signature, &public_key), + Algorithm::BlsSmall => BlsSmall::new().verify(payload, &self.payload, &public_key), + Algorithm::BlsNormal => BlsNormal::new().verify(payload, &self.payload, &public_key), }?; Ok(()) @@ -98,11 +122,28 @@ impl fmt::Debug for Signature { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct(core::any::type_name::()) .field("public_key", &self.public_key) - .field("signature", &hex::encode_upper(self.signature.as_slice())) + .field("signature", &hex::encode_upper(self.payload.as_slice())) .finish() } } +impl From for (PublicKey, Payload) { + fn from( + Signature { + public_key, + payload: signature, + }: Signature, + ) -> Self { + (public_key, signature) + } +} + +impl From> for Signature { + fn from(SignatureOf(signature, ..): SignatureOf) -> Self { + signature + } +} + /// Represents signature of the data (`Block` or `Transaction` for example). // Lint triggers when expanding #[codec(skip)] #[allow(clippy::default_trait_access)] @@ -163,13 +204,13 @@ impl IntoSchema for SignatureOf { } impl SignatureOf { - /// Create new [`SignatureOf`] via signing `T` values by [`KeyPair::private_key`] + /// Create [`SignatureOf`] from the given hash with [`KeyPair::private_key`]. /// /// # Errors - /// Fails if decoding digest of key pair fails + /// Fails if signing fails #[cfg(feature = "std")] pub fn from_hash(key_pair: KeyPair, hash: &HashOf) -> Result { - Ok(Self(Signature::new(key_pair, hash.as_ref())?, PhantomData)) + Ok(Signature::new(key_pair, hash.as_ref())?.typed()) } /// Transmutes signature to some specific type @@ -197,7 +238,7 @@ impl SignatureOf { /// /// # Errors /// - /// Forwards the 0-th tuple variant verification error + /// Fails if the given hash didn't pass verification #[cfg(feature = "std")] pub fn verify_hash(&self, hash: &HashOf) -> Result<(), Error> { self.0.verify(hash.as_ref()) @@ -206,10 +247,12 @@ impl SignatureOf { #[cfg(feature = "std")] impl SignatureOf { - /// Creates new [`SignatureOf`] by signing value via [`KeyPair::private_key`] + /// Create [`SignatureOf`] by signing the given value with [`KeyPair::private_key`]. + /// The value provided will be hashed before being signed. If you already have the + /// hash of the value you can sign it with [`SignatureOf::from_hash`] instead. /// /// # Errors - /// Fails if decoding digest of key pair fails + /// Fails if signing fails pub fn new(key_pair: KeyPair, value: &T) -> Result { Self::from_hash(key_pair, &HashOf::new(value)) } @@ -371,15 +414,6 @@ impl SignaturesOf { SignaturesOf { signatures } } - /// Builds container using single signature - pub fn from_signature(sign: SignatureOf) -> Self { - let mut me = Self { - signatures: btree_map::BTreeMap::new(), - }; - me.insert(sign); - me - } - /// Adds a signature. If the signature with this key was present, replaces it. pub fn insert(&mut self, signature: SignatureOf) { self.signatures @@ -396,27 +430,28 @@ impl SignaturesOf { /// Returns signatures that have passed verification. #[cfg(feature = "std")] - pub fn into_verified_by_hash(self, hash: HashOf) -> impl Iterator> { + pub fn into_verified_by_hash( + self, + hash: &HashOf, + ) -> impl Iterator> + '_ { self.signatures .into_values() - .filter(move |sign| sign.verify_hash(&hash).is_ok()) + .filter(move |sign| sign.verify_hash(hash).is_ok()) } /// Returns all signatures. + #[inline] pub fn iter(&self) -> impl ExactSizeIterator> { self.into_iter() } /// Number of signatures. + #[inline] + #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> usize { self.signatures.len() } - /// Number of signatures. - pub fn is_empty(&self) -> bool { - self.signatures.is_empty() - } - /// Verify signatures for this hash /// /// # Errors @@ -438,7 +473,7 @@ impl SignaturesOf { /// # Errors /// Forwards [`SignatureOf::new`] errors pub fn new(key_pair: KeyPair, value: &T) -> Result { - SignatureOf::new(key_pair, value).map(Self::from_signature) + [SignatureOf::new(key_pair, value)?].into_iter().collect() } /// Verifies all signatures @@ -446,14 +481,12 @@ impl SignaturesOf { /// # Errors /// Fails if validation of any signature fails pub fn verify(&self, item: &T) -> Result<(), SignatureVerificationFail> { - let hash = HashOf::new(item); - self.verify_hash(&hash) + self.verify_hash(&HashOf::new(item)) } /// Returns signatures that have passed verification. pub fn verified(&self, value: &T) -> impl Iterator> { - let hash = HashOf::new(value); - self.verified_by_hash(hash) + self.verified_by_hash(HashOf::new(value)) } } diff --git a/data_model/Cargo.toml b/data_model/Cargo.toml index ae48b36f1f9..e0ab79dc08a 100644 --- a/data_model/Cargo.toml +++ b/data_model/Cargo.toml @@ -18,8 +18,12 @@ maintenance = { status = "actively-developed" } [features] default = ["std", "roles"] +# Enable static linkage of the rust standard library. +# Disabled for WASM interoperability, to reduce the binary size. +# Please refer to https://docs.rust-embedded.org/book/intro/no-std.html std = ["iroha_macro/std", "iroha_version/std", "iroha_version/warp", "iroha_crypto/std", "iroha_data_primitives/std", "thiserror"] -roles = [] # https://github.com/rust-lang/cargo/issues/6915 +# Include support for account roles (FIXME: https://github.com/hyperledger/iroha/issues/2111) +roles = [] # Internal use only mutable_api = [] @@ -48,7 +52,6 @@ iroha = { path = "../cli" } test_network = { path = "../core/test_network", version = "=2.0.0-pre-rc.3" } tokio = { version = "1.6.0", features = ["rt", "rt-multi-thread"]} -hex-literal = "0.3.4" trybuild = "1.0.53" criterion = "0.3" diff --git a/data_model/primitives/Cargo.toml b/data_model/primitives/Cargo.toml index 1c5d165e3bf..677180d727c 100644 --- a/data_model/primitives/Cargo.toml +++ b/data_model/primitives/Cargo.toml @@ -18,6 +18,8 @@ maintenance = { status = "actively-developed" } [features] default = ["std"] +# Enable static linkage of the rust standard library. +# Please refer to https://docs.rust-embedded.org/book/intro/no-std.html std = ["iroha_macro/std", "fixnum/std", "thiserror"] [dependencies] diff --git a/data_model/src/domain.rs b/data_model/src/domain.rs index a35884cec27..dbe620e118e 100644 --- a/data_model/src/domain.rs +++ b/data_model/src/domain.rs @@ -191,7 +191,7 @@ impl Domain { self.asset_definitions.get(asset_definition_id) } - /// Get an iterator over [`Account`] of the `Domain` + /// Get an iterator over [`Account`]s of the `Domain` #[inline] pub fn accounts(&self) -> impl ExactSizeIterator { self.accounts.values() diff --git a/data_model/src/events/pipeline.rs b/data_model/src/events/pipeline.rs index 0b8f804192a..bff079a499c 100644 --- a/data_model/src/events/pipeline.rs +++ b/data_model/src/events/pipeline.rs @@ -204,24 +204,24 @@ mod tests { Event { entity_kind: EntityKind::Transaction, status: Status::Validating, - hash: Hash([0_u8; 32]), + hash: Hash::prehashed([0_u8; Hash::LENGTH]), }, Event { entity_kind: EntityKind::Transaction, status: Status::Rejected(Transaction(NotPermitted(NotPermittedFail { reason: "Some reason".to_string(), }))), - hash: Hash([0_u8; 32]), + hash: Hash::prehashed([0_u8; Hash::LENGTH]), }, Event { entity_kind: EntityKind::Transaction, status: Status::Committed, - hash: Hash([2_u8; 32]), + hash: Hash::prehashed([2_u8; Hash::LENGTH]), }, Event { entity_kind: EntityKind::Block, status: Status::Committed, - hash: Hash([2_u8; 32]), + hash: Hash::prehashed([2_u8; Hash::LENGTH]), }, ]; assert_eq!( @@ -229,27 +229,29 @@ mod tests { Event { entity_kind: EntityKind::Transaction, status: Status::Validating, - hash: Hash([0_u8; 32]), + hash: Hash::prehashed([0_u8; Hash::LENGTH]), }, Event { entity_kind: EntityKind::Transaction, status: Status::Rejected(Transaction(NotPermitted(NotPermittedFail { reason: "Some reason".to_string(), }))), - hash: Hash([0_u8; 32]), + hash: Hash::prehashed([0_u8; Hash::LENGTH]), }, ], events .iter() .cloned() - .filter(|event| EventFilter::new().hash(Hash([0_u8; 32])).matches(event)) + .filter(|event| EventFilter::new() + .hash(Hash::prehashed([0_u8; Hash::LENGTH])) + .matches(event)) .collect::>() ); assert_eq!( vec![Event { entity_kind: EntityKind::Block, status: Status::Committed, - hash: Hash([2_u8; 32]), + hash: Hash::prehashed([2_u8; Hash::LENGTH]), }], events .iter() @@ -263,14 +265,14 @@ mod tests { vec![Event { entity_kind: EntityKind::Transaction, status: Status::Committed, - hash: Hash([2_u8; 32]), + hash: Hash::prehashed([2_u8; Hash::LENGTH]), }], events .iter() .cloned() .filter(|event| EventFilter::new() .entity_kind(EntityKind::Transaction) - .hash(Hash([2_u8; 32])) + .hash(Hash::prehashed([2_u8; Hash::LENGTH])) .matches(event)) .collect::>() ); diff --git a/data_model/src/expression.rs b/data_model/src/expression.rs index 7a8eee9ce91..922a0816874 100644 --- a/data_model/src/expression.rs +++ b/data_model/src/expression.rs @@ -43,8 +43,8 @@ pub struct EvaluatesTo> { } impl, E: Into> From for EvaluatesTo { - fn from(expression: E) -> EvaluatesTo { - EvaluatesTo { + fn from(expression: E) -> Self { + Self { expression: expression.into(), _value_type: PhantomData::default(), } diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 00976a93aa2..0587de2bfdd 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -30,7 +30,6 @@ pub mod domain; pub mod events; pub mod expression; pub mod isi; -pub mod merkle; pub mod metadata; pub mod pagination; pub mod peer; @@ -241,7 +240,6 @@ impl std::error::Error for EnumTryAsError; /// Stored proof of the account having a permission for a certain action. #[derive( - Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Decode, Encode, Deserialize, Serialize, IntoSchema, + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Getters, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, )] +#[getset(get = "pub")] pub struct PermissionToken { /// Name of the permission rule given to account. - pub name: Name, + name: Name, /// Params identifying how this rule applies. - pub params: btree_map::BTreeMap, + #[getset(skip)] + params: btree_map::BTreeMap, } impl PermissionToken { /// Constructor. #[inline] - pub fn new(name: impl Into, params: impl IntoIterator) -> Self { - let params = params.into_iter().collect(); - let name = name.into(); - Self { name, params } + pub fn new(name: Name) -> Self { + Self { + name, + params: btree_map::BTreeMap::default(), + } + } + + /// Add parameters to the `PermissionToken` replacing any previously defined + #[inline] + #[must_use] + pub fn with_params(mut self, params: impl IntoIterator) -> Self { + self.params = params.into_iter().collect(); + self + } + + /// Return a reference to the parameter corresponding to the given name + #[inline] + pub fn get_param(&self, name: &Name) -> Option<&Value> { + self.params.get(name) + } + + /// Get an iterator over parameters of the `PermissionToken` + #[inline] + pub fn params(&self) -> impl ExactSizeIterator { + self.params.iter() } } diff --git a/data_model/src/query.rs b/data_model/src/query.rs index c1440a1095f..1e9ab9830f9 100644 --- a/data_model/src/query.rs +++ b/data_model/src/query.rs @@ -115,8 +115,8 @@ pub struct Payload { impl Payload { /// Hash of this payload. #[cfg(feature = "std")] - pub fn hash(&self) -> Hash { - Hash::new(&self.encode()) + pub fn hash(&self) -> iroha_crypto::HashOf { + iroha_crypto::HashOf::new(self) } } @@ -153,7 +153,7 @@ impl QueryRequest { /// Constructs a new request with the `query`. pub fn new(query: QueryBox, account_id: ::Id) -> Self { let timestamp_ms = crate::current_time().as_millis(); - QueryRequest { + Self { payload: Payload { timestamp_ms, query, @@ -204,7 +204,7 @@ pub mod role { Serialize, IntoSchema, )] - pub struct FindAllRoles {} + pub struct FindAllRoles; impl Query for FindAllRoles { type Output = Vec; @@ -309,7 +309,7 @@ pub mod account { Serialize, IntoSchema, )] - pub struct FindAllAccounts {} + pub struct FindAllAccounts; impl Query for FindAllAccounts { type Output = Vec; @@ -415,7 +415,7 @@ pub mod account { impl FindAllAccounts { /// Construct [`FindAllAccounts`]. pub const fn new() -> Self { - FindAllAccounts {} + FindAllAccounts } } @@ -494,7 +494,7 @@ pub mod asset { Serialize, IntoSchema, )] - pub struct FindAllAssets {} + pub struct FindAllAssets; impl Query for FindAllAssets { type Output = Vec; @@ -517,7 +517,7 @@ pub mod asset { Serialize, IntoSchema, )] - pub struct FindAllAssetsDefinitions {} + pub struct FindAllAssetsDefinitions; impl Query for FindAllAssetsDefinitions { type Output = Vec; @@ -748,14 +748,14 @@ pub mod asset { impl FindAllAssets { /// Construct [`FindAllAssets`]. pub const fn new() -> Self { - FindAllAssets {} + FindAllAssets } } impl FindAllAssetsDefinitions { /// Construct [`FindAllAssetsDefinitions`]. pub const fn new() -> Self { - FindAllAssetsDefinitions {} + FindAllAssetsDefinitions } } @@ -874,7 +874,7 @@ pub mod domain { Serialize, IntoSchema, )] - pub struct FindAllDomains {} + pub struct FindAllDomains; impl Query for FindAllDomains { type Output = Vec; @@ -906,7 +906,7 @@ pub mod domain { impl FindAllDomains { /// Construct [`FindAllDomains`]. pub const fn new() -> Self { - FindAllDomains {} + FindAllDomains } } @@ -991,7 +991,7 @@ pub mod peer { Serialize, IntoSchema, )] - pub struct FindAllPeers {} + pub struct FindAllPeers; impl Query for FindAllPeers { type Output = Vec; @@ -1013,7 +1013,7 @@ pub mod peer { Serialize, IntoSchema, )] - pub struct FindAllParameters {} + pub struct FindAllParameters; impl Query for FindAllParameters { type Output = Vec; @@ -1022,14 +1022,14 @@ pub mod peer { impl FindAllPeers { ///Construct [`FindAllPeers`]. pub const fn new() -> Self { - FindAllPeers {} + FindAllPeers } } impl FindAllParameters { /// Construct [`FindAllParameters`]. pub const fn new() -> Self { - FindAllParameters {} + FindAllParameters } } /// The prelude re-exports most commonly used traits, structs and macros from this crate. diff --git a/data_model/src/role.rs b/data_model/src/role.rs index c19de1bc12c..5e47f52d58f 100644 --- a/data_model/src/role.rs +++ b/data_model/src/role.rs @@ -93,17 +93,17 @@ impl Role { #[inline] pub fn new( id: ::Id, - permissions: impl Into, + permissions: impl IntoIterator, ) -> ::RegisteredWith { Self { id, - permissions: permissions.into(), + permissions: permissions.into_iter().collect(), } } /// Get an iterator over [`permissions`](PermissionToken) of the `Role` #[inline] - pub fn permissions(&self) -> impl Iterator { + pub fn permissions(&self) -> impl ExactSizeIterator { self.permissions.iter() } } diff --git a/data_model/src/transaction.rs b/data_model/src/transaction.rs index 8787a6e52cc..56d6e427659 100644 --- a/data_model/src/transaction.rs +++ b/data_model/src/transaction.rs @@ -52,7 +52,7 @@ pub trait Txn { where Self: Sized, { - iroha_crypto::HashOf::new(&self.payload()).transmute() + iroha_crypto::HashOf::new(self.payload()).transmute() } /// Checks if number of instructions in payload or wasm size exceeds maximum diff --git a/data_model/tests/data_model.rs b/data_model/tests/data_model.rs index 0812c69a741..59d80d5ca43 100644 --- a/data_model/tests/data_model.rs +++ b/data_model/tests/data_model.rs @@ -146,17 +146,16 @@ mod register { #[allow(unused_must_use)] #[test] fn find_rate_and_make_exchange_isi_should_succeed() { - let kp = KeyPair { - public_key: PublicKey::from_str( + let kp = KeyPair::new( + PublicKey::from_str( r#"ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"#, ) - .unwrap(), - private_key: PrivateKey { - digest_function: "ed25519".to_string(), - payload: hex_literal::hex!("9AC47ABF 59B356E0 BD7DCBBB B4DEC080 E302156A 48CA907E 47CB6AEA 1D32719E 7233BFC8 9DCBD68C 19FDE6CE 61582252 98EC1131 B6A130D1 AEB454C1 AB5183C0") - .into(), - }, - }; + .expect("Valid"), + PrivateKey::from_hex( + Algorithm::Ed25519, + "9AC47ABF 59B356E0 BD7DCBBB B4DEC080 E302156A 48CA907E 47CB6AEA 1D32719E 7233BFC8 9DCBD68C 19FDE6CE 61582252 98EC1131 B6A130D1 AEB454C1 AB5183C0" + ).expect("Valid"), + ); let mut peer = ::new().expect("Failed to create peer"); let configuration = get_config(std::iter::once(peer.id.clone()).collect(), Some(kp.clone())); let pipeline_time = Duration::from_millis(configuration.sumeragi.pipeline_time_ms()); @@ -167,7 +166,7 @@ fn find_rate_and_make_exchange_isi_should_succeed() { RawGenesisBlock::new( "alice".parse().expect("Valid"), "wonderland".parse().expect("Valid"), - kp.public_key, + kp.public_key().clone(), ), &configuration.genesis, &configuration.sumeragi.transaction_limits, diff --git a/docker-compose-local.yml b/docker-compose-local.yml index e4cff844e7a..160259b93da 100644 --- a/docker-compose-local.yml +++ b/docker-compose-local.yml @@ -9,9 +9,9 @@ services: TORII_P2P_ADDR: iroha0:1337 TORII_API_URL: iroha0:8080 TORII_TELEMETRY_URL: iroha0:8180 - IROHA_PUBLIC_KEY: "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0" - IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "9ac47abf59b356e0bd7dcbbbb4dec080e302156a48ca907e47cb6aea1d32719e7233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}' - SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' + IROHA_PUBLIC_KEY: "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" + IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "282ed9f3cf92811c3818dbc4ae594ed59dc1a2f78e4241e31924e101d6b1fb831c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}' + SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' ports: - "1337:1337" - "8080:8080" @@ -31,7 +31,7 @@ services: TORII_TELEMETRY_URL: iroha1:8181 IROHA_PUBLIC_KEY: "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1" IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "3bac34cda9e3763fa069c1198312d1ec73b53023b8180c822ac355435edc4a24cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}' - SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' + SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' ports: - "1338:1338" - "8081:8081" @@ -50,7 +50,7 @@ services: TORII_TELEMETRY_URL: iroha2:8182 IROHA_PUBLIC_KEY: "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020" IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "1261a436d36779223d7d6cf20e8b644510e488e6a50bafd77a7485264d27197dfaca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}' - SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' + SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' ports: - "1339:1339" - "8082:8082" @@ -69,7 +69,7 @@ services: TORII_TELEMETRY_URL: iroha3:8183 IROHA_PUBLIC_KEY: "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f" IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "a70dab95c7482eb9f159111b65947e482108cfe67df877bd8d3b9441a781c7c98e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}' - SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' + SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' ports: - "1340:1340" - "8083:8083" diff --git a/docker-compose-single.yml b/docker-compose-single.yml index 1c199e8915b..bfaf44e9cf1 100644 --- a/docker-compose-single.yml +++ b/docker-compose-single.yml @@ -9,9 +9,9 @@ services: TORII_P2P_ADDR: iroha0:1337 TORII_API_URL: iroha0:8080 TORII_TELEMETRY_URL: iroha0:8180 - IROHA_PUBLIC_KEY: 'ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0' - IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "9ac47abf59b356e0bd7dcbbbb4dec080e302156a48ca907e47cb6aea1d32719e7233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}' - SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}]' + IROHA_PUBLIC_KEY: "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" + IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "282ed9f3cf92811c3818dbc4ae594ed59dc1a2f78e4241e31924e101d6b1fb831c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}' + SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}]' ports: - "1337:1337" - "8080:8080" diff --git a/docker-compose.yml b/docker-compose.yml index bdd84fba7ca..a8738bc735e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,9 +6,9 @@ services: TORII_P2P_ADDR: iroha0:1337 TORII_API_URL: iroha0:8080 TORII_TELEMETRY_URL: iroha0:8180 - IROHA_PUBLIC_KEY: "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0" - IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "9ac47abf59b356e0bd7dcbbbb4dec080e302156a48ca907e47cb6aea1d32719e7233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}' - SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' + IROHA_PUBLIC_KEY: "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" + IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "282ed9f3cf92811c3818dbc4ae594ed59dc1a2f78e4241e31924e101d6b1fb831c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}' + SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' ports: - "1337:1337" - "8080:8080" @@ -23,7 +23,7 @@ services: TORII_TELEMETRY_URL: iroha1:8181 IROHA_PUBLIC_KEY: "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1" IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "3bac34cda9e3763fa069c1198312d1ec73b53023b8180c822ac355435edc4a24cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}' - SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' + SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' ports: - "1338:1338" - "8081:8081" @@ -37,7 +37,7 @@ services: TORII_TELEMETRY_URL: iroha2:8182 IROHA_PUBLIC_KEY: "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020" IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "1261a436d36779223d7d6cf20e8b644510e488e6a50bafd77a7485264d27197dfaca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}' - SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' + SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' ports: - "1339:1339" - "8082:8082" @@ -51,7 +51,7 @@ services: TORII_TELEMETRY_URL: iroha3:8183 IROHA_PUBLIC_KEY: "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f" IROHA_PRIVATE_KEY: '{"digest_function": "ed25519", "payload": "a70dab95c7482eb9f159111b65947e482108cfe67df877bd8d3b9441a781c7c98e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}' - SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' + SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337", "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b"}, {"address":"iroha1:1338", "public_key": "ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1"}, {"address": "iroha2:1339", "public_key": "ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020"}, {"address": "iroha3:1340", "public_key": "ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f"}]' ports: - "1340:1340" - "8083:8083" diff --git a/docs/source/references/config.md b/docs/source/references/config.md index f624027826b..54f4b6319af 100644 --- a/docs/source/references/config.md +++ b/docs/source/references/config.md @@ -8,10 +8,10 @@ The following is the default configuration used by Iroha. ```json { - "PUBLIC_KEY": "ed0100", + "PUBLIC_KEY": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b", "PRIVATE_KEY": { - "digest_function": "", - "payload": "" + "digest_function": "ed25519", + "payload": "282ed9f3cf92811c3818dbc4ae594ed59dc1a2f78e4241e31924e101d6b1fb831c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" }, "DISABLE_PANIC_TERMINAL_COLORS": false, "KURA": { @@ -22,11 +22,16 @@ The following is the default configuration used by Iroha. }, "SUMERAGI": { "PEER_ID": { - "address": "", - "public_key": "ed0100" + "address": "127.0.0.1:1337", + "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" }, "BLOCK_TIME_MS": 1000, - "TRUSTED_PEERS": [], + "TRUSTED_PEERS": [ + { + "address": "127.0.0.1:1337", + "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" + } + ], "COMMIT_TIME_MS": 2000, "TX_RECEIPT_TIME_MS": 500, "N_TOPOLOGY_SHIFTS_BEFORE_RESHUFFLE": 1, @@ -64,8 +69,11 @@ The following is the default configuration used by Iroha. "TERMINAL_COLORS": true }, "GENESIS": { - "ACCOUNT_PUBLIC_KEY": null, - "ACCOUNT_PRIVATE_KEY": null, + "ACCOUNT_PUBLIC_KEY": "ed01204cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf", + "ACCOUNT_PRIVATE_KEY": { + "digest_function": "ed25519", + "payload": "d748e18ce60cb30dea3e73c9019b7af45a8d465e3d71bcc9a5ef99a008205e534cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf" + }, "WAIT_FOR_PEERS_RETRY_COUNT": 100, "WAIT_FOR_PEERS_RETRY_PERIOD_MS": 500, "GENESIS_SUBMISSION_DELAY_MS": 1000 @@ -92,15 +100,15 @@ The following is the default configuration used by Iroha. "max": 128 } }, + "NETWORK": { + "MAILBOX": 100 + }, "TELEMETRY": { "NAME": null, "URL": null, "MIN_PERIOD": 1, "MAX_EXPONENT": 4, "FILE": null - }, - "NETWORK": { - "MAILBOX": 100 } } ``` @@ -167,8 +175,11 @@ Has type `GenesisConfiguration`. Can be configured via environment variable `IRO ```json { - "ACCOUNT_PRIVATE_KEY": null, - "ACCOUNT_PUBLIC_KEY": null, + "ACCOUNT_PRIVATE_KEY": { + "digest_function": "ed25519", + "payload": "d748e18ce60cb30dea3e73c9019b7af45a8d465e3d71bcc9a5ef99a008205e534cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf" + }, + "ACCOUNT_PUBLIC_KEY": "ed01204cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf", "GENESIS_SUBMISSION_DELAY_MS": 1000, "WAIT_FOR_PEERS_RETRY_COUNT": 100, "WAIT_FOR_PEERS_RETRY_PERIOD_MS": 500 @@ -182,17 +193,20 @@ Genesis account private key, only needed on the peer that submits the genesis bl Has type `Option`. Can be configured via environment variable `IROHA_GENESIS_ACCOUNT_PRIVATE_KEY` ```json -null +{ + "digest_function": "ed25519", + "payload": "d748e18ce60cb30dea3e73c9019b7af45a8d465e3d71bcc9a5ef99a008205e534cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf" +} ``` ### `genesis.account_public_key` The genesis account public key, should be supplied to all peers. -Has type `Option`. Can be configured via environment variable `IROHA_GENESIS_ACCOUNT_PUBLIC_KEY` +Has type `PublicKey`. Can be configured via environment variable `IROHA_GENESIS_ACCOUNT_PUBLIC_KEY` ```json -null +"ed01204cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf" ``` ### `genesis.genesis_submission_delay_ms` @@ -376,8 +390,8 @@ Has type `PrivateKey`. Can be configured via environment variable `IROHA_PRIVATE ```json { - "digest_function": "", - "payload": "" + "digest_function": "ed25519", + "payload": "282ed9f3cf92811c3818dbc4ae594ed59dc1a2f78e4241e31924e101d6b1fb831c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" } ``` @@ -388,7 +402,7 @@ Public key of this peer. Has type `PublicKey`. Can be configured via environment variable `IROHA_PUBLIC_KEY` ```json -"ed0100" +"ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" ``` ## `queue` @@ -461,14 +475,19 @@ Has type `SumeragiConfiguration`. Can be configured via environment variable `IR "MAILBOX": 100, "N_TOPOLOGY_SHIFTS_BEFORE_RESHUFFLE": 1, "PEER_ID": { - "address": "", - "public_key": "ed0100" + "address": "127.0.0.1:1337", + "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" }, "TRANSACTION_LIMITS": { "max_instruction_number": 4096, "max_wasm_size_bytes": 4194304 }, - "TRUSTED_PEERS": [], + "TRUSTED_PEERS": [ + { + "address": "127.0.0.1:1337", + "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" + } + ], "TX_RECEIPT_TIME_MS": 500 } ``` @@ -522,10 +541,10 @@ Has type `KeyPair`. Can be configured via environment variable `SUMERAGI_KEY_PAI ```json { "private_key": { - "digest_function": "", - "payload": "" + "digest_function": "ed25519", + "payload": "282ed9f3cf92811c3818dbc4ae594ed59dc1a2f78e4241e31924e101d6b1fb831c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" }, - "public_key": "ed0100" + "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" } ``` @@ -557,8 +576,8 @@ Has type `PeerId`. Can be configured via environment variable `SUMERAGI_PEER_ID` ```json { - "address": "", - "public_key": "ed0100" + "address": "127.0.0.1:1337", + "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" } ``` @@ -582,7 +601,12 @@ Optional list of predefined trusted peers. Has type `TrustedPeers`. Can be configured via environment variable `SUMERAGI_TRUSTED_PEERS` ```json -[] +[ + { + "address": "127.0.0.1:1337", + "public_key": "ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b" + } +] ``` ### `sumeragi.tx_receipt_time_ms` diff --git a/macro/Cargo.toml b/macro/Cargo.toml index 2ee227ad866..fee9306f727 100644 --- a/macro/Cargo.toml +++ b/macro/Cargo.toml @@ -18,6 +18,8 @@ maintenance = { status = "actively-developed" } [features] default = ["std"] +# Enable static linkage of the rust standard library. +# Please refer to https://docs.rust-embedded.org/book/intro/no-std.html std = [] [dependencies] diff --git a/p2p/tests/p2p.rs b/p2p/tests/p2p.rs index 11db43aa51c..e49936f2370 100644 --- a/p2p/tests/p2p.rs +++ b/p2p/tests/p2p.rs @@ -270,7 +270,7 @@ async fn start_network( let network = Network::::new( broker.clone(), addr.clone(), - keypair.public_key.clone(), + keypair.public_key().clone(), 100, ) .await @@ -286,7 +286,7 @@ async fn start_network( if *p != addr { let peer = PeerId { address: p.clone(), - public_key: keypair.public_key.clone(), + public_key: keypair.public_key().clone(), }; broker @@ -309,7 +309,7 @@ async fn start_network( } info!(peer_addr = %addr, %conn_count, "Got all connections!"); - (addr, broker, keypair.public_key.clone()) + (addr, broker, keypair.public_key().clone()) } #[test] diff --git a/permissions_validators/Cargo.toml b/permissions_validators/Cargo.toml index e9d7f10f9ba..32c5b7ecd16 100644 --- a/permissions_validators/Cargo.toml +++ b/permissions_validators/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] +# Include support for account roles roles = ["iroha_core/roles", "iroha_data_model/roles"] [dependencies] diff --git a/permissions_validators/src/private_blockchain/register.rs b/permissions_validators/src/private_blockchain/register.rs index 925faabde80..c52118d19b4 100644 --- a/permissions_validators/src/private_blockchain/register.rs +++ b/permissions_validators/src/private_blockchain/register.rs @@ -44,9 +44,6 @@ impl HasToken for GrantedAllowedRegisterDomains { _instruction: &Instruction, _wsv: &WorldStateView, ) -> Result { - Ok(PermissionToken::new( - CAN_REGISTER_DOMAINS_TOKEN.clone(), - BTreeMap::new(), - )) + Ok(PermissionToken::new(CAN_REGISTER_DOMAINS_TOKEN.clone())) } } diff --git a/permissions_validators/src/public_blockchain/burn.rs b/permissions_validators/src/public_blockchain/burn.rs index a6e7688de57..a3b0e186add 100644 --- a/permissions_validators/src/public_blockchain/burn.rs +++ b/permissions_validators/src/public_blockchain/burn.rs @@ -75,15 +75,13 @@ impl HasToken for GrantedByAssetCreator { } else { return Err("Destination is not an Asset.".to_owned()); }; - let mut params = BTreeMap::new(); - params.insert( - ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), - asset_id.definition_id.into(), - ); - Ok(PermissionToken::new( - CAN_BURN_ASSET_WITH_DEFINITION.clone(), - params, - )) + + Ok( + PermissionToken::new(CAN_BURN_ASSET_WITH_DEFINITION.clone()).with_params([( + ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), + asset_id.definition_id.into(), + )]), + ) } } @@ -107,7 +105,7 @@ impl IsGrantAllowed for GrantRegisteredByMeAccess { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_BURN_ASSET_WITH_DEFINITION.clone() { + if permission_token.name() != &*CAN_BURN_ASSET_WITH_DEFINITION { return Err("Grant instruction is not for burn permission.".to_owned()); } check_asset_creator_for_token(&permission_token, authority, wsv) @@ -171,12 +169,8 @@ impl HasToken for GrantedByAssetOwner { } else { return Err("Source id is not an AssetId.".to_owned()); }; - let mut params = BTreeMap::new(); - params.insert(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), destination_id.into()); - Ok(PermissionToken::new( - CAN_BURN_USER_ASSETS_TOKEN.clone(), - params, - )) + Ok(PermissionToken::new(CAN_BURN_USER_ASSETS_TOKEN.clone()) + .with_params([(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), destination_id.into())])) } } @@ -200,7 +194,7 @@ impl IsGrantAllowed for GrantMyAssetAccess { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_BURN_USER_ASSETS_TOKEN.clone() { + if permission_token.name() != &*CAN_BURN_USER_ASSETS_TOKEN { return Err("Grant instruction is not for burn permission.".to_owned()); } check_asset_owner_for_token(&permission_token, authority)?; diff --git a/permissions_validators/src/public_blockchain/key_value.rs b/permissions_validators/src/public_blockchain/key_value.rs index 4bd3c499114..d8b5f09a83d 100644 --- a/permissions_validators/src/public_blockchain/key_value.rs +++ b/permissions_validators/src/public_blockchain/key_value.rs @@ -94,12 +94,10 @@ impl HasToken for SetGrantedByAssetOwner { } else { return Err("Source id is not an AssetId.".to_owned()); }; - let mut params = BTreeMap::new(); - params.insert(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), object_id.into()); - Ok(PermissionToken::new( - CAN_SET_KEY_VALUE_USER_ASSETS_TOKEN.clone(), - params, - )) + Ok( + PermissionToken::new(CAN_SET_KEY_VALUE_USER_ASSETS_TOKEN.clone()) + .with_params([(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), object_id.into())]), + ) } } @@ -123,7 +121,7 @@ impl IsGrantAllowed for GrantMyAssetAccessSet { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_SET_KEY_VALUE_USER_ASSETS_TOKEN.clone() { + if permission_token.name() != &*CAN_SET_KEY_VALUE_USER_ASSETS_TOKEN { return Err("Grant instruction is not for set permission.".to_owned()); } check_asset_owner_for_token(&permission_token, authority)?; @@ -190,12 +188,10 @@ impl HasToken for SetGrantedByAccountOwner { } else { return Err("Source id is not an AccountId.".to_owned()); }; - let mut params = BTreeMap::new(); - params.insert(ACCOUNT_ID_TOKEN_PARAM_NAME.to_owned(), object_id.into()); - Ok(PermissionToken::new( - CAN_SET_KEY_VALUE_IN_USER_METADATA.clone(), - params, - )) + Ok( + PermissionToken::new(CAN_SET_KEY_VALUE_IN_USER_METADATA.clone()) + .with_params([(ACCOUNT_ID_TOKEN_PARAM_NAME.to_owned(), object_id.into())]), + ) } } @@ -219,7 +215,7 @@ impl IsGrantAllowed for GrantMyMetadataAccessSet { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_SET_KEY_VALUE_IN_USER_METADATA.clone() { + if permission_token.name() != &*CAN_SET_KEY_VALUE_IN_USER_METADATA { return Err("Grant instruction is not for set permission.".to_owned()); } check_account_owner_for_token(&permission_token, authority)?; @@ -285,12 +281,10 @@ impl HasToken for RemoveGrantedByAssetOwner { } else { return Err("Source id is not an AssetId.".to_owned()); }; - let mut params = BTreeMap::new(); - params.insert(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), object_id.into()); - Ok(PermissionToken::new( - CAN_REMOVE_KEY_VALUE_IN_USER_ASSETS.clone(), - params, - )) + Ok( + PermissionToken::new(CAN_REMOVE_KEY_VALUE_IN_USER_ASSETS.clone()) + .with_params([(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), object_id.into())]), + ) } } @@ -314,7 +308,7 @@ impl IsGrantAllowed for GrantMyAssetAccessRemove { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_REMOVE_KEY_VALUE_IN_USER_ASSETS.clone() { + if permission_token.name() != &*CAN_REMOVE_KEY_VALUE_IN_USER_ASSETS { return Err("Grant instruction is not for set permission.".to_owned()); } check_asset_owner_for_token(&permission_token, authority)?; @@ -381,12 +375,10 @@ impl HasToken for RemoveGrantedByAccountOwner { } else { return Err("Source id is not an AccountId.".to_owned()); }; - let mut params = BTreeMap::new(); - params.insert(ACCOUNT_ID_TOKEN_PARAM_NAME.to_owned(), object_id.into()); - Ok(PermissionToken::new( - CAN_REMOVE_KEY_VALUE_IN_USER_METADATA.clone(), - params, - )) + Ok( + PermissionToken::new(CAN_REMOVE_KEY_VALUE_IN_USER_METADATA.clone()) + .with_params([(ACCOUNT_ID_TOKEN_PARAM_NAME.to_owned(), object_id.into())]), + ) } } @@ -410,7 +402,7 @@ impl IsGrantAllowed for GrantMyMetadataAccessRemove { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_REMOVE_KEY_VALUE_IN_USER_METADATA.clone() { + if permission_token.name() != &*CAN_REMOVE_KEY_VALUE_IN_USER_METADATA { return Err("Grant instruction is not for remove permission.".to_owned()); } check_account_owner_for_token(&permission_token, authority)?; @@ -438,7 +430,7 @@ impl IsGrantAllowed for GrantMyAssetDefinitionSet { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_SET_KEY_VALUE_IN_ASSET_DEFINITION.clone() { + if permission_token.name() != &*CAN_SET_KEY_VALUE_IN_ASSET_DEFINITION { return Err( "Grant instruction is not for set key value in asset definition permission." .to_owned(), @@ -468,7 +460,7 @@ impl IsGrantAllowed for GrantMyAssetDefinitionRemove { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_REMOVE_KEY_VALUE_IN_ASSET_DEFINITION.clone() { + if permission_token.name() != &*CAN_REMOVE_KEY_VALUE_IN_ASSET_DEFINITION { return Err( "Grant instruction is not for remove key value in asset definition permission." .to_owned(), @@ -580,15 +572,12 @@ impl HasToken for SetGrantedByAssetDefinitionOwner { } else { return Err("Source id is not an AssetDefinitionId.".to_owned()); }; - let mut params = BTreeMap::new(); - params.insert( - ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), - object_id.into(), - ); - Ok(PermissionToken::new( - CAN_SET_KEY_VALUE_IN_ASSET_DEFINITION.clone(), - params, - )) + Ok( + PermissionToken::new(CAN_SET_KEY_VALUE_IN_ASSET_DEFINITION.clone()).with_params([( + ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), + object_id.into(), + )]), + ) } } @@ -619,14 +608,11 @@ impl HasToken for RemoveGrantedByAssetDefinitionOwner { } else { return Err("Source id is not an AssetDefinitionId.".to_owned()); }; - let mut params = BTreeMap::new(); - params.insert( - ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), - object_id.into(), - ); - Ok(PermissionToken::new( - CAN_REMOVE_KEY_VALUE_IN_ASSET_DEFINITION.clone(), - params, - )) + Ok( + PermissionToken::new(CAN_REMOVE_KEY_VALUE_IN_ASSET_DEFINITION.clone()).with_params([( + ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), + object_id.into(), + )]), + ) } } diff --git a/permissions_validators/src/public_blockchain/mint.rs b/permissions_validators/src/public_blockchain/mint.rs index 5292c538321..fabd67b67b1 100644 --- a/permissions_validators/src/public_blockchain/mint.rs +++ b/permissions_validators/src/public_blockchain/mint.rs @@ -71,15 +71,12 @@ impl HasToken for GrantedByAssetCreator { } else { return Err("Destination is not an Asset.".to_owned()); }; - let mut params = BTreeMap::new(); - params.insert( - ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), - asset_id.definition_id.into(), - ); - Ok(PermissionToken::new( - CAN_MINT_USER_ASSET_DEFINITIONS_TOKEN.clone(), - params, - )) + Ok( + PermissionToken::new(CAN_MINT_USER_ASSET_DEFINITIONS_TOKEN.clone()).with_params([( + ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), + asset_id.definition_id.into(), + )]), + ) } } @@ -103,7 +100,7 @@ impl IsGrantAllowed for GrantRegisteredByMeAccess { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_MINT_USER_ASSET_DEFINITIONS_TOKEN.clone() { + if permission_token.name() != &*CAN_MINT_USER_ASSET_DEFINITIONS_TOKEN { return Err("Grant instruction is not for mint permission.".to_owned()); } check_asset_creator_for_token(&permission_token, authority, wsv) diff --git a/permissions_validators/src/public_blockchain/mod.rs b/permissions_validators/src/public_blockchain/mod.rs index ee65657f60f..da233ef8214 100644 --- a/permissions_validators/src/public_blockchain/mod.rs +++ b/permissions_validators/src/public_blockchain/mod.rs @@ -85,8 +85,7 @@ pub fn check_account_owner_for_token( authority: &AccountId, ) -> Result<(), String> { let account_id = if let Value::Id(IdBox::AccountId(account_id)) = permission_token - .params - .get(&ACCOUNT_ID_TOKEN_PARAM_NAME.clone()) + .get_param(&*ACCOUNT_ID_TOKEN_PARAM_NAME) .ok_or(format!( "Failed to find permission param {}.", ACCOUNT_ID_TOKEN_PARAM_NAME.clone() @@ -114,8 +113,7 @@ pub fn check_asset_owner_for_token( authority: &AccountId, ) -> Result<(), String> { let asset_id = if let Value::Id(IdBox::AssetId(asset_id)) = permission_token - .params - .get(&ASSET_ID_TOKEN_PARAM_NAME.clone()) + .get_param(&*ASSET_ID_TOKEN_PARAM_NAME) .ok_or(format!( "Failed to find permission param {}.", ASSET_ID_TOKEN_PARAM_NAME.clone() @@ -144,8 +142,7 @@ pub fn check_asset_creator_for_token( wsv: &WorldStateView, ) -> Result<(), String> { let definition_id = if let Value::Id(IdBox::AssetDefinitionId(definition_id)) = permission_token - .params - .get(&ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.clone()) + .get_param(&*ASSET_DEFINITION_ID_TOKEN_PARAM_NAME) .ok_or(format!( "Failed to find permission param {}.", ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.clone() @@ -221,13 +218,12 @@ mod tests { ); let mut domain = Domain::new(DomainId::from_str("test").expect("Valid")).build(); let mut bob_account = Account::new(bob_id.clone(), []).build(); - assert!(bob_account.add_permission(PermissionToken::new( - transfer::CAN_TRANSFER_USER_ASSETS_TOKEN.clone(), - [( + assert!(bob_account.add_permission( + PermissionToken::new(transfer::CAN_TRANSFER_USER_ASSETS_TOKEN.clone()).with_params([( ASSET_ID_TOKEN_PARAM_NAME.clone(), alice_xor_id.clone().into(), - )], - ))); + )]) + )); assert!(domain.add_account(bob_account).is_none()); let wsv = WorldStateView::::new(World::with([domain], BTreeSet::new())); let transfer = Instruction::Transfer(TransferBox { @@ -250,10 +246,9 @@ mod tests { AssetDefinitionId::from_str("xor#test").expect("Valid"), AccountId::from_str("alice@test").expect("Valid"), ); - let permission_token_to_alice = PermissionToken::new( - transfer::CAN_TRANSFER_USER_ASSETS_TOKEN.clone(), - [(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), alice_xor_id.into())], - ); + let permission_token_to_alice = + PermissionToken::new(transfer::CAN_TRANSFER_USER_ASSETS_TOKEN.clone()) + .with_params([(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), alice_xor_id.into())]); let wsv = WorldStateView::::new(World::new()); let grant = Instruction::Grant(GrantBox::new( permission_token_to_alice, @@ -294,13 +289,13 @@ mod tests { let xor_definition = new_xor_definition(&xor_id); let mut domain = Domain::new(DomainId::from_str("test").expect("Valid")).build(); let mut bob_account = Account::new(bob_id.clone(), []).build(); - assert!(bob_account.add_permission(PermissionToken::new( - unregister::CAN_UNREGISTER_ASSET_WITH_DEFINITION.clone(), - [( - ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.clone(), - xor_id.clone().into(), - )], - ))); + assert!(bob_account.add_permission( + PermissionToken::new(unregister::CAN_UNREGISTER_ASSET_WITH_DEFINITION.clone()) + .with_params([( + ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.clone(), + xor_id.clone().into(), + )]) + )); assert!(domain.add_account(bob_account).is_none()); assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) @@ -321,13 +316,12 @@ mod tests { let bob_id = AccountId::from_str("bob@test").expect("Valid"); let xor_id = AssetDefinitionId::from_str("xor#test").expect("Valid"); let xor_definition = new_xor_definition(&xor_id); - let permission_token_to_alice = PermissionToken::new( - unregister::CAN_UNREGISTER_ASSET_WITH_DEFINITION.clone(), - [( - ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), - xor_id.into(), - )], - ); + let permission_token_to_alice = + PermissionToken::new(unregister::CAN_UNREGISTER_ASSET_WITH_DEFINITION.clone()) + .with_params([( + ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), + xor_id.into(), + )]); let mut domain = Domain::new(DomainId::from_str("test").expect("Valid")).build(); assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) @@ -384,10 +378,10 @@ mod tests { let xor_definition = new_xor_definition(&xor_id); let mut domain = Domain::new(DomainId::from_str("test").expect("Valid")).build(); let mut bob_account = Account::new(bob_id.clone(), []).build(); - assert!(bob_account.add_permission(PermissionToken::new( - mint::CAN_MINT_USER_ASSET_DEFINITIONS_TOKEN.clone(), - [(ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.clone(), xor_id.into(),)], - ))); + assert!(bob_account.add_permission( + PermissionToken::new(mint::CAN_MINT_USER_ASSET_DEFINITIONS_TOKEN.clone()) + .with_params([(ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.clone(), xor_id.into())]) + )); assert!(domain.add_account(bob_account).is_none()); assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) @@ -412,11 +406,11 @@ mod tests { let xor_definition = new_xor_definition(&xor_id); let permission_token_to_alice = PermissionToken::new( mint::CAN_MINT_USER_ASSET_DEFINITIONS_TOKEN.clone(), - [( - ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), - xor_id.into(), - )], - ); + ) + .with_params([( + ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), + xor_id.into(), + )]); let mut domain = Domain::new(DomainId::from_str("test").expect("Valid")).build(); assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) @@ -471,10 +465,10 @@ mod tests { let xor_definition = new_xor_definition(&xor_id); let mut domain = Domain::new(DomainId::from_str("test").expect("Valid")).build(); let mut bob_account = Account::new(bob_id.clone(), []).build(); - assert!(bob_account.add_permission(PermissionToken::new( - burn::CAN_BURN_ASSET_WITH_DEFINITION.clone(), - [(ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.clone(), xor_id.into(),)], - ))); + assert!(bob_account.add_permission( + PermissionToken::new(burn::CAN_BURN_ASSET_WITH_DEFINITION.clone()) + .with_params([(ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.clone(), xor_id.into())],) + )); assert!(domain.add_account(bob_account).is_none()); assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) @@ -497,13 +491,11 @@ mod tests { let bob_id = AccountId::from_str("bob@test").expect("Valid"); let xor_id = AssetDefinitionId::from_str("xor#test").expect("Valid"); let xor_definition = new_xor_definition(&xor_id); - let permission_token_to_alice = PermissionToken::new( - burn::CAN_BURN_ASSET_WITH_DEFINITION.clone(), - [( + let permission_token_to_alice = + PermissionToken::new(burn::CAN_BURN_ASSET_WITH_DEFINITION.clone()).with_params([( ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.to_owned(), xor_id.into(), - )], - ); + )]); let mut domain = Domain::new(DomainId::from_str("test").expect("Valid")).build(); assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) @@ -545,13 +537,12 @@ mod tests { ); let mut domain = Domain::new(DomainId::from_str("test").expect("Valid")).build(); let mut bob_account = Account::new(bob_id.clone(), []).build(); - assert!(bob_account.add_permission(PermissionToken::new( - burn::CAN_BURN_USER_ASSETS_TOKEN.clone(), - [( + assert!(bob_account.add_permission( + PermissionToken::new(burn::CAN_BURN_USER_ASSETS_TOKEN.clone()).with_params([( ASSET_ID_TOKEN_PARAM_NAME.clone(), alice_xor_id.clone().into(), - )], - ))); + )]) + )); assert!(domain.add_account(bob_account).is_none()); let wsv = WorldStateView::::new(World::with([domain], vec![])); let transfer = Instruction::Burn(BurnBox { @@ -573,10 +564,9 @@ mod tests { AssetDefinitionId::from_str("xor#test").expect("Valid"), AccountId::from_str("alice@test").expect("Valid"), ); - let permission_token_to_alice = PermissionToken::new( - burn::CAN_BURN_USER_ASSETS_TOKEN.clone(), - [(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), alice_xor_id.into())], - ); + let permission_token_to_alice = + PermissionToken::new(burn::CAN_BURN_USER_ASSETS_TOKEN.clone()) + .with_params([(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), alice_xor_id.into())]); let wsv = WorldStateView::::new(World::new()); let grant = Instruction::Grant(GrantBox::new( permission_token_to_alice, diff --git a/permissions_validators/src/public_blockchain/transfer.rs b/permissions_validators/src/public_blockchain/transfer.rs index 54e5f703592..241e5df524f 100644 --- a/permissions_validators/src/public_blockchain/transfer.rs +++ b/permissions_validators/src/public_blockchain/transfer.rs @@ -80,12 +80,8 @@ impl HasToken for GrantedByAssetOwner { } else { return Err("Source id is not an AssetId.".to_owned()); }; - let mut params = BTreeMap::new(); - params.insert(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), source_id.into()); - Ok(PermissionToken::new( - CAN_TRANSFER_USER_ASSETS_TOKEN.clone(), - params, - )) + Ok(PermissionToken::new(CAN_TRANSFER_USER_ASSETS_TOKEN.clone()) + .with_params([(ASSET_ID_TOKEN_PARAM_NAME.to_owned(), source_id.into())])) } } @@ -109,7 +105,7 @@ impl IsGrantAllowed for GrantMyAssetAccess { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_TRANSFER_USER_ASSETS_TOKEN.clone() { + if permission_token.name() != &*CAN_TRANSFER_USER_ASSETS_TOKEN { return Err("Grant instruction is not for transfer permission.".to_owned()); } check_asset_owner_for_token(&permission_token, authority) @@ -166,10 +162,10 @@ fn retrieve_permission_params( wsv.map_account(authority, |account| { wsv.account_permission_tokens(account) .iter() - .filter(|token| token.name == *CAN_TRANSFER_ONLY_FIXED_NUMBER_OF_TIMES_PER_PERIOD) - .map(|token| token.params.clone()) - .next() - .unwrap_or_default() + .filter(|token| token.name() == &*CAN_TRANSFER_ONLY_FIXED_NUMBER_OF_TIMES_PER_PERIOD) + .flat_map(PermissionToken::params) + .map(|(name, value)| (name.clone(), value.clone())) + .collect() }) .map_err(|e| e.to_string()) } diff --git a/permissions_validators/src/public_blockchain/unregister.rs b/permissions_validators/src/public_blockchain/unregister.rs index 8c7e01c75fc..29775670af4 100644 --- a/permissions_validators/src/public_blockchain/unregister.rs +++ b/permissions_validators/src/public_blockchain/unregister.rs @@ -73,15 +73,12 @@ impl HasToken for GrantedByAssetCreator { } else { return Err("Source id is not an AssetDefinitionId.".to_owned()); }; - let mut params = BTreeMap::new(); - params.insert( - ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.clone(), - object_id.into(), - ); - Ok(PermissionToken::new( - CAN_UNREGISTER_ASSET_WITH_DEFINITION.clone(), - params, - )) + Ok( + PermissionToken::new(CAN_UNREGISTER_ASSET_WITH_DEFINITION.clone()).with_params([( + ASSET_DEFINITION_ID_TOKEN_PARAM_NAME.clone(), + object_id.into(), + )]), + ) } } @@ -105,7 +102,7 @@ impl IsGrantAllowed for GrantRegisteredByMeAccess { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_UNREGISTER_ASSET_WITH_DEFINITION.clone() { + if permission_token.name() != &*CAN_UNREGISTER_ASSET_WITH_DEFINITION { return Err("Grant instruction is not for unregister permission.".to_owned()); } check_asset_creator_for_token(&permission_token, authority, wsv) @@ -133,7 +130,7 @@ impl IsRevokeAllowed for RevokeRegisteredByMeAccess { .map_err(|e| e.to_string())? .try_into() .map_err(|e: ErrorTryFromEnum<_, _>| e.to_string())?; - if permission_token.name != CAN_UNREGISTER_ASSET_WITH_DEFINITION.clone() { + if permission_token.name() != &*CAN_UNREGISTER_ASSET_WITH_DEFINITION { return Err("Revoke instruction is not for unregister permission.".to_owned()); } check_asset_creator_for_token(&permission_token, authority, wsv) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 0b7451505ce..49a73e1b9ac 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] channel = "1.59" -components = [ "rustc", "clippy", "fmt" ] +components = [ "rustc", "clippy", "rustfmt" ] targets = ["wasm32-unknown-unknown"] profile = "minimal" diff --git a/schema/bin/Cargo.toml b/schema/bin/Cargo.toml index cded71f56d2..54338d546c2 100644 --- a/schema/bin/Cargo.toml +++ b/schema/bin/Cargo.toml @@ -7,7 +7,8 @@ edition = "2021" [dependencies] iroha_data_model = { version = "=2.0.0-pre-rc.3", path = "../../data_model", features = ["roles"] } -iroha_schema = { version = "=2.0.0-pre-rc.3", path = "../../schema" } iroha_core = { version = "=2.0.0-pre-rc.3", path = "../../core", features = ["roles"] } +iroha_crypto = { version = "=2.0.0-pre-rc.3", path = "../../crypto" } +iroha_schema = { version = "=2.0.0-pre-rc.3", path = "../../schema" } serde_json = "1" diff --git a/schema/bin/src/lib.rs b/schema/bin/src/lib.rs index 3e102365f7a..7bd6a0e9d12 100644 --- a/schema/bin/src/lib.rs +++ b/schema/bin/src/lib.rs @@ -7,7 +7,6 @@ use iroha_core::{ genesis::RawGenesisBlock, smartcontracts::isi::query::Error as QueryError, }; -use iroha_data_model::merkle::MerkleTree; use iroha_schema::prelude::*; macro_rules! schemas { @@ -23,6 +22,7 @@ macro_rules! schemas { /// You should only include the top-level types, because other types /// shall be included automatically. pub fn build_schemas() -> MetaMap { + use iroha_crypto::MerkleTree; use iroha_data_model::prelude::*; schemas! { @@ -134,8 +134,15 @@ mod tests { } #[test] + #[allow(clippy::use_debug)] + #[allow(clippy::print_stdout)] fn no_missing_schemas() { - assert!(find_missing_schemas(&build_schemas()).is_empty()); + let schemas = build_schemas(); + + let missing_schemas = find_missing_schemas(&schemas); + println!("Missing schemas: \n{:#?}", missing_schemas); + + assert!(missing_schemas.is_empty()); } #[test] diff --git a/schema/src/lib.rs b/schema/src/lib.rs index 90ced94187c..0805de15db9 100644 --- a/schema/src/lib.rs +++ b/schema/src/lib.rs @@ -56,9 +56,9 @@ pub trait DecimalPlacesAware { pub enum Metadata { /// Structure with named fields Struct(NamedFieldsMeta), - /// Unnamed structure + /// Structure with unnamed fields TupleStruct(UnnamedFieldsMeta), - /// Enum + /// Enumeration Enum(EnumMeta), /// Integer Int(IntMode), @@ -72,10 +72,10 @@ pub enum Metadata { Array(ArrayMeta), /// Vector with type Vec(String), - /// Option with type - Option(String), /// Map Map(MapMeta), + /// Option with type + Option(String), /// Result Result(ResultMeta), } @@ -106,12 +106,12 @@ pub struct Declaration { pub ty: String, } -/// Unnamed fileds +/// Unnamed fields #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] pub struct UnnamedFieldsMeta { /// Field types pub types: Vec, - //todo add collection of properties meta defined in struct + // TODO: add collection of properties meta defined in struct } /// Enum metadata @@ -141,7 +141,6 @@ pub struct ResultMeta { /// Err type pub err: String, } - /// Map variant #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] pub struct MapMeta { @@ -186,7 +185,7 @@ macro_rules! impl_schema_int { impl IntoSchema for Compact<$t> { fn type_name() -> String { - format!("iroha_schema::Compact<{}>", <$t as IntoSchema>::type_name()) + format!("Compact<{}>", <$t as IntoSchema>::type_name()) } fn schema(map: &mut MetaMap) { let _ = map.entry(Self::type_name()).or_insert(Metadata::Int(IntMode::Compact)); diff --git a/schema/tests/numbers_compact_and_fixed.rs b/schema/tests/numbers_compact_and_fixed.rs index f5ca9400685..82a51a10c82 100644 --- a/schema/tests/numbers_compact_and_fixed.rs +++ b/schema/tests/numbers_compact_and_fixed.rs @@ -28,33 +28,18 @@ fn compact() { use Metadata::*; let expected = vec![ - ( - "iroha_schema::Compact".to_owned(), - Int(IntMode::Compact), - ), - ( - "iroha_schema::Compact".to_owned(), - Int(IntMode::Compact), - ), - ( - "iroha_schema::Compact".to_owned(), - Int(IntMode::Compact), - ), - ( - "iroha_schema::Compact".to_owned(), - Int(IntMode::Compact), - ), - ( - "iroha_schema::Compact".to_owned(), - Int(IntMode::Compact), - ), + ("Compact".to_owned(), Int(IntMode::Compact)), + ("Compact".to_owned(), Int(IntMode::Compact)), + ("Compact".to_owned(), Int(IntMode::Compact)), + ("Compact".to_owned(), Int(IntMode::Compact)), + ("Compact".to_owned(), Int(IntMode::Compact)), ( "numbers_compact_and_fixed::Foo".to_owned(), Struct(NamedFieldsMeta { declarations: vec![ Declaration { name: "u8_compact".to_owned(), - ty: "iroha_schema::Compact".to_owned(), + ty: "Compact".to_owned(), }, Declaration { name: "u8_fixed".to_owned(), @@ -62,7 +47,7 @@ fn compact() { }, Declaration { name: "u16_compact".to_owned(), - ty: "iroha_schema::Compact".to_owned(), + ty: "Compact".to_owned(), }, Declaration { name: "u16_fixed".to_owned(), @@ -70,7 +55,7 @@ fn compact() { }, Declaration { name: "u32_compact".to_owned(), - ty: "iroha_schema::Compact".to_owned(), + ty: "Compact".to_owned(), }, Declaration { name: "u32_fixed".to_owned(), @@ -78,7 +63,7 @@ fn compact() { }, Declaration { name: "u64_compact".to_owned(), - ty: "iroha_schema::Compact".to_owned(), + ty: "Compact".to_owned(), }, Declaration { name: "u64_fixed".to_owned(), @@ -86,7 +71,7 @@ fn compact() { }, Declaration { name: "u128_compact".to_owned(), - ty: "iroha_schema::Compact".to_owned(), + ty: "Compact".to_owned(), }, Declaration { name: "u128_fixed".to_owned(), diff --git a/scripts/test_env.sh b/scripts/test_env.sh index 432bdd5056c..fc03be73192 100755 --- a/scripts/test_env.sh +++ b/scripts/test_env.sh @@ -10,13 +10,13 @@ IROHA2_GENESIS_PATH="$TEST/peers/genesis.json" # TODO: don't hard-code these, instead, generate them. declare -A public_keys -public_keys[iroha0]='ed01207233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0' +public_keys[iroha0]='ed01201c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b' public_keys[iroha1]='ed0120cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1' public_keys[iroha2]='ed0120faca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020' public_keys[iroha3]='ed01208e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f' declare -A private_keys -private_keys[iroha0]='9ac47abf59b356e0bd7dcbbbb4dec080e302156a48ca907e47cb6aea1d32719e7233bfc89dcbd68c19fde6ce6158225298ec1131b6a130d1aeb454c1ab5183c0' +private_keys[iroha0]='282ed9f3cf92811c3818dbc4ae594ed59dc1a2f78e4241e31924e101d6b1fb831c61faf8fe94e253b93114240394f79a607b7fa55f9e5a41ebec74b88055768b' private_keys[iroha1]='3bac34cda9e3763fa069c1198312d1ec73b53023b8180c822ac355435edc4a24cc25624d62896d3a0bfd8940f928dc2abf27cc57cefeb442aa96d9081aae58a1' private_keys[iroha2]='1261a436d36779223d7d6cf20e8b644510e488e6a50bafd77a7485264d27197dfaca9e8aa83225cb4d16d67f27dd4f93fc30ffa11adc1f5c88fd5495ecc91020' private_keys[iroha3]='a70dab95c7482eb9f159111b65947e482108cfe67df877bd8d3b9441a781c7c98e351a70b6a603ed285d666b8d689b680865913ba03ce29fb7d13a166c4e7f1f' diff --git a/tools/crypto_cli/src/main.rs b/tools/crypto_cli/src/main.rs index 15d42b9bdc8..0c6a4db57d4 100644 --- a/tools/crypto_cli/src/main.rs +++ b/tools/crypto_cli/src/main.rs @@ -36,10 +36,10 @@ fn main() -> Result<(), Report> { .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) + .possible_value(&Algorithm::Ed25519.to_string()) + .possible_value(&Algorithm::Secp256k1.to_string()) + .possible_value(&Algorithm::BlsNormal.to_string()) + .possible_value(&Algorithm::BlsSmall.to_string()) .default_value(&default_algorithm) ) .arg( @@ -73,11 +73,10 @@ fn main() -> Result<(), Report> { }, |private_key| { KeyPair::generate_with_configuration( - key_gen_configuration.clone().use_private_key(PrivateKey { - digest_function: algorithm.to_string(), - payload: hex::decode(private_key) + key_gen_configuration.clone().use_private_key( + PrivateKey::from_hex(algorithm, &private_key) .wrap_err("Failed to decode private key.")?, - }), + ), ) .wrap_err("Failed to generate key pair") }, @@ -99,9 +98,12 @@ fn main() -> Result<(), Report> { 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); + 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/parity_scale_decoder/src/generate_map.rs b/tools/parity_scale_decoder/src/generate_map.rs index a04e558fcd9..48113424759 100644 --- a/tools/parity_scale_decoder/src/generate_map.rs +++ b/tools/parity_scale_decoder/src/generate_map.rs @@ -25,7 +25,7 @@ impl TypeName for T { } } -/// Neotype which has `type_name()` method when `T` implements [`IntoSchema`] +/// Newtype which has `type_name()` method when `T` implements [`IntoSchema`] struct WithTypeName(std::marker::PhantomData); impl WithTypeName { @@ -43,7 +43,6 @@ impl WithTypeName { macro_rules! generate_map { ($($t:ty),* $(,)?) => { - #[allow(trivial_casts)] BTreeMap::from([ $(( WithTypeName::<$t>::type_name().unwrap_or(stringify!($t).to_owned()), @@ -54,9 +53,10 @@ macro_rules! generate_map { } /// Generate map with types and `dump_decoded()` ptr +#[allow(trivial_casts)] #[allow(clippy::too_many_lines)] pub fn generate_map() -> DumpDecodedMap { - generate_map! { + let mut map = generate_map! { Account, AccountEvent, AccountEventFilter, @@ -167,8 +167,7 @@ pub fn generate_map() -> DumpDecodedMap { Hash, HashOf, HashOf, - HashOf>, - HashOf>, + HashOf>, HashOf, HashOf, IdBox, @@ -205,7 +204,6 @@ pub fn generate_map() -> DumpDecodedMap { Or, Pair, Parameter, - Payload, Peer, PeerEvent, PeerEventFilter, @@ -340,13 +338,21 @@ pub fn generate_map() -> DumpDecodedMap { sumeragi::view_change::ProofChain, sumeragi::view_change::ProofPayload, sumeragi::view_change::Reason, + transaction::Payload, transaction::TransactionLimitError, transaction::WasmSmartContract, u128, u32, u64, u8, - } + }; + + map.insert( + as IntoSchema>::type_name(), + as DumpDecoded>::dump_decoded as DumpDecodedPtr, + ); + + map } #[cfg(test)] @@ -364,11 +370,7 @@ mod tests { "Vec", "iroha_core::genesis::GenesisTransaction", "iroha_core::genesis::RawGenesisBlock", - "iroha_data_model::merkle::Leaf", - "iroha_data_model::merkle::MerkleTree", - "iroha_data_model::merkle::Node", - "iroha_data_model::merkle::Subtree", - "iroha_schema::Compact", + "iroha_crypto::merkle::MerkleTree", ]); let schemas_types = build_schemas() diff --git a/version/Cargo.toml b/version/Cargo.toml index 5703171420e..4a6916a22de 100644 --- a/version/Cargo.toml +++ b/version/Cargo.toml @@ -8,6 +8,8 @@ edition = "2021" [features] default = ["std", "derive", "scale", "json"] +# Enable static linkage of the rust standard library. +# Please refer to https://docs.rust-embedded.org/book/intro/no-std.html std = ["iroha_macro/std", "parity-scale-codec/std", "thiserror"] derive = ["iroha_version_derive"] scale = ["parity-scale-codec/full"] diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index ab1ccaf6df1..73007813eb6 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -237,7 +237,7 @@ mod tests { res.encode_to(&mut r); // Store length of encoded object as byte array at the beginning of the vec - for (i, byte) in (r.len() as WasmUsize).to_be_bytes().into_iter().enumerate() { + for (i, byte) in (r.len() as WasmUsize).to_le_bytes().into_iter().enumerate() { r[i] = byte; }