Skip to content

Commit

Permalink
feat(queries): Transaction and block predicates (#5025)
Browse files Browse the repository at this point in the history
Signed-off-by: ⭐️NINIKA⭐️ <dcnick3@users.noreply.github.com>
  • Loading branch information
DCNick3 authored Sep 5, 2024
1 parent 0b451fe commit 8bc3064
Show file tree
Hide file tree
Showing 13 changed files with 523 additions and 285 deletions.
17 changes: 1 addition & 16 deletions client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<BlockHeader>) -> FindBlockHeaderByHash {
FindBlockHeaderByHash::new(hash)
}
}

pub mod domain {
Expand All @@ -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<SignedTransaction>) -> FindTransactionByHash {
FindTransactionByHash::new(hash)
}
}

pub mod trigger {
Expand Down
3 changes: 2 additions & 1 deletion client/tests/integration/tx_history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
29 changes: 5 additions & 24 deletions core/src/smartcontracts/isi/block.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<BlockHeader, QueryExecutionFail> {
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())
}
}
71 changes: 46 additions & 25 deletions core/src/smartcontracts/isi/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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(())
Expand Down Expand Up @@ -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(),
Expand Down
61 changes: 1 addition & 60 deletions core/src/smartcontracts/isi/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use iroha_data_model::{
block::{BlockHeader, SignedBlock},
prelude::*,
query::{
error::{FindError, QueryExecutionFail},
error::QueryExecutionFail,
predicate::{
predicate_atoms::block::TransactionQueryOutputPredicateBox, CompoundPredicate,
},
Expand Down Expand Up @@ -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()
Expand All @@ -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<TransactionQueryOutputPredicateBox>,
state_ro: &impl StateReadOnly,
) -> Result<impl Iterator<Item = Self::Item>, 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<TransactionQueryOutput, QueryExecutionFail> {
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())
}
}
3 changes: 0 additions & 3 deletions data_model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,7 @@ mod seal {
FindPeers,
FindBlocks,
FindBlockHeaders,
FindBlockHeaderByHash,
FindTransactions,
FindTransactionsByAccountId,
FindTransactionByHash,
FindPermissionsByAccountId,
FindExecutorDataModel,
FindActiveTriggerIds,
Expand Down
Loading

0 comments on commit 8bc3064

Please sign in to comment.