From 6b8abfca494fdc37f4a57d4d0077bd1a82d71385 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Thu, 2 May 2024 15:57:27 +0300 Subject: [PATCH] feat: Add a test using a query filter in a smart contract Signed-off-by: Nikita Strygin --- client/tests/integration/queries/mod.rs | 46 +----------- .../integration/queries/smart_contract.rs | 73 +++++++++++++++++++ .../integration/smartcontracts/Cargo.toml | 5 +- .../Cargo.toml | 21 ++++++ .../src/lib.rs | 50 +++++++++++++ 5 files changed, 149 insertions(+), 46 deletions(-) create mode 100644 client/tests/integration/queries/smart_contract.rs create mode 100644 client/tests/integration/smartcontracts/smart_contract_can_filter_queries/Cargo.toml create mode 100644 client/tests/integration/smartcontracts/smart_contract_can_filter_queries/src/lib.rs diff --git a/client/tests/integration/queries/mod.rs b/client/tests/integration/queries/mod.rs index 4d85add4e5b..d53bb97853e 100644 --- a/client/tests/integration/queries/mod.rs +++ b/client/tests/integration/queries/mod.rs @@ -1,11 +1,8 @@ -use std::str::FromStr as _; - -use eyre::Result; use iroha_client::{ client::{self, ClientQueryError}, data_model::{ prelude::*, - query::{cursor::ForwardCursor, error::QueryExecutionFail, MAX_FETCH_SIZE}, + query::{error::QueryExecutionFail, MAX_FETCH_SIZE}, }, }; use test_network::*; @@ -14,6 +11,7 @@ mod account; mod asset; mod query_errors; mod role; +mod smart_contract; #[test] fn too_big_fetch_size_is_not_allowed() { @@ -33,43 +31,3 @@ fn too_big_fetch_size_is_not_allowed() { )) )); } - -#[test] -fn live_query_is_dropped_after_smart_contract_end() -> Result<()> { - let (_rt, _peer, client) = ::new().with_port(11_140).start_with_runtime(); - wait_for_genesis_committed(&[client.clone()], 0); - - let wasm = iroha_wasm_builder::Builder::new( - "tests/integration/smartcontracts/query_assets_and_save_cursor", - ) - .show_output() - .build()? - .optimize()? - .into_bytes()?; - - let transaction = client.build_transaction( - WasmSmartContract::from_compiled(wasm), - UnlimitedMetadata::default(), - ); - client.submit_transaction_blocking(&transaction)?; - - let metadata_value = client.request(FindAccountKeyValueByIdAndKey::new( - client.account_id.clone(), - Name::from_str("cursor").unwrap(), - ))?; - let cursor: String = metadata_value.try_into()?; - let asset_cursor = serde_json::from_str::(&cursor)?; - - let err = client - .request_with_cursor::>(asset_cursor) - .expect_err("Request with cursor from smart contract should fail"); - - assert!(matches!( - err, - ClientQueryError::Validation(ValidationFail::QueryFailed( - QueryExecutionFail::UnknownCursor - )) - )); - - Ok(()) -} diff --git a/client/tests/integration/queries/smart_contract.rs b/client/tests/integration/queries/smart_contract.rs new file mode 100644 index 00000000000..1e5cb8a3b56 --- /dev/null +++ b/client/tests/integration/queries/smart_contract.rs @@ -0,0 +1,73 @@ +use std::str::FromStr as _; + +use eyre::Result; +use iroha_client::{ + client::ClientQueryError, + data_model::{ + prelude::*, + query::{cursor::ForwardCursor, error::QueryExecutionFail}, + }, +}; +use test_network::*; + +#[test] +fn live_query_is_dropped_after_smart_contract_end() -> Result<()> { + let (_rt, _peer, client) = ::new().with_port(11_140).start_with_runtime(); + wait_for_genesis_committed(&[client.clone()], 0); + + let wasm = iroha_wasm_builder::Builder::new( + "tests/integration/smartcontracts/query_assets_and_save_cursor", + ) + .show_output() + .build()? + .optimize()? + .into_bytes()?; + + let transaction = client.build_transaction( + WasmSmartContract::from_compiled(wasm), + UnlimitedMetadata::default(), + ); + client.submit_transaction_blocking(&transaction)?; + + let metadata_value = client.request(FindAccountKeyValueByIdAndKey::new( + client.account_id.clone(), + Name::from_str("cursor").unwrap(), + ))?; + let cursor: String = metadata_value.try_into()?; + let asset_cursor = serde_json::from_str::(&cursor)?; + + let err = client + .request_with_cursor::>(asset_cursor) + .expect_err("Request with cursor from smart contract should fail"); + + assert!(matches!( + err, + ClientQueryError::Validation(ValidationFail::QueryFailed( + QueryExecutionFail::UnknownCursor + )) + )); + + Ok(()) +} + +#[test] +fn smart_contract_can_filter_queries() -> Result<()> { + let (_rt, _peer, client) = ::new().with_port(11_260).start_with_runtime(); + wait_for_genesis_committed(&[client.clone()], 0); + + let wasm = iroha_wasm_builder::Builder::new( + "tests/integration/smartcontracts/smart_contract_can_filter_queries", + ) + .show_output() + .build()? + .optimize()? + .into_bytes()?; + + let transaction = client.build_transaction( + WasmSmartContract::from_compiled(wasm), + UnlimitedMetadata::default(), + ); + client.submit_transaction_blocking(&transaction)?; + + Ok(()) +} diff --git a/client/tests/integration/smartcontracts/Cargo.toml b/client/tests/integration/smartcontracts/Cargo.toml index 4739c446174..7ec4b608a57 100644 --- a/client/tests/integration/smartcontracts/Cargo.toml +++ b/client/tests/integration/smartcontracts/Cargo.toml @@ -16,6 +16,7 @@ members = [ "executor_remove_token", "executor_with_migration_fail", "query_assets_and_save_cursor", + "smart_contract_can_filter_queries", ] [profile.dev] @@ -29,8 +30,8 @@ opt-level = "z" # Optimize for size vs speed with "s"/"z"(removes vectorizat codegen-units = 1 # Further reduces binary size but increases compilation time [workspace.dependencies] -iroha_smart_contract = { version = "=2.0.0-pre-rc.21", path = "../../../../smart_contract", features = ["debug"]} -iroha_trigger = { version = "=2.0.0-pre-rc.21", path = "../../../../smart_contract/trigger", features = ["debug"]} +iroha_smart_contract = { version = "=2.0.0-pre-rc.21", path = "../../../../smart_contract", features = ["debug"] } +iroha_trigger = { version = "=2.0.0-pre-rc.21", path = "../../../../smart_contract/trigger", features = ["debug"] } iroha_executor = { version = "=2.0.0-pre-rc.21", path = "../../../../smart_contract/executor" } iroha_schema = { version = "=2.0.0-pre-rc.21", path = "../../../../schema" } diff --git a/client/tests/integration/smartcontracts/smart_contract_can_filter_queries/Cargo.toml b/client/tests/integration/smartcontracts/smart_contract_can_filter_queries/Cargo.toml new file mode 100644 index 00000000000..8244730ed6d --- /dev/null +++ b/client/tests/integration/smartcontracts/smart_contract_can_filter_queries/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "smart_contract_can_filter_queries" + +edition.workspace = true +version.workspace = true +authors.workspace = true + +license.workspace = true + +[lib] +crate-type = ['cdylib'] + +[dependencies] +iroha_smart_contract.workspace = true + +panic-halt.workspace = true +lol_alloc.workspace = true +getrandom.workspace = true +parity-scale-codec.workspace = true +nonzero_ext.workspace = true +serde_json = { workspace = true, default-features = false } diff --git a/client/tests/integration/smartcontracts/smart_contract_can_filter_queries/src/lib.rs b/client/tests/integration/smartcontracts/smart_contract_can_filter_queries/src/lib.rs new file mode 100644 index 00000000000..5ff677f33e5 --- /dev/null +++ b/client/tests/integration/smartcontracts/smart_contract_can_filter_queries/src/lib.rs @@ -0,0 +1,50 @@ +//! Smart contract which executes [`FindAllAssets`] and saves cursor to the owner's metadata. + +#![no_std] + +#[cfg(not(test))] +extern crate panic_halt; + +extern crate alloc; + +use alloc::{collections::BTreeSet, string::ToString, vec::Vec}; + +use iroha_smart_contract::{ + data_model::query::predicate::{string::StringPredicate, value::QueryOutputPredicate}, + prelude::*, + QueryOutputCursor, +}; +use lol_alloc::{FreeListAllocator, LockedAllocator}; + +#[global_allocator] +static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); + +getrandom::register_custom_getrandom!(iroha_smart_contract::stub_getrandom); + +/// Query all accounts, but filter them to only be in the wonderland domain +#[iroha_smart_contract::main] +fn main(_owner: AccountId) { + // our genesis contains alice & bob accounts in the wonderland domain and a carpenter account in the garden_of_live_flowers domain + // with this filter we expect to only get alice and bob + let cursor: QueryOutputCursor> = FindAllAccounts + .filter(QueryOutputPredicate::Identifiable( + StringPredicate::EndsWith("@wonderland".to_string()), + )) + .execute() + .dbg_unwrap(); + + let mut account_ids = BTreeSet::new(); + + for account in cursor { + let account = account.dbg_unwrap(); + account_ids.insert(account.id().to_string()); + } + + assert_eq!( + account_ids, + ["alice@wonderland", "bob@wonderland"] + .into_iter() + .map(ToString::to_string) + .collect() + ); +}