From c6ecb01f5a29f36a7270a55d527ae460196ab647 Mon Sep 17 00:00:00 2001 From: Artem Ponomarev Date: Mon, 11 Oct 2021 17:25:41 +0300 Subject: [PATCH] Added new query FindTransactionByHash. Signed-off-by: Artem Ponomarev --- iroha/src/smartcontracts/isi/query.rs | 1 + iroha/src/smartcontracts/isi/tx.rs | 15 ++++++++++ iroha/src/wsv.rs | 22 ++++++++++++++ iroha_client/src/client.rs | 5 ++++ iroha_data_model/src/lib.rs | 6 ++-- iroha_data_model/src/query.rs | 39 ++++++++++++++++++++++++- iroha_permissions_validators/src/lib.rs | 14 +++++++++ 7 files changed, 99 insertions(+), 3 deletions(-) diff --git a/iroha/src/smartcontracts/isi/query.rs b/iroha/src/smartcontracts/isi/query.rs index e0886a8a4df..a86d8c49ec8 100644 --- a/iroha/src/smartcontracts/isi/query.rs +++ b/iroha/src/smartcontracts/isi/query.rs @@ -181,6 +181,7 @@ impl Query for QueryBox { FindAssetKeyValueByIdAndKey(query) => query.execute_into_value(wsv), FindAccountKeyValueByIdAndKey(query) => query.execute_into_value(wsv), FindTransactionsByAccountId(query) => query.execute_into_value(wsv), + FindTransactionByHash(query) => query.execute_into_value(wsv), FindPermissionTokensByAccountId(query) => query.execute_into_value(wsv), FindAssetDefinitionKeyValueByIdAndKey(query) => query.execute_into_value(wsv), diff --git a/iroha/src/smartcontracts/isi/tx.rs b/iroha/src/smartcontracts/isi/tx.rs index 6d0e27e4f43..e8d9f26a9ea 100644 --- a/iroha/src/smartcontracts/isi/tx.rs +++ b/iroha/src/smartcontracts/isi/tx.rs @@ -15,3 +15,18 @@ impl Query for FindTransactionsByAccountId { Ok(wsv.transactions_values_by_account_id(&id)) } } + +impl Query for FindTransactionByHash { + #[iroha_logger::log] + fn execute(&self, wsv: &WorldStateView) -> Result { + let hash = self + .hash + .evaluate(wsv, &Context::default()) + .wrap_err("Failed to get hash")?; + if !wsv.has_transaction(&hash) { + return Err(eyre!("Transaction not found")); + }; + wsv.transaction_value_by_hash(&hash) + .ok_or_else(|| eyre!("Failed to fetch transaction")) + } +} diff --git a/iroha/src/wsv.rs b/iroha/src/wsv.rs index 71a059289f2..d66ebc83ec6 100644 --- a/iroha/src/wsv.rs +++ b/iroha/src/wsv.rs @@ -384,6 +384,28 @@ impl WorldStateView { self.transactions.get(transaction_hash).is_some() } + /// Find a transaction by provided hash + pub fn transaction_value_by_hash(&self, transaction_hash: &Hash) -> Option { + self.blocks.iter().find_map(|b| { + b.as_inner_v1() + .rejected_transactions + .iter() + .find(|e| e.hash() == *transaction_hash) + .cloned() + .map(TransactionValue::RejectedTransaction) + .ok_or_else(|| { + b.as_inner_v1() + .transactions + .iter() + .find(|e| e.hash() == *transaction_hash) + .cloned() + .map(VersionedTransaction::from) + .map(TransactionValue::Transaction) + }) + .ok() + }) + } + /// Get committed and rejected transaction of the account. pub fn transactions_values_by_account_id( &self, diff --git a/iroha_client/src/client.rs b/iroha_client/src/client.rs index 7b078caa160..b6863547b1e 100644 --- a/iroha_client/src/client.rs +++ b/iroha_client/src/client.rs @@ -557,6 +557,11 @@ pub mod transaction { ) -> FindTransactionsByAccountId { FindTransactionsByAccountId::new(account_id) } + + /// Get query to retrieve transaction by hash + pub fn by_hash(hash: impl Into>) -> FindTransactionByHash { + FindTransactionByHash::new(hash) + } } /// URI that `Client` uses to route outgoing requests. diff --git a/iroha_data_model/src/lib.rs b/iroha_data_model/src/lib.rs index a1c71713ccf..c3404cd9843 100644 --- a/iroha_data_model/src/lib.rs +++ b/iroha_data_model/src/lib.rs @@ -6,7 +6,7 @@ use std::{convert::TryFrom, error, fmt::Debug, ops::RangeInclusive}; use eyre::{eyre, Result, WrapErr}; -use iroha_crypto::PublicKey; +use iroha_crypto::{Hash, PublicKey}; use iroha_derive::FromVariant; use iroha_macro::error::ErrorTryFromEnum; use iroha_schema::prelude::*; @@ -192,6 +192,8 @@ pub enum Value { TransactionValue(TransactionValue), /// Permission token. PermissionToken(PermissionToken), + /// Hash + Hash(Hash), } #[allow(clippy::len_without_is_empty)] @@ -202,7 +204,7 @@ impl Value { match self { U32(_) | Id(_) | PublicKey(_) | Bool(_) | Parameter(_) | Identifiable(_) - | String(_) | Fixed(_) | TransactionValue(_) | PermissionToken(_) => 1, + | String(_) | Fixed(_) | TransactionValue(_) | PermissionToken(_) | Hash(_) => 1, Vec(v) => v.iter().map(Self::len).sum::() + 1, SignatureCheckCondition(s) => s.0.len(), } diff --git a/iroha_data_model/src/query.rs b/iroha_data_model/src/query.rs index 1f8b4d49ed9..5adb1947a75 100644 --- a/iroha_data_model/src/query.rs +++ b/iroha_data_model/src/query.rs @@ -77,6 +77,8 @@ pub enum QueryBox { FindAllPeers(FindAllPeers), /// `FindTransactionsByAccountId` variant. FindTransactionsByAccountId(FindTransactionsByAccountId), + /// `FindTransactionByHash` variant. + FindTransactionByHash(FindTransactionByHash), /// `FindAllRoles` variant. #[cfg(feature = "roles")] FindAllRoles(FindAllRoles), @@ -1048,6 +1050,7 @@ pub mod transaction { #![allow(clippy::missing_inline_in_public_items)] + use iroha_crypto::Hash; use iroha_derive::Io; use iroha_schema::prelude::*; use parity_scale_codec::{Decode, Encode}; @@ -1090,9 +1093,43 @@ pub mod transaction { FindTransactionsByAccountId { account_id } } } + + /// `FindTransactionByHash` Iroha Query will find a transaction (if any) + /// with corresponding hash value + #[derive( + Clone, + Debug, + Io, + Serialize, + Deserialize, + Encode, + Decode, + PartialEq, + Eq, + PartialOrd, + Ord, + IntoSchema, + )] + pub struct FindTransactionByHash { + /// Transaction hash. + pub hash: EvaluatesTo, + } + + impl QueryOutput for FindTransactionByHash { + type Output = TransactionValue; + } + + impl FindTransactionByHash { + ///Default [`FindTransactionByHash`] constructor. + pub fn new(hash: impl Into>) -> Self { + let hash = hash.into(); + FindTransactionByHash { hash } + } + } + /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { - pub use super::FindTransactionsByAccountId; + pub use super::{FindTransactionByHash, FindTransactionsByAccountId}; } } diff --git a/iroha_permissions_validators/src/lib.rs b/iroha_permissions_validators/src/lib.rs index c8c8e8aa4ea..c9100f0f527 100644 --- a/iroha_permissions_validators/src/lib.rs +++ b/iroha_permissions_validators/src/lib.rs @@ -376,6 +376,13 @@ pub mod private_blockchain { )) } } + FindTransactionByHash(query) => { + let _hash = query + .hash + .evaluate(wsv, &context) + .map_err(|err| err.to_string())?; + Ok(()) + } #[cfg(feature = "roles")] FindRolesByAccountId(query) => { let account_id = query @@ -542,6 +549,13 @@ pub mod private_blockchain { Err(format!("Cannot access another account: {}.", account_id)) } } + FindTransactionByHash(query) => { + let _hash = query + .hash + .evaluate(wsv, &context) + .map_err(|err| err.to_string())?; + Ok(()) + } #[cfg(feature = "roles")] FindRolesByAccountId(query) => { let account_id = query