From e0036f01a9eb698b1dab0db7bd352aedb6d581cf Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Mon, 11 Dec 2023 01:47:59 +0300 Subject: [PATCH] Disallow the use of boxed instruction types Signed-off-by: Daniil Polyakov --- client/benches/torii.rs | 15 +- client/benches/tps/utils.rs | 12 +- client/examples/million_accounts_genesis.rs | 5 +- client/examples/tutorial.rs | 26 +- client/tests/integration/add_account.rs | 4 +- client/tests/integration/add_domain.rs | 4 +- client/tests/integration/asset.rs | 67 +- client/tests/integration/asset_propagation.rs | 10 +- client/tests/integration/burn_public_keys.rs | 6 +- client/tests/integration/connected_peers.rs | 4 +- client/tests/integration/domain_owner.rs | 110 +-- client/tests/integration/events/data.rs | 8 +- .../tests/integration/events/notification.rs | 6 +- .../integration/multiple_blocks_created.rs | 9 +- .../integration/multisignature_account.rs | 7 +- .../integration/multisignature_transaction.rs | 6 +- client/tests/integration/non_mintable.rs | 21 +- client/tests/integration/pagination.rs | 2 +- client/tests/integration/permissions.rs | 39 +- client/tests/integration/queries/account.rs | 6 +- client/tests/integration/queries/asset.rs | 47 +- client/tests/integration/queries/role.rs | 10 +- client/tests/integration/restart_peer.rs | 4 +- client/tests/integration/roles.rs | 22 +- client/tests/integration/set_parameter.rs | 2 +- .../src/lib.rs | 4 +- .../executor_with_admin/src/lib.rs | 2 +- .../executor_with_custom_token/src/lib.rs | 16 +- .../executor_with_migration_fail/src/lib.rs | 2 +- .../mint_rose_trigger/src/lib.rs | 2 +- .../query_assets_and_save_cursor/src/lib.rs | 2 +- client/tests/integration/sorting.rs | 21 +- client/tests/integration/transfer_asset.rs | 30 +- .../integration/triggers/by_call_trigger.rs | 50 +- .../integration/triggers/data_trigger.rs | 27 +- .../integration/triggers/event_trigger.rs | 6 +- .../integration/triggers/time_trigger.rs | 25 +- .../integration/triggers/trigger_rollback.rs | 4 +- client/tests/integration/tx_history.rs | 6 +- client/tests/integration/tx_rollback.rs | 5 +- client/tests/integration/unregister_peer.rs | 10 +- client/tests/integration/unstable_network.rs | 4 +- client/tests/integration/upgrade.rs | 6 +- client_cli/src/main.rs | 38 +- configs/peer/executor.wasm | Bin 373426 -> 388782 bytes core/benches/blocks/common.rs | 24 +- core/benches/kura.rs | 2 +- core/benches/validation.rs | 11 +- core/src/block.rs | 12 +- core/src/smartcontracts/isi/mod.rs | 18 +- core/src/smartcontracts/isi/query.rs | 2 +- core/src/smartcontracts/wasm.rs | 6 +- core/src/sumeragi/main_loop.rs | 4 +- core/test_network/src/lib.rs | 7 +- data_model/src/isi.rs | 892 ++++++++++++------ data_model/src/lib.rs | 68 +- data_model/src/visit.rs | 6 +- data_model/tests/data_model.rs | 2 +- genesis/src/lib.rs | 24 +- smart_contract/executor/src/default.rs | 357 +++---- smart_contract/executor/src/lib.rs | 19 +- smart_contract/src/lib.rs | 2 +- smart_contract/utils/src/lib.rs | 2 +- tools/kagami/src/genesis.rs | 11 +- tools/parity_scale_decoder/src/main.rs | 2 +- 65 files changed, 1299 insertions(+), 884 deletions(-) diff --git a/client/benches/torii.rs b/client/benches/torii.rs index 876105cce66..1e579b35cd8 100644 --- a/client/benches/torii.rs +++ b/client/benches/torii.rs @@ -10,6 +10,7 @@ use iroha_client::{ }; use iroha_config::base::runtime_upgrades::Reload; use iroha_crypto::KeyPair; +use iroha_data_model::isi::InstructionBox; use iroha_genesis::{GenesisNetwork, RawGenesisBlockBuilder}; use iroha_primitives::unique_vec; use iroha_version::Encode; @@ -51,17 +52,17 @@ fn query_requests(criterion: &mut Criterion) { .expect("Should not fail"); let mut group = criterion.benchmark_group("query-requests"); let domain_id: DomainId = "domain".parse().expect("Valid"); - let create_domain = RegisterBox::domain(Domain::new(domain_id.clone())); + let create_domain = Register::domain(Domain::new(domain_id.clone())); let account_id = AccountId::new("account".parse().expect("Valid"), domain_id.clone()); let (public_key, _) = KeyPair::generate() .expect("Failed to generate KeyPair") .into(); - let create_account = RegisterBox::account(Account::new(account_id.clone(), [public_key])); + let create_account = Register::account(Account::new(account_id.clone(), [public_key])); let asset_definition_id = AssetDefinitionId::new("xor".parse().expect("Valid"), domain_id); let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); let quantity: u32 = 200; - let mint_asset = MintBox::asset_quantity( + let mint_asset = Mint::asset_quantity( quantity, AssetId::new(asset_definition_id, account_id.clone()), ); @@ -141,12 +142,12 @@ fn instruction_submits(criterion: &mut Criterion) { rt.block_on(builder.start_with_peer(&mut peer)); let mut group = criterion.benchmark_group("instruction-requests"); let domain_id: DomainId = "domain".parse().expect("Valid"); - let create_domain = RegisterBox::domain(Domain::new(domain_id.clone())); + let create_domain: InstructionBox = Register::domain(Domain::new(domain_id.clone())).into(); let account_id = AccountId::new("account".parse().expect("Valid"), domain_id.clone()); let (public_key, _) = KeyPair::generate() .expect("Failed to generate Key-pair.") .into(); - let create_account = RegisterBox::account(Account::new(account_id.clone(), [public_key])); + let create_account = Register::account(Account::new(account_id.clone(), [public_key])).into(); let asset_definition_id = AssetDefinitionId::new("xor".parse().expect("Valid"), domain_id); let mut client_config = iroha_client::samples::get_client_config(&get_key_pair()); client_config.torii_api_url = format!("http://{}", peer.api_address).parse().unwrap(); @@ -161,7 +162,7 @@ fn instruction_submits(criterion: &mut Criterion) { let _dropable = group.bench_function("instructions", |b| { b.iter(|| { let quantity: u32 = 200; - let mint_asset = MintBox::asset_quantity( + let mint_asset = Mint::asset_quantity( quantity, AssetId::new(asset_definition_id.clone(), account_id.clone()), ); diff --git a/client/benches/tps/utils.rs b/client/benches/tps/utils.rs index 1687801c981..7c4d0fc7e3c 100644 --- a/client/benches/tps/utils.rs +++ b/client/benches/tps/utils.rs @@ -172,7 +172,7 @@ impl MeasurerUnit { let alice_id = AccountId::from_str("alice@wonderland")?; let asset_id = asset_id(self.name); - let register_me = RegisterBox::account(Account::new( + let register_me = Register::account(Account::new( account_id.clone(), [keypair.public_key().clone()], )); @@ -183,13 +183,13 @@ impl MeasurerUnit { &json!({ "asset_id": asset_id }), ); let allow_alice_to_burn_my_asset = - GrantBox::permission_token(can_burn_my_asset, alice_id.clone()); + Grant::permission_token(can_burn_my_asset, alice_id.clone()); let can_transfer_my_asset = PermissionToken::new( "CanTransferUserAsset".parse().unwrap(), &json!({ "asset_id": asset_id }), ); let allow_alice_to_transfer_my_asset = - GrantBox::permission_token(can_transfer_my_asset, alice_id); + Grant::permission_token(can_transfer_my_asset, alice_id); let grant_tx = TransactionBuilder::new(account_id) .with_instructions([ allow_alice_to_burn_my_asset, @@ -198,7 +198,7 @@ impl MeasurerUnit { .sign(keypair)?; self.client.submit_transaction_blocking(&grant_tx)?; - let mint_a_rose = MintBox::asset_quantity(1_u32, asset_id); + let mint_a_rose = Mint::asset_quantity(1_u32, asset_id); self.client.submit_blocking(mint_a_rose)?; Ok(self) @@ -277,11 +277,11 @@ impl MeasurerUnit { } fn mint(&self) -> InstructionBox { - MintBox::asset_quantity(1_u32, asset_id(self.name)).into() + Mint::asset_quantity(1_u32, asset_id(self.name)).into() } fn transfer(&self) -> InstructionBox { - TransferBox::asset_quantity(asset_id(self.name), 1_u32, account_id(self.next_name)).into() + Transfer::asset_quantity(asset_id(self.name), 1_u32, account_id(self.next_name)).into() } } diff --git a/client/examples/million_accounts_genesis.rs b/client/examples/million_accounts_genesis.rs index cb4dbeb9996..57993c1a972 100644 --- a/client/examples/million_accounts_genesis.rs +++ b/client/examples/million_accounts_genesis.rs @@ -3,6 +3,7 @@ use std::{thread, time::Duration}; use iroha::samples::{construct_executor, get_config}; use iroha_client::data_model::prelude::*; +use iroha_data_model::isi::InstructionBox; use iroha_genesis::{GenesisNetwork, RawGenesisBlock, RawGenesisBlockBuilder}; use iroha_primitives::unique_vec; use test_network::{ @@ -64,8 +65,8 @@ fn create_million_accounts_directly() { format!("bob-{i}").parse().expect("Valid"), domain_id.clone(), ); - let create_domain = RegisterBox::domain(Domain::new(domain_id)); - let create_account = RegisterBox::account(Account::new(normal_account_id.clone(), [])); + let create_domain: InstructionBox = Register::domain(Domain::new(domain_id)).into(); + let create_account = Register::account(Account::new(normal_account_id.clone(), [])).into(); if test_client .submit_all([create_domain, create_account]) .is_err() diff --git a/client/examples/tutorial.rs b/client/examples/tutorial.rs index 4eed1f06ca2..5cc86cd8495 100644 --- a/client/examples/tutorial.rs +++ b/client/examples/tutorial.rs @@ -50,7 +50,7 @@ fn domain_registration_test(config: &Configuration) -> Result<(), Error> { client::Client, data_model::{ metadata::UnlimitedMetadata, - prelude::{Domain, DomainId, InstructionBox, RegisterBox}, + prelude::{Domain, DomainId, InstructionBox, Register}, }, }; // #endregion domain_register_example_crates @@ -62,7 +62,7 @@ fn domain_registration_test(config: &Configuration) -> Result<(), Error> { // #region domain_register_example_create_isi // Create an ISI - let create_looking_glass = RegisterBox::domain(Domain::new(looking_glass)); + let create_looking_glass = Register::domain(Domain::new(looking_glass)); // #endregion domain_register_example_create_isi // #region rust_client_create @@ -116,7 +116,7 @@ fn account_registration_test(config: &Configuration) -> Result<(), Error> { client::Client, data_model::{ metadata::UnlimitedMetadata, - prelude::{Account, AccountId, InstructionBox, RegisterBox}, + prelude::{Account, AccountId, InstructionBox, Register}, }, }; use iroha_crypto::KeyPair; @@ -140,7 +140,7 @@ fn account_registration_test(config: &Configuration) -> Result<(), Error> { // #region register_account_generate // Generate a new account - let create_account = RegisterBox::account(Account::new(account_id, [public_key])); + let create_account = Register::account(Account::new(account_id, [public_key])); // #endregion register_account_generate // #region register_account_prepare_tx @@ -167,7 +167,7 @@ fn asset_registration_test(config: &Configuration) -> Result<(), Error> { use iroha_client::{ client::Client, data_model::prelude::{ - AccountId, AssetDefinition, AssetDefinitionId, AssetId, MintBox, RegisterBox, + AccountId, AssetDefinition, AssetDefinitionId, AssetId, Mint, Register, }, }; // #endregion register_asset_crates @@ -184,7 +184,7 @@ fn asset_registration_test(config: &Configuration) -> Result<(), Error> { // #region register_asset_init_submit // Initialise the registration time let register_time = - RegisterBox::asset_definition(AssetDefinition::fixed(asset_def_id.clone()).mintable_once()); + Register::asset_definition(AssetDefinition::fixed(asset_def_id.clone()).mintable_once()); // Submit a registration time iroha_client.submit(register_time)?; @@ -197,7 +197,7 @@ fn asset_registration_test(config: &Configuration) -> Result<(), Error> { // #region register_asset_mint_submit // Create a MintBox using a previous asset and account - let mint = MintBox::asset_fixed( + let mint = Mint::asset_fixed( 12.34_f64.try_into()?, AssetId::new(asset_def_id, account_id), ); @@ -216,7 +216,7 @@ fn asset_minting_test(config: &Configuration) -> Result<(), Error> { use iroha_client::{ client::Client, - data_model::prelude::{AccountId, AssetDefinitionId, AssetId, MintBox}, + data_model::prelude::{AccountId, AssetDefinitionId, AssetId, Mint}, }; // #endregion mint_asset_crates @@ -233,7 +233,7 @@ fn asset_minting_test(config: &Configuration) -> Result<(), Error> { // Mint the Asset instance // #region mint_asset_mint - let mint_roses = MintBox::asset_quantity(42_u32, AssetId::new(roses, alice)); + let mint_roses = Mint::asset_quantity(42_u32, AssetId::new(roses, alice)); // #endregion mint_asset_mint // #region mint_asset_submit_tx @@ -248,7 +248,7 @@ fn asset_minting_test(config: &Configuration) -> Result<(), Error> { // or `roses.to_string() + "#" + alice.to_string()`. // The `##` is a short-hand for the rose `which belongs to the same domain as the account // to which it belongs to. - let mint_roses_alt = MintBox::asset_quantity(10_u32, "rose##alice@wonderland".parse()?); + let mint_roses_alt = Mint::asset_quantity(10_u32, "rose##alice@wonderland".parse()?); // #endregion mint_asset_mint_alt // #region mint_asset_submit_tx_alt @@ -267,7 +267,7 @@ fn asset_burning_test(config: &Configuration) -> Result<(), Error> { use iroha_client::{ client::Client, - data_model::prelude::{AccountId, AssetDefinitionId, AssetId, BurnBox}, + data_model::prelude::{AccountId, AssetDefinitionId, AssetId, Burn}, }; // #endregion burn_asset_crates @@ -284,7 +284,7 @@ fn asset_burning_test(config: &Configuration) -> Result<(), Error> { // #region burn_asset_burn // Burn the Asset instance - let burn_roses = BurnBox::asset_quantity(10_u32, AssetId::new(roses, alice)); + let burn_roses = Burn::asset_quantity(10_u32, AssetId::new(roses, alice)); // #endregion burn_asset_burn // #region burn_asset_submit_tx @@ -299,7 +299,7 @@ fn asset_burning_test(config: &Configuration) -> Result<(), Error> { // or `roses.to_string() + "#" + alice.to_string()`. // The `##` is a short-hand for the rose `which belongs to the same domain as the account // to which it belongs to. - let burn_roses_alt = BurnBox::asset_quantity(10_u32, "rose##alice@wonderland".parse()?); + let burn_roses_alt = Burn::asset_quantity(10_u32, "rose##alice@wonderland".parse()?); // #endregion burn_asset_burn_alt // #region burn_asset_submit_tx_alt diff --git a/client/tests/integration/add_account.rs b/client/tests/integration/add_account.rs index 5c2f12d527d..bdec9441783 100644 --- a/client/tests/integration/add_account.rs +++ b/client/tests/integration/add_account.rs @@ -13,14 +13,14 @@ fn client_add_account_with_name_length_more_than_limit_should_not_commit_transac let pipeline_time = super::Configuration::pipeline_time(); let normal_account_id: AccountId = "bob@wonderland".parse().expect("Valid"); - let create_account = RegisterBox::account(Account::new(normal_account_id.clone(), [])); + let create_account = Register::account(Account::new(normal_account_id.clone(), [])); test_client.submit(create_account)?; let too_long_account_name = "0".repeat(2_usize.pow(14)); let incorrect_account_id: AccountId = (too_long_account_name + "@wonderland") .parse() .expect("Valid"); - let create_account = RegisterBox::account(Account::new(incorrect_account_id.clone(), [])); + let create_account = Register::account(Account::new(incorrect_account_id.clone(), [])); test_client.submit(create_account)?; thread::sleep(pipeline_time * 2); diff --git a/client/tests/integration/add_domain.rs b/client/tests/integration/add_domain.rs index 325906cfdd2..09bf95bb90d 100644 --- a/client/tests/integration/add_domain.rs +++ b/client/tests/integration/add_domain.rs @@ -16,11 +16,11 @@ fn client_add_domain_with_name_length_more_than_limit_should_not_commit_transact // Given let normal_domain_id: DomainId = "sora".parse()?; - let create_domain = RegisterBox::domain(Domain::new(normal_domain_id.clone())); + let create_domain = Register::domain(Domain::new(normal_domain_id.clone())); test_client.submit(create_domain)?; let too_long_domain_name: DomainId = "0".repeat(2_usize.pow(14)).parse()?; - let create_domain = RegisterBox::domain(Domain::new(too_long_domain_name.clone())); + let create_domain = Register::domain(Domain::new(too_long_domain_name.clone())); test_client.submit(create_domain)?; thread::sleep(pipeline_time * 2); diff --git a/client/tests/integration/asset.rs b/client/tests/integration/asset.rs index 7c2b163c00b..2cd3cab768f 100644 --- a/client/tests/integration/asset.rs +++ b/client/tests/integration/asset.rs @@ -6,6 +6,7 @@ use iroha_client::{ data_model::prelude::*, }; use iroha_crypto::{KeyPair, PublicKey}; +use iroha_data_model::isi::InstructionBox; use iroha_primitives::fixed::Fixed; use serde_json::json; use test_network::*; @@ -21,12 +22,13 @@ fn client_register_asset_should_add_asset_once_but_not_twice() -> Result<()> { let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("test_asset#wonderland").expect("Valid"); - let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); - let register_asset = RegisterBox::asset(Asset::new( + let create_asset: InstructionBox = + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())).into(); + let register_asset: InstructionBox = Register::asset(Asset::new( AssetId::new(asset_definition_id.clone(), account_id.clone()), AssetValue::Quantity(0), - )); + )) + .into(); test_client.submit_all([create_asset, register_asset.clone()])?; @@ -57,10 +59,11 @@ fn unregister_asset_should_remove_asset_from_account() -> Result<()> { let asset_definition_id = AssetDefinitionId::from_str("test_asset#wonderland").expect("Valid"); let asset_id = AssetId::new(asset_definition_id.clone(), account_id.clone()); - let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); - let register_asset = RegisterBox::asset(Asset::new(asset_id.clone(), AssetValue::Quantity(0))); - let unregister_asset = UnregisterBox::asset(asset_id); + let create_asset: InstructionBox = + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())).into(); + let register_asset = + Register::asset(Asset::new(asset_id.clone(), AssetValue::Quantity(0))).into(); + let unregister_asset = Unregister::asset(asset_id); test_client.submit_all([create_asset, register_asset])?; @@ -96,11 +99,11 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount() -> let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); let metadata = iroha_client::data_model::metadata::UnlimitedMetadata::default(); //When let quantity: u32 = 200; - let mint = MintBox::asset_quantity( + let mint = Mint::asset_quantity( quantity, AssetId::new(asset_definition_id.clone(), account_id.clone()), ); @@ -127,11 +130,11 @@ fn client_add_big_asset_quantity_to_existing_asset_should_increase_asset_amount( let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let create_asset = - RegisterBox::asset_definition(AssetDefinition::big_quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::big_quantity(asset_definition_id.clone())); let metadata = iroha_client::data_model::metadata::UnlimitedMetadata::default(); //When let quantity: u128 = 2_u128.pow(65); - let mint = MintBox::asset_big_quantity( + let mint = Mint::asset_big_quantity( quantity, AssetId::new(asset_definition_id.clone(), account_id.clone()), ); @@ -158,12 +161,12 @@ fn client_add_asset_with_decimal_should_increase_asset_amount() -> Result<()> { let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let asset_definition = AssetDefinition::fixed(asset_definition_id.clone()); - let create_asset = RegisterBox::asset_definition(asset_definition); + let create_asset = Register::asset_definition(asset_definition); let metadata = iroha_client::data_model::metadata::UnlimitedMetadata::default(); //When let quantity: Fixed = Fixed::try_from(123.456_f64).unwrap(); - let mint = MintBox::asset_fixed( + let mint = Mint::asset_fixed( quantity, AssetId::new(asset_definition_id.clone(), account_id.clone()), ); @@ -181,7 +184,7 @@ fn client_add_asset_with_decimal_should_increase_asset_amount() -> Result<()> { // Add some fractional part let quantity2: Fixed = Fixed::try_from(0.55_f64).unwrap(); - let mint = MintBox::asset_fixed( + let mint = Mint::asset_fixed( quantity2, AssetId::new(asset_definition_id.clone(), account_id.clone()), ); @@ -208,7 +211,7 @@ fn client_add_asset_with_name_length_more_than_limit_should_not_commit_transacti // Given let normal_asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::asset_definition(AssetDefinition::quantity( + let create_asset = Register::asset_definition(AssetDefinition::quantity( normal_asset_definition_id.clone(), )); test_client.submit(create_asset)?; @@ -217,7 +220,7 @@ fn client_add_asset_with_name_length_more_than_limit_should_not_commit_transacti let too_long_asset_name = "0".repeat(2_usize.pow(14)); let incorrect_asset_definition_id = AssetDefinitionId::from_str(&(too_long_asset_name + "#wonderland")).expect("Valid"); - let create_asset = RegisterBox::asset_definition(AssetDefinition::quantity( + let create_asset = Register::asset_definition(AssetDefinition::quantity( incorrect_asset_definition_id.clone(), )); @@ -264,11 +267,11 @@ fn find_rate_and_make_exchange_isi_should_succeed() { let buyer_keypair = KeyPair::generate().expect("Failed to generate seller KeyPair."); let register_account = |account_id: AccountId, signature: PublicKey| { - RegisterBox::account(Account::new(account_id, [signature])) + Register::account(Account::new(account_id, [signature])) }; let grant_alice_asset_transfer_permission = |asset_id: AssetId, owner_keypair: KeyPair| { - let allow_alice_to_transfer_asset = GrantBox::permission_token( + let allow_alice_to_transfer_asset = Grant::permission_token( PermissionToken::new( "CanTransferUserAsset".parse().unwrap(), &json!({ "asset_id": asset_id }), @@ -305,17 +308,17 @@ fn find_rate_and_make_exchange_isi_should_succeed() { register::asset_definition("btc", "crypto").into(), register::asset_definition("eth", "crypto").into(), register::asset_definition("btc2eth_rate", "exchange").into(), - MintBox::asset_quantity( + Mint::asset_quantity( 200_u32, asset_id_new("eth", "crypto", buyer_account_id.clone()), ) .into(), - MintBox::asset_quantity( + Mint::asset_quantity( 20_u32, asset_id_new("btc", "crypto", seller_account_id.clone()), ) .into(), - MintBox::asset_quantity(20_u32, asset_id.clone()).into(), + Mint::asset_quantity(20_u32, asset_id.clone()).into(), ]; test_client .submit_all_blocking(instructions) @@ -333,12 +336,12 @@ fn find_rate_and_make_exchange_isi_should_succeed() { }; test_client .submit_all_blocking([ - TransferBox::asset_quantity( + Transfer::asset_quantity( asset_id_new("btc", "crypto", seller_account_id.clone()), to_transfer, buyer_account_id.clone(), ), - TransferBox::asset_quantity( + Transfer::asset_quantity( asset_id_new("eth", "crypto", buyer_account_id), to_transfer, seller_account_id, @@ -397,7 +400,7 @@ fn transfer_asset_definition() { let asset_definition_id: AssetDefinitionId = "asset#wonderland".parse().expect("Valid"); test_client - .submit_blocking(RegisterBox::asset_definition(AssetDefinition::quantity( + .submit_blocking(Register::asset_definition(AssetDefinition::quantity( asset_definition_id.clone(), ))) .expect("Failed to submit transaction"); @@ -408,7 +411,7 @@ fn transfer_asset_definition() { assert_eq!(asset_definition.owned_by(), &alice_id); test_client - .submit_blocking(TransferBox::asset_definition( + .submit_blocking(Transfer::asset_definition( alice_id, asset_definition_id.clone(), bob_id.clone(), @@ -441,12 +444,12 @@ fn asset_id_new(definition_name: &str, definition_domain: &str, account_id: Acco mod register { use super::*; - pub fn domain(name: &str) -> RegisterBox { - RegisterBox::domain(Domain::new(DomainId::from_str(name).expect("Valid"))) + pub fn domain(name: &str) -> Register { + Register::domain(Domain::new(DomainId::from_str(name).expect("Valid"))) } - pub fn account(account_name: &str, domain_name: &str) -> RegisterBox { - RegisterBox::account(Account::new( + pub fn account(account_name: &str, domain_name: &str) -> Register { + Register::account(Account::new( AccountId::new( account_name.parse().expect("Valid"), domain_name.parse().expect("Valid"), @@ -455,8 +458,8 @@ mod register { )) } - pub fn asset_definition(asset_name: &str, domain_name: &str) -> RegisterBox { - RegisterBox::asset_definition(AssetDefinition::quantity(AssetDefinitionId::new( + pub fn asset_definition(asset_name: &str, domain_name: &str) -> Register { + Register::asset_definition(AssetDefinition::quantity(AssetDefinitionId::new( asset_name.parse().expect("Valid"), domain_name.parse().expect("Valid"), ))) diff --git a/client/tests/integration/asset_propagation.rs b/client/tests/integration/asset_propagation.rs index 5366958c0f2..de7a5238418 100644 --- a/client/tests/integration/asset_propagation.rs +++ b/client/tests/integration/asset_propagation.rs @@ -9,6 +9,7 @@ use iroha_client::{ }, }; use iroha_crypto::KeyPair; +use iroha_data_model::isi::InstructionBox; use test_network::*; use super::Configuration; @@ -27,18 +28,19 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount_on_a .into_set_parameters(), )?; - let create_domain = RegisterBox::domain(Domain::new(DomainId::from_str("domain")?)); + let create_domain: InstructionBox = + Register::domain(Domain::new(DomainId::from_str("domain")?)).into(); let account_id = AccountId::from_str("account@domain")?; let (public_key, _) = KeyPair::generate()?.into(); - let create_account = RegisterBox::account(Account::new(account_id.clone(), [public_key])); + let create_account = Register::account(Account::new(account_id.clone(), [public_key])).into(); let asset_definition_id = AssetDefinitionId::from_str("xor#domain")?; let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())).into(); client.submit_all([create_domain, create_account, create_asset])?; thread::sleep(pipeline_time * 3); //When let quantity: u32 = 200; - client.submit(MintBox::asset_quantity( + client.submit(Mint::asset_quantity( quantity, AssetId::new(asset_definition_id.clone(), account_id.clone()), ))?; diff --git a/client/tests/integration/burn_public_keys.rs b/client/tests/integration/burn_public_keys.rs index e4edae6d5bd..fb4c54b2251 100644 --- a/client/tests/integration/burn_public_keys.rs +++ b/client/tests/integration/burn_public_keys.rs @@ -51,7 +51,7 @@ fn public_keys_cannot_be_burned_to_nothing() { wait_for_genesis_committed(&vec![client.clone()], 0); let charlie_initial_keypair = KeyPair::generate().unwrap(); - let register_charlie = RegisterBox::account(Account::new( + let register_charlie = Register::account(Account::new( charlie_id.clone(), [charlie_initial_keypair.public_key().clone()], )); @@ -64,7 +64,7 @@ fn public_keys_cannot_be_burned_to_nothing() { let mint_keys = (0..KEYS_COUNT - 1).map(|_| { let (public_key, _) = KeyPair::generate().unwrap().into(); - MintBox::account_public_key(public_key, charlie_id.clone()) + Mint::account_public_key(public_key, charlie_id.clone()) }); let (tx_hash, res) = submit( @@ -80,7 +80,7 @@ fn public_keys_cannot_be_burned_to_nothing() { let charlie = client.request(account::by_id(charlie_id.clone())).unwrap(); let mut keys = charlie.signatories(); let burn = - |key: PublicKey| InstructionBox::from(BurnBox::account_public_key(key, charlie_id.clone())); + |key: PublicKey| InstructionBox::from(Burn::account_public_key(key, charlie_id.clone())); let burn_keys_leaving_one = keys .by_ref() .filter(|pub_key| pub_key != &charlie_initial_keypair.public_key()) diff --git a/client/tests/integration/connected_peers.rs b/client/tests/integration/connected_peers.rs index 40e10bc6fdd..91745b15ff8 100644 --- a/client/tests/integration/connected_peers.rs +++ b/client/tests/integration/connected_peers.rs @@ -52,7 +52,7 @@ fn connected_peers_with_f(faults: u64, start_port: Option) -> Result<()> { // then `status.peers` decrements let peer = network.peers.values().last().unwrap(); let peer_client = Client::test(&peer.api_address); - let unregister_peer = UnregisterBox::peer(peer.id.clone()); + let unregister_peer = Unregister::peer(peer.id.clone()); client.submit_blocking(unregister_peer)?; thread::sleep(pipeline_time * 2); // Wait for some time to allow peers to connect status = client.get_status()?; @@ -63,7 +63,7 @@ fn connected_peers_with_f(faults: u64, start_port: Option) -> Result<()> { // Re-register the peer: committed with f = `faults` - 1 then // `status.peers` increments - let register_peer = RegisterBox::peer(DataModelPeer::new(peer.id.clone())); + let register_peer = Register::peer(DataModelPeer::new(peer.id.clone())); client.submit_blocking(register_peer)?; thread::sleep(pipeline_time * 4); // Wait for some time to allow peers to connect status = client.get_status()?; diff --git a/client/tests/integration/domain_owner.rs b/client/tests/integration/domain_owner.rs index 1d15c58cdf1..b420d5e81c2 100644 --- a/client/tests/integration/domain_owner.rs +++ b/client/tests/integration/domain_owner.rs @@ -13,17 +13,13 @@ fn domain_owner_domain_permissions() -> Result<()> { // "alice@wonderland" is owner of "kingdom" domain let kingdom = Domain::new(kingdom_id.clone()); - test_client.submit_blocking(RegisterBox::domain(kingdom))?; + test_client.submit_blocking(Register::domain(kingdom))?; // check that "alice@wonderland" as owner of domain can edit metadata in her domain let key: Name = "key".parse()?; let value: Name = "value".parse()?; - test_client.submit_blocking(SetKeyValueBox::domain( - kingdom_id.clone(), - key.clone(), - value, - ))?; - test_client.submit_blocking(RemoveKeyValueBox::domain(kingdom_id.clone(), key))?; + test_client.submit_blocking(SetKeyValue::domain(kingdom_id.clone(), key.clone(), value))?; + test_client.submit_blocking(RemoveKeyValue::domain(kingdom_id.clone(), key))?; // check that "alice@wonderland" as owner of domain can grant and revoke domain related permission tokens let bob_id: AccountId = "bob@wonderland".parse()?; @@ -31,11 +27,11 @@ fn domain_owner_domain_permissions() -> Result<()> { "CanUnregisterDomain".parse().unwrap(), &json!({ "domain_id": kingdom_id }), ); - test_client.submit_blocking(GrantBox::permission_token(token.clone(), bob_id.clone()))?; - test_client.submit_blocking(RevokeBox::permission_token(token, bob_id))?; + test_client.submit_blocking(Grant::permission_token(token.clone(), bob_id.clone()))?; + test_client.submit_blocking(Revoke::permission_token(token, bob_id))?; // check that "alice@wonderland" as owner of domain can unregister her domain - test_client.submit_blocking(UnregisterBox::domain(kingdom_id))?; + test_client.submit_blocking(Unregister::domain(kingdom_id))?; Ok(()) } @@ -50,28 +46,28 @@ fn domain_owner_account_permissions() -> Result<()> { // "alice@wonderland" is owner of "kingdom" domain let kingdom = Domain::new(kingdom_id); - test_client.submit_blocking(RegisterBox::domain(kingdom))?; + test_client.submit_blocking(Register::domain(kingdom))?; let mad_hatter_keypair = KeyPair::generate()?; let mad_hatter = Account::new( mad_hatter_id.clone(), [mad_hatter_keypair.public_key().clone()], ); - test_client.submit_blocking(RegisterBox::account(mad_hatter))?; + test_client.submit_blocking(Register::account(mad_hatter))?; // check that "alice@wonderland" as owner of domain can burn and mint public keys for accounts in her domain let mad_hatter_new_keypair = KeyPair::generate()?; - test_client.submit_blocking(MintBox::account_public_key( + test_client.submit_blocking(Mint::account_public_key( mad_hatter_new_keypair.public_key().clone(), mad_hatter_id.clone(), ))?; - test_client.submit_blocking(BurnBox::account_public_key( + test_client.submit_blocking(Burn::account_public_key( mad_hatter_new_keypair.public_key().clone(), mad_hatter_id.clone(), ))?; // check that "alice@wonderland" as owner of domain can change signature check condition for accounts in her domain - test_client.submit_blocking(MintBox::account_signature_check_condition( + test_client.submit_blocking(Mint::account_signature_check_condition( SignatureCheckCondition::AnyAccountSignatureOr(Vec::new().into()), mad_hatter_id.clone(), ))?; @@ -79,12 +75,12 @@ fn domain_owner_account_permissions() -> Result<()> { // check that "alice@wonderland" as owner of domain can edit metadata of account in her domain let key: Name = "key".parse()?; let value: Name = "value".parse()?; - test_client.submit_blocking(SetKeyValueBox::account( + test_client.submit_blocking(SetKeyValue::account( mad_hatter_id.clone(), key.clone(), value, ))?; - test_client.submit_blocking(RemoveKeyValueBox::account(mad_hatter_id.clone(), key))?; + test_client.submit_blocking(RemoveKeyValue::account(mad_hatter_id.clone(), key))?; // check that "alice@wonderland" as owner of domain can grant and revoke account related permission tokens in her domain let bob_id: AccountId = "bob@wonderland".parse()?; @@ -92,11 +88,11 @@ fn domain_owner_account_permissions() -> Result<()> { "CanUnregisterAccount".parse().unwrap(), &json!({ "account_id": mad_hatter_id }), ); - test_client.submit_blocking(GrantBox::permission_token(token.clone(), bob_id.clone()))?; - test_client.submit_blocking(RevokeBox::permission_token(token, bob_id))?; + test_client.submit_blocking(Grant::permission_token(token.clone(), bob_id.clone()))?; + test_client.submit_blocking(Revoke::permission_token(token, bob_id))?; // check that "alice@wonderland" as owner of domain can unregister accounts in her domain - test_client.submit_blocking(UnregisterBox::account(mad_hatter_id))?; + test_client.submit_blocking(Unregister::account(mad_hatter_id))?; Ok(()) } @@ -113,24 +109,24 @@ fn domain_owner_asset_definition_permissions() -> Result<()> { // "alice@wonderland" is owner of "kingdom" domain let kingdom = Domain::new(kingdom_id); - test_client.submit_blocking(RegisterBox::domain(kingdom))?; + test_client.submit_blocking(Register::domain(kingdom))?; let bob_keypair = KeyPair::generate()?; let bob = Account::new(bob_id.clone(), [bob_keypair.public_key().clone()]); - test_client.submit_blocking(RegisterBox::account(bob))?; + test_client.submit_blocking(Register::account(bob))?; let rabbit = Account::new(rabbit_id.clone(), []); - test_client.submit_blocking(RegisterBox::account(rabbit))?; + test_client.submit_blocking(Register::account(rabbit))?; // register asset definitions by "bob@kingdom" so he is owner of it let coin = AssetDefinition::quantity(coin_id.clone()); let transaction = TransactionBuilder::new(bob_id.clone()) - .with_instructions([RegisterBox::asset_definition(coin)]) + .with_instructions([Register::asset_definition(coin)]) .sign(bob_keypair)?; test_client.submit_transaction_blocking(&transaction)?; // check that "alice@wonderland" as owner of domain can transfer asset definitions in her domain - test_client.submit_blocking(TransferBox::asset_definition( + test_client.submit_blocking(Transfer::asset_definition( bob_id, coin_id.clone(), rabbit_id, @@ -139,12 +135,12 @@ fn domain_owner_asset_definition_permissions() -> Result<()> { // check that "alice@wonderland" as owner of domain can edit metadata of asset definition in her domain let key: Name = "key".parse()?; let value: Name = "value".parse()?; - test_client.submit_blocking(SetKeyValueBox::asset_definition( + test_client.submit_blocking(SetKeyValue::asset_definition( coin_id.clone(), key.clone(), value, ))?; - test_client.submit_blocking(RemoveKeyValueBox::asset_definition(coin_id.clone(), key))?; + test_client.submit_blocking(RemoveKeyValue::asset_definition(coin_id.clone(), key))?; // check that "alice@wonderland" as owner of domain can grant and revoke asset definition related permission tokens in her domain let bob_id: AccountId = "bob@wonderland".parse()?; @@ -152,11 +148,11 @@ fn domain_owner_asset_definition_permissions() -> Result<()> { "CanUnregisterAssetDefinition".parse().unwrap(), &json!({ "asset_definition_id": coin_id }), ); - test_client.submit_blocking(GrantBox::permission_token(token.clone(), bob_id.clone()))?; - test_client.submit_blocking(RevokeBox::permission_token(token, bob_id))?; + test_client.submit_blocking(Grant::permission_token(token.clone(), bob_id.clone()))?; + test_client.submit_blocking(Revoke::permission_token(token, bob_id))?; // check that "alice@wonderland" as owner of domain can unregister asset definitions in her domain - test_client.submit_blocking(UnregisterBox::asset_definition(coin_id))?; + test_client.submit_blocking(Unregister::asset_definition(coin_id))?; Ok(()) } @@ -174,19 +170,19 @@ fn domain_owner_asset_permissions() -> Result<()> { // "alice@wonderland" is owner of "kingdom" domain let kingdom = Domain::new(kingdom_id); - test_client.submit_blocking(RegisterBox::domain(kingdom))?; + test_client.submit_blocking(Register::domain(kingdom))?; let bob_keypair = KeyPair::generate()?; let bob = Account::new(bob_id.clone(), [bob_keypair.public_key().clone()]); - test_client.submit_blocking(RegisterBox::account(bob))?; + test_client.submit_blocking(Register::account(bob))?; // register asset definitions by "bob@kingdom" so he is owner of it let coin = AssetDefinition::quantity(coin_id.clone()); let store = AssetDefinition::store(store_id.clone()); let transaction = TransactionBuilder::new(bob_id.clone()) .with_instructions([ - RegisterBox::asset_definition(coin), - RegisterBox::asset_definition(store), + Register::asset_definition(coin), + Register::asset_definition(store), ]) .sign(bob_keypair)?; test_client.submit_transaction_blocking(&transaction)?; @@ -194,24 +190,20 @@ fn domain_owner_asset_permissions() -> Result<()> { // check that "alice@wonderland" as owner of domain can register and unregister assets in her domain let bob_coin_id = AssetId::new(coin_id, bob_id.clone()); let bob_coin = Asset::new(bob_coin_id.clone(), 30u32); - test_client.submit_blocking(RegisterBox::asset(bob_coin))?; - test_client.submit_blocking(UnregisterBox::asset(bob_coin_id.clone()))?; + test_client.submit_blocking(Register::asset(bob_coin))?; + test_client.submit_blocking(Unregister::asset(bob_coin_id.clone()))?; // check that "alice@wonderland" as owner of domain can burn, mint and transfer assets in her domain - test_client.submit_blocking(MintBox::asset_quantity(10u32, bob_coin_id.clone()))?; - test_client.submit_blocking(BurnBox::asset_quantity(5u32, bob_coin_id.clone()))?; - test_client.submit_blocking(TransferBox::asset_quantity(bob_coin_id, 5u32, alice_id))?; + test_client.submit_blocking(Mint::asset_quantity(10u32, bob_coin_id.clone()))?; + test_client.submit_blocking(Burn::asset_quantity(5u32, bob_coin_id.clone()))?; + test_client.submit_blocking(Transfer::asset_quantity(bob_coin_id, 5u32, alice_id))?; // check that "alice@wonderland" as owner of domain can edit metadata of store asset in her domain let key: Name = "key".parse()?; let value: Name = "value".parse()?; let bob_store_id = AssetId::new(store_id, bob_id); - test_client.submit_blocking(SetKeyValueBox::asset( - bob_store_id.clone(), - key.clone(), - value, - ))?; - test_client.submit_blocking(RemoveKeyValueBox::asset(bob_store_id.clone(), key))?; + test_client.submit_blocking(SetKeyValue::asset(bob_store_id.clone(), key.clone(), value))?; + test_client.submit_blocking(RemoveKeyValue::asset(bob_store_id.clone(), key))?; // check that "alice@wonderland" as owner of domain can grant and revoke asset related permission tokens in her domain let bob_id: AccountId = "bob@wonderland".parse()?; @@ -219,8 +211,8 @@ fn domain_owner_asset_permissions() -> Result<()> { "CanUnregisterUserAsset".parse().unwrap(), &json!({ "asset_id": bob_store_id }), ); - test_client.submit_blocking(GrantBox::permission_token(token.clone(), bob_id.clone()))?; - test_client.submit_blocking(RevokeBox::permission_token(token, bob_id))?; + test_client.submit_blocking(Grant::permission_token(token.clone(), bob_id.clone()))?; + test_client.submit_blocking(Revoke::permission_token(token, bob_id))?; Ok(()) } @@ -236,18 +228,18 @@ fn domain_owner_trigger_permissions() -> Result<()> { // "alice@wonderland" is owner of "kingdom" domain let kingdom = Domain::new(kingdom_id); - test_client.submit_blocking(RegisterBox::domain(kingdom))?; + test_client.submit_blocking(Register::domain(kingdom))?; let bob_keypair = KeyPair::generate()?; let bob = Account::new(bob_id.clone(), [bob_keypair.public_key().clone()]); - test_client.submit_blocking(RegisterBox::account(bob))?; + test_client.submit_blocking(Register::account(bob))?; let asset_definition_id = "rose#wonderland".parse()?; let asset_id = AssetId::new(asset_definition_id, alice_id.clone()); let trigger_id: TriggerId = "trigger$kingdom".parse()?; - let trigger_instructions = vec![MintBox::asset_quantity(1_u32, asset_id)]; - let register_trigger = RegisterBox::trigger(Trigger::new( + let trigger_instructions = vec![Mint::asset_quantity(1_u32, asset_id)]; + let register_trigger = Register::trigger(Trigger::new( trigger_id.clone(), Action::new( trigger_instructions, @@ -263,8 +255,8 @@ fn domain_owner_trigger_permissions() -> Result<()> { test_client.submit_blocking(register_trigger)?; // check that "alice@wonderland" as owner of domain can edit repetitions of triggers in her domain - test_client.submit_blocking(MintBox::trigger_repetitions(1_u32, trigger_id.clone()))?; - test_client.submit_blocking(BurnBox::trigger_repetitions(1_u32, trigger_id.clone()))?; + test_client.submit_blocking(Mint::trigger_repetitions(1_u32, trigger_id.clone()))?; + test_client.submit_blocking(Burn::trigger_repetitions(1_u32, trigger_id.clone()))?; // check that "alice@wonderland" as owner of domain can call triggers in her domain let execute_trigger = ExecuteTrigger::new(trigger_id.clone()); @@ -276,11 +268,11 @@ fn domain_owner_trigger_permissions() -> Result<()> { "CanUnregisterUserTrigger".parse().unwrap(), &json!({ "trigger_id": trigger_id }), ); - test_client.submit_blocking(GrantBox::permission_token(token.clone(), bob_id.clone()))?; - test_client.submit_blocking(RevokeBox::permission_token(token, bob_id))?; + test_client.submit_blocking(Grant::permission_token(token.clone(), bob_id.clone()))?; + test_client.submit_blocking(Revoke::permission_token(token, bob_id))?; // check that "alice@wonderland" as owner of domain can unregister triggers in her domain - test_client.submit_blocking(UnregisterBox::trigger(trigger_id))?; + test_client.submit_blocking(Unregister::trigger(trigger_id))?; Ok(()) } @@ -297,17 +289,17 @@ fn domain_owner_transfer() -> Result<()> { // "alice@wonderland" is owner of "kingdom" domain let kingdom = Domain::new(kingdom_id.clone()); - test_client.submit_blocking(RegisterBox::domain(kingdom))?; + test_client.submit_blocking(Register::domain(kingdom))?; let bob_keypair = KeyPair::generate()?; let bob = Account::new(bob_id.clone(), [bob_keypair.public_key().clone()]); - test_client.submit_blocking(RegisterBox::account(bob))?; + test_client.submit_blocking(Register::account(bob))?; let domain = test_client.request(FindDomainById::new(kingdom_id.clone()))?; assert_eq!(domain.owned_by(), &alice_id); test_client - .submit_blocking(TransferBox::domain( + .submit_blocking(Transfer::domain( alice_id, kingdom_id.clone(), bob_id.clone(), diff --git a/client/tests/integration/events/data.rs b/client/tests/integration/events/data.rs index 1bd72a4102f..96380155fca 100644 --- a/client/tests/integration/events/data.rs +++ b/client/tests/integration/events/data.rs @@ -14,7 +14,7 @@ fn produce_instructions() -> Vec { domains .into_iter() - .map(RegisterBox::domain) + .map(Register::domain) .map(InstructionBox::from) .collect::>() } @@ -152,16 +152,16 @@ fn produce_multiple_events() -> Result<()> { let role = iroha_client::data_model::role::Role::new(role_id.clone()) .add_permission(token_1.clone()) .add_permission(token_2.clone()); - let instructions = [RegisterBox::role(role.clone())]; + let instructions = [Register::role(role.clone())]; client.submit_all_blocking(instructions)?; // Grants role to Bob let bob_id = AccountId::from_str("bob@wonderland")?; - let grant_role = GrantBox::role(role_id.clone(), bob_id.clone()); + let grant_role = Grant::role(role_id.clone(), bob_id.clone()); client.submit_blocking(grant_role)?; // Unregister role - let unregister_role = UnregisterBox::role(role_id.clone()); + let unregister_role = Unregister::role(role_id.clone()); client.submit_blocking(unregister_role)?; // Inspect produced events diff --git a/client/tests/integration/events/notification.rs b/client/tests/integration/events/notification.rs index 8e15dc34e6c..2cd033e2b7c 100644 --- a/client/tests/integration/events/notification.rs +++ b/client/tests/integration/events/notification.rs @@ -14,8 +14,8 @@ fn trigger_completion_success_should_produce_event() -> Result<()> { let asset_id = AssetId::new(asset_definition_id, account_id); let trigger_id = TriggerId::from_str("mint_rose")?; - let instruction = MintBox::asset_quantity(1_u32, asset_id.clone()); - let register_trigger = RegisterBox::trigger(Trigger::new( + let instruction = Mint::asset_quantity(1_u32, asset_id.clone()); + let register_trigger = Register::trigger(Trigger::new( trigger_id.clone(), Action::new( vec![InstructionBox::from(instruction)], @@ -64,7 +64,7 @@ fn trigger_completion_failure_should_produce_event() -> Result<()> { let trigger_id = TriggerId::from_str("fail_box")?; let instruction = Fail::new("Fail box".to_owned()); - let register_trigger = RegisterBox::trigger(Trigger::new( + let register_trigger = Register::trigger(Trigger::new( trigger_id.clone(), Action::new( vec![InstructionBox::from(instruction)], diff --git a/client/tests/integration/multiple_blocks_created.rs b/client/tests/integration/multiple_blocks_created.rs index 071993f5c77..aa3f3a551ba 100644 --- a/client/tests/integration/multiple_blocks_created.rs +++ b/client/tests/integration/multiple_blocks_created.rs @@ -9,6 +9,7 @@ use iroha_client::{ }, }; use iroha_crypto::KeyPair; +use iroha_data_model::isi::InstructionBox; use test_network::*; use super::Configuration; @@ -29,13 +30,13 @@ fn long_multiple_blocks_created() -> Result<()> { .into_set_parameters(), )?; - let create_domain = RegisterBox::domain(Domain::new("domain".parse()?)); + let create_domain: InstructionBox = Register::domain(Domain::new("domain".parse()?)).into(); let account_id: AccountId = "account@domain".parse()?; let (public_key, _) = KeyPair::generate()?.into(); - let create_account = RegisterBox::account(Account::new(account_id.clone(), [public_key])); + let create_account = Register::account(Account::new(account_id.clone(), [public_key])).into(); let asset_definition_id: AssetDefinitionId = "xor#domain".parse()?; let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())).into(); client.submit_all([create_domain, create_account, create_asset])?; @@ -45,7 +46,7 @@ fn long_multiple_blocks_created() -> Result<()> { //When for _ in 0..N_BLOCKS { let quantity: u32 = 1; - let mint_asset = MintBox::asset_quantity( + let mint_asset = Mint::asset_quantity( quantity, AssetId::new(asset_definition_id.clone(), account_id.clone()), ); diff --git a/client/tests/integration/multisignature_account.rs b/client/tests/integration/multisignature_account.rs index be1296d74b7..9f35fb9bbfa 100644 --- a/client/tests/integration/multisignature_account.rs +++ b/client/tests/integration/multisignature_account.rs @@ -20,17 +20,16 @@ fn transaction_signed_by_new_signatory_of_account_should_pass() -> Result<()> { let account_id: AccountId = "alice@wonderland".parse().expect("Valid"); let asset_definition_id: AssetDefinitionId = "xor#wonderland".parse().expect("Valid"); let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); let key_pair = KeyPair::generate()?; - let add_signatory = - MintBox::account_public_key(key_pair.public_key().clone(), account_id.clone()); + let add_signatory = Mint::account_public_key(key_pair.public_key().clone(), account_id.clone()); let instructions: [InstructionBox; 2] = [create_asset.into(), add_signatory.into()]; client.submit_all(instructions)?; thread::sleep(pipeline_time * 2); //When let quantity: u32 = 200; - let mint_asset = MintBox::asset_quantity( + let mint_asset = Mint::asset_quantity( quantity, AssetId::new(asset_definition_id.clone(), account_id.clone()), ); diff --git a/client/tests/integration/multisignature_transaction.rs b/client/tests/integration/multisignature_transaction.rs index 3fd8c80b8f8..280a07751f3 100644 --- a/client/tests/integration/multisignature_transaction.rs +++ b/client/tests/integration/multisignature_transaction.rs @@ -32,8 +32,8 @@ fn multisignature_transactions_should_wait_for_all_signatures() -> Result<()> { let key_pair_2 = KeyPair::generate()?; let asset_definition_id = AssetDefinitionId::from_str("camomile#wonderland")?; let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); - let set_signature_condition = MintBox::account_signature_check_condition( + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + let set_signature_condition = Mint::account_signature_check_condition( SignatureCheckCondition::AllAccountSignaturesAnd( vec![key_pair_2.public_key().clone()].into(), ), @@ -48,7 +48,7 @@ fn multisignature_transactions_should_wait_for_all_signatures() -> Result<()> { //When let quantity: u32 = 200; let asset_id = AssetId::new(asset_definition_id, alice_id.clone()); - let mint_asset = MintBox::asset_quantity(quantity, asset_id.clone()); + let mint_asset = Mint::asset_quantity(quantity, asset_id.clone()); let (public_key1, private_key1) = alice_key_pair.into(); client_configuration.account_id = alice_id.clone(); diff --git a/client/tests/integration/non_mintable.rs b/client/tests/integration/non_mintable.rs index d2bde541848..c80be2ca4d9 100644 --- a/client/tests/integration/non_mintable.rs +++ b/client/tests/integration/non_mintable.rs @@ -5,6 +5,7 @@ use iroha_client::{ client::{self, QueryResult}, data_model::{metadata::UnlimitedMetadata, prelude::*}, }; +use iroha_data_model::isi::InstructionBox; use test_network::*; #[test] @@ -15,13 +16,13 @@ fn non_mintable_asset_can_be_minted_once_but_not_twice() -> Result<()> { // Given let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::asset_definition( + let create_asset = Register::asset_definition( AssetDefinition::quantity(asset_definition_id.clone()).mintable_once(), ); let metadata = UnlimitedMetadata::default(); - let mint = MintBox::asset_quantity( + let mint = Mint::asset_quantity( 200_u32, AssetId::new(asset_definition_id.clone(), account_id.clone()), ); @@ -63,12 +64,14 @@ fn non_mintable_asset_cannot_be_minted_if_registered_with_non_zero_value() -> Re // Given let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::asset_definition( + let create_asset: InstructionBox = Register::asset_definition( AssetDefinition::quantity(asset_definition_id.clone()).mintable_once(), - ); + ) + .into(); let asset_id = AssetId::new(asset_definition_id.clone(), account_id.clone()); - let register_asset = RegisterBox::asset(Asset::new(asset_id.clone(), 1_u32)); + let register_asset: InstructionBox = + Register::asset(Asset::new(asset_id.clone(), 1_u32)).into(); // We can register the non-mintable token test_client.submit_all([create_asset, register_asset.clone()])?; @@ -84,7 +87,7 @@ fn non_mintable_asset_cannot_be_minted_if_registered_with_non_zero_value() -> Re assert!(test_client.submit_blocking(register_asset).is_err()); // And can't be minted - let mint = MintBox::asset_quantity(1_u32, asset_id); + let mint = Mint::asset_quantity(1_u32, asset_id); assert!(test_client.submit_blocking(mint).is_err()); Ok(()) @@ -98,13 +101,13 @@ fn non_mintable_asset_can_be_minted_if_registered_with_zero_value() -> Result<() // Given let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::asset_definition( + let create_asset = Register::asset_definition( AssetDefinition::quantity(asset_definition_id.clone()).mintable_once(), ); let asset_id = AssetId::new(asset_definition_id.clone(), account_id.clone()); - let register_asset = RegisterBox::asset(Asset::new(asset_id.clone(), 0_u32)); - let mint = MintBox::asset_quantity(1_u32, asset_id); + let register_asset = Register::asset(Asset::new(asset_id.clone(), 0_u32)); + let mint = Mint::asset_quantity(1_u32, asset_id); // We can register the non-mintable token wih zero value and then mint it let instructions: [InstructionBox; 3] = diff --git a/client/tests/integration/pagination.rs b/client/tests/integration/pagination.rs index 30221d101c7..6e0ed462ec2 100644 --- a/client/tests/integration/pagination.rs +++ b/client/tests/integration/pagination.rs @@ -50,7 +50,7 @@ fn register_assets(client: &Client) -> Result<()> { .map(|c| c.to_string()) .map(|name| (name + "#wonderland").parse().expect("Valid")) .map(|asset_definition_id| { - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id)).into() + Register::asset_definition(AssetDefinition::quantity(asset_definition_id)).into() }) .collect(); let _ = client.submit_all_blocking(register)?; diff --git a/client/tests/integration/permissions.rs b/client/tests/integration/permissions.rs index dea4bce29a6..fb829ed2ce3 100644 --- a/client/tests/integration/permissions.rs +++ b/client/tests/integration/permissions.rs @@ -18,7 +18,7 @@ fn genesis_transactions_are_validated() { let mut genesis = GenesisNetwork::test(true).expect("Expected genesis"); - let grant_invalid_token = GrantBox::permission_token( + let grant_invalid_token = Grant::permission_token( PermissionToken::new("InvalidToken".parse().unwrap(), &json!(null)), AccountId::from_str("alice@wonderland").unwrap(), ); @@ -79,7 +79,7 @@ fn permissions_disallow_asset_transfer() { let mouse_id: AccountId = "mouse@wonderland".parse().expect("Valid"); let asset_definition_id: AssetDefinitionId = "xor#wonderland".parse().expect("Valid"); let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); let mouse_keypair = iroha_crypto::KeyPair::generate().expect("Failed to generate KeyPair."); let alice_start_assets = get_assets(&iroha_client, &alice_id); @@ -88,7 +88,7 @@ fn permissions_disallow_asset_transfer() { .expect("Failed to prepare state."); let quantity: u32 = 200; - let mint_asset = MintBox::asset_quantity( + let mint_asset = Mint::asset_quantity( quantity, AssetId::new(asset_definition_id.clone(), bob_id.clone()), ); @@ -97,7 +97,7 @@ fn permissions_disallow_asset_transfer() { .expect("Failed to create asset."); //When - let transfer_asset = TransferBox::asset_quantity( + let transfer_asset = Transfer::asset_quantity( AssetId::new(asset_definition_id, bob_id), quantity, alice_id.clone(), @@ -133,7 +133,7 @@ fn permissions_disallow_asset_burn() { let mouse_id: AccountId = "mouse@wonderland".parse().expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); let mouse_keypair = iroha_crypto::KeyPair::generate().expect("Failed to generate KeyPair."); let alice_start_assets = get_assets(&iroha_client, &alice_id); @@ -144,11 +144,11 @@ fn permissions_disallow_asset_burn() { let quantity: u32 = 200; let mint_asset = - MintBox::asset_quantity(quantity, AssetId::new(asset_definition_id.clone(), bob_id)); + Mint::asset_quantity(quantity, AssetId::new(asset_definition_id.clone(), bob_id)); iroha_client .submit_blocking(mint_asset) .expect("Failed to create asset."); - let burn_asset = BurnBox::asset_quantity( + let burn_asset = Burn::asset_quantity( quantity, AssetId::new(asset_definition_id, mouse_id.clone()), ); @@ -184,7 +184,7 @@ fn account_can_query_only_its_own_domain() -> Result<()> { // Given let domain_id: DomainId = "wonderland".parse()?; let new_domain_id: DomainId = "wonderland2".parse()?; - let register_domain = RegisterBox::domain(Domain::new(new_domain_id.clone())); + let register_domain = Register::domain(Domain::new(new_domain_id.clone())); client.submit_blocking(register_domain)?; @@ -213,20 +213,20 @@ fn permissions_differ_not_only_by_names() { let new_shoes_definition = AssetDefinition::store(shoes_definition_id.clone()); client .submit_all_blocking([ - RegisterBox::asset_definition(new_hat_definition), - RegisterBox::asset_definition(new_shoes_definition), + Register::asset_definition(new_hat_definition), + Register::asset_definition(new_shoes_definition), ]) .expect("Failed to register new asset definitions"); // Registering mouse let new_mouse_account = Account::new(mouse_id.clone(), [mouse_keypair.public_key().clone()]); client - .submit_blocking(RegisterBox::account(new_mouse_account)) + .submit_blocking(Register::account(new_mouse_account)) .expect("Failed to register mouse"); // Granting permission to Alice to modify metadata in Mouse's hats let mouse_hat_id = AssetId::new(hat_definition_id, mouse_id.clone()); - let allow_alice_to_set_key_value_in_hats = GrantBox::permission_token( + let allow_alice_to_set_key_value_in_hats = Grant::permission_token( PermissionToken::new( "CanSetKeyValueInUserAsset".parse().unwrap(), &json!({ "asset_id": mouse_hat_id }), @@ -244,7 +244,7 @@ fn permissions_differ_not_only_by_names() { // Checking that Alice can modify Mouse's hats ... client - .submit_blocking(SetKeyValueBox::asset( + .submit_blocking(SetKeyValue::asset( mouse_hat_id, Name::from_str("color").expect("Valid"), "red".to_owned(), @@ -253,7 +253,7 @@ fn permissions_differ_not_only_by_names() { // ... but not shoes let mouse_shoes_id = AssetId::new(shoes_definition_id, mouse_id.clone()); - let set_shoes_color = SetKeyValueBox::asset( + let set_shoes_color = SetKeyValue::asset( mouse_shoes_id.clone(), Name::from_str("color").expect("Valid"), "yellow".to_owned(), @@ -263,7 +263,7 @@ fn permissions_differ_not_only_by_names() { .expect_err("Expected Alice to fail to modify Mouse's shoes"); // Granting permission to Alice to modify metadata in Mouse's shoes - let allow_alice_to_set_key_value_in_shoes = GrantBox::permission_token( + let allow_alice_to_set_key_value_in_shoes = Grant::permission_token( PermissionToken::new( "CanSetKeyValueInUserAsset".parse().unwrap(), &json!({ "asset_id": mouse_shoes_id }), @@ -298,12 +298,12 @@ fn stored_vs_granted_token_payload() -> Result<()> { // Registering mouse and asset definition let asset_definition_id: AssetDefinitionId = "xor#wonderland".parse().expect("Valid"); let create_asset = - RegisterBox::asset_definition(AssetDefinition::store(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::store(asset_definition_id.clone())); let mouse_id: AccountId = "mouse@wonderland".parse().expect("Valid"); let mouse_keypair = iroha_crypto::KeyPair::generate().expect("Failed to generate KeyPair."); let new_mouse_account = Account::new(mouse_id.clone(), [mouse_keypair.public_key().clone()]); let instructions: [InstructionBox; 2] = [ - RegisterBox::account(new_mouse_account).into(), + Register::account(new_mouse_account).into(), create_asset.into(), ]; iroha_client @@ -312,7 +312,7 @@ fn stored_vs_granted_token_payload() -> Result<()> { // Allow alice to mint mouse asset and mint initial value let mouse_asset = AssetId::new(asset_definition_id, mouse_id.clone()); - let allow_alice_to_set_key_value_in_mouse_asset = GrantBox::permission_token( + let allow_alice_to_set_key_value_in_mouse_asset = Grant::permission_token( PermissionToken::from_str_unchecked( "CanSetKeyValueInUserAsset".parse().unwrap(), // NOTE: Introduced additional whitespaces in the serialized form @@ -330,8 +330,7 @@ fn stored_vs_granted_token_payload() -> Result<()> { .expect("Failed to grant permission to alice."); // Check that alice can indeed mint mouse asset - let set_key_value = - SetKeyValueBox::asset(mouse_asset, Name::from_str("color")?, "red".to_owned()); + let set_key_value = SetKeyValue::asset(mouse_asset, Name::from_str("color")?, "red".to_owned()); iroha_client .submit_blocking(set_key_value) .expect("Failed to mint asset for mouse."); diff --git a/client/tests/integration/queries/account.rs b/client/tests/integration/queries/account.rs index c21243efc6c..69d28c66e6f 100644 --- a/client/tests/integration/queries/account.rs +++ b/client/tests/integration/queries/account.rs @@ -15,7 +15,7 @@ fn find_accounts_with_asset() -> Result<()> { // Registering new asset definition let definition_id = AssetDefinitionId::from_str("test_coin#wonderland").expect("Valid"); let asset_definition = AssetDefinition::quantity(definition_id.clone()); - test_client.submit_blocking(RegisterBox::asset_definition(asset_definition.clone()))?; + test_client.submit_blocking(Register::asset_definition(asset_definition.clone()))?; // Checking results before all let received_asset_definition = @@ -40,7 +40,7 @@ fn find_accounts_with_asset() -> Result<()> { .iter() .skip(1) // Alice has already been registered in genesis .cloned() - .map(|account_id| RegisterBox::account(Account::new(account_id, []))) + .map(|account_id| Register::account(Account::new(account_id, []))) .collect::>(); test_client.submit_all_blocking(register_accounts)?; @@ -48,7 +48,7 @@ fn find_accounts_with_asset() -> Result<()> { .iter() .cloned() .map(|account_id| AssetId::new(definition_id.clone(), account_id)) - .map(|asset_id| MintBox::asset_quantity(1_u32, asset_id)) + .map(|asset_id| Mint::asset_quantity(1_u32, asset_id)) .collect::>(); test_client.submit_all_blocking(mint_asset)?; diff --git a/client/tests/integration/queries/asset.rs b/client/tests/integration/queries/asset.rs index 2f6a4996b96..bb34d302158 100644 --- a/client/tests/integration/queries/asset.rs +++ b/client/tests/integration/queries/asset.rs @@ -8,6 +8,7 @@ use iroha_client::{ }, }; use iroha_crypto::KeyPair; +use iroha_data_model::isi::Instruction; use iroha_primitives::fixed::Fixed; use test_network::*; @@ -20,7 +21,7 @@ fn find_asset_total_quantity() -> Result<()> { // Register new domain let domain_id: DomainId = "looking_glass".parse()?; let domain = Domain::new(domain_id); - test_client.submit_blocking(RegisterBox::domain(domain))?; + test_client.submit_blocking(Register::domain(domain))?; let accounts: [AccountId; 5] = [ "alice@wonderland".parse()?, @@ -41,7 +42,7 @@ fn find_asset_total_quantity() -> Result<()> { .skip(1) // Alice has already been registered in genesis .cloned() .zip(keys.iter().map(KeyPair::public_key).cloned()) - .map(|(account_id, public_key)| RegisterBox::account(Account::new(account_id, [public_key]))) + .map(|(account_id, public_key)| Register::account(Account::new(account_id, [public_key]))) .collect::>(); test_client.submit_all_blocking(register_accounts)?; @@ -55,8 +56,8 @@ fn find_asset_total_quantity() -> Result<()> { 10_u32, 5_u32, NumericValue::U32(30_u32), - MintBox::asset_quantity, - BurnBox::asset_quantity, + Mint::asset_quantity, + Burn::asset_quantity, )?; test_total_quantity( &test_client, @@ -67,8 +68,8 @@ fn find_asset_total_quantity() -> Result<()> { 10_u128, 5_u128, NumericValue::U128(30_u128), - MintBox::asset_big_quantity, - BurnBox::asset_big_quantity, + Mint::asset_big_quantity, + Burn::asset_big_quantity, )?; test_total_quantity( &test_client, @@ -79,14 +80,14 @@ fn find_asset_total_quantity() -> Result<()> { Fixed::try_from(10.0)?, Fixed::try_from(5.0)?, NumericValue::Fixed(Fixed::try_from(30.0)?), - MintBox::asset_fixed, - BurnBox::asset_fixed, + Mint::asset_fixed, + Burn::asset_fixed, )?; // Test for `Store` asset value type let definition_id: AssetDefinitionId = "store#wonderland".parse().expect("Valid"); let asset_definition = AssetDefinition::store(definition_id.clone()); - test_client.submit_blocking(RegisterBox::asset_definition(asset_definition))?; + test_client.submit_blocking(Register::asset_definition(asset_definition))?; let asset_ids = accounts .iter() @@ -104,7 +105,7 @@ fn find_asset_total_quantity() -> Result<()> { .iter() .cloned() .map(|asset_id| Asset::new(asset_id, Metadata::default())) - .map(RegisterBox::asset) + .map(Register::asset) .collect::>(); test_client.submit_all_blocking(register_assets)?; @@ -117,7 +118,7 @@ fn find_asset_total_quantity() -> Result<()> { let unregister_assets = asset_ids .iter() .cloned() - .map(UnregisterBox::asset) + .map(Unregister::asset) .collect::>(); test_client.submit_all_blocking(unregister_assets)?; @@ -128,7 +129,7 @@ fn find_asset_total_quantity() -> Result<()> { assert!(total_asset_quantity.is_zero_value()); // Unregister asset definition - test_client.submit_blocking(UnregisterBox::asset_definition(definition_id.clone()))?; + test_client.submit_blocking(Unregister::asset_definition(definition_id.clone()))?; // Assert that total asset quantity cleared with unregistering of asset definition let result = test_client.request(FindTotalAssetQuantityByAssetDefinitionId::new( @@ -145,7 +146,7 @@ fn find_asset_total_quantity() -> Result<()> { } #[allow(clippy::too_many_arguments)] -fn test_total_quantity>( +fn test_total_quantity( test_client: &Client, accounts: &[AccountId; 5], definition: &str, @@ -154,14 +155,20 @@ fn test_total_quantity>( to_mint: T, to_burn: T, expected_total_asset_quantity: NumericValue, - mint_ctr: impl Fn(T, AssetId) -> MintBox, - burn_ctr: impl Fn(T, AssetId) -> BurnBox, -) -> Result<()> { + mint_ctr: impl Fn(T, AssetId) -> Mint, + burn_ctr: impl Fn(T, AssetId) -> Burn, +) -> Result<()> +where + T: Copy + Into, + Value: From, + Mint: Instruction, + Burn: Instruction, +{ // Registering new asset definition let definition_id: AssetDefinitionId = definition.parse().expect("Failed to parse `definition_id`"); let asset_definition = AssetDefinition::new(definition_id.clone(), asset_value_type); - test_client.submit_blocking(RegisterBox::asset_definition(asset_definition))?; + test_client.submit_blocking(Register::asset_definition(asset_definition))?; let asset_ids = accounts .iter() @@ -179,7 +186,7 @@ fn test_total_quantity>( .iter() .cloned() .map(|asset_id| Asset::new(asset_id, initial_value)) - .map(RegisterBox::asset) + .map(Register::asset) .collect::>(); test_client.submit_all_blocking(register_assets)?; @@ -205,7 +212,7 @@ fn test_total_quantity>( let unregister_assets = asset_ids .iter() .cloned() - .map(UnregisterBox::asset) + .map(Unregister::asset) .collect::>(); test_client.submit_all_blocking(unregister_assets)?; @@ -216,7 +223,7 @@ fn test_total_quantity>( assert!(total_asset_quantity.is_zero_value()); // Unregister asset definition - test_client.submit_blocking(UnregisterBox::asset_definition(definition_id.clone()))?; + test_client.submit_blocking(Unregister::asset_definition(definition_id.clone()))?; // Assert that total asset quantity cleared with unregistering of asset definition let result = test_client.request(FindTotalAssetQuantityByAssetDefinitionId::new( diff --git a/client/tests/integration/queries/role.rs b/client/tests/integration/queries/role.rs index 996ea88cfc6..9d18b523910 100644 --- a/client/tests/integration/queries/role.rs +++ b/client/tests/integration/queries/role.rs @@ -29,7 +29,7 @@ fn find_roles() -> Result<()> { let register_roles = role_ids .iter() .cloned() - .map(|role_id| RegisterBox::role(Role::new(role_id))) + .map(|role_id| Register::role(Role::new(role_id))) .collect::>(); test_client.submit_all_blocking(register_roles)?; @@ -61,7 +61,7 @@ fn find_role_ids() -> Result<()> { let register_roles = role_ids .iter() .cloned() - .map(|role_id| RegisterBox::role(Role::new(role_id))) + .map(|role_id| Register::role(Role::new(role_id))) .collect::>(); test_client.submit_all_blocking(register_roles)?; @@ -87,7 +87,7 @@ fn find_role_by_id() -> Result<()> { let new_role = Role::new(role_id.clone()); // Registering role - let register_role = RegisterBox::role(new_role.clone()); + let register_role = Register::role(new_role.clone()); test_client.submit_blocking(register_role)?; let found_role = test_client.request(client::role::by_id(role_id))?; @@ -130,7 +130,7 @@ fn find_roles_by_account_id() -> Result<()> { .iter() .cloned() .map(|role_id| { - RegisterBox::role(Role::new(role_id).add_permission(PermissionToken::new( + Register::role(Role::new(role_id).add_permission(PermissionToken::new( "CanSetKeyValueInUserAccount".parse().unwrap(), &json!({ "account_id": alice_id }), ))) @@ -142,7 +142,7 @@ fn find_roles_by_account_id() -> Result<()> { let grant_roles = role_ids .iter() .cloned() - .map(|role_id| GrantBox::role(role_id, alice_id.clone())) + .map(|role_id| Grant::role(role_id, alice_id.clone())) .collect::>(); test_client.submit_all_blocking(grant_roles)?; diff --git a/client/tests/integration/restart_peer.rs b/client/tests/integration/restart_peer.rs index 24bec3fd62c..1699ae9763e 100644 --- a/client/tests/integration/restart_peer.rs +++ b/client/tests/integration/restart_peer.rs @@ -23,7 +23,7 @@ fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> { let account_id = AccountId::from_str("alice@wonderland").unwrap(); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").unwrap(); let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); let quantity: u32 = 200; let iroha_client = client::Client::test(&peer.api_address); @@ -39,7 +39,7 @@ fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> { wait_for_genesis_committed(&vec![iroha_client.clone()], 0); iroha_client.submit_blocking(create_asset)?; - let mint_asset = MintBox::asset_quantity( + let mint_asset = Mint::asset_quantity( quantity, AssetId::new(asset_definition_id.clone(), account_id.clone()), ); diff --git a/client/tests/integration/roles.rs b/client/tests/integration/roles.rs index 2bf0632e016..8523cfb39b6 100644 --- a/client/tests/integration/roles.rs +++ b/client/tests/integration/roles.rs @@ -14,7 +14,7 @@ fn register_empty_role() -> Result<()> { wait_for_genesis_committed(&vec![test_client.clone()], 0); let role_id = "root".parse().expect("Valid"); - let register_role = RegisterBox::role(Role::new(role_id)); + let register_role = Register::role(Role::new(role_id)); test_client.submit(register_role)?; Ok(()) @@ -29,7 +29,7 @@ fn register_role_with_empty_token_params() -> Result<()> { let token = PermissionToken::new("token".parse()?, &json!(null)); let role = Role::new(role_id).add_permission(token); - test_client.submit(RegisterBox::role(role))?; + test_client.submit(Register::role(role))?; Ok(()) } @@ -53,7 +53,7 @@ fn register_and_grant_role_for_metadata_access() -> Result<()> { // Registering Mouse let mouse_key_pair = iroha_crypto::KeyPair::generate()?; - let register_mouse = RegisterBox::account(Account::new( + let register_mouse = Register::account(Account::new( mouse_id.clone(), [mouse_key_pair.public_key().clone()], )); @@ -70,18 +70,18 @@ fn register_and_grant_role_for_metadata_access() -> Result<()> { "CanRemoveKeyValueInUserAccount".parse()?, &json!({ "account_id": mouse_id }), )); - let register_role = RegisterBox::role(role); + let register_role = Register::role(role); test_client.submit_blocking(register_role)?; // Mouse grants role to Alice - let grant_role = GrantBox::role(role_id.clone(), alice_id.clone()); + let grant_role = Grant::role(role_id.clone(), alice_id.clone()); let grant_role_tx = TransactionBuilder::new(mouse_id.clone()) .with_instructions([grant_role]) .sign(mouse_key_pair)?; test_client.submit_transaction_blocking(&grant_role_tx)?; // Alice modifies Mouse's metadata - let set_key_value = SetKeyValueBox::account( + let set_key_value = SetKeyValue::account( mouse_id, Name::from_str("key").expect("Valid"), Value::String("value".to_owned()), @@ -107,11 +107,11 @@ fn unregistered_role_removed_from_account() -> Result<()> { let mouse_id: AccountId = "mouse@wonderland".parse().expect("Valid"); // Registering Mouse - let register_mouse = RegisterBox::account(Account::new(mouse_id.clone(), [])); + let register_mouse = Register::account(Account::new(mouse_id.clone(), [])); test_client.submit_blocking(register_mouse)?; // Register root role - let register_role = RegisterBox::role(Role::new(role_id.clone()).add_permission( + let register_role = Register::role(Role::new(role_id.clone()).add_permission( PermissionToken::new( "CanSetKeyValueInUserAccount".parse()?, &json!({ "account_id": alice_id }), @@ -120,7 +120,7 @@ fn unregistered_role_removed_from_account() -> Result<()> { test_client.submit_blocking(register_role)?; // Grant root role to Mouse - let grant_role = GrantBox::role(role_id.clone(), mouse_id.clone()); + let grant_role = Grant::role(role_id.clone(), mouse_id.clone()); test_client.submit_blocking(grant_role)?; // Check that Mouse has root role @@ -130,7 +130,7 @@ fn unregistered_role_removed_from_account() -> Result<()> { assert!(found_mouse_roles.contains(&role_id)); // Unregister root role - let unregister_role = UnregisterBox::role(role_id.clone()); + let unregister_role = Unregister::role(role_id.clone()); test_client.submit_blocking(unregister_role)?; // Check that Mouse doesn't have the root role @@ -155,7 +155,7 @@ fn role_with_invalid_permissions_is_not_accepted() -> Result<()> { )); let err = test_client - .submit_blocking(RegisterBox::role(role)) + .submit_blocking(Register::role(role)) .expect_err("Submitting role with invalid permission token should fail"); let rejection_reason = err diff --git a/client/tests/integration/set_parameter.rs b/client/tests/integration/set_parameter.rs index 6ff409710b6..08012429e01 100644 --- a/client/tests/integration/set_parameter.rs +++ b/client/tests/integration/set_parameter.rs @@ -46,7 +46,7 @@ fn parameter_propagated() -> Result<()> { wait_for_genesis_committed(&vec![test_client.clone()], 0); let too_long_domain_name: DomainId = "0".repeat(2_usize.pow(8)).parse()?; - let create_domain = RegisterBox::domain(Domain::new(too_long_domain_name)); + let create_domain = Register::domain(Domain::new(too_long_domain_name)); let _ = test_client .submit_blocking(create_domain.clone()) .expect_err("Should fail before ident length limits update"); diff --git a/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs b/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs index 3cc5a5df9e2..bce2802adcb 100644 --- a/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs +++ b/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs @@ -43,10 +43,10 @@ fn main(_owner: AccountId, _event: Event) { let account_nft_id = AssetId::new(nft_id, account.id().clone()); let account_nft = Asset::new(account_nft_id, Metadata::new()); - RegisterBox::asset_definition(nft_definition) + Register::asset_definition(nft_definition) .execute() .dbg_unwrap(); - RegisterBox::asset(account_nft).execute().dbg_unwrap(); + Register::asset(account_nft).execute().dbg_unwrap(); } iroha_trigger::log::info!("Smart contract executed successfully"); diff --git a/client/tests/integration/smartcontracts/executor_with_admin/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_admin/src/lib.rs index 92cb6b1c9e8..8a950ee38cd 100644 --- a/client/tests/integration/smartcontracts/executor_with_admin/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_admin/src/lib.rs @@ -21,7 +21,7 @@ struct Executor { fn visit_instruction(executor: &mut Executor, authority: &AccountId, isi: &InstructionBox) { if parse!("admin@admin" as AccountId) == *authority { - pass!(executor); + execute!(executor, isi); } iroha_executor::default::visit_instruction(executor, authority, isi); diff --git a/client/tests/integration/smartcontracts/executor_with_custom_token/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_custom_token/src/lib.rs index 43ab94b72f4..bd9322a7f87 100644 --- a/client/tests/integration/smartcontracts/executor_with_custom_token/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_custom_token/src/lib.rs @@ -118,7 +118,7 @@ impl Executor { accounts .iter() .try_for_each(|(account, domain_id)| { - RevokeBox::permission_token( + Revoke::permission_token( PermissionToken::new( can_unregister_domain_definition_id.clone(), &json!({ "domain_id": domain_id }), @@ -137,7 +137,7 @@ impl Executor { ) })?; - GrantBox::permission_token( + Grant::permission_token( PermissionToken::new( can_control_domain_lives_definition_id.clone(), &json!(null), @@ -169,12 +169,12 @@ impl Executor { } } -fn visit_register_domain(executor: &mut Executor, authority: &AccountId, _isi: &Register) { +fn visit_register_domain(executor: &mut Executor, authority: &AccountId, isi: &Register) { if executor.block_height() == 0 { - pass!(executor) + execute!(executor, isi); } if token::CanControlDomainLives.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -186,13 +186,13 @@ fn visit_register_domain(executor: &mut Executor, authority: &AccountId, _isi: & fn visit_unregister_domain( executor: &mut Executor, authority: &AccountId, - _isi: &Unregister, + isi: &Unregister, ) { if executor.block_height() == 0 { - pass!(executor); + execute!(executor, isi); } if token::CanControlDomainLives.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "You don't have permission to unregister domain"); diff --git a/client/tests/integration/smartcontracts/executor_with_migration_fail/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_migration_fail/src/lib.rs index 69c6dad9871..e603758dd1d 100644 --- a/client/tests/integration/smartcontracts/executor_with_migration_fail/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_migration_fail/src/lib.rs @@ -27,7 +27,7 @@ pub fn migrate(_block_height: u64) -> MigrationResult { // Registering a new domain (using ISI) let domain_id = parse!("failed_migration_test_domain" as DomainId); - RegisterBox::domain(Domain::new(domain_id)) + Register::domain(Domain::new(domain_id)) .execute() .map_err(|error| { format!( diff --git a/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs b/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs index cac419a3c37..f794772bebd 100644 --- a/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs +++ b/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs @@ -20,7 +20,7 @@ fn main(owner: AccountId, _event: Event) { .dbg_expect("Failed to parse `rose#wonderland` asset definition id"); let rose_id = AssetId::new(rose_definition_id, owner); - MintBox::asset_quantity(1_u32, rose_id) + Mint::asset_quantity(1_u32, rose_id) .execute() .dbg_expect("Failed to mint rose"); } diff --git a/client/tests/integration/smartcontracts/query_assets_and_save_cursor/src/lib.rs b/client/tests/integration/smartcontracts/query_assets_and_save_cursor/src/lib.rs index 66b078b2acf..87137474596 100644 --- a/client/tests/integration/smartcontracts/query_assets_and_save_cursor/src/lib.rs +++ b/client/tests/integration/smartcontracts/query_assets_and_save_cursor/src/lib.rs @@ -26,7 +26,7 @@ fn main(owner: AccountId) { let (_batch, cursor) = asset_cursor.into_raw_parts(); - SetKeyValueBox::account( + SetKeyValue::account( owner, parse!("cursor" as Name), Value::String( diff --git a/client/tests/integration/sorting.rs b/client/tests/integration/sorting.rs index f12f80bc36a..19f69f3b86e 100644 --- a/client/tests/integration/sorting.rs +++ b/client/tests/integration/sorting.rs @@ -14,6 +14,7 @@ use iroha_client::{ query::{Pagination, Sorting}, }, }; +use iroha_data_model::isi::InstructionBox; use test_network::*; #[test] @@ -46,8 +47,9 @@ fn correct_pagination_assets_after_creating_new_one() { assets.push(asset.clone()); - let create_asset_definition = RegisterBox::asset_definition(asset_definition); - let create_asset = RegisterBox::asset(asset); + let create_asset_definition: InstructionBox = + Register::asset_definition(asset_definition).into(); + let create_asset = Register::asset(asset).into(); instructions.push(create_asset_definition); instructions.push(create_asset); @@ -94,8 +96,9 @@ fn correct_pagination_assets_after_creating_new_one() { AssetValue::Store(new_asset_metadata), ); - let create_asset_definition = RegisterBox::asset_definition(new_asset_definition); - let create_asset = RegisterBox::asset(new_asset.clone()); + let create_asset_definition: InstructionBox = + Register::asset_definition(new_asset_definition).into(); + let create_asset = Register::asset(new_asset.clone()).into(); test_client .submit_all_blocking([create_asset_definition, create_asset]) @@ -153,7 +156,7 @@ fn correct_sorting_of_entities() { metadata_of_assets.push(asset_metadata); asset_definitions.push(asset_definition_id); - let create_asset_definition = RegisterBox::asset_definition(asset_definition); + let create_asset_definition = Register::asset_definition(asset_definition); instructions.push(create_asset_definition); } @@ -203,7 +206,7 @@ fn correct_sorting_of_entities() { accounts.push(account_id); metadata_of_accounts.push(account_metadata); - let create_account = RegisterBox::account(account); + let create_account = Register::account(account); instructions.push(create_account); } @@ -249,7 +252,7 @@ fn correct_sorting_of_entities() { domains.push(domain_id); metadata_of_domains.push(domain_metadata); - let create_account = RegisterBox::domain(domain); + let create_account = Register::domain(domain); instructions.push(create_account); } @@ -294,7 +297,7 @@ fn correct_sorting_of_entities() { domains.push(domain_id); metadata_of_domains.push(domain_metadata); - let create_account = RegisterBox::domain(domain); + let create_account = Register::domain(domain); instructions.push(create_account); } test_client @@ -356,7 +359,7 @@ fn sort_only_elements_which_have_sorting_key() -> Result<()> { account }; - let create_account = RegisterBox::account(account); + let create_account = Register::account(account); instructions.push(create_account); } diff --git a/client/tests/integration/transfer_asset.rs b/client/tests/integration/transfer_asset.rs index da844b08f3d..cbc23b190fa 100644 --- a/client/tests/integration/transfer_asset.rs +++ b/client/tests/integration/transfer_asset.rs @@ -3,6 +3,7 @@ use iroha_client::{ data_model::{prelude::*, Registered}, }; use iroha_crypto::KeyPair; +use iroha_data_model::isi::Instruction; use iroha_primitives::fixed::Fixed; use test_network::*; @@ -12,8 +13,8 @@ fn simulate_transfer_quantity() { 200_u32, &20_u32, AssetDefinition::quantity, - MintBox::asset_quantity, - TransferBox::asset_quantity, + Mint::asset_quantity, + Transfer::asset_quantity, 10_710, ) } @@ -24,8 +25,8 @@ fn simulate_transfer_big_quantity() { 200_u128, &20_u128, AssetDefinition::big_quantity, - MintBox::asset_big_quantity, - TransferBox::asset_big_quantity, + Mint::asset_big_quantity, + Transfer::asset_big_quantity, 10_785, ) } @@ -36,8 +37,8 @@ fn simulate_transfer_fixed() { Fixed::try_from(200_f64).expect("Valid"), &Fixed::try_from(20_f64).expect("Valid"), AssetDefinition::fixed, - MintBox::asset_fixed, - TransferBox::asset_fixed, + Mint::asset_fixed, + Transfer::asset_fixed, 10_790, ) } @@ -50,21 +51,24 @@ fn simulate_insufficient_funds() { Fixed::try_from(20_f64).expect("Valid"), &Fixed::try_from(200_f64).expect("Valid"), AssetDefinition::fixed, - MintBox::asset_fixed, - TransferBox::asset_fixed, + Mint::asset_fixed, + Transfer::asset_fixed, 10_800, ) } -fn simulate_transfer>( +fn simulate_transfer( starting_amount: T, amount_to_transfer: &T, asset_definition_ctr: impl FnOnce(AssetDefinitionId) -> ::With, - mint_ctr: impl FnOnce(T, AssetId) -> MintBox, - transfer_ctr: impl FnOnce(AssetId, T, AccountId) -> TransferBox, + mint_ctr: impl FnOnce(T, AssetId) -> Mint, + transfer_ctr: impl FnOnce(AssetId, T, AccountId) -> Transfer, port_number: u16, ) where + T: std::fmt::Debug + Clone + Into, Value: From, + Mint: Instruction, + Transfer: Instruction, { let (_rt, _peer, iroha_client) = ::new() .with_port(port_number) @@ -76,10 +80,10 @@ fn simulate_transfer>( let (bob_public_key, _) = KeyPair::generate() .expect("Failed to generate KeyPair") .into(); - let create_mouse = RegisterBox::account(Account::new(mouse_id.clone(), [bob_public_key])); + let create_mouse = Register::account(Account::new(mouse_id.clone(), [bob_public_key])); let asset_definition_id: AssetDefinitionId = "camomile#wonderland".parse().expect("Valid"); let create_asset = - RegisterBox::asset_definition(asset_definition_ctr(asset_definition_id.clone())); + Register::asset_definition(asset_definition_ctr(asset_definition_id.clone())); let mint_asset = mint_ctr( starting_amount, AssetId::new(asset_definition_id.clone(), alice_id.clone()), diff --git a/client/tests/integration/triggers/by_call_trigger.rs b/client/tests/integration/triggers/by_call_trigger.rs index 31862f45478..41644169a73 100644 --- a/client/tests/integration/triggers/by_call_trigger.rs +++ b/client/tests/integration/triggers/by_call_trigger.rs @@ -9,6 +9,7 @@ use iroha_client::{ transaction::Executable, }, }; +use iroha_data_model::events::TriggeringFilterBox; use iroha_genesis::GenesisNetwork; use iroha_logger::info; use test_network::*; @@ -25,7 +26,7 @@ fn call_execute_trigger() -> Result<()> { let asset_id = AssetId::new(asset_definition_id, account_id); let prev_value = get_asset_value(&mut test_client, asset_id.clone())?; - let instruction = MintBox::asset_quantity(1_u32, asset_id.clone()); + let instruction = Mint::asset_quantity(1_u32, asset_id.clone()); let register_trigger = build_register_trigger_isi(asset_id.clone(), vec![instruction.into()]); test_client.submit_blocking(register_trigger)?; @@ -48,7 +49,7 @@ fn execute_trigger_should_produce_event() -> Result<()> { let account_id: AccountId = "alice@wonderland".parse()?; let asset_id = AssetId::new(asset_definition_id, account_id.clone()); - let instruction = MintBox::asset_quantity(1_u32, asset_id.clone()); + let instruction = Mint::asset_quantity(1_u32, asset_id.clone()); let register_trigger = build_register_trigger_isi(asset_id, vec![instruction.into()]); test_client.submit_blocking(register_trigger)?; @@ -87,7 +88,7 @@ fn infinite_recursion_should_produce_one_call_per_block() -> Result<()> { let prev_value = get_asset_value(&mut test_client, asset_id.clone())?; let instructions = vec![ - MintBox::asset_quantity(1_u32, asset_id.clone()).into(), + Mint::asset_quantity(1_u32, asset_id.clone()).into(), call_trigger.clone().into(), ]; let register_trigger = build_register_trigger_isi(asset_id.clone(), instructions); @@ -114,7 +115,7 @@ fn trigger_failure_should_not_cancel_other_triggers_execution() -> Result<()> { let bad_trigger_id = TriggerId::from_str("bad_trigger")?; // Invalid instruction let bad_trigger_instructions = vec![Fail::new("Bad trigger".to_owned())]; - let register_bad_trigger = RegisterBox::trigger(Trigger::new( + let register_bad_trigger = Register::trigger(Trigger::new( bad_trigger_id.clone(), Action::new( bad_trigger_instructions, @@ -130,8 +131,8 @@ fn trigger_failure_should_not_cancel_other_triggers_execution() -> Result<()> { // Registering normal trigger let trigger_id = TriggerId::from_str(TRIGGER_NAME)?; - let trigger_instructions = vec![MintBox::asset_quantity(1_u32, asset_id.clone())]; - let register_trigger = RegisterBox::trigger(Trigger::new( + let trigger_instructions = vec![Mint::asset_quantity(1_u32, asset_id.clone())]; + let register_trigger = Register::trigger(Trigger::new( trigger_id, Action::new( trigger_instructions, @@ -165,8 +166,8 @@ fn trigger_should_not_be_executed_with_zero_repeats_count() -> Result<()> { let asset_id = AssetId::new(asset_definition_id, account_id.clone()); let trigger_id = TriggerId::from_str("self_modifying_trigger")?; - let trigger_instructions = vec![MintBox::asset_quantity(1_u32, asset_id.clone())]; - let register_trigger = RegisterBox::trigger(Trigger::new( + let trigger_instructions = vec![Mint::asset_quantity(1_u32, asset_id.clone())]; + let register_trigger = Register::trigger(Trigger::new( trigger_id.clone(), Action::new( trigger_instructions, @@ -224,10 +225,10 @@ fn trigger_should_be_able_to_modify_its_own_repeats_count() -> Result<()> { let trigger_id = TriggerId::from_str("self_modifying_trigger")?; let trigger_instructions = vec![ - MintBox::trigger_repetitions(1_u32, trigger_id.clone()), - MintBox::asset_quantity(1_u32, asset_id.clone()), + InstructionBox::from(Mint::trigger_repetitions(1_u32, trigger_id.clone())), + InstructionBox::from(Mint::asset_quantity(1_u32, asset_id.clone())), ]; - let register_trigger = RegisterBox::trigger(Trigger::new( + let register_trigger = Register::trigger(Trigger::new( trigger_id.clone(), Action::new( trigger_instructions, @@ -279,7 +280,7 @@ fn unregister_trigger() -> Result<()> { )), ), ); - let register_trigger = RegisterBox::trigger(trigger.clone()); + let register_trigger = Register::trigger(trigger.clone()); test_client.submit_blocking(register_trigger)?; // Finding trigger @@ -303,7 +304,7 @@ fn unregister_trigger() -> Result<()> { assert_eq!(found_trigger, trigger); // Unregistering trigger - let unregister_trigger = UnregisterBox::trigger(trigger_id); + let unregister_trigger = Unregister::trigger(trigger_id); test_client.submit_blocking(unregister_trigger)?; // Checking result @@ -362,7 +363,7 @@ fn trigger_in_genesis_using_base64() -> Result<()> { let tx_ref = &mut genesis.transactions[0].0; match &mut tx_ref.payload_mut().instructions { Executable::Instructions(instructions) => { - instructions.push(RegisterBox::trigger(trigger).into()); + instructions.push(Register::trigger(trigger).into()); } Executable::Wasm(_) => panic!("Expected instructions"), } @@ -399,10 +400,9 @@ fn trigger_should_be_able_to_modify_other_trigger() -> Result<()> { let trigger_id_unregister = TriggerId::from_str("unregister_other_trigger")?; let trigger_id_to_be_unregistered = TriggerId::from_str("should_be_unregistered_trigger")?; - let trigger_unregister_instructions = vec![UnregisterBox::trigger( - trigger_id_to_be_unregistered.clone(), - )]; - let register_trigger = RegisterBox::trigger(Trigger::new( + let trigger_unregister_instructions = + vec![Unregister::trigger(trigger_id_to_be_unregistered.clone())]; + let register_trigger = Register::trigger(Trigger::new( trigger_id_unregister.clone(), Action::new( trigger_unregister_instructions, @@ -417,8 +417,8 @@ fn trigger_should_be_able_to_modify_other_trigger() -> Result<()> { test_client.submit_blocking(register_trigger)?; let trigger_should_be_unregistered_instructions = - vec![MintBox::asset_quantity(1_u32, asset_id.clone())]; - let register_trigger = RegisterBox::trigger(Trigger::new( + vec![Mint::asset_quantity(1_u32, asset_id.clone())]; + let register_trigger = Register::trigger(Trigger::new( trigger_id_to_be_unregistered.clone(), Action::new( trigger_should_be_unregistered_instructions, @@ -461,8 +461,8 @@ fn trigger_burn_repetitions() -> Result<()> { let asset_id = AssetId::new(asset_definition_id, account_id.clone()); let trigger_id = TriggerId::from_str("trigger")?; - let trigger_instructions = vec![MintBox::asset_quantity(1_u32, asset_id)]; - let register_trigger = RegisterBox::trigger(Trigger::new( + let trigger_instructions = vec![Mint::asset_quantity(1_u32, asset_id)]; + let register_trigger = Register::trigger(Trigger::new( trigger_id.clone(), Action::new( trigger_instructions, @@ -476,7 +476,7 @@ fn trigger_burn_repetitions() -> Result<()> { )); test_client.submit_blocking(register_trigger)?; - test_client.submit_blocking(BurnBox::trigger_repetitions(1_u32, trigger_id.clone()))?; + test_client.submit_blocking(Burn::trigger_repetitions(1_u32, trigger_id.clone()))?; // Executing trigger let execute_trigger = ExecuteTrigger::new(trigger_id); @@ -495,10 +495,10 @@ fn get_asset_value(client: &mut Client, asset_id: AssetId) -> Result { fn build_register_trigger_isi( asset_id: AssetId, trigger_instructions: Vec, -) -> RegisterBox { +) -> Register> { let trigger_id: TriggerId = TRIGGER_NAME.parse().expect("Valid"); - RegisterBox::trigger(Trigger::new( + Register::trigger(Trigger::new( trigger_id.clone(), Action::new( trigger_instructions, diff --git a/client/tests/integration/triggers/data_trigger.rs b/client/tests/integration/triggers/data_trigger.rs index 7e09d794341..e7096f7b024 100644 --- a/client/tests/integration/triggers/data_trigger.rs +++ b/client/tests/integration/triggers/data_trigger.rs @@ -13,8 +13,8 @@ fn must_execute_both_triggers() -> Result<()> { let prev_value = get_asset_value(&test_client, asset_id.clone())?; - let instruction = MintBox::asset_quantity(1_u32, asset_id.clone()); - let register_trigger = RegisterBox::trigger(Trigger::new( + let instruction = Mint::asset_quantity(1_u32, asset_id.clone()); + let register_trigger = Register::trigger(Trigger::new( "mint_rose_1".parse()?, Action::new( [instruction.clone()], @@ -27,7 +27,7 @@ fn must_execute_both_triggers() -> Result<()> { )); test_client.submit_blocking(register_trigger)?; - let register_trigger = RegisterBox::trigger(Trigger::new( + let register_trigger = Register::trigger(Trigger::new( "mint_rose_2".parse()?, Action::new( [instruction], @@ -40,11 +40,11 @@ fn must_execute_both_triggers() -> Result<()> { )); test_client.submit_blocking(register_trigger)?; - test_client.submit_blocking(RegisterBox::account(Account::new( + test_client.submit_blocking(Register::account(Account::new( "bunny@wonderland".parse()?, [], )))?; - test_client.submit_blocking(RegisterBox::domain(Domain::new("neverland".parse()?)))?; + test_client.submit_blocking(Register::domain(Domain::new("neverland".parse()?)))?; let new_value = get_asset_value(&test_client, asset_id)?; assert_eq!(new_value, prev_value + 2); @@ -57,18 +57,19 @@ fn domain_scoped_trigger_must_be_executed_only_on_events_in_its_domain() -> Resu let (_rt, _peer, test_client) = ::new().with_port(10_655).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); - let create_neverland_domain = RegisterBox::domain(Domain::new("neverland".parse()?)); + let create_neverland_domain: InstructionBox = + Register::domain(Domain::new("neverland".parse()?)).into(); let account_id: AccountId = "sapporo@neverland".parse()?; - let create_sapporo_account = RegisterBox::account(Account::new(account_id.clone(), [])); + let create_sapporo_account = Register::account(Account::new(account_id.clone(), [])).into(); let asset_definition_id: AssetDefinitionId = "sakura#neverland".parse()?; let create_sakura_asset_definition = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())).into(); let asset_id = AssetId::new(asset_definition_id, account_id.clone()); let create_sakura_asset = - RegisterBox::asset(Asset::new(asset_id.clone(), AssetValue::Quantity(0))); + Register::asset(Asset::new(asset_id.clone(), AssetValue::Quantity(0))).into(); test_client.submit_all_blocking([ create_neverland_domain, @@ -79,10 +80,10 @@ fn domain_scoped_trigger_must_be_executed_only_on_events_in_its_domain() -> Resu let prev_value = get_asset_value(&test_client, asset_id.clone())?; - let register_trigger = RegisterBox::trigger(Trigger::new( + let register_trigger = Register::trigger(Trigger::new( "mint_sakura$neverland".parse()?, Action::new( - [MintBox::asset_quantity(1_u32, asset_id.clone())], + [Mint::asset_quantity(1_u32, asset_id.clone())], Repeats::Indefinitely, account_id, TriggeringFilterBox::Data(BySome(DataEntityFilter::ByAccount(BySome( @@ -92,12 +93,12 @@ fn domain_scoped_trigger_must_be_executed_only_on_events_in_its_domain() -> Resu )); test_client.submit_blocking(register_trigger)?; - test_client.submit_blocking(RegisterBox::account(Account::new( + test_client.submit_blocking(Register::account(Account::new( "asahi@wonderland".parse()?, [], )))?; - test_client.submit_blocking(RegisterBox::account(Account::new( + test_client.submit_blocking(Register::account(Account::new( "asahi@neverland".parse()?, [], )))?; diff --git a/client/tests/integration/triggers/event_trigger.rs b/client/tests/integration/triggers/event_trigger.rs index 4f39c18690a..8269a244ad4 100644 --- a/client/tests/integration/triggers/event_trigger.rs +++ b/client/tests/integration/triggers/event_trigger.rs @@ -17,8 +17,8 @@ fn test_mint_asset_when_new_asset_definition_created() -> Result<()> { let asset_id = AssetId::new(asset_definition_id, account_id.clone()); let prev_value = get_asset_value(&mut test_client, asset_id.clone())?; - let instruction = MintBox::asset_quantity(1_u32, asset_id.clone()); - let register_trigger = RegisterBox::trigger(Trigger::new( + let instruction = Mint::asset_quantity(1_u32, asset_id.clone()); + let register_trigger = Register::trigger(Trigger::new( "mint_rose".parse()?, Action::new( vec![instruction], @@ -36,7 +36,7 @@ fn test_mint_asset_when_new_asset_definition_created() -> Result<()> { let tea_definition_id = "tea#wonderland".parse()?; let register_tea_definition = - RegisterBox::asset_definition(AssetDefinition::quantity(tea_definition_id)); + Register::asset_definition(AssetDefinition::quantity(tea_definition_id)); test_client.submit_blocking(register_tea_definition)?; let new_value = get_asset_value(&mut test_client, asset_id)?; diff --git a/client/tests/integration/triggers/time_trigger.rs b/client/tests/integration/triggers/time_trigger.rs index 8797ec8ca9c..9b9c76d3fe6 100644 --- a/client/tests/integration/triggers/time_trigger.rs +++ b/client/tests/integration/triggers/time_trigger.rs @@ -44,8 +44,8 @@ fn time_trigger_execution_count_error_should_be_less_than_15_percent() -> Result let schedule = TimeSchedule::starting_at(start_time).with_period(Duration::from_millis(PERIOD_MS)); - let instruction = MintBox::asset_quantity(1_u32, asset_id.clone()); - let register_trigger = RegisterBox::trigger(Trigger::new( + let instruction = Mint::asset_quantity(1_u32, asset_id.clone()); + let register_trigger = Register::trigger(Trigger::new( "mint_rose".parse()?, Action::new( vec![instruction], @@ -97,12 +97,9 @@ fn change_asset_metadata_after_1_sec() -> Result<()> { let key = Name::from_str("petal")?; let schedule = TimeSchedule::starting_at(start_time + Duration::from_millis(PERIOD_MS)); - let instruction = SetKeyValueBox::asset_definition( - asset_definition_id.clone(), - key.clone(), - 3_u32.to_value(), - ); - let register_trigger = RegisterBox::trigger(Trigger::new( + let instruction = + SetKeyValue::asset_definition(asset_definition_id.clone(), key.clone(), 3_u32.to_value()); + let register_trigger = Register::trigger(Trigger::new( "change_rose_metadata".parse().expect("Valid"), Action::new( vec![instruction], @@ -147,8 +144,8 @@ fn pre_commit_trigger_should_be_executed() -> Result<()> { // Start listening BEFORE submitting any transaction not to miss any block committed event let event_listener = get_block_committed_event_listener(&test_client)?; - let instruction = MintBox::asset_quantity(1_u32, asset_id.clone()); - let register_trigger = RegisterBox::trigger(Trigger::new( + let instruction = Mint::asset_quantity(1_u32, asset_id.clone()); + let register_trigger = Register::trigger(Trigger::new( "mint_rose".parse()?, Action::new( vec![instruction], @@ -165,7 +162,7 @@ fn pre_commit_trigger_should_be_executed() -> Result<()> { prev_value = new_value; // ISI just to create a new block - let sample_isi = SetKeyValueBox::account( + let sample_isi = SetKeyValue::account( account_id.clone(), "key".parse::()?, String::from("value"), @@ -199,7 +196,7 @@ fn mint_nft_for_every_user_every_1_sec() -> Result<()> { .iter() .skip(1) // Alice has already been registered in genesis .cloned() - .map(|account_id| RegisterBox::account(Account::new(account_id, []))) + .map(|account_id| Register::account(Account::new(account_id, []))) .collect::>(); test_client.submit_all_blocking(register_accounts)?; @@ -223,7 +220,7 @@ fn mint_nft_for_every_user_every_1_sec() -> Result<()> { let start_time = current_time(); let schedule = TimeSchedule::starting_at(start_time).with_period(Duration::from_millis(TRIGGER_PERIOD_MS)); - let register_trigger = RegisterBox::trigger(Trigger::new( + let register_trigger = Register::trigger(Trigger::new( "mint_nft_for_all".parse()?, Action::new( WasmSmartContract::from_compiled(wasm), @@ -298,7 +295,7 @@ fn submit_sample_isi_on_every_block_commit( for _ in block_committed_event_listener.take(times) { std::thread::sleep(timeout); // ISI just to create a new block - let sample_isi = SetKeyValueBox::account( + let sample_isi = SetKeyValue::account( account_id.clone(), "key".parse::()?, String::from("value"), diff --git a/client/tests/integration/triggers/trigger_rollback.rs b/client/tests/integration/triggers/trigger_rollback.rs index 701b2801f92..182045a2c7e 100644 --- a/client/tests/integration/triggers/trigger_rollback.rs +++ b/client/tests/integration/triggers/trigger_rollback.rs @@ -15,12 +15,12 @@ fn failed_trigger_revert() -> Result<()> { let account_id = AccountId::from_str("alice@wonderland")?; let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland")?; let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); let instructions: [InstructionBox; 2] = [ create_asset.into(), Fail::new("Always fail".to_owned()).into(), ]; - let register_trigger = RegisterBox::trigger(Trigger::new( + let register_trigger = Register::trigger(Trigger::new( trigger_id.clone(), Action::new( instructions, diff --git a/client/tests/integration/tx_history.rs b/client/tests/integration/tx_history.rs index f24c869d5da..8cbf9a3f5cc 100644 --- a/client/tests/integration/tx_history.rs +++ b/client/tests/integration/tx_history.rs @@ -25,14 +25,14 @@ fn client_has_rejected_and_acepted_txs_should_return_tx_history() -> Result<()> let account_id = AccountId::from_str("alice@wonderland")?; let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland")?; let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); client.submit_blocking(create_asset)?; //When let quantity: u32 = 200; let asset_id = AssetId::new(asset_definition_id, account_id.clone()); - let mint_existed_asset = MintBox::asset_quantity(quantity, asset_id); - let mint_not_existed_asset = MintBox::asset_quantity( + let mint_existed_asset = Mint::asset_quantity(quantity, asset_id); + let mint_not_existed_asset = Mint::asset_quantity( quantity, AssetId::new( AssetDefinitionId::from_str("foo#wonderland")?, diff --git a/client/tests/integration/tx_rollback.rs b/client/tests/integration/tx_rollback.rs index 8f5186aa66b..0c04bbec3a8 100644 --- a/client/tests/integration/tx_rollback.rs +++ b/client/tests/integration/tx_rollback.rs @@ -16,10 +16,9 @@ fn client_sends_transaction_with_invalid_instruction_should_not_see_any_changes( let account_id = AccountId::from_str("alice@wonderland")?; let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland")?; let wrong_asset_definition_id = AssetDefinitionId::from_str("ksor#wonderland")?; - let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id)); + let create_asset = Register::asset_definition(AssetDefinition::quantity(asset_definition_id)); let quantity: u32 = 200; - let mint_asset = MintBox::asset_quantity( + let mint_asset = Mint::asset_quantity( quantity, AssetId::new(wrong_asset_definition_id.clone(), account_id.clone()), ); diff --git a/client/tests/integration/unregister_peer.rs b/client/tests/integration/unregister_peer.rs index 6f3a6ea6887..84a2e4fa5b3 100644 --- a/client/tests/integration/unregister_peer.rs +++ b/client/tests/integration/unregister_peer.rs @@ -34,7 +34,7 @@ fn unstable_network_stable_after_add_and_after_remove_peer() -> Result<()> { // Then the new peer should already have the mint result. check_assets(&peer_client, &account_id, &asset_definition_id, 100); // Also, when a peer is unregistered - let remove_peer = UnregisterBox::peer(peer.id.clone()); + let remove_peer = Unregister::peer(peer.id.clone()); genesis_client.submit(remove_peer)?; thread::sleep(pipeline_time * 2); // We can mint without error. @@ -82,7 +82,7 @@ fn mint( pipeline_time: std::time::Duration, quantity: u32, ) -> Result { - let mint_asset = MintBox::asset_quantity( + let mint_asset = Mint::asset_quantity( quantity, AssetId::new(asset_definition_id.clone(), account_id.clone()), ); @@ -106,13 +106,13 @@ fn init() -> Result<( let parameters = ParametersBuilder::new() .add_parameter(MAX_TRANSACTIONS_IN_BLOCK, 1u32)? .into_set_parameters(); - let create_domain = RegisterBox::domain(Domain::new("domain".parse()?)); + let create_domain = Register::domain(Domain::new("domain".parse()?)); let account_id: AccountId = "account@domain".parse()?; let (public_key, _) = KeyPair::generate()?.into(); - let create_account = RegisterBox::account(Account::new(account_id.clone(), [public_key])); + let create_account = Register::account(Account::new(account_id.clone(), [public_key])); let asset_definition_id: AssetDefinitionId = "xor#domain".parse()?; let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); let instructions = parameters.into_iter().chain( [ create_domain.into(), diff --git a/client/tests/integration/unstable_network.rs b/client/tests/integration/unstable_network.rs index b78ae31a28b..510ab880394 100644 --- a/client/tests/integration/unstable_network.rs +++ b/client/tests/integration/unstable_network.rs @@ -78,7 +78,7 @@ fn unstable_network( let account_id: AccountId = "alice@wonderland".parse().expect("Valid"); let asset_definition_id: AssetDefinitionId = "camomile#wonderland".parse().expect("Valid"); let register_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); iroha_client .submit_blocking(register_asset) .expect("Failed to register asset"); @@ -100,7 +100,7 @@ fn unstable_network( } let quantity = 1; - let mint_asset = MintBox::asset_quantity( + let mint_asset = Mint::asset_quantity( quantity, AssetId::new(asset_definition_id.clone(), account_id.clone()), ); diff --git a/client/tests/integration/upgrade.rs b/client/tests/integration/upgrade.rs index 19f2f3b564a..cfa822046c2 100644 --- a/client/tests/integration/upgrade.rs +++ b/client/tests/integration/upgrade.rs @@ -17,19 +17,19 @@ fn executor_upgrade_should_work() -> Result<()> { // Register `admin` domain and account let admin_domain = Domain::new("admin".parse()?); - let register_admin_domain = RegisterBox::domain(admin_domain); + let register_admin_domain = Register::domain(admin_domain); client.submit_blocking(register_admin_domain)?; let admin_id: AccountId = "admin@admin".parse()?; let admin_keypair = KeyPair::generate()?; let admin_account = Account::new(admin_id.clone(), [admin_keypair.public_key().clone()]); - let register_admin_account = RegisterBox::account(admin_account); + let register_admin_account = Register::account(admin_account); client.submit_blocking(register_admin_account)?; // Check that admin isn't allowed to transfer alice's rose by default let alice_rose: AssetId = "rose##alice@wonderland".parse()?; let admin_rose: AccountId = "admin@admin".parse()?; - let transfer_alice_rose = TransferBox::asset_quantity(alice_rose, 1_u32, admin_rose); + let transfer_alice_rose = Transfer::asset_quantity(alice_rose, 1_u32, admin_rose); let transfer_rose_tx = TransactionBuilder::new(admin_id.clone()) .with_instructions([transfer_alice_rose.clone()]) .sign(admin_keypair.clone())?; diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index 0aaacb4f5b9..8aca7cef98c 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -391,7 +391,7 @@ mod domain { id, metadata: Metadata(metadata), } = self; - let create_domain = RegisterBox::domain(Domain::new(id)); + let create_domain = iroha_client::data_model::isi::Register::domain(Domain::new(id)); submit([create_domain], metadata, context).wrap_err("Failed to create domain") } } @@ -449,7 +449,7 @@ mod domain { to, metadata: Metadata(metadata), } = self; - let transfer_domain = TransferBox::domain(from, id, to); + let transfer_domain = iroha_client::data_model::isi::Transfer::domain(from, id, to); submit([transfer_domain], metadata, context).wrap_err("Failed to transfer domain") } } @@ -512,7 +512,8 @@ mod account { key, metadata: Metadata(metadata), } = self; - let create_account = RegisterBox::account(Account::new(id, [key])); + let create_account = + iroha_client::data_model::isi::Register::account(Account::new(id, [key])); submit([create_account], metadata, context).wrap_err("Failed to register account") } } @@ -563,7 +564,7 @@ mod account { condition: Signature(condition), metadata: Metadata(metadata), } = self; - let mint_box = MintBox::account_signature_check_condition(condition, account_id); + let mint_box = Mint::account_signature_check_condition(condition, account_id); submit([mint_box], metadata, context).wrap_err("Failed to set signature condition") } } @@ -634,7 +635,7 @@ mod account { permission, metadata: Metadata(metadata), } = self; - let grant = GrantBox::permission_token(permission.0, id); + let grant = iroha_client::data_model::isi::Grant::permission_token(permission.0, id); submit([grant], metadata, context) .wrap_err("Failed to grant the permission to the account") } @@ -727,7 +728,8 @@ mod asset { if unmintable { asset_definition = asset_definition.mintable_once(); } - let create_asset_definition = RegisterBox::asset_definition(asset_definition); + let create_asset_definition = + iroha_client::data_model::isi::Register::asset_definition(asset_definition); submit([create_asset_definition], metadata, context) .wrap_err("Failed to register asset") } @@ -758,7 +760,10 @@ mod asset { quantity, metadata: Metadata(metadata), } = self; - let mint_asset = MintBox::asset_quantity(quantity, AssetId::new(asset, account)); + let mint_asset = iroha_client::data_model::isi::Mint::asset_quantity( + quantity, + AssetId::new(asset, account), + ); submit([mint_asset], metadata, context) .wrap_err("Failed to mint asset of type `NumericValue::U32`") } @@ -789,7 +794,10 @@ mod asset { quantity, metadata: Metadata(metadata), } = self; - let burn_asset = BurnBox::asset_quantity(quantity, AssetId::new(asset, account)); + let burn_asset = iroha_client::data_model::isi::Burn::asset_quantity( + quantity, + AssetId::new(asset, account), + ); submit([burn_asset], metadata, context) .wrap_err("Failed to burn asset of type `NumericValue::U32`") } @@ -824,8 +832,11 @@ mod asset { quantity, metadata: Metadata(metadata), } = self; - let transfer_asset = - TransferBox::asset_quantity(AssetId::new(asset_id, from), quantity, to); + let transfer_asset = iroha_client::data_model::isi::Transfer::asset_quantity( + AssetId::new(asset_id, from), + quantity, + to, + ); submit([transfer_asset], metadata, context).wrap_err("Failed to transfer asset") } } @@ -925,7 +936,9 @@ mod peer { key, metadata: Metadata(metadata), } = self; - let register_peer = RegisterBox::peer(Peer::new(PeerId::new(&address, &key))); + let register_peer = iroha_client::data_model::isi::Register::peer(Peer::new( + PeerId::new(&address, &key), + )); submit([register_peer], metadata, context).wrap_err("Failed to register peer") } } @@ -951,7 +964,8 @@ mod peer { key, metadata: Metadata(metadata), } = self; - let unregister_peer = UnregisterBox::peer(PeerId::new(&address, &key)); + let unregister_peer = + iroha_client::data_model::isi::Unregister::peer(PeerId::new(&address, &key)); submit([unregister_peer], metadata, context).wrap_err("Failed to unregister peer") } } diff --git a/configs/peer/executor.wasm b/configs/peer/executor.wasm index c6af9008e112a65ea317eff5a28790841f787c27..66a20387a4a1365c27a57bcfb4e9bd00b739f608 100644 GIT binary patch literal 388782 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
    )kr&)~pfaNjkSF>1n?n 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

    ySq%mNd7l2F*2^e? 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 SignedTransaction { let domain_name = "domain"; let domain_id = DomainId::from_str(domain_name).expect("does not panic"); - let create_domain = RegisterBox::domain(Domain::new(domain_id)); + let create_domain: InstructionBox = Register::domain(Domain::new(domain_id)).into(); let account_name = "account"; let (public_key, _) = KeyPair::generate() .expect("Failed to generate KeyPair.") .into(); - let create_account = RegisterBox::account(Account::new( + let create_account = Register::account(Account::new( AccountId::new( account_name.parse().expect("Valid"), domain_name.parse().expect("Valid"), ), [public_key], - )); + )) + .into(); let asset_definition_id = AssetDefinitionId::new( "xor".parse().expect("Valid"), domain_name.parse().expect("Valid"), ); let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id)); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id)).into(); let instructions = [create_domain, create_account, create_asset]; TransactionBuilder::new(AccountId::new( diff --git a/core/src/block.rs b/core/src/block.rs index 7686c92b297..21a7405ef42 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -735,7 +735,7 @@ mod tests { // Creating an instruction let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let create_asset_definition = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id)); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id)); // Making two transactions that have the same instruction let transaction_limits = &wsv.transaction_executor().transaction_limits; @@ -778,7 +778,7 @@ mod tests { // Creating an instruction let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let create_asset_definition = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id.clone())); // Making two transactions that have the same instruction let transaction_limits = &wsv.transaction_executor().transaction_limits; @@ -791,12 +791,12 @@ mod tests { let quantity: u32 = 200; let fail_quantity: u32 = 20; - let fail_mint = MintBox::asset_quantity( + let fail_mint = Mint::asset_quantity( fail_quantity, AssetId::new(asset_definition_id.clone(), alice_id.clone()), ); - let succeed_mint = MintBox::asset_quantity( + let succeed_mint = Mint::asset_quantity( quantity, AssetId::new(asset_definition_id, alice_id.clone()), ); @@ -848,10 +848,10 @@ mod tests { let transaction_limits = &wsv.transaction_executor().transaction_limits; let domain_id = DomainId::from_str("domain").expect("Valid"); - let create_domain = RegisterBox::domain(Domain::new(domain_id)); + let create_domain = Register::domain(Domain::new(domain_id)); let asset_definition_id = AssetDefinitionId::from_str("coin#domain").expect("Valid"); let create_asset = - RegisterBox::asset_definition(AssetDefinition::quantity(asset_definition_id)); + Register::asset_definition(AssetDefinition::quantity(asset_definition_id)); let instructions_fail: [InstructionBox; 2] = [ create_domain.clone().into(), Fail::new("Always fail".to_owned()).into(), diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index 4497e77a4a9..a0bf424f1ef 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -245,11 +245,11 @@ mod tests { let account_id = AccountId::from_str("alice@wonderland")?; let (public_key, _) = KeyPair::generate()?.into(); let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; - RegisterBox::domain(Domain::new(DomainId::from_str("wonderland")?)) + Register::domain(Domain::new(DomainId::from_str("wonderland")?)) .execute(&genesis_account_id, &mut wsv)?; - RegisterBox::account(Account::new(account_id, [public_key])) + Register::account(Account::new(account_id, [public_key])) .execute(&genesis_account_id, &mut wsv)?; - RegisterBox::asset_definition(AssetDefinition::store(asset_definition_id)) + Register::asset_definition(AssetDefinition::store(asset_definition_id)) .execute(&genesis_account_id, &mut wsv)?; Ok(wsv) } @@ -261,7 +261,7 @@ mod tests { let account_id = AccountId::from_str("alice@wonderland")?; let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; let asset_id = AssetId::new(asset_definition_id, account_id.clone()); - SetKeyValueBox::asset( + SetKeyValue::asset( asset_id.clone(), Name::from_str("Bytes")?, vec![1_u32, 2_u32, 3_u32], @@ -288,7 +288,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let mut wsv = wsv_with_test_domains(&kura)?; let account_id = AccountId::from_str("alice@wonderland")?; - SetKeyValueBox::account( + SetKeyValue::account( account_id.clone(), Name::from_str("Bytes")?, vec![1_u32, 2_u32, 3_u32], @@ -317,7 +317,7 @@ mod tests { let mut wsv = wsv_with_test_domains(&kura)?; let definition_id = AssetDefinitionId::from_str("rose#wonderland")?; let account_id = AccountId::from_str("alice@wonderland")?; - SetKeyValueBox::asset_definition( + SetKeyValue::asset_definition( definition_id.clone(), Name::from_str("Bytes")?, vec![1_u32, 2_u32, 3_u32], @@ -345,7 +345,7 @@ mod tests { let mut wsv = wsv_with_test_domains(&kura)?; let domain_id = DomainId::from_str("wonderland")?; let account_id = AccountId::from_str("alice@wonderland")?; - SetKeyValueBox::domain( + SetKeyValue::domain( domain_id.clone(), Name::from_str("Bytes")?, vec![1_u32, 2_u32, 3_u32], @@ -397,11 +397,11 @@ mod tests { .expect("Failed to generate KeyPair") .into(); let register_account = - RegisterBox::account(Account::new(fake_account_id.clone(), [public_key])); + Register::account(Account::new(fake_account_id.clone(), [public_key])); register_account.execute(&account_id, &mut wsv)?; // register the trigger - let register_trigger = RegisterBox::trigger(Trigger::new( + let register_trigger = Register::trigger(Trigger::new( trigger_id.clone(), Action::new( Vec::::new(), diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 84381a80755..d14ed740d0b 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -432,7 +432,7 @@ mod tests { kura.store_block(vcb); let unapplied_tx = TransactionBuilder::new(ALICE_ID.clone()) - .with_instructions([UnregisterBox::account("account@domain".parse().unwrap())]) + .with_instructions([Unregister::account("account@domain".parse().unwrap())]) .sign(ALICE_KEYS.clone())?; let wrong_hash = unapplied_tx.hash(); let not_found = FindTransactionByHash::new(wrong_hash).execute(&wsv); diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 251be5be71d..2dc0cbbb3b9 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -1716,7 +1716,7 @@ mod tests { let isi_hex = { let new_authority = AccountId::from_str("mad_hatter@wonderland").expect("Valid"); - let register_isi = RegisterBox::account(Account::new(new_authority, [])); + let register_isi = Register::account(Account::new(new_authority, [])); encode_hex(InstructionBox::from(register_isi)) }; @@ -1802,7 +1802,7 @@ mod tests { let isi_hex = { let new_authority = AccountId::from_str("mad_hatter@wonderland").expect("Valid"); - let register_isi = RegisterBox::account(Account::new(new_authority, [])); + let register_isi = Register::account(Account::new(new_authority, [])); encode_hex(InstructionBox::from(register_isi)) }; @@ -1851,7 +1851,7 @@ mod tests { let isi_hex = { let new_authority = AccountId::from_str("mad_hatter@wonderland").expect("Valid"); - let register_isi = RegisterBox::account(Account::new(new_authority, [])); + let register_isi = Register::account(Account::new(new_authority, [])); encode_hex(InstructionBox::from(register_isi)) }; diff --git a/core/src/sumeragi/main_loop.rs b/core/src/sumeragi/main_loop.rs index 65dc838c123..b24b263188a 100644 --- a/core/src/sumeragi/main_loop.rs +++ b/core/src/sumeragi/main_loop.rs @@ -1231,10 +1231,10 @@ mod tests { kura.store_block(genesis); // Making two transactions that have the same instruction - let create_asset_definition1 = RegisterBox::asset_definition(AssetDefinition::quantity( + let create_asset_definition1 = Register::asset_definition(AssetDefinition::quantity( "xor1#wonderland".parse().expect("Valid"), )); - let create_asset_definition2 = RegisterBox::asset_definition(AssetDefinition::quantity( + let create_asset_definition2 = Register::asset_definition(AssetDefinition::quantity( "xor2#wonderland".parse().expect("Valid"), )); diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index e9f0986c969..b359d7367a3 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -117,9 +117,8 @@ impl TestGenesis for GenesisNetwork { unregister_wonderland_domain, upgrade_executor_permission, ] { - first_transaction.append_instruction( - GrantBox::permission_token(permission, alice_id.clone()).into(), - ); + first_transaction + .append_instruction(Grant::permission_token(permission, alice_id.clone()).into()); } if submit_genesis { @@ -212,7 +211,7 @@ impl Network { time::sleep(Configuration::pipeline_time() + Configuration::block_sync_gossip_time()).await; - let add_peer = RegisterBox::peer(DataModelPeer::new(peer.id.clone())); + let add_peer = Register::peer(DataModelPeer::new(peer.id.clone())); genesis_client .submit(add_peer) .expect("Failed to add new peer."); diff --git a/data_model/src/isi.rs b/data_model/src/isi.rs index 27323e65f51..0dd3b178d9e 100644 --- a/data_model/src/isi.rs +++ b/data_model/src/isi.rs @@ -6,9 +6,8 @@ use alloc::{boxed::Box, format, string::String, vec::Vec}; use core::fmt::{Debug, Display}; -use derive_more::{DebugCustom, Display}; +use derive_more::{Constructor, DebugCustom, Display}; use iroha_data_model_derive::model; -use iroha_macro::FromVariant; use iroha_schema::IntoSchema; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; @@ -18,7 +17,11 @@ pub use self::{model::*, transparent::*}; use super::{prelude::*, Value}; use crate::{seal, Level, Registered}; -/// Marker trait designating instruction +/// Marker trait designating instruction. +/// +/// Instructions allows to change the state of `Iroha`. +/// All possible instructions are implementors of this trait, excluding +/// [`InstructionBox`] which is just a wrapper. pub trait Instruction: Into + seal::Sealed {} #[model] @@ -28,6 +31,10 @@ pub mod model { use super::*; /// Sized structure for all possible Instructions. + /// + /// Note that [`InstructionBox`] is not a self-sufficient instruction, + /// but just a wrapper to pass instructions back and forth. + /// If you are a client SDK user then you likely don't need to use this type directly. #[derive( DebugCustom, Display, @@ -36,7 +43,6 @@ pub mod model { Eq, PartialOrd, Ord, - FromVariant, EnumDiscriminants, Decode, Encode, @@ -101,15 +107,57 @@ pub mod model { impl Instruction for InstructionBox {} - impl Instruction for SetKeyValueBox {} - impl Instruction for RemoveKeyValueBox {} - impl Instruction for RegisterBox {} - impl Instruction for UnregisterBox {} - impl Instruction for MintBox {} - impl Instruction for BurnBox {} - impl Instruction for TransferBox {} - impl Instruction for GrantBox {} - impl Instruction for RevokeBox {} + impl Instruction for SetKeyValue {} + impl Instruction for SetKeyValue {} + impl Instruction for SetKeyValue {} + impl Instruction for SetKeyValue {} + + impl Instruction for RemoveKeyValue {} + impl Instruction for RemoveKeyValue {} + impl Instruction for RemoveKeyValue {} + impl Instruction for RemoveKeyValue {} + + impl Instruction for Register {} + impl Instruction for Register {} + impl Instruction for Register {} + impl Instruction for Register {} + impl Instruction for Register {} + impl Instruction for Register {} + impl Instruction for Register> {} + + impl Instruction for Unregister {} + impl Instruction for Unregister {} + impl Instruction for Unregister {} + impl Instruction for Unregister {} + impl Instruction for Unregister {} + impl Instruction for Unregister {} + impl Instruction for Unregister> {} + + impl Instruction for Mint {} + impl Instruction for Mint {} + impl Instruction for Mint {} + impl Instruction for Mint {} + impl Instruction for Mint {} + impl Instruction for Mint> {} + + impl Instruction for Burn {} + impl Instruction for Burn {} + impl Instruction for Burn {} + impl Instruction for Burn {} + impl Instruction for Burn> {} + + impl Instruction for Transfer {} + impl Instruction for Transfer {} + impl Instruction for Transfer {} + impl Instruction for Transfer {} + impl Instruction for Transfer {} + + impl Instruction for Grant {} + impl Instruction for Grant {} + + impl Instruction for Revoke {} + impl Instruction for Revoke {} + impl Instruction for SetParameter {} impl Instruction for NewParameter {} impl Instruction for Upgrade {} @@ -120,12 +168,13 @@ pub mod model { mod transparent { use super::*; + use crate::{account::NewAccount, domain::NewDomain}; macro_rules! isi { ($($meta:meta)* $item:item) => { iroha_data_model_derive::model_single! { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] - #[derive(derive_more::Constructor, getset::Getters)] + #[derive(getset::Getters)] #[derive(parity_scale_codec::Decode, parity_scale_codec::Encode)] #[derive(serde::Deserialize, serde::Serialize)] #[derive(iroha_schema::IntoSchema)] @@ -158,9 +207,32 @@ mod transparent { } } + macro_rules! impl_into_box { + ( + $($isi:ident $(< $($generic:ident $(< $nested_generic:ident >)?),+ >)?)|* + ==> $boxed:ident :: $variant:ident + ) => {$( + impl From<$isi $(< $($generic $(< $nested_generic >)?),+ >)? > for $boxed { + fn from(instruction: $isi $(< $($generic $(< $nested_generic >)?),+ >)?) -> Self { + Self::$variant(instruction) + } + } + )*}; + ( + $($isi:ident $(< $($generic:ident $(< $nested_generic:ident >)?),+ >)?)|* + => $middle:ident ==> $boxed:ident :: $variant:ident + ) => {$( + impl From<$isi $(< $($generic $(< $nested_generic >)?),+ >)? > for $boxed { + fn from(instruction: $isi $(< $($generic $(< $nested_generic >)?),+ >)?) -> Self { + Self::$variant($middle::from(instruction)) + } + } + )*}; + } + isi! { /// Generic instruction for setting a chain-wide config parameter. - #[derive(Display)] + #[derive(Constructor, Display)] #[display(fmt = "SET `{parameter}`")] #[serde(transparent)] #[repr(transparent)] @@ -171,10 +243,12 @@ mod transparent { } } + impl_into_box!(SetParameter ==> InstructionBox::SetParameter); + isi! { /// Sized structure for all possible on-chain configuration parameters when they are first created. /// Generic instruction for setting a chain-wide config parameter. - #[derive(Display)] + #[derive(Constructor, Display)] #[display(fmt = "SET `{parameter}`")] #[serde(transparent)] #[repr(transparent)] @@ -185,6 +259,8 @@ mod transparent { } } + impl_into_box!(NewParameter ==> InstructionBox::NewParameter); + isi! { /// Generic instruction to set key value at the object. #[schema(bounds = "O: Identifiable, O::Id: IntoSchema")] @@ -199,6 +275,54 @@ mod transparent { } } + impl SetKeyValue { + /// Constructs a new [`SetKeyValue`] for a [`Domain`] with the given `key` and `value`. + pub fn domain(domain_id: DomainId, key: Name, value: impl Into) -> Self { + Self { + object_id: domain_id, + key, + value: value.into(), + } + } + } + + impl SetKeyValue { + /// Constructs a new [`SetKeyValue`] for an [`Account`] with the given `key` and `value`. + pub fn account(account_id: AccountId, key: Name, value: impl Into) -> Self { + Self { + object_id: account_id, + key, + value: value.into(), + } + } + } + + impl SetKeyValue { + /// Constructs a new [`SetKeyValue`] for an [`AssetDefinition`] with the given `key` and `value`. + pub fn asset_definition( + asset_definition_id: AssetDefinitionId, + key: Name, + value: impl Into, + ) -> Self { + Self { + object_id: asset_definition_id, + key, + value: value.into(), + } + } + } + + impl SetKeyValue { + /// Constructs a new [`SetKeyValue`] for an [`Asset`] with the given `key` and `value`. + pub fn asset(asset_id: AssetId, key: Name, value: impl Into) -> Self { + Self { + object_id: asset_id, + key, + value: value.into(), + } + } + } + impl_display! { SetKeyValue where @@ -209,6 +333,13 @@ mod transparent { key, value, object_id, } + impl_into_box! { + SetKeyValue | + SetKeyValue | + SetKeyValue | + SetKeyValue => SetKeyValueBox ==> InstructionBox::SetKeyValue + } + isi! { /// Generic instruction to remove key value at the object. #[schema(bounds = "O: Identifiable, O::Id: IntoSchema")] @@ -221,6 +352,46 @@ mod transparent { } } + impl RemoveKeyValue { + /// Constructs a new [`RemoveKeyValue`] for a [`Domain`] with the given `key`. + pub fn domain(domain_id: DomainId, key: Name) -> Self { + Self { + object_id: domain_id, + key, + } + } + } + + impl RemoveKeyValue { + /// Constructs a new [`RemoveKeyValue`] for an [`Account`] with the given `key`. + pub fn account(account_id: AccountId, key: Name) -> Self { + Self { + object_id: account_id, + key, + } + } + } + + impl RemoveKeyValue { + /// Constructs a new [`RemoveKeyValue`] for an [`AssetDefinition`] with the given `key`. + pub fn asset_definition(asset_definition_id: AssetDefinitionId, key: Name) -> Self { + Self { + object_id: asset_definition_id, + key, + } + } + } + + impl RemoveKeyValue { + /// Constructs a new [`RemoveKeyValue`] for an [`Asset`] with the given `key`. + pub fn asset(asset_id: AssetId, key: Name) -> Self { + Self { + object_id: asset_id, + key, + } + } + } + impl_display! { RemoveKeyValue where @@ -231,6 +402,13 @@ mod transparent { key, object_id, } + impl_into_box! { + RemoveKeyValue | + RemoveKeyValue | + RemoveKeyValue | + RemoveKeyValue => RemoveKeyValueBox ==> InstructionBox::RemoveKeyValue + } + isi! { /// Generic instruction for a registration of an object to the identifiable destination. #[schema(bounds = "O: Registered, O::With: IntoSchema")] @@ -241,6 +419,61 @@ mod transparent { } } + impl Register { + /// Constructs a new [`Register`] for a [`Peer`]. + pub fn peer(new_peer: Peer) -> Self { + Self { object: new_peer } + } + } + + impl Register { + /// Constructs a new [`Register`] for a [`Domain`]. + pub fn domain(new_domain: NewDomain) -> Self { + Self { object: new_domain } + } + } + + impl Register { + /// Constructs a new [`Register`] for an [`Account`]. + pub fn account(new_account: NewAccount) -> Self { + Self { + object: new_account, + } + } + } + + impl Register { + /// Constructs a new [`Register`] for an [`AssetDefinition`]. + pub fn asset_definition(new_asset_definition: NewAssetDefinition) -> Self { + Self { + object: new_asset_definition, + } + } + } + + impl Register { + /// Constructs a new [`Register`] for an [`Asset`]. + pub fn asset(new_asset: Asset) -> Self { + Self { object: new_asset } + } + } + + impl Register { + /// Constructs a new [`Register`] for a [`Role`]. + pub fn role(new_role: NewRole) -> Self { + Self { object: new_role } + } + } + + impl Register> { + /// Constructs a new [`Register`] for a [`Trigger`]. + pub fn trigger(new_trigger: Trigger) -> Self { + Self { + object: new_trigger, + } + } + } + impl_display! { Register where @@ -251,6 +484,16 @@ mod transparent { object, } + impl_into_box! { + Register | + Register | + Register | + Register | + Register | + Register | + Register > => RegisterBox ==> InstructionBox::Register + } + isi! { /// Generic instruction for an unregistration of an object from the identifiable destination. #[schema(bounds = "O: Identifiable, O::Id: IntoSchema")] @@ -270,6 +513,75 @@ mod transparent { object_id, } + impl_into_box! { + Unregister | + Unregister | + Unregister | + Unregister | + Unregister | + Unregister | + Unregister > => UnregisterBox ==> InstructionBox::Unregister + } + + impl Unregister { + /// Constructs a new [`Unregister`] for a [`Peer`]. + pub fn peer(peer_id: PeerId) -> Self { + Self { object_id: peer_id } + } + } + + impl Unregister { + /// Constructs a new [`Unregister`] for a [`Domain`]. + pub fn domain(domain_id: DomainId) -> Self { + Self { + object_id: domain_id, + } + } + } + + impl Unregister { + /// Constructs a new [`Unregister`] for an [`Account`]. + pub fn account(account_id: AccountId) -> Self { + Self { + object_id: account_id, + } + } + } + + impl Unregister { + /// Constructs a new [`Unregister`] for an [`AssetDefinition`]. + pub fn asset_definition(asset_definition_id: AssetDefinitionId) -> Self { + Self { + object_id: asset_definition_id, + } + } + } + + impl Unregister { + /// Constructs a new [`Unregister`] for an [`Asset`]. + pub fn asset(asset_id: AssetId) -> Self { + Self { + object_id: asset_id, + } + } + } + + impl Unregister { + /// Constructs a new [`Unregister`] for a [`Role`]. + pub fn role(role_id: RoleId) -> Self { + Self { object_id: role_id } + } + } + + impl Unregister> { + /// Constructs a new [`Unregister`] for a [`Trigger`]. + pub fn trigger(trigger_id: TriggerId) -> Self { + Self { + object_id: trigger_id, + } + } + } + isi! { /// Generic instruction for a mint of an object to the identifiable destination. #[schema(bounds = "O: Into + IntoSchema, D: Identifiable, D::Id: IntoSchema")] @@ -281,6 +593,69 @@ mod transparent { } } + impl Mint { + /// Constructs a new [`Mint`] for a [`PublicKey`] for [`Account`]. + pub fn account_public_key(public_key: PublicKey, account_id: AccountId) -> Self { + Self { + object: public_key, + destination_id: account_id, + } + } + } + + impl Mint { + /// Constructs a new [`Mint`] for a [`SignatureCheckCondition`] for [`Account`]. + pub fn account_signature_check_condition( + signature_check_condition: SignatureCheckCondition, + account_id: AccountId, + ) -> Self { + Self { + object: signature_check_condition, + destination_id: account_id, + } + } + } + + impl Mint { + /// Constructs a new [`Mint`] for an [`Asset`] of [`Quantity`] type. + pub fn asset_quantity(quantity: u32, asset_id: AssetId) -> Self { + Self { + object: quantity, + destination_id: asset_id, + } + } + } + + impl Mint { + /// Constructs a new [`Mint`] for an [`Asset`] of [`BigQuantity`] type. + pub fn asset_big_quantity(big_quantity: u128, asset_id: AssetId) -> Self { + Self { + object: big_quantity, + destination_id: asset_id, + } + } + } + + impl Mint { + /// Constructs a new [`Mint`] for an [`Asset`] of [`Fixed`] type. + pub fn asset_fixed(fixed: Fixed, asset_id: AssetId) -> Self { + Self { + object: fixed, + destination_id: asset_id, + } + } + } + + impl Mint> { + /// Constructs a new [`Mint`] for repetition count of [`Trigger`]. + pub fn trigger_repetitions(repetitions: u32, trigger_id: TriggerId) -> Self { + Self { + object: repetitions, + destination_id: trigger_id, + } + } + } + impl_display! { Mint where @@ -293,6 +668,26 @@ mod transparent { destination_id, } + impl_into_box! { + Mint | + Mint => AccountMintBox ==> MintBox::Account + } + + impl_into_box! { + Mint | + Mint | + Mint => AssetMintBox ==> MintBox::Asset + } + + impl_into_box! { + Mint | + Mint | + Mint | + Mint | + Mint | + Mint > => MintBox ==> InstructionBox::Mint + } + isi! { /// Generic instruction for a burn of an object to the identifiable destination. #[schema(bounds = "O: Into + IntoSchema, D: Identifiable, D::Id: IntoSchema")] @@ -304,6 +699,56 @@ mod transparent { } } + impl Burn { + /// Constructs a new [`Burn`] for a [`PublicKey`] for [`Account`]. + pub fn account_public_key(public_key: PublicKey, account_id: AccountId) -> Self { + Self { + object: public_key, + destination_id: account_id, + } + } + } + + impl Burn { + /// Constructs a new [`Burn`] for an [`Asset`] of [`Quantity`] type. + pub fn asset_quantity(quantity: u32, asset_id: AssetId) -> Self { + Self { + object: quantity, + destination_id: asset_id, + } + } + } + + impl Burn { + /// Constructs a new [`Burn`] for an [`Asset`] of [`BigQuantity`] type. + pub fn asset_big_quantity(big_quantity: u128, asset_id: AssetId) -> Self { + Self { + object: big_quantity, + destination_id: asset_id, + } + } + } + + impl Burn { + /// Constructs a new [`Burn`] for an [`Asset`] of [`Fixed`] type. + pub fn asset_fixed(fixed: Fixed, asset_id: AssetId) -> Self { + Self { + object: fixed, + destination_id: asset_id, + } + } + } + + impl Burn> { + /// Constructs a new [`Burn`] for repetition count of [`Trigger`]. + pub fn trigger_repetitions(repetitions: u32, trigger_id: TriggerId) -> Self { + Self { + object: repetitions, + destination_id: trigger_id, + } + } + } + impl_display! { Burn where @@ -316,6 +761,20 @@ mod transparent { destination_id, } + impl_into_box! { + Burn | + Burn | + Burn => AssetBurnBox ==> BurnBox::Asset + } + + impl_into_box! { + Burn | + Burn | + Burn | + Burn | + Burn > => BurnBox ==> InstructionBox::Burn + } + isi! { /// Generic instruction for a transfer of an object from the identifiable source to the identifiable destination. #[schema(bounds = "S: Identifiable, S::Id: IntoSchema, \ @@ -331,6 +790,65 @@ mod transparent { } } + impl Transfer { + /// Constructs a new [`Transfer`] for a [`Domain`]. + pub fn domain(from: AccountId, domain_id: DomainId, to: AccountId) -> Self { + Self { + source_id: from, + object: domain_id, + destination_id: to, + } + } + } + + impl Transfer { + /// Constructs a new [`Transfer`] for an [`AssetDefinition`]. + pub fn asset_definition( + from: AccountId, + asset_definition_id: AssetDefinitionId, + to: AccountId, + ) -> Self { + Self { + source_id: from, + object: asset_definition_id, + destination_id: to, + } + } + } + + impl Transfer { + /// Constructs a new [`Transfer`] for an [`Asset`] of [`Quantity`] type. + pub fn asset_quantity(asset_id: AssetId, quantity: u32, to: AccountId) -> Self { + Self { + source_id: asset_id, + object: quantity, + destination_id: to, + } + } + } + + impl Transfer { + /// Constructs a new [`Transfer`] for an [`Asset`] of [`BigQuantity`] type. + pub fn asset_big_quantity(asset_id: AssetId, big_quantity: u128, to: AccountId) -> Self { + Self { + source_id: asset_id, + object: big_quantity, + destination_id: to, + } + } + } + + impl Transfer { + /// Constructs a new [`Transfer`] for an [`Asset`] of [`Fixed`] type. + pub fn asset_fixed(asset_id: AssetId, fixed: Fixed, to: AccountId) -> Self { + Self { + source_id: asset_id, + object: fixed, + destination_id: to, + } + } + } + impl_display! { Transfer where @@ -346,9 +864,23 @@ mod transparent { destination_id, } + impl_into_box! { + Transfer | + Transfer | + Transfer => AssetTransferBox ==> TransferBox::Asset + } + + impl_into_box! { + Transfer | + Transfer | + Transfer | + Transfer | + Transfer => TransferBox ==> InstructionBox::Transfer + } + isi! { /// Utilitary instruction to fail execution and submit an error `message`. - #[derive(Display)] + #[derive(Constructor, Display)] #[display(fmt = "FAIL `{message}`")] #[serde(transparent)] #[repr(transparent)] @@ -358,6 +890,8 @@ mod transparent { } } + impl_into_box!(Fail ==> InstructionBox::Fail); + isi! { /// Generic instruction for granting permission to an entity. pub struct Grant> { @@ -368,6 +902,26 @@ mod transparent { } } + impl Grant { + /// Constructs a new [`Grant`] for a [`PermissionToken`]. + pub fn permission_token(permission_token: PermissionToken, to: AccountId) -> Self { + Self { + object: permission_token, + destination_id: to, + } + } + } + + impl Grant { + /// Constructs a new [`Grant`] for a [`Role`]. + pub fn role(role_id: RoleId, to: AccountId) -> Self { + Self { + object: role_id, + destination_id: to, + } + } + } + impl_display! { Grant where @@ -378,6 +932,11 @@ mod transparent { destination_id, } + impl_into_box! { + Grant | + Grant => GrantBox ==> InstructionBox::Grant + } + isi! { /// Generic instruction for revoking permission from an entity. pub struct Revoke> { @@ -388,6 +947,26 @@ mod transparent { } } + impl Revoke { + /// Constructs a new [`Revoke`] for a [`PermissionToken`]. + pub fn permission_token(permission_token: PermissionToken, from: AccountId) -> Self { + Self { + object: permission_token, + destination_id: from, + } + } + } + + impl Revoke { + /// Constructs a new [`Revoke`] for a [`Role`]. + pub fn role(role_id: RoleId, from: AccountId) -> Self { + Self { + object: role_id, + destination_id: from, + } + } + } + impl_display! { Revoke where @@ -398,9 +977,14 @@ mod transparent { destination_id, } + impl_into_box! { + Revoke | + Revoke => RevokeBox ==> InstructionBox::Revoke + } + isi! { /// Instruction to execute specified trigger - #[derive(Display)] + #[derive(Constructor, Display)] #[display(fmt = "EXECUTE `{trigger_id}`")] #[serde(transparent)] #[repr(transparent)] @@ -410,9 +994,11 @@ mod transparent { } } + impl_into_box!(ExecuteTrigger ==> InstructionBox::ExecuteTrigger); + isi! { /// Generic instruction for upgrading runtime objects. - #[derive(Display)] + #[derive(Constructor, Display)] #[display(fmt = "UPGRADE")] #[serde(transparent)] #[repr(transparent)] @@ -422,9 +1008,11 @@ mod transparent { } } + impl_into_box!(Upgrade ==> InstructionBox::Upgrade); + isi! { /// Instruction to print logs - #[derive(Display)] + #[derive(Constructor, Display)] #[display(fmt = "LOG({level}): {msg}")] pub struct Log { /// Message log level @@ -435,6 +1023,8 @@ mod transparent { pub msg: String, } } + + impl_into_box!(Log ==> InstructionBox::Log); } macro_rules! isi_box { @@ -473,32 +1063,6 @@ isi_box! { } } -impl SetKeyValueBox { - /// Constructs a new [`SetKeyValueBox`] for a [`Domain`] with the given `key` and `value`. - pub fn domain(domain_id: DomainId, key: Name, value: impl Into) -> Self { - Self::Domain(SetKeyValue::new(domain_id, key, value.into())) - } - - /// Constructs a new [`SetKeyValueBox`] for an [`Account`] with the given `key` and `value`. - pub fn account(account_id: AccountId, key: Name, value: impl Into) -> Self { - Self::Account(SetKeyValue::new(account_id, key, value.into())) - } - - /// Constructs a new [`SetKeyValueBox`] for an [`AssetDefinition`] with the given `key` and `value`. - pub fn asset_definition( - asset_definition_id: AssetDefinitionId, - key: Name, - value: impl Into, - ) -> Self { - Self::AssetDefinition(SetKeyValue::new(asset_definition_id, key, value.into())) - } - - /// Constructs a new [`SetKeyValueBox`] for an [`Asset`] with the given `key` and `value`. - pub fn asset(asset_id: AssetId, key: Name, value: impl Into) -> Self { - Self::Asset(SetKeyValue::new(asset_id, key, value.into())) - } -} - isi_box! { /// Enum with all supported [`RemoveKeyValue`] instructions. pub enum RemoveKeyValueBox { @@ -513,28 +1077,6 @@ isi_box! { } } -impl RemoveKeyValueBox { - /// Constructs a new [`RemoveKeyValueBox`] for a [`Domain`] with the given `key`. - pub fn domain(domain_id: DomainId, key: Name) -> Self { - Self::Domain(RemoveKeyValue::new(domain_id, key)) - } - - /// Constructs a new [`RemoveKeyValueBox`] for an [`Account`] with the given `key`. - pub fn account(account_id: AccountId, key: Name) -> Self { - Self::Account(RemoveKeyValue::new(account_id, key)) - } - - /// Constructs a new [`RemoveKeyValueBox`] for an [`AssetDefinition`] with the given `key`. - pub fn asset_definition(asset_definition_id: AssetDefinitionId, key: Name) -> Self { - Self::AssetDefinition(RemoveKeyValue::new(asset_definition_id, key)) - } - - /// Constructs a new [`RemoveKeyValueBox`] for an [`Asset`] with the given `key`. - pub fn asset(asset_id: AssetId, key: Name) -> Self { - Self::Asset(RemoveKeyValue::new(asset_id, key)) - } -} - isi_box! { /// Enum with all supported [`Register`] instructions. pub enum RegisterBox { @@ -555,43 +1097,6 @@ isi_box! { } } -impl RegisterBox { - /// Constructs a new [`RegisterBox`] for a [`Peer`]. - pub fn peer(new_peer: ::With) -> Self { - Self::Peer(Register::new(new_peer)) - } - - /// Constructs a new [`RegisterBox`] for a [`Domain`]. - pub fn domain(new_domain: ::With) -> Self { - Self::Domain(Register::new(new_domain)) - } - - /// Constructs a new [`RegisterBox`] for an [`Account`]. - pub fn account(new_account: ::With) -> Self { - Self::Account(Register::new(new_account)) - } - - /// Constructs a new [`RegisterBox`] for an [`AssetDefinition`]. - pub fn asset_definition(new_asset_definition: ::With) -> Self { - Self::AssetDefinition(Register::new(new_asset_definition)) - } - - /// Constructs a new [`RegisterBox`] for an [`Asset`]. - pub fn asset(new_asset: ::With) -> Self { - Self::Asset(Register::new(new_asset)) - } - - /// Constructs a new [`RegisterBox`] for a [`Role`]. - pub fn role(new_role: ::With) -> Self { - Self::Role(Register::new(new_role)) - } - - /// Constructs a new [`RegisterBox`] for a [`Trigger`]. - pub fn trigger(new_trigger: as Registered>::With) -> Self { - Self::Trigger(Register::new(new_trigger)) - } -} - isi_box! { /// Enum with all supported [`Unregister`] instructions. pub enum UnregisterBox { @@ -612,43 +1117,6 @@ isi_box! { } } -impl UnregisterBox { - /// Constructs a new [`UnregisterBox`] for a [`Peer`]. - pub fn peer(peer_id: PeerId) -> Self { - Self::Peer(Unregister::new(peer_id)) - } - - /// Constructs a new [`UnregisterBox`] for a [`Domain`]. - pub fn domain(domain_id: DomainId) -> Self { - Self::Domain(Unregister::new(domain_id)) - } - - /// Constructs a new [`UnregisterBox`] for an [`Account`]. - pub fn account(account_id: AccountId) -> Self { - Self::Account(Unregister::new(account_id)) - } - - /// Constructs a new [`UnregisterBox`] for an [`AssetDefinition`]. - pub fn asset_definition(asset_definition_id: AssetDefinitionId) -> Self { - Self::AssetDefinition(Unregister::new(asset_definition_id)) - } - - /// Constructs a new [`UnregisterBox`] for an [`Asset`]. - pub fn asset(asset_id: AssetId) -> Self { - Self::Asset(Unregister::new(asset_id)) - } - - /// Constructs a new [`UnregisterBox`] for a [`Role`]. - pub fn role(role_id: RoleId) -> Self { - Self::Role(Unregister::new(role_id)) - } - - /// Constructs a new [`UnregisterBox`] for a [`Trigger`]. - pub fn trigger(trigger_id: TriggerId) -> Self { - Self::Trigger(Unregister::new(trigger_id)) - } -} - isi_box! { /// Enum with all supported [`Mint`] instructions. pub enum MintBox { @@ -683,44 +1151,6 @@ isi_box! { } } -impl MintBox { - /// Constructs a new [`MintBox`] to mint [`PublicKey`] for [`Account`]. - pub fn account_public_key(public_key: PublicKey, account_id: AccountId) -> Self { - Self::Account(AccountMintBox::PublicKey(Mint::new(public_key, account_id))) - } - - /// Constructs a new [`MintBox`] to mint [`SignatureCheckCondition`] for [`Account`]. - pub fn account_signature_check_condition( - signature_check_condition: SignatureCheckCondition, - account_id: AccountId, - ) -> Self { - Self::Account(AccountMintBox::SignatureCheckCondition(Mint::new( - signature_check_condition, - account_id, - ))) - } - - /// Constructs a new [`MintBox`] to mint [`Asset`] of [`Quantity`] type. - pub fn asset_quantity(quantity: u32, asset_id: AssetId) -> Self { - Self::Asset(AssetMintBox::Quantity(Mint::new(quantity, asset_id))) - } - - /// Constructs a new [`MintBox`] to mint [`Asset`] of [`BigQuantity`] type. - pub fn asset_big_quantity(quantity: u128, asset_id: AssetId) -> Self { - Self::Asset(AssetMintBox::BigQuantity(Mint::new(quantity, asset_id))) - } - - /// Constructs a new [`MintBox`] to mint [`Asset`] of [`Fixed`] type. - pub fn asset_fixed(quantity: Fixed, asset_id: AssetId) -> Self { - Self::Asset(AssetMintBox::Fixed(Mint::new(quantity, asset_id))) - } - - /// Constructs a new [`MintBox`] to mint [`Trigger`] repetitions. - pub fn trigger_repetitions(repetitions: u32, trigger_id: TriggerId) -> Self { - Self::TriggerRepetitions(Mint::new(repetitions, trigger_id)) - } -} - isi_box! { /// Enum with all supported [`Burn`] instructions. pub enum BurnBox { @@ -745,33 +1175,6 @@ isi_box! { } } -impl BurnBox { - /// Constructs a new [`BurnBox`] to burn [`PublicKey`] for [`Account`]. - pub fn account_public_key(public_key: PublicKey, account_id: AccountId) -> Self { - Self::AccountPublicKey(Burn::new(public_key, account_id)) - } - - /// Constructs a new [`BurnBox`] to burn [`Asset`] of [`Quantity`] type. - pub fn asset_quantity(quantity: u32, asset_id: AssetId) -> Self { - Self::Asset(AssetBurnBox::Quantity(Burn::new(quantity, asset_id))) - } - - /// Constructs a new [`BurnBox`] to burn [`Asset`] of [`BigQuantity`] type. - pub fn asset_big_quantity(quantity: u128, asset_id: AssetId) -> Self { - Self::Asset(AssetBurnBox::BigQuantity(Burn::new(quantity, asset_id))) - } - - /// Constructs a new [`BurnBox`] to burn [`Asset`] of [`Fixed`] type. - pub fn asset_fixed(quantity: Fixed, asset_id: AssetId) -> Self { - Self::Asset(AssetBurnBox::Fixed(Burn::new(quantity, asset_id))) - } - - /// Constructs a new [`BurnBox`] to burn [`Trigger`] repetitions. - pub fn trigger_repetitions(repetitions: u32, trigger_id: TriggerId) -> Self { - Self::TriggerRepetitions(Burn::new(repetitions, trigger_id)) - } -} - isi_box! { /// Enum with all supported [`Transfer`] instructions. pub enum TransferBox { @@ -796,57 +1199,6 @@ isi_box! { } } -impl TransferBox { - /// Constructs a new [`TransferBox`] to transfer [`Domain`] to another [`Account`]. - pub fn domain(source_id: AccountId, domain_id: DomainId, destination_id: AccountId) -> Self { - Self::Domain(Transfer::new(source_id, domain_id, destination_id)) - } - - /// Constructs a new [`TransferBox`] to transfer [`AssetDefinition`] to another [`Account`]. - pub fn asset_definition( - source_id: AccountId, - asset_definition_id: AssetDefinitionId, - destination_id: AccountId, - ) -> Self { - Self::AssetDefinition(Transfer::new( - source_id, - asset_definition_id, - destination_id, - )) - } - - /// Constructs a new [`TransferBox`] to transfer [`Asset`] of [`Quantity`] type. - pub fn asset_quantity(source_id: AssetId, quantity: u32, destination_id: AccountId) -> Self { - Self::Asset(AssetTransferBox::Quantity(Transfer::new( - source_id, - quantity, - destination_id, - ))) - } - - /// Constructs a new [`TransferBox`] to transfer [`Asset`] of [`BigQuantity`] type. - pub fn asset_big_quantity( - source_id: AssetId, - quantity: u128, - destination_id: AccountId, - ) -> Self { - Self::Asset(AssetTransferBox::BigQuantity(Transfer::new( - source_id, - quantity, - destination_id, - ))) - } - - /// Constructs a new [`TransferBox`] to transfer [`Asset`] of [`Fixed`] type. - pub fn asset_fixed(source_id: AssetId, quantity: Fixed, destination_id: AccountId) -> Self { - Self::Asset(AssetTransferBox::Fixed(Transfer::new( - source_id, - quantity, - destination_id, - ))) - } -} - isi_box! { /// Enum with all supported [`Grant`] instructions. pub enum GrantBox { @@ -857,18 +1209,6 @@ isi_box! { } } -impl GrantBox { - /// Constructs a new [`GrantBox`] to grant [`PermissionToken`] to [`Account`]. - pub fn permission_token(permission_token: PermissionToken, account_id: AccountId) -> Self { - Self::PermissionToken(Grant::new(permission_token, account_id)) - } - - /// Constructs a new [`GrantBox`] to grant [`Role`] to [`Account`]. - pub fn role(role_id: RoleId, account_id: AccountId) -> Self { - Self::Role(Grant::new(role_id, account_id)) - } -} - isi_box! { /// Enum with all supported [`Revoke`] instructions. pub enum RevokeBox { @@ -879,18 +1219,6 @@ isi_box! { } } -impl RevokeBox { - /// Constructs a new [`RevokeBox`] to revoke [`PermissionToken`] from [`Account`]. - pub fn permission_token(permission_token: PermissionToken, account_id: AccountId) -> Self { - Self::PermissionToken(Revoke::new(permission_token, account_id)) - } - - /// Constructs a new [`RevokeBox`] to revoke [`Role`] from [`Account`]. - pub fn role(role_id: RoleId, account_id: AccountId) -> Self { - Self::Role(Revoke::new(role_id, account_id)) - } -} - pub mod error { //! Module containing errors that can occur during instruction evaluation diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 1b1764d4de8..0852f58d05f 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -75,34 +75,76 @@ pub mod trigger; pub mod visit; mod seal { - use crate::{isi::prelude::*, query::prelude::*}; + use crate::prelude::*; pub trait Sealed {} macro_rules! impl_sealed { - ($($ident:ident),+ $(,)?) => { $( - impl Sealed for $ident {} )+ + ($($ident:ident $(< $($generic:ident $(< $inner_generic:ident >)?),+ >)?),+ $(,)?) => { $( + impl Sealed for $ident $(< $($generic $(< $inner_generic >)?),+ >)? {} )+ }; } impl_sealed! { // Boxed instructions InstructionBox, - SetKeyValueBox, - RemoveKeyValueBox, - RegisterBox, - UnregisterBox, - MintBox, - BurnBox, - TransferBox, - GrantBox, - RevokeBox, + + SetKeyValue, + SetKeyValue, + SetKeyValue, + SetKeyValue, + + RemoveKeyValue, + RemoveKeyValue, + RemoveKeyValue, + RemoveKeyValue, + + Register, + Register, + Register, + Register, + Register, + Register, + Register >, + + Unregister, + Unregister, + Unregister, + Unregister, + Unregister, + Unregister, + Unregister >, + + Mint, + Mint, + Mint, + Mint, + Mint, + Mint >, + + Burn, + Burn, + Burn, + Burn, + Burn >, + + Transfer, + Transfer, + Transfer, + Transfer, + Transfer, + + Grant, + Grant, + + Revoke, + Revoke, + SetParameter, NewParameter, Upgrade, ExecuteTrigger, Log, - Fail, // Boxed queries diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index 884c0848ad7..9f82b19baae 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -60,7 +60,7 @@ pub trait Visit { visit_find_all_block_headers(&FindAllBlockHeaders), visit_find_all_blocks(&FindAllBlocks), visit_find_all_domains(&FindAllDomains), - visit_find_all_parammeters(&FindAllParameters), + visit_find_all_parameters(&FindAllParameters), visit_find_all_peers(&FindAllPeers), visit_find_permission_token_schema(&FindPermissionTokenSchema), visit_find_all_role_ids(&FindAllRoleIds), @@ -190,7 +190,7 @@ pub fn visit_query(visitor: &mut V, authority: &AccountId, qu visit_find_all_block_headers(FindAllBlockHeaders), visit_find_all_blocks(FindAllBlocks), visit_find_all_domains(FindAllDomains), - visit_find_all_parammeters(FindAllParameters), + visit_find_all_parameters(FindAllParameters), visit_find_all_peers(FindAllPeers), visit_find_permission_token_schema(FindPermissionTokenSchema), visit_find_all_role_ids(FindAllRoleIds), @@ -472,7 +472,7 @@ leaf_visitors! { visit_find_all_block_headers(&FindAllBlockHeaders), visit_find_all_blocks(&FindAllBlocks), visit_find_all_domains(&FindAllDomains), - visit_find_all_parammeters(&FindAllParameters), + visit_find_all_parameters(&FindAllParameters), visit_find_all_peers(&FindAllPeers), visit_find_permission_token_schema(&FindPermissionTokenSchema), visit_find_all_role_ids(&FindAllRoleIds), diff --git a/data_model/tests/data_model.rs b/data_model/tests/data_model.rs index 8fe4b98a7a0..c795f7590a4 100644 --- a/data_model/tests/data_model.rs +++ b/data_model/tests/data_model.rs @@ -2,7 +2,7 @@ use iroha_data_model::{prelude::*, ParseError}; #[test] fn transfer_isi_should_be_valid() { - let _instruction = TransferBox::asset_quantity( + let _instruction = Transfer::asset_quantity( "btc##seller@crypto".parse().expect("Valid"), 12_u32, "buyer@crypto".parse().expect("Valid"), diff --git a/genesis/src/lib.rs b/genesis/src/lib.rs index b6ce21dd8c2..84cd9964e49 100644 --- a/genesis/src/lib.rs +++ b/genesis/src/lib.rs @@ -287,7 +287,7 @@ impl RawGenesisBlockBuilder { let new_domain = Domain::new(domain_id.clone()).with_metadata(metadata); self.transaction .isi - .push(RegisterBox::domain(new_domain).into()); + .push(Register::domain(new_domain).into()); RawGenesisDomainBuilder { transaction: self.transaction, domain_id, @@ -322,7 +322,7 @@ impl RawGenesisDomainBuilder { let account_id = AccountId::new(account_name, self.domain_id.clone()); self.transaction .isi - .push(RegisterBox::account(Account::new(account_id, [])).into()); + .push(Register::account(Account::new(account_id, [])).into()); self } @@ -340,7 +340,7 @@ impl RawGenesisDomainBuilder { ) -> Self { let account_id = AccountId::new(account_name, self.domain_id.clone()); let register = - RegisterBox::account(Account::new(account_id, [public_key]).with_metadata(metadata)); + Register::account(Account::new(account_id, [public_key]).with_metadata(metadata)); self.transaction.isi.push(register.into()); self } @@ -356,7 +356,7 @@ impl RawGenesisDomainBuilder { }; self.transaction .isi - .push(RegisterBox::asset_definition(asset_definition).into()); + .push(Register::asset_definition(asset_definition).into()); self } } @@ -418,11 +418,11 @@ mod tests { let domain_id: DomainId = "wonderland".parse().unwrap(); assert_eq!( finished_genesis_block.transactions[0].isi[0], - RegisterBox::domain(Domain::new(domain_id.clone())).into() + Register::domain(Domain::new(domain_id.clone())).into() ); assert_eq!( finished_genesis_block.transactions[0].isi[1], - RegisterBox::account(Account::new( + Register::account(Account::new( AccountId::new("alice".parse().unwrap(), domain_id.clone()), [] )) @@ -430,7 +430,7 @@ mod tests { ); assert_eq!( finished_genesis_block.transactions[0].isi[2], - RegisterBox::account(Account::new( + Register::account(Account::new( AccountId::new("bob".parse().unwrap(), domain_id), [] )) @@ -441,11 +441,11 @@ mod tests { let domain_id: DomainId = "tulgey_wood".parse().unwrap(); assert_eq!( finished_genesis_block.transactions[0].isi[3], - RegisterBox::domain(Domain::new(domain_id.clone())).into() + Register::domain(Domain::new(domain_id.clone())).into() ); assert_eq!( finished_genesis_block.transactions[0].isi[4], - RegisterBox::account(Account::new( + Register::account(Account::new( AccountId::new("Cheshire_Cat".parse().unwrap(), domain_id), [] )) @@ -456,11 +456,11 @@ mod tests { let domain_id: DomainId = "meadow".parse().unwrap(); assert_eq!( finished_genesis_block.transactions[0].isi[5], - RegisterBox::domain(Domain::new(domain_id.clone())).into() + Register::domain(Domain::new(domain_id.clone())).into() ); assert_eq!( finished_genesis_block.transactions[0].isi[6], - RegisterBox::account(Account::new( + Register::account(Account::new( AccountId::new("Mad_Hatter".parse().unwrap(), domain_id), [public_key.parse().unwrap()], )) @@ -468,7 +468,7 @@ mod tests { ); assert_eq!( finished_genesis_block.transactions[0].isi[7], - RegisterBox::asset_definition(AssetDefinition::big_quantity( + Register::asset_definition(AssetDefinition::big_quantity( "hats#meadow".parse().unwrap() )) .into() diff --git a/smart_contract/executor/src/default.rs b/smart_contract/executor/src/default.rs index a09ddc11de4..f0c5fd273bc 100644 --- a/smart_contract/executor/src/default.rs +++ b/smart_contract/executor/src/default.rs @@ -26,6 +26,7 @@ pub use domain::{ visit_transfer_domain, visit_unregister_domain, }; pub use executor::visit_upgrade; +use iroha_smart_contract::data_model::isi::InstructionBox; pub use parameter::{visit_new_parameter, visit_set_parameter}; pub use peer::{visit_register_peer, visit_unregister_peer}; pub use permission_token::{visit_grant_account_permission, visit_revoke_account_permission}; @@ -86,41 +87,52 @@ pub fn visit_instruction( authority: &AccountId, isi: &InstructionBox, ) { - macro_rules! isi_executors { - ($( - $executor:ident($isi:ident) - ),+ $(,)?) => { - match isi { $( - InstructionBox::$isi(isi) => { - executor.$executor(authority, isi); - - if executor.verdict().is_ok() { - // TODO: Execution should be infallible after successful validation - if let Err(err) = isi.execute() { - executor.deny(err); - } - } - } - )+ } - }; - } - - isi_executors! { - visit_new_parameter(NewParameter), - visit_set_parameter(SetParameter), - visit_log(Log), - visit_execute_trigger(ExecuteTrigger), - visit_burn(Burn), - visit_fail(Fail), - visit_grant(Grant), - visit_mint(Mint), - visit_register(Register), - visit_remove_key_value(RemoveKeyValue), - visit_revoke(Revoke), - visit_set_key_value(SetKeyValue), - visit_transfer(Transfer), - visit_unregister(Unregister), - visit_upgrade(Upgrade), + match isi { + InstructionBox::NewParameter(isi) => { + executor.visit_new_parameter(authority, isi); + } + InstructionBox::SetParameter(isi) => { + executor.visit_set_parameter(authority, isi); + } + InstructionBox::Log(isi) => { + executor.visit_log(authority, isi); + } + InstructionBox::ExecuteTrigger(isi) => { + executor.visit_execute_trigger(authority, isi); + } + InstructionBox::Burn(isi) => { + executor.visit_burn(authority, isi); + } + InstructionBox::Fail(isi) => { + executor.visit_fail(authority, isi); + } + InstructionBox::Grant(isi) => { + executor.visit_grant(authority, isi); + } + InstructionBox::Mint(isi) => { + executor.visit_mint(authority, isi); + } + InstructionBox::Register(isi) => { + executor.visit_register(authority, isi); + } + InstructionBox::RemoveKeyValue(isi) => { + executor.visit_remove_key_value(authority, isi); + } + InstructionBox::Revoke(isi) => { + executor.visit_revoke(authority, isi); + } + InstructionBox::SetKeyValue(isi) => { + executor.visit_set_key_value(authority, isi); + } + InstructionBox::Transfer(isi) => { + executor.visit_transfer(authority, isi); + } + InstructionBox::Unregister(isi) => { + executor.visit_unregister(authority, isi); + } + InstructionBox::Upgrade(isi) => { + executor.visit_upgrade(authority, isi); + } } } @@ -128,23 +140,24 @@ pub mod peer { use super::*; pub fn visit_register_peer( - _executor: &mut V, + executor: &mut V, _authority: &AccountId, - _isi: &Register, + isi: &Register, ) { + execute!(executor, isi) } #[allow(clippy::needless_pass_by_value)] pub fn visit_unregister_peer( executor: &mut V, authority: &AccountId, - _isi: &Unregister, + isi: &Unregister, ) { if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } if tokens::peer::CanUnregisterAnyPeer.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't unregister peer"); @@ -157,10 +170,11 @@ pub mod domain { use super::*; pub fn visit_register_domain( - _executor: &mut V, + executor: &mut V, _authority: &AccountId, - _isi: &Register, + isi: &Register, ) { + execute!(executor, isi) } pub fn visit_unregister_domain( @@ -171,18 +185,18 @@ pub mod domain { let domain_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_domain_owner(domain_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_unregister_domain_token = tokens::domain::CanUnregisterDomain { domain_id: domain_id.clone(), }; if can_unregister_domain_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't unregister domain"); @@ -196,11 +210,11 @@ pub mod domain { let destination_id = isi.object(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_domain_owner(destination_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } @@ -215,18 +229,18 @@ pub mod domain { let domain_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_domain_owner(domain_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_set_key_value_in_domain_token = tokens::domain::CanSetKeyValueInDomain { domain_id: domain_id.clone(), }; if can_set_key_value_in_domain_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't set key value in domain metadata"); @@ -240,18 +254,18 @@ pub mod domain { let domain_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_domain_owner(domain_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_remove_key_value_in_domain_token = tokens::domain::CanRemoveKeyValueInDomain { domain_id: domain_id.clone(), }; if can_remove_key_value_in_domain_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't remove key value in domain metadata"); @@ -271,18 +285,18 @@ pub mod account { let account_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_account_owner(account_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_unregister_user_account = tokens::account::CanUnregisterAccount { account_id: account_id.clone(), }; if can_unregister_user_account.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't unregister another account"); @@ -296,18 +310,18 @@ pub mod account { let account_id = isi.destination_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_account_owner(account_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_mint_user_public_keys = tokens::account::CanMintUserPublicKeys { account_id: account_id.clone(), }; if can_mint_user_public_keys.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't mint public keys of another account"); @@ -321,18 +335,18 @@ pub mod account { let account_id = isi.destination_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_account_owner(account_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_burn_user_public_keys = tokens::account::CanBurnUserPublicKeys { account_id: account_id.clone(), }; if can_burn_user_public_keys.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't burn public keys of another account"); @@ -346,11 +360,11 @@ pub mod account { let account_id = isi.destination_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_account_owner(account_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_mint_user_signature_check_conditions_token = @@ -358,7 +372,7 @@ pub mod account { account_id: account_id.clone(), }; if can_mint_user_signature_check_conditions_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -375,11 +389,11 @@ pub mod account { let account_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_account_owner(account_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_set_key_value_in_user_account_token = @@ -387,7 +401,7 @@ pub mod account { account_id: account_id.clone(), }; if can_set_key_value_in_user_account_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -404,11 +418,11 @@ pub mod account { let account_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_account_owner(account_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_remove_key_value_in_user_account_token = @@ -416,7 +430,7 @@ pub mod account { account_id: account_id.clone(), }; if can_remove_key_value_in_user_account_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -439,11 +453,11 @@ pub mod asset_definition { let asset_definition_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_asset_definition_owner(asset_definition_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_unregister_asset_definition_token = @@ -451,7 +465,7 @@ pub mod asset_definition { asset_definition_id: asset_definition_id.clone(), }; if can_unregister_asset_definition_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -469,16 +483,16 @@ pub mod asset_definition { let destination_id = isi.object(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_account_owner(source_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } match is_asset_definition_owner(destination_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } @@ -496,11 +510,11 @@ pub mod asset_definition { let asset_definition_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_asset_definition_owner(asset_definition_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_set_key_value_in_asset_definition_token = @@ -508,7 +522,7 @@ pub mod asset_definition { asset_definition_id: asset_definition_id.clone(), }; if can_set_key_value_in_asset_definition_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -525,11 +539,11 @@ pub mod asset_definition { let asset_definition_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_asset_definition_owner(asset_definition_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_remove_key_value_in_asset_definition_token = @@ -537,7 +551,7 @@ pub mod asset_definition { asset_definition_id: asset_definition_id.clone(), }; if can_remove_key_value_in_asset_definition_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -548,6 +562,8 @@ pub mod asset_definition { } pub mod asset { + use iroha_smart_contract::data_model::isi::Instruction; + use iroha_smart_contract_utils::Encode; use permission::{asset::is_asset_owner, asset_definition::is_asset_definition_owner}; use super::*; @@ -560,11 +576,11 @@ pub mod asset { let asset = isi.object(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_asset_definition_owner(asset.id().definition_id(), authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_register_assets_with_definition_token = @@ -572,7 +588,7 @@ pub mod asset { asset_definition_id: asset.id().definition_id().clone(), }; if can_register_assets_with_definition_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -589,16 +605,16 @@ pub mod asset { let asset_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_asset_owner(asset_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } match is_asset_definition_owner(asset_id.definition_id(), authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_unregister_assets_with_definition_token = @@ -606,36 +622,38 @@ pub mod asset { asset_definition_id: asset_id.definition_id().clone(), }; if can_unregister_assets_with_definition_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } let can_unregister_user_asset_token = tokens::asset::CanUnregisterUserAsset { asset_id: asset_id.clone(), }; if can_unregister_user_asset_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't unregister asset from another account"); } - fn validate_mint_asset( - executor: &mut V, - authority: &AccountId, - asset_id: &AssetId, - ) { + fn validate_mint_asset(executor: &mut V, authority: &AccountId, isi: &Mint) + where + V: Validate + ?Sized, + Q: Into, + Mint: Instruction + Encode + Clone, + { + let asset_id = isi.destination_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_asset_definition_owner(asset_id.definition_id(), authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_mint_assets_with_definition_token = tokens::asset::CanMintAssetsWithDefinition { asset_definition_id: asset_id.definition_id().clone(), }; if can_mint_assets_with_definition_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -649,8 +667,7 @@ pub mod asset { authority: &AccountId, isi: &Mint, ) { - let asset_id = isi.destination_id(); - validate_mint_asset(executor, authority, asset_id); + validate_mint_asset(executor, authority, isi); } pub fn visit_mint_asset_big_quantity( @@ -658,8 +675,7 @@ pub mod asset { authority: &AccountId, isi: &Mint, ) { - let asset_id = isi.destination_id(); - validate_mint_asset(executor, authority, asset_id); + validate_mint_asset(executor, authority, isi); } pub fn visit_mint_asset_fixed( @@ -667,39 +683,40 @@ pub mod asset { authority: &AccountId, isi: &Mint, ) { - let asset_id = isi.destination_id(); - validate_mint_asset(executor, authority, asset_id); + validate_mint_asset(executor, authority, isi); } - fn validate_burn_asset( - executor: &mut V, - authority: &AccountId, - asset_id: &AssetId, - ) { + fn validate_burn_asset(executor: &mut V, authority: &AccountId, isi: &Burn) + where + V: Validate + ?Sized, + Q: Into, + Burn: Instruction + Encode + Clone, + { + let asset_id = isi.destination_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_asset_owner(asset_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } match is_asset_definition_owner(asset_id.definition_id(), authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_burn_assets_with_definition_token = tokens::asset::CanBurnAssetsWithDefinition { asset_definition_id: asset_id.definition_id().clone(), }; if can_burn_assets_with_definition_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } let can_burn_user_asset_token = tokens::asset::CanBurnUserAsset { asset_id: asset_id.clone(), }; if can_burn_user_asset_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't burn assets from another account"); @@ -710,8 +727,7 @@ pub mod asset { authority: &AccountId, isi: &Burn, ) { - let asset_id = isi.destination_id(); - validate_burn_asset(executor, authority, asset_id); + validate_burn_asset(executor, authority, isi); } pub fn visit_burn_asset_big_quantity( @@ -719,8 +735,7 @@ pub mod asset { authority: &AccountId, isi: &Burn, ) { - let asset_id = isi.destination_id(); - validate_burn_asset(executor, authority, asset_id); + validate_burn_asset(executor, authority, isi); } pub fn visit_burn_asset_fixed( @@ -728,26 +743,30 @@ pub mod asset { authority: &AccountId, isi: &Burn, ) { - let asset_id = isi.destination_id(); - validate_burn_asset(executor, authority, asset_id); + validate_burn_asset(executor, authority, isi); } - fn validate_transfer_asset( + fn validate_transfer_asset( executor: &mut V, authority: &AccountId, - asset_id: &AssetId, - ) { + isi: &Transfer, + ) where + V: Validate + ?Sized, + Q: Into, + Transfer: Instruction + Encode + Clone, + { + let asset_id = isi.source_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_asset_owner(asset_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } match is_asset_definition_owner(asset_id.definition_id(), authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_transfer_assets_with_definition_token = @@ -755,13 +774,13 @@ pub mod asset { asset_definition_id: asset_id.definition_id().clone(), }; if can_transfer_assets_with_definition_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } let can_transfer_user_asset_token = tokens::asset::CanTransferUserAsset { asset_id: asset_id.clone(), }; if can_transfer_user_asset_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't transfer assets of another account"); @@ -772,8 +791,7 @@ pub mod asset { authority: &AccountId, isi: &Transfer, ) { - let asset_id = isi.source_id(); - validate_transfer_asset(executor, authority, asset_id); + validate_transfer_asset(executor, authority, isi); } pub fn visit_transfer_asset_big_quantity( @@ -781,8 +799,7 @@ pub mod asset { authority: &AccountId, isi: &Transfer, ) { - let asset_id = isi.source_id(); - validate_transfer_asset(executor, authority, asset_id); + validate_transfer_asset(executor, authority, isi); } pub fn visit_transfer_asset_fixed( @@ -790,8 +807,7 @@ pub mod asset { authority: &AccountId, isi: &Transfer, ) { - let asset_id = isi.source_id(); - validate_transfer_asset(executor, authority, asset_id); + validate_transfer_asset(executor, authority, isi); } pub fn visit_set_asset_key_value( @@ -802,11 +818,11 @@ pub mod asset { let asset_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_asset_owner(asset_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } @@ -814,7 +830,7 @@ pub mod asset { asset_id: asset_id.clone(), }; if can_set_key_value_in_user_asset_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -831,11 +847,11 @@ pub mod asset { let asset_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_asset_owner(asset_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_remove_key_value_in_user_asset_token = @@ -843,7 +859,7 @@ pub mod asset { asset_id: asset_id.clone(), }; if can_remove_key_value_in_user_asset_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -860,13 +876,13 @@ pub mod parameter { pub fn visit_new_parameter( executor: &mut V, authority: &AccountId, - _isi: &NewParameter, + isi: &NewParameter, ) { if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } if tokens::parameter::CanCreateParameters.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -879,13 +895,13 @@ pub mod parameter { pub fn visit_set_parameter( executor: &mut V, authority: &AccountId, - _isi: &SetParameter, + isi: &SetParameter, ) { if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } if tokens::parameter::CanSetParameters.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -934,6 +950,7 @@ pub mod role { } assert!(unknown_tokens.is_empty(), "Role contains unknown permission tokens: {unknown_tokens:?}"); + execute!($executor, $isi) }; } @@ -969,20 +986,20 @@ pub mod role { ); } - pass!(executor); + execute!(executor, isi); } #[allow(clippy::needless_pass_by_value)] pub fn visit_unregister_role( executor: &mut V, authority: &AccountId, - _isi: &Unregister, + isi: &Unregister, ) { if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } if tokens::role::CanUnregisterAnyRole.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't unregister role"); @@ -1018,18 +1035,18 @@ pub mod trigger { let trigger_id = isi.object_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_trigger_owner(trigger_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_unregister_user_trigger_token = tokens::trigger::CanUnregisterUserTrigger { trigger_id: trigger_id.clone(), }; if can_unregister_user_trigger_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -1046,18 +1063,18 @@ pub mod trigger { let trigger_id = isi.destination_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_trigger_owner(trigger_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_mint_user_trigger_token = tokens::trigger::CanMintUserTrigger { trigger_id: trigger_id.clone(), }; if can_mint_user_trigger_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -1074,18 +1091,18 @@ pub mod trigger { let trigger_id = isi.destination_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_trigger_owner(trigger_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_mint_user_trigger_token = tokens::trigger::CanBurnUserTrigger { trigger_id: trigger_id.clone(), }; if can_mint_user_trigger_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!( @@ -1102,18 +1119,18 @@ pub mod trigger { let trigger_id = isi.trigger_id(); if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } match is_trigger_owner(trigger_id, authority) { Err(err) => deny!(executor, err), - Ok(true) => pass!(executor), + Ok(true) => execute!(executor, isi), Ok(false) => {} } let can_execute_trigger_token = tokens::trigger::CanExecuteUserTrigger { trigger_id: trigger_id.clone(), }; if can_execute_trigger_token.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't execute trigger owned by another account"); @@ -1124,14 +1141,14 @@ pub mod permission_token { use super::*; macro_rules! impl_validate { - ($executor:ident, $authority:ident, $self:ident, $method:ident) => { + ($executor:ident, $authority:ident, $isi:ident, $method:ident) => { // TODO: https://github.com/hyperledger/iroha/issues/4082 - let token = $self.object().clone(); + let token = $isi.object().clone(); macro_rules! visit_internal { ($token:ident) => { if is_genesis($executor) { - pass!($executor); + execute!($executor, $isi); } if let Err(error) = permission::ValidateGrantRevoke::$method( &$token, @@ -1141,7 +1158,7 @@ pub mod permission_token { deny!($executor, error); } - pass!($executor); + execute!($executor, $isi); }; } @@ -1178,13 +1195,13 @@ pub mod executor { pub fn visit_upgrade( executor: &mut V, authority: &AccountId, - _isi: &Upgrade, + isi: &Upgrade, ) { if is_genesis(executor) { - pass!(executor); + execute!(executor, isi); } if tokens::executor::CanUpgradeExecutor.is_owned_by(authority) { - pass!(executor); + execute!(executor, isi); } deny!(executor, "Can't upgrade executor"); diff --git a/smart_contract/executor/src/lib.rs b/smart_contract/executor/src/lib.rs index e3770f4fb98..ef953f78f14 100644 --- a/smart_contract/executor/src/lib.rs +++ b/smart_contract/executor/src/lib.rs @@ -131,20 +131,23 @@ mod host { } } -/// Shortcut for `return Ok(())`. +/// Execute instruction if verdict is [`Ok`], deny if execution failed and return. +/// +/// Convention is that you have no checks left if you decided to execute instruction. #[macro_export] -macro_rules! pass { - ($executor:ident) => {{ - #[cfg(debug_assertions)] - if let Err(_error) = $executor.verdict() { - unreachable!("Executor already denied"); +macro_rules! execute { + ($executor:ident, $isi:ident) => {{ + if $executor.verdict().is_ok() { + if let Err(err) = $isi.execute() { + $executor.deny(err); + } } return; }}; } -/// Shortcut for `return Err(ValidationFail)`. +/// Shortcut for setting verdict to [`Err`] and return. /// /// Supports [`format!`](alloc::fmt::format) syntax as well as any expression returning [`String`](alloc::string::String). #[macro_export] @@ -229,6 +232,6 @@ pub mod prelude { visit::Visit, ValidationFail, }, - deny, pass, PermissionTokenSchema, Validate, + deny, execute, PermissionTokenSchema, Validate, }; } diff --git a/smart_contract/src/lib.rs b/smart_contract/src/lib.rs index 86c6407a101..2bdd93706db 100644 --- a/smart_contract/src/lib.rs +++ b/smart_contract/src/lib.rs @@ -438,7 +438,7 @@ mod tests { fn get_test_instruction() -> InstructionBox { let new_account_id = "mad_hatter@wonderland".parse().expect("Valid"); - let register_isi = RegisterBox::account(Account::new(new_account_id, [])); + let register_isi = Register::account(Account::new(new_account_id, [])); register_isi.into() } diff --git a/smart_contract/utils/src/lib.rs b/smart_contract/utils/src/lib.rs index ec9f70a242e..5e0919b095a 100644 --- a/smart_contract/utils/src/lib.rs +++ b/smart_contract/utils/src/lib.rs @@ -7,7 +7,7 @@ extern crate alloc; use alloc::{boxed::Box, format, vec::Vec}; use core::ops::RangeFrom; -use parity_scale_codec::{DecodeAll, Encode}; +pub use parity_scale_codec::{DecodeAll, Encode}; pub mod debug; pub mod log; diff --git a/tools/kagami/src/genesis.rs b/tools/kagami/src/genesis.rs index 2fcde10db5f..6036e4723ab 100644 --- a/tools/kagami/src/genesis.rs +++ b/tools/kagami/src/genesis.rs @@ -4,7 +4,6 @@ use clap::{ArgGroup, Parser, Subcommand}; use iroha_config::{sumeragi::default::*, wasm::default::*, wsv::default::*}; use iroha_data_model::{ asset::AssetValueType, - isi::{MintBox, RegisterBox}, metadata::Limits, parameter::{default::*, ParametersBuilder}, prelude::AssetId, @@ -145,19 +144,19 @@ pub fn generate_default(executor: ExecutorMode) -> color_eyre::Result::new( - vec![MintBox::asset_quantity(1_u32, rose_id)], + vec![Mint::asset_quantity(1_u32, rose_id)], Repeats::Indefinitely, account_id, FilterBox::Data(DataEventFilter::BySome(DataEntityFilter::ByAccount(