Skip to content

Commit

Permalink
[feature] hyperledger-iroha#2098: Block header queries (hyperledger-i…
Browse files Browse the repository at this point in the history
…roha#2453)

* [feature] hyperledger-iroha#2098: add block header queries

Signed-off-by: Artemii Gerasimovich <[email protected]>
  • Loading branch information
QuentinI authored Jul 19, 2022
1 parent 6a61ab8 commit 64d0993
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 138 deletions.
22 changes: 22 additions & 0 deletions client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<EvaluatesTo<Hash>>) -> FindBlockHeaderByHash {
FindBlockHeaderByHash::new(hash)
}
}

pub mod domain {
//! Module with queries for domains
use super::*;
Expand Down
42 changes: 38 additions & 4 deletions core/src/smartcontracts/isi/block.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,52 @@
//! 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::*;

impl ValidQuery for FindAllBlocks {
#[metrics(+"find_all_blocks")]
fn execute(&self, wsv: &WorldStateView) -> Result<Self::Output, query::Error> {
let mut blocks: Vec<BlockValue> = 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<Self::Output, query::Error> {
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<Self::Output, query::Error> {
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)
}
}
183 changes: 97 additions & 86 deletions core/src/smartcontracts/isi/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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<Arc<WorldStateView>> {
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,
Expand All @@ -283,20 +210,23 @@ mod tests {
max_instruction_number: 1000,
max_wasm_size_bytes: 0,
};

let valid_tx = {
let tx = Transaction::new(ALICE_ID.clone(), Vec::<Instruction>::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)
.sign(ALICE_KEYS.clone())?;
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,
Expand All @@ -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,
Expand All @@ -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);
Expand Down
8 changes: 6 additions & 2 deletions data_model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -336,6 +336,8 @@ pub enum Value {
Hash(Hash),
/// Block
Block(BlockValueWrapper),
/// Block headers
BlockHeader(BlockHeaderValue),
}

/// Cross-platform wrapper for `BlockValue`.
Expand Down Expand Up @@ -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),
}
}
}
Expand All @@ -454,7 +457,8 @@ impl Value {
| TransactionQueryResult(_)
| PermissionToken(_)
| Hash(_)
| Block(_) => 1_usize,
| Block(_)
| BlockHeader(_) => 1_usize,
Vec(v) => v.iter().map(Self::len).sum::<usize>() + 1_usize,
LimitedMetadata(data) => data.nested_len() + 1_usize,
SignatureCheckCondition(s) => s.0.len(),
Expand Down
Loading

0 comments on commit 64d0993

Please sign in to comment.