diff --git a/client/src/client.rs b/client/src/client.rs index ce45562c393..1f322cb61f0 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -28,7 +28,7 @@ use crate::{ config::Config, crypto::{HashOf, KeyPair}, data_model::{ - block::{BlockHeader, SignedBlock}, + block::SignedBlock, events::pipeline::{ BlockEventFilter, BlockStatus, PipelineEventBox, PipelineEventFilterBox, TransactionEventFilter, TransactionStatus, @@ -1010,11 +1010,6 @@ pub mod block { pub const fn all_headers() -> FindBlockHeaders { FindBlockHeaders } - - /// Construct a query to find block header by hash - pub fn header_by_hash(hash: HashOf) -> FindBlockHeaderByHash { - FindBlockHeaderByHash::new(hash) - } } pub mod domain { @@ -1036,16 +1031,6 @@ pub mod transaction { pub fn all() -> FindTransactions { FindTransactions } - - /// Construct a query to retrieve transactions for account - pub fn by_account_id(account_id: AccountId) -> FindTransactionsByAccountId { - FindTransactionsByAccountId::new(account_id) - } - - /// Construct a query to retrieve transaction by hash - pub fn by_hash(hash: HashOf) -> FindTransactionByHash { - FindTransactionByHash::new(hash) - } } pub mod trigger { diff --git a/client/tests/integration/tx_history.rs b/client/tests/integration/tx_history.rs index c10083f8712..281e62a969d 100644 --- a/client/tests/integration/tx_history.rs +++ b/client/tests/integration/tx_history.rs @@ -52,7 +52,8 @@ fn client_has_rejected_and_acepted_txs_should_return_tx_history() -> Result<()> thread::sleep(pipeline_time * 5); let transactions = client - .query(transaction::by_account_id(account_id.clone())) + .query(transaction::all()) + .filter_with(|tx| tx.transaction.value.authority.eq(account_id.clone())) .with_pagination(Pagination { limit: Some(nonzero!(50_u64)), offset: 1, diff --git a/core/src/smartcontracts/isi/block.rs b/core/src/smartcontracts/isi/block.rs index 05674f8fd47..b41451c68c2 100644 --- a/core/src/smartcontracts/isi/block.rs +++ b/core/src/smartcontracts/isi/block.rs @@ -1,14 +1,10 @@ //! This module contains trait implementations related to block queries use eyre::Result; -use iroha_data_model::{ - block::BlockHeader, - query::{ - block::FindBlockHeaderByHash, - error::{FindError, QueryExecutionFail}, - predicate::{ - predicate_atoms::block::{BlockHeaderPredicateBox, SignedBlockPredicateBox}, - CompoundPredicate, - }, +use iroha_data_model::query::{ + error::QueryExecutionFail, + predicate::{ + predicate_atoms::block::{BlockHeaderPredicateBox, SignedBlockPredicateBox}, + CompoundPredicate, }, }; use iroha_telemetry::metrics; @@ -46,18 +42,3 @@ impl ValidQuery for FindBlockHeaders { .map(|block| block.header().clone())) } } - -impl ValidSingularQuery for FindBlockHeaderByHash { - #[metrics(+"find_block_header")] - fn execute(&self, state_ro: &impl StateReadOnly) -> Result { - let hash = self.hash; - - let block = state_ro - .kura() - .get_block_height_by_hash(hash) - .and_then(|height| state_ro.kura().get_block_by_height(height)) - .ok_or_else(|| QueryExecutionFail::Find(FindError::Block(hash)))?; - - Ok(block.header().clone()) - } -} diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 519d6b34829..043d5cf8fba 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -263,12 +263,6 @@ impl ValidQueryRequest { SingularQueryBox::FindTriggerMetadata(q) => { SingularQueryOutputBox::from(q.execute(state)?) } - SingularQueryBox::FindTransactionByHash(q) => { - SingularQueryOutputBox::from(q.execute(state)?) - } - SingularQueryBox::FindBlockHeaderByHash(q) => { - SingularQueryOutputBox::from(q.execute(state)?) - } }; Ok(QueryResponse::Singular(output)) @@ -308,10 +302,6 @@ impl ValidQueryRequest { ValidQuery::execute(q.query, q.predicate, state)?, &iter_query.params, )?, - QueryBox::FindTransactionsByAccountId(q) => apply_query_postprocessing( - ValidQuery::execute(q.query, q.predicate, state)?, - &iter_query.params, - )?, QueryBox::FindAccountsWithAsset(q) => apply_query_postprocessing( ValidQuery::execute(q.query, q.predicate, state)?, &iter_query.params, @@ -353,8 +343,8 @@ impl ValidQueryRequest { mod tests { use std::str::FromStr as _; - use iroha_crypto::{Hash, HashOf, KeyPair}; - use iroha_data_model::query::{error::FindError, predicate::CompoundPredicate}; + use iroha_crypto::{Hash, KeyPair}; + use iroha_data_model::query::predicate::CompoundPredicate; use iroha_primitives::json::JsonString; use nonzero_ext::nonzero; use test_samples::{gen_account_in, ALICE_ID, ALICE_KEYPAIR}; @@ -545,14 +535,30 @@ mod tests { .expect("state is empty"); assert_eq!( - FindBlockHeaderByHash::new(block.hash()).execute(&state_view)?, + FindBlockHeaders::new() + .execute( + BlockHeaderPredicateBox::build(|header| header.hash.eq(block.hash())), + &state_view, + ) + .expect("Query execution should not fail") + .next() + .expect("Query should return a block header"), *block.header() ); - assert!( - FindBlockHeaderByHash::new(HashOf::from_untyped_unchecked(Hash::new([42]))) - .execute(&state_view) - .is_err() + FindBlockHeaders::new() + .execute( + BlockHeaderPredicateBox::build(|header| { + header + .hash + .eq(HashOf::from_untyped_unchecked(Hash::new([42]))) + }), + &state_view, + ) + .expect("Query execution should not fail") + .next() + .is_none(), + "Block header should not be found" ); Ok(()) @@ -624,14 +630,29 @@ mod tests { .with_instructions([Unregister::account(gen_account_in("domain").0)]) .sign(ALICE_KEYPAIR.private_key()); let wrong_hash = unapplied_tx.hash(); - let not_found = FindTransactionByHash::new(wrong_hash).execute(&state_view); - assert!(matches!( - not_found, - Err(Error::Find(FindError::Transaction(_))) - )); - - let found_accepted = - FindTransactionByHash::new(va_tx.as_ref().hash()).execute(&state_view)?; + + let not_found = FindTransactions::new() + .execute( + TransactionQueryOutputPredicateBox::build(|tx| { + tx.transaction.value.hash.eq(wrong_hash) + }), + &state_view, + ) + .expect("Query execution should not fail") + .next(); + assert_eq!(not_found, None, "Transaction should not be found"); + + let found_accepted = FindTransactions::new() + .execute( + TransactionQueryOutputPredicateBox::build(|tx| { + tx.transaction.value.hash.eq(va_tx.as_ref().hash()) + }), + &state_view, + ) + .expect("Query execution should not fail") + .next() + .expect("Query should return a transaction"); + if found_accepted.transaction.error.is_none() { assert_eq!( va_tx.as_ref().hash(), diff --git a/core/src/smartcontracts/isi/tx.rs b/core/src/smartcontracts/isi/tx.rs index fd6c5023d0c..e12fd93073d 100644 --- a/core/src/smartcontracts/isi/tx.rs +++ b/core/src/smartcontracts/isi/tx.rs @@ -8,7 +8,7 @@ use iroha_data_model::{ block::{BlockHeader, SignedBlock}, prelude::*, query::{ - error::{FindError, QueryExecutionFail}, + error::QueryExecutionFail, predicate::{ predicate_atoms::block::TransactionQueryOutputPredicateBox, CompoundPredicate, }, @@ -51,14 +51,6 @@ impl BlockTransactionRef { self.0.hash() } - fn authority(&self) -> &AccountId { - self.0 - .transactions() - .nth(self.1) - .expect("The transaction is not found") - .as_ref() - .authority() - } fn value(&self) -> CommittedTransaction { self.0 .transactions() @@ -85,54 +77,3 @@ impl ValidQuery for FindTransactions { .filter(move |tx| filter.applies(tx))) } } - -impl ValidQuery for FindTransactionsByAccountId { - #[metrics(+"find_transactions_by_account_id")] - fn execute( - self, - filter: CompoundPredicate, - state_ro: &impl StateReadOnly, - ) -> Result, QueryExecutionFail> { - let account_id = self.account.clone(); - - Ok(state_ro - .all_blocks(nonzero!(1_usize)) - .flat_map(BlockTransactionIter::new) - .filter(move |tx| *tx.authority() == account_id) - .map(|tx| TransactionQueryOutput { - block_hash: tx.block_hash(), - transaction: tx.value(), - }) - .filter(move |tx| filter.applies(tx))) - } -} - -impl ValidSingularQuery for FindTransactionByHash { - #[metrics(+"find_transaction_by_hash")] - fn execute( - &self, - state_ro: &impl StateReadOnly, - ) -> Result { - let tx_hash = self.hash; - - iroha_logger::trace!(%tx_hash); - if !state_ro.has_transaction(tx_hash) { - return Err(FindError::Transaction(tx_hash).into()); - }; - let block = state_ro - .block_with_tx(&tx_hash) - .ok_or_else(|| FindError::Transaction(tx_hash))?; - - let block_hash = block.hash(); - - let mut transactions = block.transactions(); - transactions - .find(|transaction| transaction.value.hash() == tx_hash) - .cloned() - .map(|transaction| TransactionQueryOutput { - block_hash, - transaction, - }) - .ok_or_else(|| FindError::Transaction(tx_hash).into()) - } -} diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 5c18a6bb956..70387816120 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -136,10 +136,7 @@ mod seal { FindPeers, FindBlocks, FindBlockHeaders, - FindBlockHeaderByHash, FindTransactions, - FindTransactionsByAccountId, - FindTransactionByHash, FindPermissionsByAccountId, FindExecutorDataModel, FindActiveTriggerIds, diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index ae3776d84b5..0ca4df2fdbb 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -95,7 +95,6 @@ mod model { FindRoleIds(QueryWithFilterFor), FindPermissionsByAccountId(QueryWithFilterFor), FindRolesByAccountId(QueryWithFilterFor), - FindTransactionsByAccountId(QueryWithFilterFor), FindAccountsWithAsset(QueryWithFilterFor), FindPeers(QueryWithFilterFor), @@ -142,9 +141,6 @@ mod model { FindAssetMetadata(FindAssetMetadata), FindAssetDefinitionMetadata(FindAssetDefinitionMetadata), FindTriggerMetadata(FindTriggerMetadata), - - FindTransactionByHash(FindTransactionByHash), - FindBlockHeaderByHash(FindBlockHeaderByHash), } /// An enum of all possible singular query outputs @@ -564,7 +560,6 @@ impl_iter_queries! { FindPeers => crate::peer::Peer, FindActiveTriggerIds => crate::trigger::TriggerId, FindTransactions => TransactionQueryOutput, - FindTransactionsByAccountId => TransactionQueryOutput, FindAccountsWithAsset => crate::account::Account, FindBlockHeaders => crate::block::BlockHeader, FindBlocks => SignedBlock, @@ -579,8 +574,6 @@ impl_singular_queries! { FindParameters => crate::parameter::Parameters, FindTriggerById => crate::trigger::Trigger, FindTriggerMetadata => JsonString, - FindTransactionByHash => TransactionQueryOutput, - FindBlockHeaderByHash => crate::block::BlockHeader, FindExecutorDataModel => crate::executor::ExecutorDataModel, } @@ -946,9 +939,6 @@ pub mod transaction { use alloc::{format, string::String, vec::Vec}; use derive_more::Display; - use iroha_crypto::HashOf; - - use crate::{account::AccountId, transaction::SignedTransaction}; queries! { /// [`FindTransactions`] Iroha Query lists all transactions included in a blockchain @@ -956,35 +946,11 @@ pub mod transaction { #[display(fmt = "Find all transactions")] #[ffi_type] pub struct FindTransactions; - - /// [`FindTransactionsByAccountId`] Iroha Query finds all transactions included in a blockchain - /// for the account - #[derive(Display)] - #[display(fmt = "Find all transactions for `{account}` account")] - #[repr(transparent)] - // SAFETY: `FindTransactionsByAccountId` has no trap representation in `AccountId` - #[ffi_type(unsafe {robust})] - pub struct FindTransactionsByAccountId { - /// Signer's [`AccountId`] under which transactions should be found. - pub account: AccountId, - } - - /// [`FindTransactionByHash`] Iroha Query finds a transaction (if any) - /// with corresponding hash value - #[derive(Copy, Display)] - #[display(fmt = "Find transaction with `{hash}` hash")] - #[repr(transparent)] - // SAFETY: `FindTransactionByHash` has no trap representation in `HashOf` - #[ffi_type(unsafe {robust})] - pub struct FindTransactionByHash { - /// Transaction hash. - pub hash: HashOf, - } } /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { - pub use super::{FindTransactionByHash, FindTransactions, FindTransactionsByAccountId}; + pub use super::FindTransactions; } } @@ -997,9 +963,6 @@ pub mod block { use alloc::{format, string::String, vec::Vec}; use derive_more::Display; - use iroha_crypto::HashOf; - - use super::BlockHeader; queries! { /// [`FindBlocks`] Iroha Query lists all blocks sorted by @@ -1015,22 +978,11 @@ pub mod block { #[display(fmt = "Find all block headers")] #[ffi_type] pub struct FindBlockHeaders; - - /// [`FindBlockHeaderByHash`] Iroha Query finds block header by block hash - #[derive(Copy, Display)] - #[display(fmt = "Find block header with `{hash}` hash")] - #[repr(transparent)] - // SAFETY: `FindBlockHeaderByHash` has no trap representation in `HashOf` - #[ffi_type(unsafe {robust})] - pub struct FindBlockHeaderByHash { - /// Block hash. - pub hash: HashOf, - } } /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { - pub use super::{FindBlockHeaderByHash, FindBlockHeaders, FindBlocks}; + pub use super::{FindBlockHeaders, FindBlocks}; } } diff --git a/data_model/src/query/predicate/predicate_atoms/block.rs b/data_model/src/query/predicate/predicate_atoms/block.rs index 49ad879bd00..666ba288fcf 100644 --- a/data_model/src/query/predicate/predicate_atoms/block.rs +++ b/data_model/src/query/predicate/predicate_atoms/block.rs @@ -3,6 +3,7 @@ #[cfg(not(feature = "std"))] use alloc::{format, string::String, vec::Vec}; +use iroha_crypto::HashOf; use iroha_schema::IntoSchema; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; @@ -10,6 +11,7 @@ use serde::{Deserialize, Serialize}; use super::impl_predicate_box; use crate::{ block::{BlockHeader, SignedBlock}, + prelude::{AccountIdPredicateBox, TransactionRejectionReason}, query::{ predicate::{ predicate_ast_extensions::AstPredicateExt as _, @@ -19,53 +21,254 @@ use crate::{ }, TransactionQueryOutput, }, + transaction::{CommittedTransaction, SignedTransaction}, }; +/// A predicate that can be applied to a [`HashOf`] +#[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] +pub enum BlockHashPredicateBox { + // object-specific predicates + /// Checks if the input is equal to the expected value. + Equals(HashOf), +} + +impl_predicate_box!(HashOf: BlockHashPredicateBox); + +impl EvaluatePredicate> for BlockHashPredicateBox { + fn applies(&self, input: &HashOf) -> bool { + match self { + BlockHashPredicateBox::Equals(hash) => input == hash, + } + } +} + /// A predicate that can be applied to a [`BlockHeader`]. #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum BlockHeaderPredicateBox { - // nothing here yet + // projections + /// Checks if a predicate applies to the hash of the block header. + Hash(BlockHashPredicateBox), } impl_predicate_box!(BlockHeader: BlockHeaderPredicateBox); impl EvaluatePredicate for BlockHeaderPredicateBox { - fn applies(&self, _input: &BlockHeader) -> bool { - match *self {} + fn applies(&self, input: &BlockHeader) -> bool { + match self { + BlockHeaderPredicateBox::Hash(hash) => hash.applies(&input.hash()), + } } } /// A predicate that can be applied to a [`SignedBlock`]. #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum SignedBlockPredicateBox { - // nothing here yet + // projections + /// Checks if a predicate applies to the header of the block. + Header(BlockHeaderPredicateBox), } impl_predicate_box!(SignedBlock: SignedBlockPredicateBox); impl EvaluatePredicate for SignedBlockPredicateBox { - fn applies(&self, _input: &SignedBlock) -> bool { - match *self {} + fn applies(&self, input: &SignedBlock) -> bool { + match self { + SignedBlockPredicateBox::Header(header) => header.applies(input.header()), + } + } +} + +/// A predicate that can be applied to a [`HashOf`]. +#[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] +pub enum TransactionHashPredicateBox { + // object-specific predicates + /// Checks if the input is equal to the expected value. + Equals(HashOf), +} + +impl_predicate_box!(HashOf: TransactionHashPredicateBox); + +impl EvaluatePredicate> for TransactionHashPredicateBox { + fn applies(&self, input: &HashOf) -> bool { + match self { + TransactionHashPredicateBox::Equals(hash) => input == hash, + } + } +} + +/// A predicate that can be applied to a [`SignedTransaction`] +#[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] +pub enum SignedTransactionPredicateBox { + // projections + /// Checks if a predicate applies to the hash of the signed transaction. + Hash(TransactionHashPredicateBox), + /// Checks if a predicate applies to the authority of the signed transaction. + Authority(AccountIdPredicateBox), +} + +impl_predicate_box!(SignedTransaction: SignedTransactionPredicateBox); + +impl EvaluatePredicate for SignedTransactionPredicateBox { + fn applies(&self, input: &SignedTransaction) -> bool { + match self { + SignedTransactionPredicateBox::Hash(hash) => hash.applies(&input.hash()), + SignedTransactionPredicateBox::Authority(authority) => { + authority.applies(input.authority()) + } + } + } +} + +// TODO: maybe we would want to have a generic `Option` predicate box & predicate +/// A predicate that can be applied to an [`Option`] +#[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] +pub enum TransactionErrorPredicateBox { + // object-specific predicates + /// Checks if there was an error while applying the transaction. + IsSome, +} + +impl_predicate_box!(Option: TransactionErrorPredicateBox); + +impl EvaluatePredicate> for TransactionErrorPredicateBox { + fn applies(&self, input: &Option) -> bool { + match self { + TransactionErrorPredicateBox::IsSome => input.is_some(), + } + } +} + +/// A predicate that can be applied to a [`CommittedTransaction`] +#[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] +pub enum CommittedTransactionPredicateBox { + // projections + /// Checks if a predicate applies to the signed transaction inside. + Value(SignedTransactionPredicateBox), + /// Checks if a predicate applies to the error of the transaction. + Error(TransactionErrorPredicateBox), +} + +impl_predicate_box!(CommittedTransaction: CommittedTransactionPredicateBox); + +impl EvaluatePredicate for CommittedTransactionPredicateBox { + fn applies(&self, input: &CommittedTransaction) -> bool { + match self { + CommittedTransactionPredicateBox::Value(signed_transaction) => { + signed_transaction.applies(&input.value) + } + CommittedTransactionPredicateBox::Error(error) => error.applies(&input.error), + } } } /// A predicate that can be applied to a [`TransactionQueryOutput`]. #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum TransactionQueryOutputPredicateBox { - // nothing here yet + // projections + /// Checks if a predicate applies to the committed transaction inside. + Transaction(CommittedTransactionPredicateBox), + /// Checks if a predicate applies to the hash of the block the transaction was included in. + BlockHash(BlockHashPredicateBox), } impl_predicate_box!(TransactionQueryOutput: TransactionQueryOutputPredicateBox); impl EvaluatePredicate for TransactionQueryOutputPredicateBox { - fn applies(&self, _input: &TransactionQueryOutput) -> bool { - match *self {} + fn applies(&self, input: &TransactionQueryOutput) -> bool { + match self { + TransactionQueryOutputPredicateBox::Transaction(committed_transaction) => { + committed_transaction.applies(&input.transaction) + } + TransactionQueryOutputPredicateBox::BlockHash(block_hash) => { + block_hash.applies(&input.block_hash) + } + } } } pub mod prelude { //! Re-export all predicate boxes for a glob import `(::*)` pub use super::{ - BlockHeaderPredicateBox, SignedBlockPredicateBox, TransactionQueryOutputPredicateBox, + BlockHashPredicateBox, BlockHeaderPredicateBox, CommittedTransactionPredicateBox, + SignedBlockPredicateBox, SignedTransactionPredicateBox, TransactionErrorPredicateBox, + TransactionHashPredicateBox, TransactionQueryOutputPredicateBox, + }; +} + +#[cfg(test)] +mod test { + use iroha_crypto::{Hash, HashOf}; + + use crate::{ + account::AccountId, + prelude::{ + AccountIdPredicateBox, BlockHeaderPredicateBox, CompoundPredicate, + SignedBlockPredicateBox, TransactionQueryOutputPredicateBox, + }, + query::predicate::predicate_atoms::block::{ + BlockHashPredicateBox, CommittedTransactionPredicateBox, SignedTransactionPredicateBox, + TransactionErrorPredicateBox, TransactionHashPredicateBox, + }, }; + + #[test] + fn transaction_smoke() { + let hash = Hash::prehashed([0; 32]); + let account_id: AccountId = + "ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland" + .parse() + .unwrap(); + + let predicate = TransactionQueryOutputPredicateBox::build(|tx| { + tx.block_hash.eq(HashOf::from_untyped_unchecked(hash)) + & tx.transaction.error.is_some() + & tx.transaction.value.authority.eq(account_id.clone()) + & tx.transaction + .value + .hash + .eq(HashOf::from_untyped_unchecked(hash)) + }); + + assert_eq!( + predicate, + CompoundPredicate::And(vec![ + CompoundPredicate::Atom(TransactionQueryOutputPredicateBox::BlockHash( + BlockHashPredicateBox::Equals(HashOf::from_untyped_unchecked(hash)) + )), + CompoundPredicate::Atom(TransactionQueryOutputPredicateBox::Transaction( + CommittedTransactionPredicateBox::Error(TransactionErrorPredicateBox::IsSome) + )), + CompoundPredicate::Atom(TransactionQueryOutputPredicateBox::Transaction( + CommittedTransactionPredicateBox::Value( + SignedTransactionPredicateBox::Authority(AccountIdPredicateBox::Equals( + account_id.clone() + )) + ) + )), + CompoundPredicate::Atom(TransactionQueryOutputPredicateBox::Transaction( + CommittedTransactionPredicateBox::Value(SignedTransactionPredicateBox::Hash( + TransactionHashPredicateBox::Equals(HashOf::from_untyped_unchecked(hash)) + )) + )), + ]) + ); + } + + #[test] + fn block_smoke() { + let hash = Hash::prehashed([0; 32]); + + let predicate = SignedBlockPredicateBox::build(|block| { + block.header.hash.eq(HashOf::from_untyped_unchecked(hash)) + }); + + assert_eq!( + predicate, + CompoundPredicate::Atom(SignedBlockPredicateBox::Header( + BlockHeaderPredicateBox::Hash(BlockHashPredicateBox::Equals( + HashOf::from_untyped_unchecked(hash) + )) + )) + ); + } } diff --git a/data_model/src/query/predicate/projectors.rs b/data_model/src/query/predicate/projectors.rs index 47f445bc0ec..4fe3d194f8d 100644 --- a/data_model/src/query/predicate/projectors.rs +++ b/data_model/src/query/predicate/projectors.rs @@ -7,19 +7,29 @@ use core::marker::PhantomData; use super::{AstPredicate, CompoundPredicate}; -use crate::query::predicate::{ - predicate_atoms::{ - account::{AccountIdPredicateBox, AccountPredicateBox}, - asset::{ - AssetDefinitionIdPredicateBox, AssetDefinitionPredicateBox, AssetIdPredicateBox, - AssetPredicateBox, AssetValuePredicateBox, +use crate::{ + prelude::{ + BlockHeaderPredicateBox, SignedBlockPredicateBox, TransactionQueryOutputPredicateBox, + }, + query::predicate::{ + predicate_atoms::{ + account::{AccountIdPredicateBox, AccountPredicateBox}, + asset::{ + AssetDefinitionIdPredicateBox, AssetDefinitionPredicateBox, AssetIdPredicateBox, + AssetPredicateBox, AssetValuePredicateBox, + }, + block::{ + BlockHashPredicateBox, CommittedTransactionPredicateBox, + SignedTransactionPredicateBox, TransactionErrorPredicateBox, + TransactionHashPredicateBox, + }, + domain::{DomainIdPredicateBox, DomainPredicateBox}, + role::{RoleIdPredicateBox, RolePredicateBox}, + trigger::{TriggerIdPredicateBox, TriggerPredicateBox}, + MetadataPredicateBox, PublicKeyPredicateBox, StringPredicateBox, }, - domain::{DomainIdPredicateBox, DomainPredicateBox}, - role::{RoleIdPredicateBox, RolePredicateBox}, - trigger::{TriggerIdPredicateBox, TriggerPredicateBox}, - MetadataPredicateBox, PublicKeyPredicateBox, StringPredicateBox, + predicate_combinators::{AndAstPredicate, NotAstPredicate, OrAstPredicate}, }, - predicate_combinators::{AndAstPredicate, NotAstPredicate, OrAstPredicate}, }; /// Describes how to convert `AstPredicate` to `AstPredicate` by wrapping them in some projection predicate combinator. @@ -166,7 +176,7 @@ proj!(AssetDefinitionIdNameProjector(AssetDefinitionIdNameProjection): StringPre proj!(AssetIdDefinitionIdProjector(AssetIdDefinitionIdProjection): AssetDefinitionIdPredicateBox => AssetIdPredicateBox::DefinitionId); proj!(AssetIdAccountIdProjector(AssetIdAccountIdProjection): AccountIdPredicateBox => AssetIdPredicateBox::AccountId); -// projections in AssetDefinition +// projections on AssetDefinition proj!(AssetDefinitionIdProjector(AssetDefinitionIdProjection): AssetDefinitionIdPredicateBox => AssetDefinitionPredicateBox::Id); proj!(AssetDefinitionMetadataProjector(AssetDefinitionMetadataProjection): MetadataPredicateBox => AssetDefinitionPredicateBox::Metadata); @@ -187,8 +197,26 @@ proj!(RoleIdNameProjector(RoleIdNameProjection): StringPredicateBox => RoleIdPre // projections on Role proj!(RoleIdProjector(RoleIdProjection): RoleIdPredicateBox => RolePredicateBox::Id); -// projections in TriggerId +// projections on TriggerId proj!(TriggerIdNameProjector(TriggerIdNameProjection): StringPredicateBox => TriggerIdPredicateBox::Name); -// projections in Trigger +// projections on Trigger proj!(TriggerIdProjector(TriggerIdProjection): TriggerIdPredicateBox => TriggerPredicateBox::Id); + +// projections on BlockHeader +proj!(BlockHeaderHashProjector(BlockHeaderHashProjection): BlockHashPredicateBox => BlockHeaderPredicateBox::Hash); + +// projections on SignedBlock +proj!(SignedBlockHeaderProjector(SignedBlockHeaderProjection): BlockHeaderPredicateBox => SignedBlockPredicateBox::Header); + +// projections on SignedTransaction +proj!(SignedTransactionHashProjector(SignedTransactionHashProjection): TransactionHashPredicateBox => SignedTransactionPredicateBox::Hash); +proj!(SignedTransactionAuthorityProjector(SignedTransactionAuthorityProjection): AccountIdPredicateBox => SignedTransactionPredicateBox::Authority); + +// projections on CommittedTransaction +proj!(CommittedTransactionValueProjector(CommittedTransactionValueProjection): SignedTransactionPredicateBox => CommittedTransactionPredicateBox::Value); +proj!(CommittedTransactionErrorProjector(CommittedTransactionErrorProjection): TransactionErrorPredicateBox => CommittedTransactionPredicateBox::Error); + +// projections on TransactionQueryOutput +proj!(TransactionQueryOutputTransactionProjector(TransactionQueryOutputTransactionProjection): CommittedTransactionPredicateBox => TransactionQueryOutputPredicateBox::Transaction); +proj!(TransactionQueryOutputBlockHashProjector(TransactionQueryOutputBlockHashProjection): BlockHashPredicateBox => TransactionQueryOutputPredicateBox::BlockHash); diff --git a/data_model/src/query/predicate/prototypes/block.rs b/data_model/src/query/predicate/prototypes/block.rs index bfbb0dcb9f1..236d927446b 100644 --- a/data_model/src/query/predicate/prototypes/block.rs +++ b/data_model/src/query/predicate/prototypes/block.rs @@ -2,35 +2,146 @@ use core::marker::PhantomData; +use iroha_crypto::HashOf; + use super::impl_prototype; -use crate::query::predicate::{ - predicate_atoms::block::{ - BlockHeaderPredicateBox, SignedBlockPredicateBox, TransactionQueryOutputPredicateBox, +use crate::{ + block::BlockHeader, + query::predicate::{ + predicate_ast_extensions::AstPredicateExt, + predicate_atoms::block::{ + BlockHashPredicateBox, BlockHeaderPredicateBox, CommittedTransactionPredicateBox, + SignedBlockPredicateBox, SignedTransactionPredicateBox, TransactionErrorPredicateBox, + TransactionHashPredicateBox, TransactionQueryOutputPredicateBox, + }, + predicate_combinators::NotAstPredicate, + projectors::{ + BlockHeaderHashProjector, CommittedTransactionErrorProjector, + CommittedTransactionValueProjector, ObjectProjector, SignedBlockHeaderProjector, + SignedTransactionAuthorityProjector, SignedTransactionHashProjector, + TransactionQueryOutputBlockHashProjector, TransactionQueryOutputTransactionProjector, + }, + prototypes::account::AccountIdPrototype, + AstPredicate, HasPrototype, }, - projectors::ObjectProjector, - AstPredicate, HasPrototype, + transaction::SignedTransaction, }; -/// A prototype of [`crate::block::BlockHeader`] for predicate construction. +/// A prototype of [`HashOf`] for predicate construction. #[derive(Default, Copy, Clone)] -pub struct BlockHeaderPrototype { +pub struct BlockHashPrototype { phantom: PhantomData, } +impl_prototype!(BlockHashPrototype: BlockHashPredicateBox); + +impl BlockHashPrototype +where + Projector: ObjectProjector, +{ + /// Creates a predicate that checks if the hash equals the expected value. + pub fn eq( + &self, + expected: HashOf, + ) -> Projector::ProjectedPredicate { + Projector::project_predicate(BlockHashPredicateBox::Equals(expected)) + } +} + +/// A prototype of [`BlockHeader`] for predicate construction. +#[derive(Default, Copy, Clone)] +pub struct BlockHeaderPrototype { + /// Build a predicate on hash of this [`BlockHeader`] + pub hash: BlockHashPrototype>, +} + impl_prototype!(BlockHeaderPrototype: BlockHeaderPredicateBox); /// A prototype of [`crate::block::SignedBlock`] for predicate construction. #[derive(Default, Copy, Clone)] pub struct SignedBlockPrototype { - phantom: PhantomData, + /// Build a predicate on header of this [`crate::block::SignedBlock`] + pub header: BlockHeaderPrototype>, } impl_prototype!(SignedBlockPrototype: SignedBlockPredicateBox); +/// A prototype of [`HashOf`] +#[derive(Default, Copy, Clone)] +pub struct TransactionHashPrototype { + phantom: PhantomData, +} + +impl_prototype!(TransactionHashPrototype: TransactionHashPredicateBox); + +impl TransactionHashPrototype +where + Projector: ObjectProjector, +{ + /// Creates a predicate that checks if the hash equals the expected value. + pub fn eq( + &self, + expected: HashOf, + ) -> Projector::ProjectedPredicate { + Projector::project_predicate(TransactionHashPredicateBox::Equals(expected)) + } +} + +/// A prototype of [`SignedTransaction`] +#[derive(Default, Copy, Clone)] +pub struct SignedTransactionPrototype { + /// Build a predicate on hash of this [`SignedTransaction`] + pub hash: TransactionHashPrototype>, + /// Build a predicate on the transaction authority + pub authority: AccountIdPrototype>, +} + +impl_prototype!(SignedTransactionPrototype: SignedTransactionPredicateBox); + +/// A prototype of [`Option`] +#[derive(Default, Copy, Clone)] +pub struct TransactionErrorPrototype { + phantom: PhantomData, +} + +impl_prototype!(TransactionErrorPrototype: TransactionErrorPredicateBox); + +impl TransactionErrorPrototype +where + Projector: ObjectProjector, +{ + /// Creates a predicate that checks if there is an error. + pub fn is_some(&self) -> Projector::ProjectedPredicate { + Projector::project_predicate(TransactionErrorPredicateBox::IsSome) + } + + /// Creates a predicate that checks if there is no error. + pub fn is_none( + &self, + ) -> NotAstPredicate> { + Projector::project_predicate(TransactionErrorPredicateBox::IsSome).not() + } +} + +/// A prototype of [`crate::transaction::CommittedTransaction`] +#[derive(Default, Copy, Clone)] +pub struct CommittedTransactionPrototype { + /// Build a predicate on the signed transaction inside + pub value: SignedTransactionPrototype>, + /// Build a predicate on the transaction error + pub error: TransactionErrorPrototype>, +} + +impl_prototype!(CommittedTransactionPrototype: CommittedTransactionPredicateBox); + /// A prototype of [`crate::query::TransactionQueryOutput`] for predicate construction. #[derive(Default, Copy, Clone)] pub struct TransactionQueryOutputPrototype { - phantom: PhantomData, + /// Build a predicate on the transaction inside + pub transaction: + CommittedTransactionPrototype>, + /// Build a predicate on the block hash inside + pub block_hash: BlockHashPrototype>, } impl_prototype!(TransactionQueryOutputPrototype: TransactionQueryOutputPredicateBox); diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index 47c88d5a377..8bc6c460da4 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -59,8 +59,6 @@ pub trait Visit { visit_find_asset_metadata(&FindAssetMetadata), visit_find_asset_definition_metadata(&FindAssetDefinitionMetadata), visit_find_trigger_metadata(&FindTriggerMetadata), - visit_find_transaction_by_hash(&FindTransactionByHash), - visit_find_block_header_by_hash(&FindBlockHeaderByHash), // Visit IterableQueryBox visit_find_domains(&QueryWithFilterFor), @@ -71,7 +69,6 @@ pub trait Visit { visit_find_role_ids(&QueryWithFilterFor), visit_find_permissions_by_account_id(&QueryWithFilterFor), visit_find_roles_by_account_id(&QueryWithFilterFor), - visit_find_transactions_by_account_id(&QueryWithFilterFor), visit_find_accounts_with_asset(&QueryWithFilterFor), visit_find_peers(&QueryWithFilterFor), visit_find_active_trigger_ids(&QueryWithFilterFor), @@ -176,8 +173,6 @@ pub fn visit_singular_query( visit_find_asset_metadata(FindAssetMetadata), visit_find_asset_definition_metadata(FindAssetDefinitionMetadata), visit_find_trigger_metadata(FindTriggerMetadata), - visit_find_transaction_by_hash(FindTransactionByHash), - visit_find_block_header_by_hash(FindBlockHeaderByHash), } } @@ -203,7 +198,6 @@ pub fn visit_iter_query( visit_find_role_ids(FindRoleIds), visit_find_permissions_by_account_id(FindPermissionsByAccountId), visit_find_roles_by_account_id(FindRolesByAccountId), - visit_find_transactions_by_account_id(FindTransactionsByAccountId), visit_find_accounts_with_asset(FindAccountsWithAsset), visit_find_peers(FindPeers), visit_find_active_trigger_ids(FindActiveTriggerIds), @@ -444,8 +438,6 @@ leaf_visitors! { visit_find_asset_metadata(&FindAssetMetadata), visit_find_asset_definition_metadata(&FindAssetDefinitionMetadata), visit_find_trigger_metadata(&FindTriggerMetadata), - visit_find_transaction_by_hash(&FindTransactionByHash), - visit_find_block_header_by_hash(&FindBlockHeaderByHash), // Iterable Query visitors visit_find_domains(&QueryWithFilterFor), @@ -456,7 +448,6 @@ leaf_visitors! { visit_find_role_ids(&QueryWithFilterFor), visit_find_permissions_by_account_id(&QueryWithFilterFor), visit_find_roles_by_account_id(&QueryWithFilterFor), - visit_find_transactions_by_account_id(&QueryWithFilterFor), visit_find_accounts_with_asset(&QueryWithFilterFor), visit_find_peers(&QueryWithFilterFor), visit_find_active_trigger_ids(&QueryWithFilterFor), diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index 97e3038a873..e95b33d6e5c 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -652,6 +652,15 @@ } ] }, + "BlockHashPredicateBox": { + "Enum": [ + { + "tag": "Equals", + "discriminant": 0, + "type": "HashOf" + } + ] + }, "BlockHeader": { "Struct": [ { @@ -681,7 +690,13 @@ ] }, "BlockHeaderPredicateBox": { - "Enum": [] + "Enum": [ + { + "tag": "Hash", + "discriminant": 0, + "type": "BlockHashPredicateBox" + } + ] }, "BlockMessage": "SignedBlock", "BlockParameter": { @@ -1036,6 +1051,20 @@ } ] }, + "CommittedTransactionPredicateBox": { + "Enum": [ + { + "tag": "Value", + "discriminant": 0, + "type": "SignedTransactionPredicateBox" + }, + { + "tag": "Error", + "discriminant": 1, + "type": "TransactionErrorPredicateBox" + } + ] + }, "Compact": { "Int": "Compact" }, @@ -1875,14 +1904,6 @@ }, "FindAssets": null, "FindAssetsDefinitions": null, - "FindBlockHeaderByHash": { - "Struct": [ - { - "name": "hash", - "type": "HashOf" - } - ] - }, "FindBlockHeaders": null, "FindBlocks": null, "FindDomainMetadata": { @@ -1983,23 +2004,7 @@ } ] }, - "FindTransactionByHash": { - "Struct": [ - { - "name": "hash", - "type": "HashOf" - } - ] - }, "FindTransactions": null, - "FindTransactionsByAccountId": { - "Struct": [ - { - "name": "account", - "type": "AccountId" - } - ] - }, "FindTriggerById": { "Struct": [ { @@ -3005,39 +3010,34 @@ "discriminant": 7, "type": "QueryWithFilter" }, - { - "tag": "FindTransactionsByAccountId", - "discriminant": 8, - "type": "QueryWithFilter" - }, { "tag": "FindAccountsWithAsset", - "discriminant": 9, + "discriminant": 8, "type": "QueryWithFilter" }, { "tag": "FindPeers", - "discriminant": 10, + "discriminant": 9, "type": "QueryWithFilter" }, { "tag": "FindActiveTriggerIds", - "discriminant": 11, + "discriminant": 10, "type": "QueryWithFilter" }, { "tag": "FindTransactions", - "discriminant": 12, + "discriminant": 11, "type": "QueryWithFilter" }, { "tag": "FindBlocks", - "discriminant": 13, + "discriminant": 12, "type": "QueryWithFilter" }, { "tag": "FindBlockHeaders", - "discriminant": 14, + "discriminant": 13, "type": "QueryWithFilter" } ] @@ -3387,18 +3387,6 @@ } ] }, - "QueryWithFilter": { - "Struct": [ - { - "name": "query", - "type": "FindTransactionsByAccountId" - }, - { - "name": "predicate", - "type": "CompoundPredicate" - } - ] - }, "QueryWithParams": { "Struct": [ { @@ -3956,7 +3944,13 @@ ] }, "SignedBlockPredicateBox": { - "Enum": [] + "Enum": [ + { + "tag": "Header", + "discriminant": 0, + "type": "BlockHeaderPredicateBox" + } + ] }, "SignedBlockV1": { "Struct": [ @@ -4000,6 +3994,20 @@ } ] }, + "SignedTransactionPredicateBox": { + "Enum": [ + { + "tag": "Hash", + "discriminant": 0, + "type": "TransactionHashPredicateBox" + }, + { + "tag": "Authority", + "discriminant": 1, + "type": "AccountIdPredicateBox" + } + ] + }, "SignedTransactionV1": { "Struct": [ { @@ -4058,16 +4066,6 @@ "tag": "FindTriggerMetadata", "discriminant": 8, "type": "FindTriggerMetadata" - }, - { - "tag": "FindTransactionByHash", - "discriminant": 9, - "type": "FindTransactionByHash" - }, - { - "tag": "FindBlockHeaderByHash", - "discriminant": 10, - "type": "FindBlockHeaderByHash" } ] }, @@ -4302,6 +4300,14 @@ } ] }, + "TransactionErrorPredicateBox": { + "Enum": [ + { + "tag": "IsSome", + "discriminant": 0 + } + ] + }, "TransactionEvent": { "Struct": [ { @@ -4334,6 +4340,15 @@ } ] }, + "TransactionHashPredicateBox": { + "Enum": [ + { + "tag": "Equals", + "discriminant": 0, + "type": "HashOf" + } + ] + }, "TransactionLimitError": { "Struct": [ { @@ -4413,7 +4428,18 @@ ] }, "TransactionQueryOutputPredicateBox": { - "Enum": [] + "Enum": [ + { + "tag": "Transaction", + "discriminant": 0, + "type": "CommittedTransactionPredicateBox" + }, + { + "tag": "BlockHash", + "discriminant": 1, + "type": "BlockHashPredicateBox" + } + ] }, "TransactionRejectionReason": { "Enum": [ diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index c2257685440..8eaab624d6a 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -131,6 +131,7 @@ types!( AssetValuePredicateBox, BlockEvent, BlockEventFilter, + BlockHashPredicateBox, BlockHeader, BlockHeaderPredicateBox, BlockMessage, @@ -163,6 +164,7 @@ types!( Burn, ChainId, CommittedTransaction, + CommittedTransactionPredicateBox, CompoundPredicate, CompoundPredicate, CompoundPredicate, @@ -227,14 +229,11 @@ types!( FindAssetDefinitionMetadata, FindAssetMetadata, FindAssetQuantityById, - FindBlockHeaderByHash, FindDomainMetadata, FindError, FindExecutorDataModel, FindPermissionsByAccountId, FindRolesByAccountId, - FindTransactionByHash, - FindTransactionsByAccountId, FindTriggerById, FindTriggerMetadata, ForwardCursor, @@ -274,7 +273,6 @@ types!( QueryWithFilter, QueryWithFilter, QueryWithFilter, - QueryWithFilter, QueryWithParams, JsonString, Level, @@ -392,6 +390,7 @@ types!( SignedQuery, SignedQueryV1, SignedTransaction, + SignedTransactionPredicateBox, SignedTransactionV1, SingularQueryBox, SingularQueryOutputBox, @@ -410,8 +409,10 @@ types!( TimeEventFilter, TimeInterval, TimeSchedule, + TransactionErrorPredicateBox, TransactionEvent, TransactionEventFilter, + TransactionHashPredicateBox, TransactionLimitError, TransactionParameter, TransactionParameters,