diff --git a/client/src/client.rs b/client/src/client.rs index a91bd6dce0f..f431927258b 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -1109,6 +1109,28 @@ pub mod asset { } } +pub mod block { + //! Module with queries related to blocks + use iroha_crypto::Hash; + + use super::*; + + /// Get query to find all blocks + pub const fn all() -> FindAllBlocks { + FindAllBlocks::new() + } + + /// Get query to find all block headers + pub const fn all_headers() -> FindAllBlockHeaders { + FindAllBlockHeaders::new() + } + + /// Get query to find block header by hash + pub fn header_by_hash(hash: impl Into>) -> FindBlockHeaderByHash { + FindBlockHeaderByHash::new(hash) + } +} + pub mod domain { //! Module with queries for domains use super::*; diff --git a/core/src/smartcontracts/isi/block.rs b/core/src/smartcontracts/isi/block.rs index ccef1412b23..75bbd452288 100644 --- a/core/src/smartcontracts/isi/block.rs +++ b/core/src/smartcontracts/isi/block.rs @@ -1,5 +1,6 @@ //! This module contains trait implementations related to block queries -use eyre::Result; +use eyre::{Result, WrapErr}; +use iroha_data_model::query::block::FindBlockHeaderByHash; use iroha_telemetry::metrics; use super::*; @@ -7,12 +8,45 @@ use super::*; impl ValidQuery for FindAllBlocks { #[metrics(+"find_all_blocks")] fn execute(&self, wsv: &WorldStateView) -> Result { - let mut blocks: Vec = wsv + let blocks = wsv .blocks() - .map(|blk| blk.clone()) + .map(|block| block.clone()) .map(VersionedCommittedBlock::into_value) + .rev() // Sorted by height desc. .collect(); - blocks.reverse(); Ok(blocks) } } + +impl ValidQuery for FindAllBlockHeaders { + #[metrics(+"find_all_block_headers")] + fn execute(&self, wsv: &WorldStateView) -> Result { + let block_headers = wsv + .blocks() + .map(|block| block.clone()) + .map(VersionedCommittedBlock::into_value) + .map(|block_value| block_value.header) + .rev() // Sorted by height desc. + .collect(); + Ok(block_headers) + } +} + +impl ValidQuery for FindBlockHeaderByHash { + #[metrics(+"find_block_header")] + fn execute(&self, wsv: &WorldStateView) -> Result { + let hash = self + .hash + .evaluate(wsv, &Context::default()) + .wrap_err("Failed to evaluate hash") + .map_err(|e| query::Error::Evaluate(e.to_string()))? + .typed(); + + let block = wsv + .blocks() + .find(|block| block.hash() == hash) + .ok_or_else(|| query::Error::Find(Box::new(FindError::Block(hash))))?; + + Ok(block.clone().into_value().header) + } +} diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 8256c451ee8..4ae2b2bdc7c 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -92,6 +92,8 @@ impl ValidQuery for QueryBox { FindAssetKeyValueByIdAndKey(query) => query.execute_into_value(wsv), FindAccountKeyValueByIdAndKey(query) => query.execute_into_value(wsv), FindAllBlocks(query) => query.execute_into_value(wsv), + FindAllBlockHeaders(query) => query.execute_into_value(wsv), + FindBlockHeaderByHash(query) => query.execute_into_value(wsv), FindAllTransactions(query) => query.execute_into_value(wsv), FindTransactionsByAccountId(query) => query.execute_into_value(wsv), FindTransactionByHash(query) => query.execute_into_value(wsv), @@ -193,88 +195,13 @@ mod tests { Ok(World::with([domain], PeersIds::new())) } - #[test] - fn asset_store() -> Result<()> { - let wsv = WorldStateView::new(world_with_test_asset_with_metadata()); - - let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; - let asset_id = AssetId::new(asset_definition_id, ALICE_ID.clone()); - let bytes = - FindAssetKeyValueByIdAndKey::new(asset_id, Name::from_str("Bytes")?).execute(&wsv)?; - assert_eq!( - bytes, - Value::Vec(vec![Value::U32(1), Value::U32(2), Value::U32(3)]) - ); - Ok(()) - } - - #[test] - fn account_metadata() -> Result<()> { - let wsv = WorldStateView::new(world_with_test_account_with_metadata()?); - - let bytes = FindAccountKeyValueByIdAndKey::new(ALICE_ID.clone(), Name::from_str("Bytes")?) - .execute(&wsv)?; - assert_eq!( - bytes, - Value::Vec(vec![Value::U32(1), Value::U32(2), Value::U32(3)]) - ); - Ok(()) - } - - #[tokio::test] - async fn find_all_blocks() -> Result<()> { + async fn wsv_with_test_blocks_and_transactions( + blocks: u64, + valid_tx_per_block: usize, + invalid_tx_per_block: usize, + ) -> Result> { let wsv = Arc::new(WorldStateView::new(world_with_test_domains())); - let validator = TransactionValidator::new( - TransactionLimits { - max_instruction_number: 0, - max_wasm_size_bytes: 0, - }, - Arc::new(AllowAll::new()), - Arc::new(AllowAll::new()), - Arc::clone(&wsv), - ); - - let first_block = PendingBlock::new(vec![], vec![]) - .chain_first() - .validate(&validator) - .sign(ALICE_KEYS.clone()) - .expect("Failed to sign blocks.") - .commit(); - - let mut curr_hash = first_block.hash(); - - wsv.apply(first_block).await?; - - let num_blocks: u64 = 100; - - for height in 1u64..num_blocks { - let block = PendingBlock::new(vec![], vec![]) - .chain( - height, - curr_hash, - crate::sumeragi::view_change::ProofChain::empty(), - vec![], - ) - .validate(&validator) - .sign(ALICE_KEYS.clone()) - .expect("Failed to sign blocks.") - .commit(); - curr_hash = block.hash(); - wsv.apply(block).await?; - } - - let blocks = FindAllBlocks::new().execute(&wsv)?; - - assert_eq!(blocks.len() as u64, num_blocks); - assert!(blocks.windows(2).all(|wnd| wnd[0] >= wnd[1])); - - Ok(()) - } - - #[tokio::test] - async fn find_all_transactions() -> Result<()> { - let wsv = Arc::new(WorldStateView::new(world_with_test_domains())); let limits = TransactionLimits { max_instruction_number: 1, max_wasm_size_bytes: 0, @@ -283,12 +210,12 @@ mod tests { max_instruction_number: 1000, max_wasm_size_bytes: 0, }; + let valid_tx = { let tx = Transaction::new(ALICE_ID.clone(), Vec::::new().into(), 4000) .sign(ALICE_KEYS.clone())?; crate::VersionedAcceptedTransaction::from_transaction(tx, &limits)? }; - let invalid_tx = { let isi = Instruction::Fail(FailBox::new("fail")); let tx = Transaction::new(ALICE_ID.clone(), vec![isi.clone(), isi].into(), 4000) @@ -296,7 +223,10 @@ mod tests { crate::VersionedAcceptedTransaction::from_transaction(tx, &huge_limits)? }; - let first_block = PendingBlock::new(vec![], vec![]) + let mut transactions = vec![valid_tx.clone(); valid_tx_per_block]; + transactions.append(&mut vec![invalid_tx.clone(); invalid_tx_per_block]); + + let first_block = PendingBlock::new(transactions.clone(), vec![]) .chain_first() .validate(&TransactionValidator::new( limits, @@ -312,10 +242,8 @@ mod tests { wsv.apply(first_block).await?; - let num_blocks: u64 = 100; - - for height in 1u64..=num_blocks { - let block = PendingBlock::new(vec![valid_tx.clone(), invalid_tx.clone()], vec![]) + for height in 1u64..blocks { + let block = PendingBlock::new(transactions.clone(), vec![]) .chain( height, curr_hash, @@ -335,6 +263,89 @@ mod tests { wsv.apply(block).await?; } + Ok(wsv) + } + + #[test] + fn asset_store() -> Result<()> { + let wsv = WorldStateView::new(world_with_test_asset_with_metadata()); + + let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; + let asset_id = AssetId::new(asset_definition_id, ALICE_ID.clone()); + let bytes = + FindAssetKeyValueByIdAndKey::new(asset_id, Name::from_str("Bytes")?).execute(&wsv)?; + assert_eq!( + bytes, + Value::Vec(vec![Value::U32(1), Value::U32(2), Value::U32(3)]) + ); + Ok(()) + } + + #[test] + fn account_metadata() -> Result<()> { + let wsv = WorldStateView::new(world_with_test_account_with_metadata()?); + + let bytes = FindAccountKeyValueByIdAndKey::new(ALICE_ID.clone(), Name::from_str("Bytes")?) + .execute(&wsv)?; + assert_eq!( + bytes, + Value::Vec(vec![Value::U32(1), Value::U32(2), Value::U32(3)]) + ); + Ok(()) + } + + #[tokio::test] + async fn find_all_blocks() -> Result<()> { + let num_blocks = 100; + + let wsv = wsv_with_test_blocks_and_transactions(num_blocks, 1, 1).await?; + + let blocks = FindAllBlocks::new().execute(&wsv)?; + + assert_eq!(blocks.len() as u64, num_blocks); + assert!(blocks.windows(2).all(|wnd| wnd[0] >= wnd[1])); + + Ok(()) + } + + #[tokio::test] + async fn find_all_block_headers() -> Result<()> { + let num_blocks = 100; + + let wsv = wsv_with_test_blocks_and_transactions(num_blocks, 1, 1).await?; + + let block_headers = FindAllBlockHeaders::new().execute(&wsv)?; + + assert_eq!(block_headers.len() as u64, num_blocks); + assert!(block_headers.windows(2).all(|wnd| wnd[0] >= wnd[1])); + + Ok(()) + } + + #[tokio::test] + async fn find_block_header_by_hash() -> Result<()> { + let wsv = wsv_with_test_blocks_and_transactions(1, 1, 1).await?; + + let block = wsv.blocks().last().expect("WSV is empty"); + + assert_eq!( + FindBlockHeaderByHash::new(*block.hash()).execute(&wsv)?, + block.clone().into_value().header + ); + + assert!(FindBlockHeaderByHash::new(Hash::zeroed()) + .execute(&wsv) + .is_err()); + + Ok(()) + } + + #[tokio::test] + async fn find_all_transactions() -> Result<()> { + let num_blocks = 100; + + let wsv = wsv_with_test_blocks_and_transactions(num_blocks, 1, 1).await?; + let txs = FindAllTransactions::new().execute(&wsv)?; assert_eq!(txs.len() as u64, num_blocks * 2); diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 95bed348cba..449ef093fd6 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -17,7 +17,7 @@ use alloc::{ }; use core::{convert::AsRef, fmt, fmt::Debug, ops::RangeInclusive}; -use block_value::BlockValue; +use block_value::{BlockHeaderValue, BlockValue}; #[cfg(not(target_arch = "aarch64"))] use derive_more::Into; use derive_more::{AsRef, Deref, Display, From}; @@ -336,6 +336,8 @@ pub enum Value { Hash(Hash), /// Block Block(BlockValueWrapper), + /// Block headers + BlockHeader(BlockHeaderValue), } /// Cross-platform wrapper for `BlockValue`. @@ -429,6 +431,7 @@ impl fmt::Display for Value { Value::PermissionToken(v) => fmt::Display::fmt(&v, f), Value::Hash(v) => fmt::Display::fmt(&v, f), Value::Block(v) => fmt::Display::fmt(&**v, f), + Value::BlockHeader(v) => fmt::Display::fmt(&v, f), } } } @@ -454,7 +457,8 @@ impl Value { | TransactionQueryResult(_) | PermissionToken(_) | Hash(_) - | Block(_) => 1_usize, + | Block(_) + | BlockHeader(_) => 1_usize, Vec(v) => v.iter().map(Self::len).sum::() + 1_usize, LimitedMetadata(data) => data.nested_len() + 1_usize, SignatureCheckCondition(s) => s.0.len(), diff --git a/data_model/src/query.rs b/data_model/src/query.rs index 208d08c7a68..a406b75f829 100644 --- a/data_model/src/query.rs +++ b/data_model/src/query.rs @@ -83,6 +83,10 @@ pub enum QueryBox { FindAllPeers(FindAllPeers), /// [`FindAllBlocks`] variant. FindAllBlocks(FindAllBlocks), + /// [`FindAllBlockHeaders`] variant. + FindAllBlockHeaders(FindAllBlockHeaders), + /// [`FindBlockHeaderByHash`] variant. + FindBlockHeaderByHash(FindBlockHeaderByHash), /// [`FindAllTransactions`] variant. FindAllTransactions(FindAllTransactions), /// [`FindTransactionsByAccountId`] variant. @@ -232,7 +236,7 @@ pub mod role { use crate::prelude::*; - /// `FindAllRoles` Iroha Query will find all `Roles`s presented. + /// `FindAllRoles` Iroha Query finds all `Roles`s presented. #[derive( Debug, Clone, @@ -254,7 +258,8 @@ pub mod role { type Output = Vec; } - /// `FindAllRoles` Iroha Query will find all `Roles`s presented. + /// `FindAllRoleIds` Iroha Query finds [`Id`](crate::role::Id)s of + /// all `Roles`s presented. #[derive( Debug, Clone, @@ -276,7 +281,7 @@ pub mod role { type Output = Vec<::Id>; } - /// `FindRoleByRoleId` Iroha Query to find the [`Role`] which has the given [`Id`](crate::role::Id) + /// `FindRoleByRoleId` Iroha Query finds the [`Role`] which has the given [`Id`](crate::role::Id) #[derive( Debug, Clone, @@ -299,7 +304,7 @@ pub mod role { type Output = Role; } - /// `FindRolesByAccountId` Iroha Query will find an [`Role`]s for a specified account. + /// `FindRolesByAccountId` Iroha Query finds all [`Role`]s for a specified account. #[derive( Debug, Clone, @@ -370,7 +375,8 @@ pub mod permissions { use crate::prelude::*; - /// `FindPermissionTokensByAccountId` Iroha Query will find an `Role`s for a specified account. + /// `FindPermissionTokensByAccountId` Iroha Query finds all `PermissionToken`s + /// for a specified account. #[derive( Debug, Clone, @@ -412,7 +418,7 @@ pub mod account { use crate::prelude::*; // TODO: Better to have find all account ids query instead. - /// `FindAllAccounts` Iroha Query will find all `Account`s presented. + /// `FindAllAccounts` Iroha Query finds all `Account`s presented. #[derive( Debug, Clone, @@ -434,7 +440,7 @@ pub mod account { type Output = Vec; } - /// `FindAccountById` Iroha Query will find an `Account` by it's identification. + /// `FindAccountById` Iroha Query finds an `Account` by it's identification. #[derive( Debug, Clone, @@ -457,8 +463,8 @@ pub mod account { type Output = Account; } - /// `FindAccountById` Iroha Query will find a [`Value`] of the key-value metadata pair - /// in the specified account. + /// `FindAccountKeyValueByIdAndKey` Iroha Query finds a [`Value`] + /// of the key-value metadata pair in the specified account. #[derive( Debug, Clone, @@ -483,8 +489,8 @@ pub mod account { type Output = Value; } - /// `FindAccountsByName` Iroha Query will get `Account`s name as input and - /// find all `Account`s with this name. + /// `FindAccountsByName` Iroha Query gets `Account`s name as input and + /// finds all `Account`s with this name. #[derive( Debug, Clone, @@ -507,8 +513,8 @@ pub mod account { type Output = Vec; } - /// `FindAccountsByDomainId` Iroha Query will get `Domain`s id as input and - /// find all `Account`s under this `Domain`. + /// `FindAccountsByDomainId` Iroha Query gets `Domain`s id as input and + /// finds all `Account`s under this `Domain`. #[derive( Debug, Clone, @@ -531,8 +537,8 @@ pub mod account { type Output = Vec; } - /// `FindAccountsWithAsset` Iroha Query will get `AssetDefinition`s id as input and - /// find all `Account`s storing `Asset` with such definition. + /// `FindAccountsWithAsset` Iroha Query gets `AssetDefinition`s id as input and + /// finds all `Account`s storing `Asset` with such definition. #[derive( Debug, Clone, @@ -631,7 +637,7 @@ pub mod asset { use crate::prelude::*; - /// `FindAllAssets` Iroha Query will find all `Asset`s presented in Iroha Peer. + /// `FindAllAssets` Iroha Query finds all `Asset`s presented in Iroha Peer. #[derive( Debug, Clone, @@ -653,7 +659,7 @@ pub mod asset { type Output = Vec; } - /// `FindAllAssetsDefinitions` Iroha Query will find all `AssetDefinition`s presented + /// `FindAllAssetsDefinitions` Iroha Query finds all `AssetDefinition`s presented /// in Iroha Peer. #[derive( Debug, @@ -676,7 +682,7 @@ pub mod asset { type Output = Vec; } - /// `FindAssetById` Iroha Query will find an `Asset` by it's identification in Iroha `Peer`. + /// `FindAssetById` Iroha Query finds an `Asset` by it's identification in Iroha `Peer`. #[derive( Debug, Clone, @@ -699,7 +705,7 @@ pub mod asset { type Output = Asset; } - /// `FindAssetDefinitionById` Iroha Query will find an `AssetDefinition` by it's identification in Iroha `Peer`. + /// `FindAssetDefinitionById` Iroha Query finds an `AssetDefinition` by it's identification in Iroha `Peer`. #[derive( Debug, Clone, @@ -722,8 +728,8 @@ pub mod asset { type Output = AssetDefinition; } - /// `FindAssetsByName` Iroha Query will get `Asset`s name as input and - /// find all `Asset`s with it in Iroha `Peer`. + /// `FindAssetsByName` Iroha Query gets `Asset`s name as input and + /// finds all `Asset`s with it in Iroha `Peer`. #[derive( Debug, Clone, @@ -746,7 +752,7 @@ pub mod asset { type Output = Vec; } - /// `FindAssetsByAccountId` Iroha Query will get `AccountId` as input and find all `Asset`s + /// `FindAssetsByAccountId` Iroha Query gets `AccountId` as input and find all `Asset`s /// owned by the `Account` in Iroha Peer. #[derive( Debug, @@ -770,8 +776,8 @@ pub mod asset { type Output = Vec; } - /// `FindAssetsByAssetDefinitionId` Iroha Query will get `AssetDefinitionId` as input and - /// find all `Asset`s with this `AssetDefinition` in Iroha Peer. + /// `FindAssetsByAssetDefinitionId` Iroha Query gets `AssetDefinitionId` as input and + /// finds all `Asset`s with this `AssetDefinition` in Iroha Peer. #[derive( Debug, Clone, @@ -794,8 +800,8 @@ pub mod asset { type Output = Vec; } - /// `FindAssetsByDomainId` Iroha Query will get `Domain`s id as input and - /// find all `Asset`s under this `Domain` in Iroha `Peer`. + /// `FindAssetsByDomainId` Iroha Query gets `Domain`s id as input and + /// finds all `Asset`s under this `Domain` in Iroha `Peer`. #[derive( Debug, Clone, @@ -818,8 +824,8 @@ pub mod asset { type Output = Vec; } - /// `FindAssetsByDomainIdAndAssetDefinitionId` Iroha Query will get `Domain`'s id and - /// `AssetDefinitionId` as inputs and find all `Asset`s under the `Domain` + /// `FindAssetsByDomainIdAndAssetDefinitionId` Iroha Query gets `Domain`'s id and + /// `AssetDefinitionId` as inputs and finds `Asset`s under the `Domain` /// with this `AssetDefinition` in Iroha `Peer`. #[derive( Debug, @@ -845,7 +851,7 @@ pub mod asset { type Output = Vec; } - /// `FindAssetQuantityById` Iroha Query will get `AssetId` as input and find `Asset::quantity` + /// `FindAssetQuantityById` Iroha Query gets `AssetId` as input and finds `Asset::quantity` /// parameter's value if `Asset` is presented in Iroha Peer. #[derive( Debug, @@ -869,7 +875,7 @@ pub mod asset { type Output = u32; } - /// `FindAssetKeyValueByIdAndKey` Iroha Query will get `AssetId` and key as input and find [`Value`] + /// `FindAssetKeyValueByIdAndKey` Iroha Query gets `AssetId` and key as input and finds [`Value`] /// of the key-value pair stored in this asset. #[derive( Debug, @@ -895,7 +901,7 @@ pub mod asset { type Output = Value; } - /// `FindAssetDefinitionKeyValueByIdAndKey` Iroha Query will get `AssetDefinitionId` and key as input and find [`Value`] + /// `FindAssetDefinitionKeyValueByIdAndKey` Iroha Query gets `AssetDefinitionId` and key as input and finds [`Value`] /// of the key-value pair stored in this asset definition. #[derive( Debug, @@ -1054,7 +1060,7 @@ pub mod domain { use crate::prelude::*; - /// `FindAllDomains` Iroha Query will find all `Domain`s presented in Iroha `Peer`. + /// `FindAllDomains` Iroha Query finds all `Domain`s presented in Iroha `Peer`. #[derive( Debug, Clone, @@ -1076,7 +1082,7 @@ pub mod domain { type Output = Vec; } - /// `FindDomainById` Iroha Query will find a `Domain` by it's identification in Iroha `Peer`. + /// `FindDomainById` Iroha Query finds a `Domain` by it's identification in Iroha `Peer`. #[derive( Debug, Clone, @@ -1114,7 +1120,7 @@ pub mod domain { } } - /// `FindDomainKeyValueByIdAndKey` Iroha Query will find a [`Value`] of the key-value metadata pair + /// `FindDomainKeyValueByIdAndKey` Iroha Query finds a [`Value`] of the key-value metadata pair /// in the specified domain. #[derive( Debug, @@ -1171,7 +1177,7 @@ pub mod peer { use super::Query; use crate::{peer::Peer, Parameter}; - /// `FindAllPeers` Iroha Query will find all trusted `Peer`s presented in current Iroha `Peer`. + /// `FindAllPeers` Iroha Query finds all trusted `Peer`s presented in current Iroha `Peer`. #[derive( Debug, Clone, @@ -1193,7 +1199,7 @@ pub mod peer { type Output = Vec; } - /// `FindAllParameters` Iroha Query will find all `Peer`s parameters. + /// `FindAllParameters` Iroha Query finds all `Peer`s parameters. #[derive( Debug, Clone, @@ -1362,7 +1368,7 @@ pub mod trigger { } pub mod transaction { - //! Queries related to `Transaction`. + //! Queries related to transactions. #![allow(clippy::missing_inline_in_public_items)] @@ -1396,7 +1402,7 @@ pub mod transaction { PartialOrd, Ord, )] - /// `FindAllTransactions` Iroha Query will list all transactions included in blockchain + /// `FindAllTransactions` Iroha Query lists all transactions included in blockchain pub struct FindAllTransactions; impl Query for FindAllTransactions { @@ -1410,7 +1416,7 @@ pub mod transaction { } } - /// `FindTransactionsByAccountId` Iroha Query will find all transaction included in blockchain + /// `FindTransactionsByAccountId` Iroha Query finds all transaction included in blockchain /// for the account #[derive( Debug, @@ -1442,7 +1448,7 @@ pub mod transaction { } } - /// `FindTransactionByHash` Iroha Query will find a transaction (if any) + /// `FindTransactionByHash` Iroha Query finds a transaction (if any) /// with corresponding hash value #[derive( Debug, @@ -1481,20 +1487,26 @@ pub mod transaction { } pub mod block { - //! Queries related to `Transaction`. + //! Queries related to blocks. #![allow(clippy::missing_inline_in_public_items)] #[cfg(not(feature = "std"))] use alloc::{boxed::Box, format, string::String, vec::Vec}; + use iroha_crypto::Hash; use iroha_schema::prelude::*; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; use super::Query; - use crate::block_value::BlockValue; + use crate::{ + block_value::{BlockHeaderValue, BlockValue}, + prelude::EvaluatesTo, + }; + /// `FindAllBlocks` Iroha Query lists all blocks sorted by + /// height in descending order #[derive( Default, Debug, @@ -1510,7 +1522,6 @@ pub mod block { PartialOrd, Ord, )] - /// `FindAllBlocks` Iroha Query will list all blocks pub struct FindAllBlocks; impl Query for FindAllBlocks { @@ -1519,14 +1530,74 @@ pub mod block { impl FindAllBlocks { /// Construct [`FindAllBlocks`]. - pub fn new() -> Self { - Self {} + pub const fn new() -> Self { + Self + } + } + + /// `FindAllBlockHeaders` Iroha Query lists all block headers + /// sorted by height in descending order + #[derive( + Default, + Debug, + Clone, + Copy, + PartialEq, + Eq, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, + PartialOrd, + Ord, + )] + pub struct FindAllBlockHeaders; + + impl Query for FindAllBlockHeaders { + type Output = Vec; + } + + impl FindAllBlockHeaders { + /// Construct [`FindAllBlockHeaders`]. + pub const fn new() -> Self { + Self + } + } + + /// `FindBlockHeaderByHash` Iroha Query finds block header by block hash + #[derive( + Debug, + Clone, + PartialEq, + Eq, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, + PartialOrd, + Ord, + )] + pub struct FindBlockHeaderByHash { + /// Block hash. + pub hash: EvaluatesTo, + } + + impl Query for FindBlockHeaderByHash { + type Output = BlockHeaderValue; + } + + impl FindBlockHeaderByHash { + /// Construct [`FindBlockHeaderByHash`]. + pub fn new(hash: impl Into>) -> Self { + Self { hash: hash.into() } } } /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { - pub use super::FindAllBlocks; + pub use super::{FindAllBlockHeaders, FindAllBlocks, FindBlockHeaderByHash}; } } diff --git a/permissions_validators/src/private_blockchain/query.rs b/permissions_validators/src/private_blockchain/query.rs index c36d2052717..42420478642 100644 --- a/permissions_validators/src/private_blockchain/query.rs +++ b/permissions_validators/src/private_blockchain/query.rs @@ -219,6 +219,12 @@ impl IsAllowed for OnlyAccountsDomain { } } FindAllBlocks(_) => Deny("You are not permitted to access all blocks.".to_owned()), + FindAllBlockHeaders(_) => { + Deny("You are not permitted to access all blocks.".to_owned()) + } + FindBlockHeaderByHash(_) => { + Deny("You are not permitted to access arbitrary blocks.".to_owned()) + } FindAllTransactions(_) => { Deny("Cannot access transactions of another domain.".to_owned()) } @@ -418,6 +424,12 @@ impl IsAllowed for OnlyAccountsData { FindAllBlocks(_) => { Deny("You are not permitted to access all blocks.".to_owned()) } + FindAllBlockHeaders(_) => { + Deny("Access to all block headers not permitted".to_owned()) + } + FindBlockHeaderByHash(_) => { + Deny("Access to arbitrary block headers not permitted".to_owned()) + } FindAllTransactions(_) => { Deny("Cannot access transactions of another account.".to_owned()) }, diff --git a/tools/parity_scale_decoder/src/generate_map.rs b/tools/parity_scale_decoder/src/generate_map.rs index c81ca34021c..43a3f3da932 100644 --- a/tools/parity_scale_decoder/src/generate_map.rs +++ b/tools/parity_scale_decoder/src/generate_map.rs @@ -147,6 +147,7 @@ pub fn generate_map() -> DumpDecodedMap { FindAllActiveTriggerIds, FindAllAssets, FindAllAssetsDefinitions, + FindAllBlockHeaders, FindAllBlocks, FindAllDomains, FindAllParameters, @@ -164,6 +165,7 @@ pub fn generate_map() -> DumpDecodedMap { FindAssetsByDomainId, FindAssetsByDomainIdAndAssetDefinitionId, FindAssetsByName, + FindBlockHeaderByHash, FindDomainById, FindDomainKeyValueByIdAndKey, FindPermissionTokensByAccountId,