From 52db4df9ab941aff31dd2ec4dea8cffc596f3936 Mon Sep 17 00:00:00 2001 From: Dmitry Balashov <43530070+0x009922@users.noreply.github.com> Date: Thu, 16 May 2024 11:57:45 +0900 Subject: [PATCH 1/4] feat!: unify executor data model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marin Veršić <marin.versic101@gmail.com> Co-authored-by: Nikita Strygin <dcnick3@users.noreply.github.com> Co-authored-by: Shanin Roman <shanin1000@yandex.ru> Co-authored-by: Dmitry Murzin <diralik@yandex.ru> Signed-off-by: Dmitry Balashov <43530070+0x009922@users.noreply.github.com> --- client/benches/tps/utils.rs | 20 +- client/src/client.rs | 17 +- client/tests/integration/asset_propagation.rs | 18 +- client/tests/integration/events/data.rs | 8 +- client/tests/integration/events/pipeline.rs | 22 +- .../extra_functional/connected_peers.rs | 19 +- .../multiple_blocks_created.rs | 18 +- .../extra_functional/offline_peers.rs | 13 +- .../extra_functional/restart_peer.rs | 4 +- .../extra_functional/unregister_peer.rs | 21 +- .../extra_functional/unstable_network.rs | 15 +- client/tests/integration/mod.rs | 2 +- client/tests/integration/parameters.rs | 83 +++ client/tests/integration/permissions.rs | 18 +- client/tests/integration/roles.rs | 13 +- client/tests/integration/set_parameter.rs | 62 --- .../integration/smartcontracts/Cargo.toml | 1 + .../executor_remove_permission/src/lib.rs | 15 +- .../executor_with_custom_parameter/Cargo.toml | 24 + .../executor_with_custom_parameter/src/lib.rs | 68 +++ .../src/lib.rs | 42 +- client/tests/integration/status_response.rs | 3 +- client/tests/integration/upgrade.rs | 61 ++- client_cli/src/main.rs | 8 +- configs/swarm/executor.wasm | Bin 522309 -> 526886 bytes configs/swarm/genesis.json | 48 +- core/src/smartcontracts/isi/account.rs | 16 +- core/src/smartcontracts/isi/mod.rs | 1 - core/src/smartcontracts/isi/query.rs | 4 +- core/src/smartcontracts/isi/world.rs | 117 ++--- core/src/smartcontracts/wasm.rs | 48 +- core/src/state.rs | 120 ++--- core/src/sumeragi/main_loop.rs | 20 +- core/test_network/src/lib.rs | 113 +++-- data_model/src/events/data/events.rs | 86 ++-- data_model/src/events/data/filters.rs | 22 - data_model/src/executor.rs | 71 ++- data_model/src/isi.rs | 25 +- data_model/src/lib.rs | 471 ++++++------------ data_model/src/permission.rs | 184 ++----- data_model/src/query/mod.rs | 58 ++- data_model/src/role.rs | 2 +- data_model/src/transaction.rs | 1 - data_model/src/visit.rs | 11 +- default_executor/src/lib.rs | 8 +- docs/source/references/schema.json | 243 +++------ schema/gen/src/lib.rs | 34 +- smart_contract/executor/derive/src/default.rs | 9 +- .../executor/derive/src/entrypoint.rs | 1 + smart_contract/executor/derive/src/lib.rs | 16 +- .../executor/derive/src/permission.rs | 34 ++ smart_contract/executor/derive/src/token.rs | 80 --- smart_contract/executor/src/default.rs | 206 ++++---- .../src/default/{tokens.rs => permissions.rs} | 204 ++++---- smart_contract/executor/src/lib.rs | 134 +++-- smart_contract/executor/src/parameter.rs | 59 +++ smart_contract/executor/src/permission.rs | 94 +++- tools/kagami/Cargo.toml | 2 +- tools/kagami/src/genesis.rs | 59 --- tools/parity_scale_cli/src/main.rs | 46 +- 60 files changed, 1434 insertions(+), 1788 deletions(-) create mode 100644 client/tests/integration/parameters.rs delete mode 100644 client/tests/integration/set_parameter.rs create mode 100644 client/tests/integration/smartcontracts/executor_with_custom_parameter/Cargo.toml create mode 100644 client/tests/integration/smartcontracts/executor_with_custom_parameter/src/lib.rs create mode 100644 smart_contract/executor/derive/src/permission.rs delete mode 100644 smart_contract/executor/derive/src/token.rs rename smart_contract/executor/src/default/{tokens.rs => permissions.rs} (77%) create mode 100644 smart_contract/executor/src/parameter.rs diff --git a/client/benches/tps/utils.rs b/client/benches/tps/utils.rs index 913aca11688..94a4e5a95de 100644 --- a/client/benches/tps/utils.rs +++ b/client/benches/tps/utils.rs @@ -1,14 +1,7 @@ use std::{fmt, fs::File, io::BufReader, path::Path, sync::mpsc, thread, time}; use eyre::{Result, WrapErr}; -use iroha_client::{ - client::Client, - crypto::KeyPair, - data_model::{ - parameter::{default::MAX_TRANSACTIONS_IN_BLOCK, ParametersBuilder}, - prelude::*, - }, -}; +use iroha_client::{client::Client, crypto::KeyPair, data_model::prelude::*}; use iroha_data_model::events::pipeline::{BlockEventFilter, BlockStatus}; use nonzero_ext::nonzero; use serde::Deserialize; @@ -51,16 +44,13 @@ impl Config { pub fn measure(self) -> Result<Tps> { // READY - let (_rt, network, client) = Network::start_test_with_runtime(self.peers, None); + let (_rt, network, _client) = Network::start_test_with_runtime( + NetworkOptions::with_n_peers(self.peers) + .with_max_txs_in_block(self.max_txs_per_block.try_into().unwrap()), + ); let clients = network.clients(); wait_for_genesis_committed_with_max_retries(&clients, 0, self.genesis_max_retries); - client.submit_all_blocking( - ParametersBuilder::new() - .add_parameter(MAX_TRANSACTIONS_IN_BLOCK, self.max_txs_per_block)? - .into_set_parameters(), - )?; - let unit_names = (UnitName::MIN..).take(self.peers as usize); let units = clients .into_iter() diff --git a/client/src/client.rs b/client/src/client.rs index f1079c1138a..4840144e195 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -328,7 +328,7 @@ impl_query_output! { crate::data_model::block::BlockHeader, crate::data_model::metadata::MetadataValueBox, crate::data_model::query::TransactionQueryOutput, - crate::data_model::permission::PermissionSchema, + crate::data_model::executor::ExecutorDataModel, crate::data_model::trigger::Trigger, crate::data_model::prelude::Numeric, } @@ -1517,11 +1517,6 @@ pub mod permission { //! Module with queries for permission tokens use super::*; - /// Construct a query to get all registered [`PermissionDefinition`]s - pub const fn permission_schema() -> FindPermissionSchema { - FindPermissionSchema {} - } - /// Construct a query to get all [`Permission`] granted /// to account with given [`Id`][AccountId] pub fn by_account_id(account_id: AccountId) -> FindPermissionsByAccountId { @@ -1564,6 +1559,16 @@ pub mod parameter { } } +pub mod executor { + //! Queries for executor entities + use super::*; + + /// Retrieve executor data model + pub const fn data_model() -> FindExecutorDataModel { + FindExecutorDataModel + } +} + #[cfg(test)] mod tests { use std::str::FromStr; diff --git a/client/tests/integration/asset_propagation.rs b/client/tests/integration/asset_propagation.rs index 84396976c85..ac46b31174d 100644 --- a/client/tests/integration/asset_propagation.rs +++ b/client/tests/integration/asset_propagation.rs @@ -3,12 +3,10 @@ use std::{str::FromStr as _, thread}; use eyre::Result; use iroha_client::{ client::{self, QueryResult}, - data_model::{ - parameter::{default::MAX_TRANSACTIONS_IN_BLOCK, ParametersBuilder}, - prelude::*, - }, + data_model::prelude::*, }; use iroha_config::parameters::actual::Root as Config; +use nonzero_ext::nonzero; use test_network::*; use test_samples::gen_account_in; @@ -18,16 +16,14 @@ use test_samples::gen_account_in; fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount_on_another_peer( ) -> Result<()> { // Given - let (_rt, network, client) = Network::start_test_with_runtime(4, Some(10_450)); + let (_rt, network, client) = Network::start_test_with_runtime( + NetworkOptions::with_n_peers(4) + .with_start_port(10_450) + .with_max_txs_in_block(nonzero!(1u32)), + ); wait_for_genesis_committed(&network.clients(), 0); let pipeline_time = Config::pipeline_time(); - client.submit_all_blocking( - ParametersBuilder::new() - .add_parameter(MAX_TRANSACTIONS_IN_BLOCK, 1u32)? - .into_set_parameters(), - )?; - let create_domain: InstructionBox = Register::domain(Domain::new(DomainId::from_str("domain")?)).into(); let (account_id, _account_keypair) = gen_account_in("domain"); diff --git a/client/tests/integration/events/data.rs b/client/tests/integration/events/data.rs index 9d29901409f..7dcbe278d2c 100644 --- a/client/tests/integration/events/data.rs +++ b/client/tests/integration/events/data.rs @@ -240,13 +240,13 @@ fn produce_multiple_events() -> Result<()> { DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionAdded( AccountPermissionChanged { account_id: bob_id.clone(), - permission_id: token_1.definition_id.clone(), + permission_id: token_1.id.clone(), }, ))), DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionAdded( AccountPermissionChanged { account_id: bob_id.clone(), - permission_id: token_2.definition_id.clone(), + permission_id: token_2.id.clone(), }, ))), DataEvent::Domain(DomainEvent::Account(AccountEvent::RoleGranted( @@ -258,13 +258,13 @@ fn produce_multiple_events() -> Result<()> { DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionRemoved( AccountPermissionChanged { account_id: bob_id.clone(), - permission_id: token_1.definition_id, + permission_id: token_1.id, }, ))), DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionRemoved( AccountPermissionChanged { account_id: bob_id.clone(), - permission_id: token_2.definition_id, + permission_id: token_2.id, }, ))), DataEvent::Domain(DomainEvent::Account(AccountEvent::RoleRevoked( diff --git a/client/tests/integration/events/pipeline.rs b/client/tests/integration/events/pipeline.rs index 778cb29615f..67ece93cf73 100644 --- a/client/tests/integration/events/pipeline.rs +++ b/client/tests/integration/events/pipeline.rs @@ -1,13 +1,7 @@ use std::thread::{self, JoinHandle}; use eyre::Result; -use iroha_client::{ - crypto::HashOf, - data_model::{ - parameter::{default::MAX_TRANSACTIONS_IN_BLOCK, ParametersBuilder}, - prelude::*, - }, -}; +use iroha_client::{crypto::HashOf, data_model::prelude::*}; use iroha_config::parameters::actual::Root as Config; use iroha_data_model::{ events::pipeline::{ @@ -17,6 +11,7 @@ use iroha_data_model::{ transaction::error::TransactionRejectionReason, ValidationFail, }; +use nonzero_ext::nonzero; use test_network::*; // Needed to re-enable ignored tests. @@ -49,18 +44,15 @@ fn test_with_instruction_and_status_and_port( should_be: &TransactionStatus, port: u16, ) -> Result<()> { - let (_rt, network, client) = - Network::start_test_with_runtime(PEER_COUNT.try_into().unwrap(), Some(port)); + let (_rt, network, client) = Network::start_test_with_runtime( + NetworkOptions::with_n_peers(PEER_COUNT.try_into().unwrap()) + .with_start_port(port) + .with_max_txs_in_block(nonzero!(1u32)), + ); let clients = network.clients(); wait_for_genesis_committed(&clients, 0); let pipeline_time = Config::pipeline_time(); - client.submit_all_blocking( - ParametersBuilder::new() - .add_parameter(MAX_TRANSACTIONS_IN_BLOCK, 1u32)? - .into_set_parameters(), - )?; - // Given let submitter = client; let transaction = submitter.build_transaction(instruction, UnlimitedMetadata::new()); diff --git a/client/tests/integration/extra_functional/connected_peers.rs b/client/tests/integration/extra_functional/connected_peers.rs index 000a352ce3d..a8b248b4f8e 100644 --- a/client/tests/integration/extra_functional/connected_peers.rs +++ b/client/tests/integration/extra_functional/connected_peers.rs @@ -17,17 +17,18 @@ use tokio::runtime::Runtime; #[ignore = "ignore, more in #2851"] #[test] fn connected_peers_with_f_2_1_2() -> Result<()> { - connected_peers_with_f(2, Some(11_020)) + connected_peers_with_f(2, 11_020) } #[test] fn connected_peers_with_f_1_0_1() -> Result<()> { - connected_peers_with_f(1, Some(11_000)) + connected_peers_with_f(1, 11_000) } #[test] fn register_new_peer() -> Result<()> { - let (_rt, network, _) = Network::start_test_with_runtime(4, Some(11_180)); + let (_rt, network, _) = + Network::start_test_with_runtime(NetworkOptions::with_n_peers(4).with_start_port(11_180)); wait_for_genesis_committed(&network.clients(), 0); let pipeline_time = Config::pipeline_time(); @@ -65,14 +66,16 @@ fn register_new_peer() -> Result<()> { } /// Test the number of connected peers, changing the number of faults tolerated down and up -fn connected_peers_with_f(faults: u64, start_port: Option<u16>) -> Result<()> { +fn connected_peers_with_f(faults: u64, start_port: u16) -> Result<()> { let n_peers = 3 * faults + 1; let (_rt, network, _) = Network::start_test_with_runtime( - (n_peers) - .try_into() - .wrap_err("`faults` argument `u64` value too high, cannot convert to `u32`")?, - start_port, + NetworkOptions::with_n_peers( + (n_peers) + .try_into() + .wrap_err("`faults` argument `u64` value too high, cannot convert to `u32`")?, + ) + .with_start_port(start_port), ); wait_for_genesis_committed(&network.clients(), 0); let pipeline_time = Config::pipeline_time(); diff --git a/client/tests/integration/extra_functional/multiple_blocks_created.rs b/client/tests/integration/extra_functional/multiple_blocks_created.rs index 0c96b849824..175cc809d10 100644 --- a/client/tests/integration/extra_functional/multiple_blocks_created.rs +++ b/client/tests/integration/extra_functional/multiple_blocks_created.rs @@ -3,12 +3,10 @@ use std::thread; use eyre::Result; use iroha_client::{ client::{self, Client, QueryResult}, - data_model::{ - parameter::{default::MAX_TRANSACTIONS_IN_BLOCK, ParametersBuilder}, - prelude::*, - }, + data_model::prelude::*, }; use iroha_config::parameters::actual::Root as Config; +use nonzero_ext::nonzero; use test_network::*; use test_samples::gen_account_in; @@ -18,16 +16,14 @@ const N_BLOCKS: usize = 510; #[test] fn long_multiple_blocks_created() -> Result<()> { // Given - let (_rt, network, client) = Network::start_test_with_runtime(4, Some(10_965)); + let (_rt, network, client) = Network::start_test_with_runtime( + NetworkOptions::with_n_peers(4) + .with_start_port(10_965) + .with_max_txs_in_block(nonzero!(1u32)), + ); wait_for_genesis_committed(&network.clients(), 0); let pipeline_time = Config::pipeline_time(); - client.submit_all_blocking( - ParametersBuilder::new() - .add_parameter(MAX_TRANSACTIONS_IN_BLOCK, 1u32)? - .into_set_parameters(), - )?; - let create_domain: InstructionBox = Register::domain(Domain::new("domain".parse()?)).into(); let (account_id, _account_keypair) = gen_account_in("domain"); let create_account = Register::account(Account::new(account_id.clone())).into(); diff --git a/client/tests/integration/extra_functional/offline_peers.rs b/client/tests/integration/extra_functional/offline_peers.rs index b6455eed100..1b5fd66535a 100644 --- a/client/tests/integration/extra_functional/offline_peers.rs +++ b/client/tests/integration/extra_functional/offline_peers.rs @@ -18,10 +18,10 @@ fn genesis_block_is_committed_with_some_offline_peers() -> Result<()> { // Given let rt = Runtime::test(); - let (network, client) = rt.block_on(Network::start_test_with_offline_and_set_n_shifts( - 4, - 1, - Some(10_560), + let (network, client) = rt.block_on(Network::start_test( + NetworkOptions::with_n_peers(4) + .with_offline_peers(1) + .with_start_port(10_560), )); wait_for_genesis_committed(&network.clients(), 1); @@ -44,9 +44,8 @@ fn genesis_block_is_committed_with_some_offline_peers() -> Result<()> { #[test] fn register_offline_peer() -> Result<()> { - let n_peers = 4; - - let (_rt, network, client) = Network::start_test_with_runtime(n_peers, Some(11_160)); + let (_rt, network, client) = + Network::start_test_with_runtime(NetworkOptions::with_n_peers(4).with_start_port(11_160)); wait_for_genesis_committed(&network.clients(), 0); let pipeline_time = Config::pipeline_time(); let peer_clients = Network::clients(&network); diff --git a/client/tests/integration/extra_functional/restart_peer.rs b/client/tests/integration/extra_functional/restart_peer.rs index 5b1995ad2d2..c16aa8d63b2 100644 --- a/client/tests/integration/extra_functional/restart_peer.rs +++ b/client/tests/integration/extra_functional/restart_peer.rs @@ -20,7 +20,9 @@ fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> { let mut removed_peer = { let n_peers = 4; - let (_rt, network, _) = Network::start_test_with_runtime(n_peers, Some(11_205)); + let (_rt, network, _) = Network::start_test_with_runtime( + NetworkOptions::with_n_peers(n_peers).with_start_port(11_205), + ); wait_for_genesis_committed(&network.clients(), 0); let pipeline_time = Config::pipeline_time(); let peer_clients = Network::clients(&network); diff --git a/client/tests/integration/extra_functional/unregister_peer.rs b/client/tests/integration/extra_functional/unregister_peer.rs index 5742025cc01..0e79c8fe55d 100644 --- a/client/tests/integration/extra_functional/unregister_peer.rs +++ b/client/tests/integration/extra_functional/unregister_peer.rs @@ -3,12 +3,10 @@ use std::thread; use eyre::Result; use iroha_client::{ client::{self, QueryResult}, - data_model::{ - parameter::{default::MAX_TRANSACTIONS_IN_BLOCK, ParametersBuilder}, - prelude::*, - }, + data_model::prelude::*, }; use iroha_config::parameters::actual::Root as Config; +use nonzero_ext::nonzero; use test_network::*; use test_samples::gen_account_in; @@ -114,24 +112,25 @@ fn init() -> Result<( AccountId, AssetDefinitionId, )> { - let (rt, network, client) = Network::start_test_with_runtime(4, Some(10_925)); + let (rt, network, client) = Network::start_test_with_runtime( + NetworkOptions::with_n_peers(4) + .with_start_port(10_925) + .with_max_txs_in_block(nonzero!(1u32)), + ); let pipeline_time = Config::pipeline_time(); iroha_logger::info!("Started"); - let parameters = ParametersBuilder::new() - .add_parameter(MAX_TRANSACTIONS_IN_BLOCK, 1u32)? - .into_set_parameters(); let create_domain = Register::domain(Domain::new("domain".parse()?)); let (account_id, _account_keypair) = gen_account_in("domain"); let create_account = Register::account(Account::new(account_id.clone())); let asset_definition_id: AssetDefinitionId = "xor#domain".parse()?; let create_asset = Register::asset_definition(AssetDefinition::numeric(asset_definition_id.clone())); - let instructions = parameters.into_iter().chain([ + let isi: [InstructionBox; 3] = [ create_domain.into(), create_account.into(), create_asset.into(), - ]); - client.submit_all_blocking(instructions)?; + ]; + client.submit_all_blocking(isi)?; iroha_logger::info!("Init"); Ok(( rt, diff --git a/client/tests/integration/extra_functional/unstable_network.rs b/client/tests/integration/extra_functional/unstable_network.rs index 52b2b9ad851..d0b1fd2c90b 100644 --- a/client/tests/integration/extra_functional/unstable_network.rs +++ b/client/tests/integration/extra_functional/unstable_network.rs @@ -61,11 +61,16 @@ fn unstable_network( { configuration.sumeragi.debug_force_soft_fork = force_soft_fork; } - let network = Network::new_with_offline_peers( - Some(configuration), - n_peers + n_offline_peers, - 0, - Some(port), + let network = Network::new( + NetworkOptions::with_n_peers(n_peers + n_offline_peers) + .with_start_port(port) + .with_max_txs_in_block(MAX_TRANSACTIONS_IN_BLOCK.try_into().unwrap()) + .with_config_mut(|cfg| { + #[cfg(debug_assertions)] + { + cfg.sumeragi.debug_force_soft_fork = force_soft_fork; + } + }), ) .await .expect("Failed to init peers"); diff --git a/client/tests/integration/mod.rs b/client/tests/integration/mod.rs index 37299969665..1dc38c9fc08 100644 --- a/client/tests/integration/mod.rs +++ b/client/tests/integration/mod.rs @@ -6,10 +6,10 @@ mod events; mod extra_functional; mod non_mintable; mod pagination; +mod parameters; mod permissions; mod queries; mod roles; -mod set_parameter; mod sorting; mod status_response; mod transfer_asset; diff --git a/client/tests/integration/parameters.rs b/client/tests/integration/parameters.rs new file mode 100644 index 00000000000..290babbb2b9 --- /dev/null +++ b/client/tests/integration/parameters.rs @@ -0,0 +1,83 @@ +use std::collections::BTreeSet; + +use eyre::Result; +use iroha_client::{client, data_model::prelude::*}; +use serde_json::json; +use test_network::*; + +#[test] +fn playing_with_custom_parameter() -> Result<()> { + let (_rt, _peer, client) = <PeerBuilder>::new().with_port(11_135).start_with_runtime(); + wait_for_genesis_committed(&vec![client.clone()], 0); + + assert!( + client + .request(client::executor::data_model())? + .parameters() + .is_empty(), + "existing parameters should be empty" + ); + + // Registering some domain while there is no prefix requirement + client + .submit_blocking(Register::domain(Domain::new("axolotl".parse().unwrap()))) + .expect("should be fine"); + + let _err = client + .submit_blocking(SetParameter::new(Parameter::new( + "Whatever".parse().unwrap(), + json!({ "foo": "bar" }), + ))) + .expect_err("should not allow setting unknown parameters"); + + super::upgrade::upgrade_executor( + &client, + "tests/integration/smartcontracts/executor_with_custom_parameter", + )?; + + assert_eq!( + *client.request(client::executor::data_model())?.parameters(), + ["EnforceDomainPrefix"] + .into_iter() + .map(|x| ParameterId::new(x.parse().unwrap())) + .collect::<BTreeSet<_>>(), + "data model should have this set of parameters after upgrade" + ); + + let parameter = Parameter::new( + "EnforceDomainPrefix".parse().unwrap(), + json!({ "prefix": "disney_" }), + ); + + client + .submit_blocking(SetParameter::new(parameter.clone())) + .expect("should work, since this parameter is now registered"); + + let _err = client + .submit_blocking(SetParameter::new(Parameter::new( + "WrongNonExistingParameter".parse().unwrap(), + json!({ "prefix": "whatever" }), + ))) + .expect_err("should still not work"); + + assert_eq!( + client + .request(client::parameter::all())? + .map(Result::unwrap) + .collect::<BTreeSet<_>>(), + [parameter.clone()].into_iter().collect(), + "we should find set parameter in the parameters list" + ); + + let _err = client + .submit_blocking(Register::domain(Domain::new("land".parse().unwrap()))) + .expect_err("should fail since `land` is not prefixed with `disney_`"); + + client + .submit_blocking(Register::domain(Domain::new( + "disney_land".parse().unwrap(), + ))) + .expect("should be fine, since we used prefix according to the parameter"); + + Ok(()) +} diff --git a/client/tests/integration/permissions.rs b/client/tests/integration/permissions.rs index 678d7b71b1a..7aebf8f5e35 100644 --- a/client/tests/integration/permissions.rs +++ b/client/tests/integration/permissions.rs @@ -315,10 +315,9 @@ 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 = Grant::permission( - Permission::from_str_unchecked( + Permission::new( "CanSetKeyValueInUserAsset".parse().unwrap(), - // NOTE: Introduced additional whitespaces in the serialized form - &*format!(r###"{{ "asset_id" : "xor#wonderland#{mouse_id}" }}"###), + json!({ "asset_id": format!("xor#wonderland#{mouse_id}") }), ), alice_id, ); @@ -349,19 +348,18 @@ fn permissions_are_unified() { let alice_id = ALICE_ID.clone(); let allow_alice_to_transfer_rose_1 = Grant::permission( - Permission::from_str_unchecked( + Permission::new( "CanTransferUserAsset".parse().unwrap(), - // NOTE: Introduced additional whitespaces in the serialized form - &*format!(r###"{{ "asset_id" : "rose#wonderland#{alice_id}" }}"###), + json!({ "asset_id": format!("rose#wonderland#{alice_id}") }), ), alice_id.clone(), ); let allow_alice_to_transfer_rose_2 = Grant::permission( - Permission::from_str_unchecked( + Permission::new( "CanTransferUserAsset".parse().unwrap(), - // NOTE: Introduced additional whitespaces in the serialized form - &*format!(r###"{{ "asset_id" : "rose##{alice_id}" }}"###), + // different content, but same meaning + json!({ "asset_id": format!("rose##{alice_id}") }), ), alice_id, ); @@ -372,7 +370,7 @@ fn permissions_are_unified() { let _ = iroha_client .submit_blocking(allow_alice_to_transfer_rose_2) - .expect_err("permission tokens are not unified"); + .expect_err("should reject due to duplication"); } #[test] diff --git a/client/tests/integration/roles.rs b/client/tests/integration/roles.rs index 6efab725cd5..a27875fff2a 100644 --- a/client/tests/integration/roles.rs +++ b/client/tests/integration/roles.rs @@ -172,20 +172,19 @@ fn role_with_invalid_permissions_is_not_accepted() -> Result<()> { #[test] #[allow(deprecated)] -fn role_permissions_unified() { +fn role_permissions_are_deduplicated() { let (_rt, _peer, test_client) = <PeerBuilder>::new().with_port(11_235).start_with_runtime(); wait_for_genesis_committed(&vec![test_client.clone()], 0); - let allow_alice_to_transfer_rose_1 = Permission::from_str_unchecked( + let allow_alice_to_transfer_rose_1 = Permission::new( "CanTransferUserAsset".parse().unwrap(), - // NOTE: Introduced additional whitespaces in the serialized form - "{ \"asset_id\" : \"rose#wonderland#ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland\" }", + json!({ "asset_id": "rose#wonderland#ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland" }), ); - let allow_alice_to_transfer_rose_2 = Permission::from_str_unchecked( + // Different content, but same meaning + let allow_alice_to_transfer_rose_2 = Permission::new( "CanTransferUserAsset".parse().unwrap(), - // NOTE: Introduced additional whitespaces in the serialized form - "{ \"asset_id\" : \"rose##ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland\" }", + json!({ "asset_id": "rose##ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland" }), ); let role_id: RoleId = "role_id".parse().expect("Valid"); diff --git a/client/tests/integration/set_parameter.rs b/client/tests/integration/set_parameter.rs deleted file mode 100644 index e35209b0101..00000000000 --- a/client/tests/integration/set_parameter.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::str::FromStr; - -use eyre::Result; -use iroha_client::{ - client::{self, QueryResult}, - data_model::prelude::*, -}; -use test_network::*; - -#[test] -fn can_change_parameter_value() -> Result<()> { - let (_rt, _peer, test_client) = <PeerBuilder>::new().with_port(11_135).start_with_runtime(); - wait_for_genesis_committed(&vec![test_client.clone()], 0); - - let parameter = Parameter::from_str("?BlockTime=4000")?; - let parameter_id = ParameterId::from_str("BlockTime")?; - let param_box = SetParameter::new(parameter); - - let old_params = test_client - .request(client::parameter::all())? - .collect::<QueryResult<Vec<_>>>()?; - let param_val_old = old_params - .iter() - .find(|param| param.id() == ¶meter_id) - .expect("Parameter should exist") - .val(); - - test_client.submit_blocking(param_box)?; - - let new_params = test_client - .request(client::parameter::all())? - .collect::<QueryResult<Vec<_>>>()?; - let param_val_new = new_params - .iter() - .find(|param| param.id() == ¶meter_id) - .expect("Parameter should exist") - .val(); - - assert_ne!(param_val_old, param_val_new); - Ok(()) -} - -#[test] -fn parameter_propagated() -> Result<()> { - let (_rt, _peer, test_client) = <PeerBuilder>::new().with_port(10_985).start_with_runtime(); - 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 = 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"); - - let parameter = Parameter::from_str("?WSVIdentLengthLimits=1,256_LL")?; - let param_box = SetParameter::new(parameter); - test_client.submit_blocking(param_box)?; - - test_client - .submit_blocking(create_domain) - .expect("Should work after ident length limits update"); - Ok(()) -} diff --git a/client/tests/integration/smartcontracts/Cargo.toml b/client/tests/integration/smartcontracts/Cargo.toml index a03698db1b2..a9433d0a026 100644 --- a/client/tests/integration/smartcontracts/Cargo.toml +++ b/client/tests/integration/smartcontracts/Cargo.toml @@ -12,6 +12,7 @@ members = [ "create_nft_for_every_user_trigger", "mint_rose_trigger", "executor_with_admin", + "executor_with_custom_parameter", "executor_with_custom_permission", "executor_remove_permission", "executor_with_migration_fail", diff --git a/client/tests/integration/smartcontracts/executor_remove_permission/src/lib.rs b/client/tests/integration/smartcontracts/executor_remove_permission/src/lib.rs index 9ed9fba3b5d..a81d80355f4 100644 --- a/client/tests/integration/smartcontracts/executor_remove_permission/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_remove_permission/src/lib.rs @@ -3,11 +3,12 @@ #![no_std] -extern crate alloc; #[cfg(not(test))] extern crate panic_halt; -use iroha_executor::{default::default_permission_schema, prelude::*}; +use iroha_executor::{ + default::permissions::domain::CanUnregisterDomain, prelude::*, DataModelBuilder, +}; use lol_alloc::{FreeListAllocator, LockedAllocator}; #[global_allocator] @@ -25,13 +26,9 @@ struct Executor { pub fn migrate(_block_height: u64) -> MigrationResult { // Note that actually migration will reset token schema to default (minus `CanUnregisterDomain`) // So any added custom permission tokens will be also removed - let mut schema = default_permission_schema(); - schema.remove::<iroha_executor::default::tokens::domain::CanUnregisterDomain>(); - - let (token_ids, schema_str) = schema.serialize(); - iroha_executor::set_permission_schema( - &iroha_executor::data_model::permission::PermissionSchema::new(token_ids, schema_str), - ); + DataModelBuilder::with_default_permissions() + .remove_permission::<CanUnregisterDomain>() + .set(); Ok(()) } diff --git a/client/tests/integration/smartcontracts/executor_with_custom_parameter/Cargo.toml b/client/tests/integration/smartcontracts/executor_with_custom_parameter/Cargo.toml new file mode 100644 index 00000000000..9287d2caff4 --- /dev/null +++ b/client/tests/integration/smartcontracts/executor_with_custom_parameter/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "executor_with_custom_parameter" + +edition.workspace = true +version.workspace = true +authors.workspace = true + +license.workspace = true + +[lib] +crate-type = ['cdylib'] + +[dependencies] +iroha_executor.workspace = true +iroha_schema.workspace = true + +parity-scale-codec.workspace = true +anyhow.workspace = true +serde_json.workspace = true +serde.workspace = true + +panic-halt.workspace = true +lol_alloc.workspace = true +getrandom.workspace = true diff --git a/client/tests/integration/smartcontracts/executor_with_custom_parameter/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_custom_parameter/src/lib.rs new file mode 100644 index 00000000000..4f7a9f391d8 --- /dev/null +++ b/client/tests/integration/smartcontracts/executor_with_custom_parameter/src/lib.rs @@ -0,0 +1,68 @@ +//! Runtime Executor which defines a custom configuration parameter + +#![no_std] + +extern crate alloc; +#[cfg(not(test))] +extern crate panic_halt; + +use alloc::{format, string::String}; + +use iroha_executor::{parameter::Parameter, prelude::*, DataModelBuilder}; +use iroha_schema::IntoSchema; +use lol_alloc::{FreeListAllocator, LockedAllocator}; +use serde::{Deserialize, Serialize}; + +#[global_allocator] +static ALLOC: LockedAllocator<FreeListAllocator> = LockedAllocator::new(FreeListAllocator::new()); + +getrandom::register_custom_getrandom!(iroha_executor::stub_getrandom); + +#[derive(Constructor, ValidateEntrypoints, Validate, Visit)] +#[visit(custom(visit_register_domain, visit_set_parameter))] +struct Executor { + verdict: Result, + block_height: u64, +} + +fn visit_set_parameter(executor: &mut Executor, _authority: &AccountId, isi: &SetParameter) { + execute!(executor, isi); +} + +fn visit_register_domain(executor: &mut Executor, _authority: &AccountId, isi: &Register<Domain>) { + // FIXME: unwrap is ok here? + let required_prefix = FindAllParameters + .execute() + .unwrap() + .into_iter() + .map(Result::unwrap) + .find_map(|parameter| EnforceDomainPrefix::try_from_object(¶meter).ok()); + + if let Some(EnforceDomainPrefix { prefix }) = required_prefix { + let domain_id = isi.object().id().name().as_ref(); + if domain_id.strip_prefix(&prefix).is_none() { + deny!( + executor, + "Domain `{domain_id}` must be prefixed with `{prefix}`" + ); + } + } + + execute!(executor, isi); +} + +#[derive(IntoSchema, Serialize, Deserialize)] +struct EnforceDomainPrefix { + prefix: String, +} + +impl Parameter for EnforceDomainPrefix {} + +#[entrypoint] +pub fn migrate(_block_height: u64) -> MigrationResult { + DataModelBuilder::new() + .add_parameter::<EnforceDomainPrefix>() + .set(); + + Ok(()) +} diff --git a/client/tests/integration/smartcontracts/executor_with_custom_permission/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_custom_permission/src/lib.rs index 3c4033465c1..af0c6f04392 100644 --- a/client/tests/integration/smartcontracts/executor_with_custom_permission/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_custom_permission/src/lib.rs @@ -3,9 +3,9 @@ //! //! This executor should be applied on top of the blockchain with default validation. //! -//! It also doesn't have [`iroha_executor::default::tokens::domain::CanUnregisterDomain`]. +//! It also doesn't have [`iroha_executor::default::permissions::domain::CanUnregisterDomain`]. //! -//! In migration it replaces [`iroha_executor::default::tokens::domain::CanUnregisterDomain`] +//! In migration it replaces [`iroha_executor::default::permissions::domain::CanUnregisterDomain`] //! with [`token::CanControlDomainLives`] for all accounts. //! So it doesn't matter which domain user was able to unregister before migration, they will //! get access to control all domains. Remember that this is just a test example. @@ -16,10 +16,10 @@ extern crate alloc; #[cfg(not(test))] extern crate panic_halt; -use alloc::{borrow::ToOwned, string::String}; +use alloc::string::String; use anyhow::anyhow; -use iroha_executor::{default::default_permission_schema, permission::Token as _, prelude::*}; +use iroha_executor::{permission::Permission as _, prelude::*, DataModelBuilder}; use iroha_schema::IntoSchema; use lol_alloc::{FreeListAllocator, LockedAllocator}; use parity_scale_codec::{Decode, Encode}; @@ -42,7 +42,7 @@ mod token { #[derive( PartialEq, Eq, - Token, + Permission, ValidateGrantRevoke, Decode, Encode, @@ -95,7 +95,9 @@ impl Executor { })?; if let Ok(can_unregister_domain_token) = - iroha_executor::default::tokens::domain::CanUnregisterDomain::try_from(&token) + iroha_executor::default::permissions::domain::CanUnregisterDomain::try_from_object( + &token, + ) { found_accounts.push((account, can_unregister_domain_token.domain_id)); break; @@ -107,19 +109,16 @@ impl Executor { } fn replace_token(accounts: &[(Account, DomainId)]) -> MigrationResult { - let can_unregister_domain_definition_id = PermissionId::try_from( - iroha_executor::default::tokens::domain::CanUnregisterDomain::type_name(), - ) - .unwrap(); + let can_unregister_domain_definition_id = + iroha_executor::default::permissions::domain::CanUnregisterDomain::id(); - let can_control_domain_lives_definition_id = - PermissionId::try_from(token::CanControlDomainLives::type_name()).unwrap(); + let can_control_domain_lives_definition_id = token::CanControlDomainLives::id(); accounts .iter() .try_for_each(|(account, domain_id)| { Revoke::permission( - Permission::new( + PermissionObject::new( can_unregister_domain_definition_id.clone(), &json!({ "domain_id": domain_id }), ), @@ -138,7 +137,10 @@ impl Executor { })?; Grant::permission( - Permission::new(can_control_domain_lives_definition_id.clone(), &json!(null)), + PermissionObject::new( + can_control_domain_lives_definition_id.clone(), + &json!(null), + ), account.id().clone(), ) .execute() @@ -199,14 +201,10 @@ fn visit_unregister_domain( pub fn migrate(_block_height: u64) -> MigrationResult { let accounts = Executor::get_all_accounts_with_can_unregister_domain_permission()?; - let mut schema = default_permission_schema(); - schema.remove::<iroha_executor::default::tokens::domain::CanUnregisterDomain>(); - schema.insert::<token::CanControlDomainLives>(); - - let (token_ids, schema_str) = schema.serialize(); - iroha_executor::set_permission_schema( - &iroha_executor::data_model::permission::PermissionSchema::new(token_ids, schema_str), - ); + DataModelBuilder::with_default_permissions() + .remove_permission::<iroha_executor::default::permissions::domain::CanUnregisterDomain>() + .add_permission::<token::CanControlDomainLives>() + .set(); Executor::replace_token(&accounts) } diff --git a/client/tests/integration/status_response.rs b/client/tests/integration/status_response.rs index 8209d46b5dd..726500cf39e 100644 --- a/client/tests/integration/status_response.rs +++ b/client/tests/integration/status_response.rs @@ -16,7 +16,8 @@ fn status_eq_excluding_uptime_and_queue(lhs: &Status, rhs: &Status) -> bool { #[test] fn json_and_scale_statuses_equality() -> Result<()> { - let (_rt, network, client) = Network::start_test_with_runtime(2, Some(11_200)); + let (_rt, network, client) = + Network::start_test_with_runtime(NetworkOptions::with_n_peers(4).with_start_port(11_200)); wait_for_genesis_committed(&network.clients(), 0); let json_status_zero = get_status_json(&client).unwrap(); diff --git a/client/tests/integration/upgrade.rs b/client/tests/integration/upgrade.rs index 8910e7f4abe..637a6ea879a 100644 --- a/client/tests/integration/upgrade.rs +++ b/client/tests/integration/upgrade.rs @@ -1,6 +1,7 @@ use std::{path::Path, str::FromStr as _}; use eyre::Result; +use futures_util::TryStreamExt as _; use iroha_client::{ client::{self, Client, QueryResult}, crypto::KeyPair, @@ -10,6 +11,7 @@ use iroha_logger::info; use serde_json::json; use test_network::*; use test_samples::ALICE_ID; +use tokio::sync::mpsc; const ADMIN_PUBLIC_KEY_MULTIHASH: &str = "ed012076E5CA9698296AF9BE2CA45F525CB3BCFDEB7EE068BA56F973E9DD90564EF4FC"; @@ -76,7 +78,7 @@ fn executor_upgrade_should_run_migration() -> Result<()> { let can_unregister_domain_token_id = "CanUnregisterDomain".parse().unwrap(); // Check that `CanUnregisterDomain` exists - let definitions = client.request(FindPermissionSchema)?; + let definitions = client.request(FindExecutorDataModel)?; assert!(definitions .permissions() .iter() @@ -99,15 +101,15 @@ fn executor_upgrade_should_run_migration() -> Result<()> { )?; // Check that `CanUnregisterDomain` doesn't exist - let definitions = client.request(FindPermissionSchema)?; - assert!(!definitions + let data_model = client.request(FindExecutorDataModel)?; + assert!(!data_model .permissions() .iter() .any(|id| id == &can_unregister_domain_token_id)); let can_control_domain_lives_token_id = "CanControlDomainLives".parse().unwrap(); - assert!(definitions + assert!(data_model .permissions() .iter() .any(|id| id == &can_control_domain_lives_token_id)); @@ -144,9 +146,9 @@ fn executor_upgrade_should_revoke_removed_permissions() -> Result<()> { // Check that permission exists assert!(client - .request(FindPermissionSchema)? + .request(FindExecutorDataModel)? .permissions() - .contains(&can_unregister_domain_token.definition_id)); + .contains(&can_unregister_domain_token.id)); // Check that `TEST_ROLE` has permission assert!(client @@ -172,9 +174,9 @@ fn executor_upgrade_should_revoke_removed_permissions() -> Result<()> { // Check that permission doesn't exist assert!(!client - .request(FindPermissionSchema)? + .request(FindExecutorDataModel)? .permissions() - .contains(&can_unregister_domain_token.definition_id)); + .contains(&can_unregister_domain_token.id)); // Check that `TEST_ROLE` doesn't have permission assert!(!client @@ -225,7 +227,48 @@ fn migration_fail_should_not_cause_any_effects() { // been changed, because `executor_with_migration_fail` does not allow any queries } -fn upgrade_executor(client: &Client, executor: impl AsRef<Path>) -> Result<()> { +#[test] +fn migration_should_cause_upgrade_event() { + let (rt, _peer, client) = <PeerBuilder>::new().with_port(10_996).start_with_runtime(); + wait_for_genesis_committed(&vec![client.clone()], 0); + + let (sender, mut receiver) = mpsc::channel(1); + let events_client = client.clone(); + + let _handle = rt.spawn(async move { + let mut stream = events_client + .listen_for_events_async([ExecutorEventFilter::new()]) + .await + .unwrap(); + while let Some(event) = stream.try_next().await.unwrap() { + if let EventBox::Data(DataEvent::Executor(ExecutorEvent::Upgraded(ExecutorUpgrade { + new_data_model, + }))) = event + { + let _ = sender.send(new_data_model).await; + } + } + }); + + upgrade_executor( + &client, + "tests/integration/smartcontracts/executor_with_custom_permission", + ) + .unwrap(); + + let data_model = rt + .block_on(async { + tokio::time::timeout(std::time::Duration::from_secs(60), receiver.recv()).await + }) + .ok() + .flatten() + .expect("should receive upgraded event immediately after upgrade"); + + assert!(!data_model.permissions.is_empty()); + assert!(data_model.parameters.is_empty()); +} + +pub fn upgrade_executor(client: &Client, executor: impl AsRef<Path>) -> Result<()> { info!("Building executor"); let wasm = iroha_wasm_builder::Builder::new(executor.as_ref()) diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index d8d96386c88..6e93284efc9 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -522,7 +522,7 @@ mod account { use iroha_client::client::{self}; - use super::{Permission as DataModelPermission, *}; + use super::{Permission as PermissionObject, *}; /// subcommands for account subcommand #[derive(clap::Subcommand, Debug)] @@ -608,9 +608,9 @@ mod account { pub metadata: MetadataArgs, } - /// [`DataModelPermission`] wrapper implementing [`FromStr`] + /// [`PermissionObject`] wrapper implementing [`FromStr`] #[derive(Debug, Clone)] - pub struct Permission(DataModelPermission); + pub struct Permission(PermissionObject); impl FromStr for Permission { type Err = Error; @@ -618,7 +618,7 @@ mod account { fn from_str(s: &str) -> Result<Self> { let content = fs::read_to_string(s) .wrap_err(format!("Failed to read the permission token file {}", &s))?; - let permission: DataModelPermission = json5::from_str(&content).wrap_err(format!( + let permission: PermissionObject = json5::from_str(&content).wrap_err(format!( "Failed to deserialize the permission token from file {}", &s ))?; diff --git a/configs/swarm/executor.wasm b/configs/swarm/executor.wasm index 8c552ccf2056fc4ab83600ba6fae647b7db903ad..57349508d97d53808e2d4086357cc13e61f8c2bc 100644 GIT binary patch delta 211185 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 EAM$lCwEzGB delta 206323 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�%$7p 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 J%Mbtf{{c7cVaEUf diff --git a/configs/swarm/genesis.json b/configs/swarm/genesis.json index 5a3633d398d..b1d6e12d309 100644 --- a/configs/swarm/genesis.json +++ b/configs/swarm/genesis.json @@ -115,68 +115,26 @@ "Grant": { "Permission": { "object": { - "definition_id": "CanSetParameters", + "id": "CanSetParameters", "payload": null }, "destination_id": "ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland" } } }, - { - "NewParameter": "?MaxTransactionsInBlock=512" - }, - { - "NewParameter": "?BlockTime=2000" - }, - { - "NewParameter": "?CommitTimeLimit=4000" - }, - { - "NewParameter": "?TransactionLimits=4096,4194304_TL" - }, - { - "NewParameter": "?WSVDomainMetadataLimits=1048576,4096_ML" - }, - { - "NewParameter": "?WSVAssetDefinitionMetadataLimits=1048576,4096_ML" - }, - { - "NewParameter": "?WSVAccountMetadataLimits=1048576,4096_ML" - }, - { - "NewParameter": "?WSVAssetMetadataLimits=1048576,4096_ML" - }, - { - "NewParameter": "?WSVTriggerMetadataLimits=1048576,4096_ML" - }, - { - "NewParameter": "?WSVIdentLengthLimits=1,128_LL" - }, - { - "NewParameter": "?ExecutorFuelLimit=55000000" - }, - { - "NewParameter": "?ExecutorMaxMemory=524288000" - }, - { - "NewParameter": "?WASMFuelLimit=55000000" - }, - { - "NewParameter": "?WASMMaxMemory=524288000" - }, { "Register": { "Role": { "id": "ALICE_METADATA_ACCESS", "permissions": [ { - "definition_id": "CanRemoveKeyValueInAccount", + "id": "CanRemoveKeyValueInAccount", "payload": { "account_id": "ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland" } }, { - "definition_id": "CanSetKeyValueInAccount", + "id": "CanSetKeyValueInAccount", "payload": { "account_id": "ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland" } diff --git a/core/src/smartcontracts/isi/account.rs b/core/src/smartcontracts/isi/account.rs index 0604680ba00..2d2667c259f 100644 --- a/core/src/smartcontracts/isi/account.rs +++ b/core/src/smartcontracts/isi/account.rs @@ -245,15 +245,15 @@ pub mod isi { ) -> Result<(), Error> { let account_id = self.destination_id; let permission = self.object; - let permission_id = permission.definition_id.clone(); + let permission_id = permission.id.clone(); // Check if account exists state_transaction.world.account_mut(&account_id)?; if !state_transaction .world - .permission_schema - .token_ids + .executor_data_model + .permissions .contains(&permission_id) { return Err(FindError::Permission(permission_id).into()); @@ -265,7 +265,7 @@ pub mod isi { { return Err(RepetitionError { instruction_type: InstructionType::Grant, - id: permission.definition_id.into(), + id: permission_id.into(), } .into()); } @@ -304,7 +304,7 @@ pub mod isi { .world .remove_account_permission(&account_id, &permission) { - return Err(FindError::Permission(permission.definition_id).into()); + return Err(FindError::Permission(permission.id).into()); } state_transaction @@ -312,7 +312,7 @@ pub mod isi { .emit_events(Some(AccountEvent::PermissionRemoved( AccountPermissionChanged { account_id, - permission_id: permission.definition_id, + permission_id: permission.id, }, ))); @@ -338,7 +338,7 @@ pub mod isi { .clone() .permissions .into_iter() - .map(|token| token.definition_id); + .map(|token| token.id); state_transaction.world.account(&account_id)?; @@ -397,7 +397,7 @@ pub mod isi { .clone() .permissions .into_iter() - .map(|token| token.definition_id); + .map(|token| token.id); if state_transaction .world diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index 7eecbd9b406..e1c2bf27848 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -55,7 +55,6 @@ impl Execute for InstructionBox { Self::Revoke(isi) => isi.execute(authority, state_transaction), Self::ExecuteTrigger(isi) => isi.execute(authority, state_transaction), Self::SetParameter(isi) => isi.execute(authority, state_transaction), - Self::NewParameter(isi) => isi.execute(authority, state_transaction), Self::Upgrade(isi) => isi.execute(authority, state_transaction), Self::Log(isi) => isi.execute(authority, state_transaction), } diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 4bb37a6e8d0..2de8aec3d7b 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -162,8 +162,8 @@ impl_lazy! { iroha_data_model::block::BlockHeader, iroha_data_model::metadata::MetadataValueBox, iroha_data_model::query::TransactionQueryOutput, - iroha_data_model::permission::PermissionSchema, iroha_data_model::trigger::Trigger, + iroha_data_model::executor::ExecutorDataModel } /// Query Request statefully validated on the Iroha node side. @@ -259,7 +259,7 @@ impl ValidQuery for QueryBox { FindAccountKeyValueByIdAndKey, FindAssetDefinitionKeyValueByIdAndKey, FindTriggerKeyValueByIdAndKey, - FindPermissionSchema, + FindExecutorDataModel, } FindAllAccounts, diff --git a/core/src/smartcontracts/isi/world.rs b/core/src/smartcontracts/isi/world.rs index ec89111cf2c..fc1b00484a6 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -17,8 +17,9 @@ impl Registrable for NewRole { /// Iroha Special Instructions that have `World` as their target. pub mod isi { + use std::collections::BTreeSet; + use eyre::Result; - use indexmap::IndexSet; use iroha_data_model::{ isi::error::{InstructionExecutionError, InvalidParameterError, RepetitionError}, prelude::*, @@ -162,11 +163,11 @@ pub mod isi { for permission in &role.permissions { if !state_transaction .world - .permission_schema - .token_ids - .contains(&permission.definition_id) + .executor_data_model + .permissions + .contains(&permission.id) { - return Err(FindError::Permission(permission.definition_id.clone()).into()); + return Err(FindError::Permission(permission.id.clone()).into()); } } @@ -227,15 +228,14 @@ pub mod isi { ) -> Result<(), Error> { let role_id = self.destination_id; let permission = self.object; - let permission_id = permission.definition_id.clone(); if !state_transaction .world - .permission_schema - .token_ids - .contains(&permission_id) + .executor_data_model + .permissions + .contains(&permission.id) { - return Err(FindError::Permission(permission_id).into()); + return Err(FindError::Permission(permission.id).into()); } let Some(role) = state_transaction.world.roles.get_mut(&role_id) else { @@ -245,7 +245,7 @@ pub mod isi { if !role.permissions.insert(permission.clone()) { return Err(RepetitionError { instruction_type: InstructionType::Grant, - id: permission.definition_id.into(), + id: permission.id.into(), } .into()); } @@ -254,7 +254,7 @@ pub mod isi { .world .emit_events(Some(RoleEvent::PermissionAdded(RolePermissionChanged { role_id, - permission_id, + permission_id: permission.id, }))); Ok(()) @@ -270,21 +270,20 @@ pub mod isi { ) -> Result<(), Error> { let role_id = self.destination_id; let permission = self.object; - let permission_id = permission.definition_id.clone(); let Some(role) = state_transaction.world.roles.get_mut(&role_id) else { return Err(FindError::Role(role_id).into()); }; if !role.permissions.remove(&permission) { - return Err(FindError::Permission(permission_id).into()); + return Err(FindError::Permission(permission.id).into()); } state_transaction .world .emit_events(Some(RoleEvent::PermissionRemoved(RolePermissionChanged { role_id, - permission_id, + permission_id: permission.id, }))); Ok(()) @@ -299,41 +298,14 @@ pub mod isi { state_transaction: &mut StateTransaction<'_, '_>, ) -> Result<(), Error> { let parameter = self.parameter; - let parameter_id = parameter.id.clone(); - let world = &mut state_transaction.world; - if !world.parameters.remove(¶meter) { - return Err(FindError::Parameter(parameter_id).into()); - } - - world.parameters.insert(parameter); - - world.emit_events(Some(ConfigurationEvent::Changed(parameter_id))); - - Ok(()) - } - } - - impl Execute for NewParameter { - #[metrics(+"new_parameter")] - fn execute( - self, - _authority: &AccountId, - state_transaction: &mut StateTransaction<'_, '_>, - ) -> Result<(), Error> { - let parameter = self.parameter; - let parameter_id = parameter.id.clone(); - let world = &mut state_transaction.world; - if !world.parameters.insert(parameter) { - return Err(RepetitionError { - instruction_type: InstructionType::NewParameter, - id: IdBox::ParameterId(parameter_id), - } - .into()); + if !world.executor_data_model.parameters.contains(¶meter.id) { + return Err(FindError::Parameter(parameter.id).into()); } - world.emit_events(Some(ConfigurationEvent::Created(parameter_id))); + let _maybe_previous = world.parameters.replace(parameter.clone()); + world.emit_events(Some(ConfigurationEvent::Changed(parameter))); Ok(()) } @@ -348,7 +320,11 @@ pub mod isi { ) -> Result<(), Error> { let raw_executor = self.executor; - let permissions_before = state_transaction.world.permission_schema.token_ids.clone(); + let permissions_before = state_transaction + .world + .executor_data_model + .permissions + .clone(); // Cloning executor to avoid multiple mutable borrows of `state_transaction`. // Also it's a cheap operation. @@ -365,10 +341,13 @@ pub mod isi { *state_transaction.world.executor.get_mut() = upgraded_executor; revoke_removed_permissions(authority, state_transaction, permissions_before)?; + prune_unknown_parameters(state_transaction); state_transaction .world - .emit_events(std::iter::once(ExecutorEvent::Upgraded)); + .emit_events(std::iter::once(ExecutorEvent::Upgraded(ExecutorUpgrade { + new_data_model: state_transaction.world.executor_data_model.clone(), + }))); Ok(()) } @@ -377,18 +356,14 @@ pub mod isi { fn revoke_removed_permissions( authority: &AccountId, state_transaction: &mut StateTransaction, - permissions_before: Vec<PermissionId>, + permissions_before: BTreeSet<PermissionId>, ) -> Result<(), Error> { let world = state_transaction.world(); - let permissions_after = world - .permission_schema() - .token_ids - .iter() - .collect::<IndexSet<_>>(); + let permissions_after = &world.executor_data_model().permissions; let permissions_removed = permissions_before .into_iter() .filter(|permission| !permissions_after.contains(permission)) - .collect::<IndexSet<_>>(); + .collect::<BTreeSet<_>>(); if permissions_removed.is_empty() { return Ok(()); } @@ -407,9 +382,23 @@ pub mod isi { Ok(()) } + fn prune_unknown_parameters(state_transaction: &mut StateTransaction) { + state_transaction + .world + .parameters + .get_mut() + .retain(|parameter| { + state_transaction + .world + .executor_data_model + .parameters + .contains(¶meter.id) + }); + } + fn find_related_accounts( world: &impl WorldReadOnly, - permissions: &IndexSet<PermissionId>, + permissions: &BTreeSet<PermissionId>, ) -> Vec<(AccountId, Permission)> { world .account_permissions() @@ -417,7 +406,7 @@ pub mod isi { .flat_map(|(account_id, account_permissions)| { account_permissions .iter() - .filter(|permission| permissions.contains(&permission.definition_id)) + .filter(|permission| permissions.contains(&permission.id)) .map(|permission| (account_id.clone(), permission.clone())) }) .collect() @@ -425,7 +414,7 @@ pub mod isi { fn find_related_roles( world: &impl WorldReadOnly, - permissions: &IndexSet<PermissionId>, + permissions: &BTreeSet<PermissionId>, ) -> Vec<(RoleId, Permission)> { world .roles() @@ -433,7 +422,7 @@ pub mod isi { .flat_map(|(role_id, role)| { role.permissions .iter() - .filter(|permission| permissions.contains(&permission.definition_id)) + .filter(|permission| permissions.contains(&permission.id)) .map(|permission| (role_id.clone(), permission.clone())) }) .collect() @@ -464,9 +453,9 @@ pub mod isi { pub mod query { use eyre::Result; use iroha_data_model::{ + executor::ExecutorDataModel, parameter::Parameter, peer::Peer, - permission::PermissionSchema, prelude::*, query::error::{FindError, QueryExecutionFail as Error}, role::{Role, RoleId}, @@ -534,10 +523,10 @@ pub mod query { } } - impl ValidQuery for FindPermissionSchema { - #[metrics("find_permission_schema")] - fn execute(&self, state_ro: &impl StateReadOnly) -> Result<PermissionSchema, Error> { - Ok(state_ro.world().permission_schema().clone()) + impl ValidQuery for FindExecutorDataModel { + #[metrics("find_executor_data_model")] + fn execute(&self, state_ro: &impl StateReadOnly) -> Result<ExecutorDataModel, Error> { + Ok(state_ro.world().executor_data_model().clone()) } } diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 955134976da..4663558f009 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -5,13 +5,12 @@ use std::borrow::Borrow; use error::*; -use import::traits::{ExecuteOperations as _, GetExecutorPayloads as _, SetPermissionSchema as _}; +use import::traits::{ExecuteOperations as _, GetExecutorPayloads as _, SetDataModel as _}; use iroha_config::parameters::actual::WasmRuntime as Config; use iroha_data_model::{ account::AccountId, - executor::{self, MigrationResult}, + executor::{self, ExecutorDataModel, MigrationResult}, isi::InstructionBox, - permission::PermissionSchema, prelude::*, query::{QueryBox, QueryId, QueryOutputBox, QueryRequest, SmartContractQuery}, smart_contract::payloads::{self, Validate}, @@ -47,7 +46,7 @@ mod export { pub const GET_VALIDATE_TRANSACTION_PAYLOAD: &str = "get_validate_transaction_payload"; pub const GET_VALIDATE_INSTRUCTION_PAYLOAD: &str = "get_validate_instruction_payload"; pub const GET_VALIDATE_QUERY_PAYLOAD: &str = "get_validate_query_payload"; - pub const SET_PERMISSION_SCHEMA: &str = "set_permission_schema"; + pub const SET_DATA_MODEL: &str = "set_data_model"; pub const DBG: &str = "dbg"; pub const LOG: &str = "log"; @@ -102,9 +101,9 @@ mod import { fn get_validate_query_payload(state: &S) -> Validate<QueryBox>; } - pub trait SetPermissionSchema<S> { + pub trait SetDataModel<S> { #[codec::wrap_trait_fn] - fn set_permission_schema(schema: PermissionSchema, state: &mut S); + fn set_data_model(data_model: ExecutorDataModel, state: &mut S); } } } @@ -1076,23 +1075,23 @@ where } } -/// Marker trait to auto-implement [`import_traits::SetPermissionSchema`] for a concrete [`Runtime`]. +/// Marker trait to auto-implement [`import_traits::SetExecutorDataModel`] for a concrete [`Runtime`]. /// /// Useful because *Executor* exposes more entrypoints than just `migrate()` which is the /// only entrypoint allowed to execute operations on permission tokens. -trait FakeSetPermissionSchema<S> { +trait FakeSetExecutorDataModel<S> { /// Entrypoint function name for panic message const ENTRYPOINT_FN_NAME: &'static str; } -impl<R, S> import::traits::SetPermissionSchema<S> for R +impl<R, S> import::traits::SetDataModel<S> for R where - R: FakeSetPermissionSchema<S>, + R: FakeSetExecutorDataModel<S>, { #[codec::wrap] - fn set_permission_schema(_schema: PermissionSchema, _state: &mut S) { + fn set_data_model(_model: ExecutorDataModel, _state: &mut S) { panic!( - "Executor `{}()` entrypoint should not set permission token schema", + "Executor `{}()` entrypoint should not set data model", Self::ENTRYPOINT_FN_NAME ) } @@ -1172,7 +1171,7 @@ impl<'wrld, 'block, 'state> } } -impl<'wrld> FakeSetPermissionSchema<state::executor::ValidateTransaction<'wrld, '_, '_>> +impl<'wrld> FakeSetExecutorDataModel<state::executor::ValidateTransaction<'wrld, '_, '_>> for Runtime<state::executor::ValidateTransaction<'wrld, '_, '_>> { const ENTRYPOINT_FN_NAME: &'static str = "validate_transaction"; @@ -1252,7 +1251,7 @@ impl<'wrld, 'block, 'state> } } -impl<'wrld> FakeSetPermissionSchema<state::executor::ValidateInstruction<'wrld, '_, '_>> +impl<'wrld> FakeSetExecutorDataModel<state::executor::ValidateInstruction<'wrld, '_, '_>> for Runtime<state::executor::ValidateInstruction<'wrld, '_, '_>> { const ENTRYPOINT_FN_NAME: &'static str = "validate_instruction"; @@ -1348,7 +1347,7 @@ impl<'wrld, S: StateReadOnly> } } -impl<'wrld, S: StateReadOnly> FakeSetPermissionSchema<state::executor::ValidateQuery<'wrld, S>> +impl<'wrld, S: StateReadOnly> FakeSetExecutorDataModel<state::executor::ValidateQuery<'wrld, S>> for Runtime<state::executor::ValidateQuery<'wrld, S>> { const ENTRYPOINT_FN_NAME: &'static str = "validate_query"; @@ -1447,17 +1446,17 @@ impl<'wrld, 'block, 'state> } impl<'wrld, 'block, 'state> - import::traits::SetPermissionSchema<state::executor::Migrate<'wrld, 'block, 'state>> + import::traits::SetDataModel<state::executor::Migrate<'wrld, 'block, 'state>> for Runtime<state::executor::Migrate<'wrld, 'block, 'state>> { #[codec::wrap] - fn set_permission_schema( - schema: PermissionSchema, + fn set_data_model( + data_model: ExecutorDataModel, state: &mut state::executor::Migrate<'wrld, 'block, 'state>, ) { - debug!(%schema, "Setting permission token schema"); + debug!(%data_model, "Setting executor data model"); - state.state.0.world.set_permission_schema(schema) + state.state.0.world.set_executor_data_model(data_model) } } @@ -1602,7 +1601,7 @@ impl<'wrld, 'block, 'state> export::GET_VALIDATE_TRANSACTION_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::ValidateTransaction<'wrld, 'block, 'state>>| Runtime::get_validate_transaction_payload(caller), export::GET_VALIDATE_INSTRUCTION_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::ValidateTransaction<'wrld, 'block, 'state>>| Runtime::get_validate_instruction_payload(caller), export::GET_VALIDATE_QUERY_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::ValidateTransaction<'wrld, 'block, 'state>>| Runtime::get_validate_query_payload(caller), - export::SET_PERMISSION_SCHEMA => |caller: ::wasmtime::Caller<state::executor::ValidateTransaction<'wrld, 'block, 'state>>, offset, len| Runtime::set_permission_schema(caller, offset, len), + export::SET_DATA_MODEL => |caller: ::wasmtime::Caller<state::executor::ValidateTransaction<'wrld, 'block, 'state>>, offset, len| Runtime::set_data_model(caller, offset, len), )?; Ok(linker) }) @@ -1630,7 +1629,7 @@ impl<'wrld, 'block, 'state> export::GET_VALIDATE_TRANSACTION_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::ValidateInstruction<'wrld, 'block, 'state>>| Runtime::get_validate_transaction_payload(caller), export::GET_VALIDATE_INSTRUCTION_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::ValidateInstruction<'wrld, 'block, 'state>>| Runtime::get_validate_instruction_payload(caller), export::GET_VALIDATE_QUERY_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::ValidateInstruction<'wrld, 'block, 'state>>| Runtime::get_validate_query_payload(caller), - export::SET_PERMISSION_SCHEMA => |caller: ::wasmtime::Caller<state::executor::ValidateInstruction<'wrld, 'block, 'state>>, offset, len| Runtime::set_permission_schema(caller, offset, len), + export::SET_DATA_MODEL => |caller: ::wasmtime::Caller<state::executor::ValidateInstruction<'wrld, 'block, 'state>>, offset, len| Runtime::set_data_model(caller, offset, len), )?; Ok(linker) }) @@ -1655,7 +1654,7 @@ impl<'wrld, S: StateReadOnly> RuntimeBuilder<state::executor::ValidateQuery<'wrl export::GET_VALIDATE_TRANSACTION_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::ValidateQuery<'_, S>>| Runtime::get_validate_transaction_payload(caller), export::GET_VALIDATE_INSTRUCTION_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::ValidateQuery<'_, S>>| Runtime::get_validate_instruction_payload(caller), export::GET_VALIDATE_QUERY_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::ValidateQuery<'_, S>>| Runtime::get_validate_query_payload(caller), - export::SET_PERMISSION_SCHEMA => |caller: ::wasmtime::Caller<state::executor::ValidateQuery<'_, S>>, offset, len| Runtime::set_permission_schema(caller, offset, len), + export::SET_DATA_MODEL => |caller: ::wasmtime::Caller<state::executor::ValidateQuery<'_, S>>, offset, len| Runtime::set_data_model(caller, offset, len), )?; Ok(linker) }) @@ -1663,6 +1662,7 @@ impl<'wrld, S: StateReadOnly> RuntimeBuilder<state::executor::ValidateQuery<'wrl } impl<'wrld, 'block, 'state> RuntimeBuilder<state::executor::Migrate<'wrld, 'block, 'state>> { + // FIXME: is this accurate doc? /// Builds the [`Runtime`] to execute `permissions()` entrypoint of *Executor* /// /// # Errors @@ -1679,7 +1679,7 @@ impl<'wrld, 'block, 'state> RuntimeBuilder<state::executor::Migrate<'wrld, 'bloc export::GET_VALIDATE_TRANSACTION_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::Migrate<'wrld, 'block, 'state>>| Runtime::get_validate_transaction_payload(caller), export::GET_VALIDATE_INSTRUCTION_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::Migrate<'wrld, 'block, 'state>>| Runtime::get_validate_instruction_payload(caller), export::GET_VALIDATE_QUERY_PAYLOAD => |caller: ::wasmtime::Caller<state::executor::Migrate<'wrld, 'block, 'state>>| Runtime::get_validate_query_payload(caller), - export::SET_PERMISSION_SCHEMA => |caller: ::wasmtime::Caller<state::executor::Migrate<'wrld, 'block, 'state>>, offset, len| Runtime::set_permission_schema(caller, offset, len), + export::SET_DATA_MODEL => |caller: ::wasmtime::Caller<state::executor::Migrate<'wrld, 'block, 'state>>, offset, len| Runtime::set_data_model(caller, offset, len), )?; Ok(linker) }) diff --git a/core/src/state.rs b/core/src/state.rs index 49c2a12fa4d..0af2d8abb32 100644 --- a/core/src/state.rs +++ b/core/src/state.rs @@ -1,5 +1,5 @@ //! This module provides the [`State`] — an in-memory representation of the current blockchain state. -use std::{borrow::Borrow, collections::BTreeSet, marker::PhantomData, sync::Arc, time::Duration}; +use std::{collections::BTreeSet, marker::PhantomData, sync::Arc, time::Duration}; use eyre::Result; use iroha_config::parameters::actual::ChainWide as Config; @@ -13,9 +13,10 @@ use iroha_data_model::{ trigger_completed::{TriggerCompletedEvent, TriggerCompletedOutcome}, EventBox, }, + executor::ExecutorDataModel, isi::error::{InstructionExecutionError as Error, MathError}, - parameter::{Parameter, ParameterValueBox}, - permission::{PermissionSchema, Permissions}, + parameter::Parameter, + permission::Permissions, prelude::*, query::error::{FindError, QueryExecutionFail}, role::RoleId, @@ -61,7 +62,7 @@ use crate::{ /// For example registration of domain, will have this as an ISI target. #[derive(Default, Serialize)] pub struct World { - /// Iroha config parameters. + /// Executor config parameters. pub(crate) parameters: Cell<Parameters>, /// Identifications of discovered trusted peers. pub(crate) trusted_peers_ids: Cell<PeersIds>, @@ -73,12 +74,12 @@ pub struct World { pub(crate) account_permissions: Storage<AccountId, Permissions>, /// Roles of an account. pub(crate) account_roles: Storage<RoleIdWithOwner, ()>, - /// Registered permission token ids. - pub(crate) permission_schema: Cell<PermissionSchema>, /// Triggers pub(crate) triggers: TriggerSet, /// Runtime Executor pub(crate) executor: Cell<Executor>, + /// Executor-defined data model + pub(crate) executor_data_model: Cell<ExecutorDataModel>, } /// Struct for block's aggregated changes @@ -95,12 +96,12 @@ pub struct WorldBlock<'world> { pub(crate) account_permissions: StorageBlock<'world, AccountId, Permissions>, /// Roles of an account. pub(crate) account_roles: StorageBlock<'world, RoleIdWithOwner, ()>, - /// Registered permission token ids. - pub(crate) permission_schema: CellBlock<'world, PermissionSchema>, /// Triggers pub(crate) triggers: TriggerSetBlock<'world>, /// Runtime Executor pub(crate) executor: CellBlock<'world, Executor>, + /// Executor-defined data model + pub(crate) executor_data_model: CellBlock<'world, ExecutorDataModel>, /// Events produced during execution of block events_buffer: Vec<EventBox>, } @@ -119,12 +120,12 @@ pub struct WorldTransaction<'block, 'world> { pub(crate) account_permissions: StorageTransaction<'block, 'world, AccountId, Permissions>, /// Roles of an account. pub(crate) account_roles: StorageTransaction<'block, 'world, RoleIdWithOwner, ()>, - /// Registered permission token ids. - pub(crate) permission_schema: CellTransaction<'block, 'world, PermissionSchema>, /// Triggers pub(crate) triggers: TriggerSetTransaction<'block, 'world>, /// Runtime Executor pub(crate) executor: CellTransaction<'block, 'world, Executor>, + /// Executor-defined data model + pub(crate) executor_data_model: CellTransaction<'block, 'world, ExecutorDataModel>, /// Events produced during execution of a transaction events_buffer: TransactionEventBuffer<'block>, } @@ -151,12 +152,12 @@ pub struct WorldView<'world> { pub(crate) account_permissions: StorageView<'world, AccountId, Permissions>, /// Roles of an account. pub(crate) account_roles: StorageView<'world, RoleIdWithOwner, ()>, - /// Registered permission token ids. - pub(crate) permission_schema: CellView<'world, PermissionSchema>, /// Triggers pub(crate) triggers: TriggerSetView<'world>, /// Runtime Executor pub(crate) executor: CellView<'world, Executor>, + /// Executor-defined data model + pub(crate) executor_data_model: CellView<'world, ExecutorDataModel>, } /// Current state of the blockchain @@ -284,9 +285,9 @@ impl World { roles: self.roles.block(), account_permissions: self.account_permissions.block(), account_roles: self.account_roles.block(), - permission_schema: self.permission_schema.block(), triggers: self.triggers.block(), executor: self.executor.block(), + executor_data_model: self.executor_data_model.block(), events_buffer: Vec::new(), } } @@ -300,9 +301,9 @@ impl World { roles: self.roles.block_and_revert(), account_permissions: self.account_permissions.block_and_revert(), account_roles: self.account_roles.block_and_revert(), - permission_schema: self.permission_schema.block_and_revert(), triggers: self.triggers.block_and_revert(), executor: self.executor.block_and_revert(), + executor_data_model: self.executor_data_model.block_and_revert(), events_buffer: Vec::new(), } } @@ -316,9 +317,9 @@ impl World { roles: self.roles.view(), account_permissions: self.account_permissions.view(), account_roles: self.account_roles.view(), - permission_schema: self.permission_schema.view(), triggers: self.triggers.view(), executor: self.executor.view(), + executor_data_model: self.executor_data_model.view(), } } } @@ -332,9 +333,9 @@ pub trait WorldReadOnly { fn roles(&self) -> &impl StorageReadOnly<RoleId, Role>; fn account_permissions(&self) -> &impl StorageReadOnly<AccountId, Permissions>; fn account_roles(&self) -> &impl StorageReadOnly<RoleIdWithOwner, ()>; - fn permission_schema(&self) -> &PermissionSchema; fn triggers(&self) -> &impl TriggerSetReadOnly; fn executor(&self) -> &Executor; + fn executor_data_model(&self) -> &ExecutorDataModel; // Domain-related methods @@ -535,21 +536,6 @@ pub trait WorldReadOnly { self.parameters().iter() } - /// Query parameter and convert it to a proper type - fn query_param<T: TryFrom<ParameterValueBox>, P: core::hash::Hash + Eq + ?Sized>( - &self, - param: &P, - ) -> Option<T> - where - Parameter: Borrow<P>, - { - Parameters::get(self.parameters(), param) - .as_ref() - .map(|param| ¶m.val) - .cloned() - .and_then(|param_val| param_val.try_into().ok()) - } - /// Returns reference for trusted peer ids #[inline] fn peers_ids(&self) -> &PeersIds { @@ -578,15 +564,15 @@ macro_rules! impl_world_ro { fn account_roles(&self) -> &impl StorageReadOnly<RoleIdWithOwner, ()> { &self.account_roles } - fn permission_schema(&self) -> &PermissionSchema { - &self.permission_schema - } fn triggers(&self) -> &impl TriggerSetReadOnly { &self.triggers } fn executor(&self) -> &Executor { &self.executor } + fn executor_data_model(&self) -> &ExecutorDataModel { + &self.executor_data_model + } } )*}; } @@ -605,9 +591,9 @@ impl<'world> WorldBlock<'world> { roles: self.roles.transaction(), account_permissions: self.account_permissions.transaction(), account_roles: self.account_roles.transaction(), - permission_schema: self.permission_schema.transaction(), triggers: self.triggers.transaction(), executor: self.executor.transaction(), + executor_data_model: self.executor_data_model.transaction(), events_buffer: TransactionEventBuffer { events_buffer: &mut self.events_buffer, events_created_in_transaction: 0, @@ -619,8 +605,8 @@ impl<'world> WorldBlock<'world> { pub fn commit(self) { // IMPORTANT!!! Commit fields in reverse order, this way consistent results are insured self.executor.commit(); + self.executor_data_model.commit(); self.triggers.commit(); - self.permission_schema.commit(); self.account_roles.commit(); self.account_permissions.commit(); self.roles.commit(); @@ -634,8 +620,8 @@ impl WorldTransaction<'_, '_> { /// Apply transaction's changes pub fn apply(mut self) { self.executor.apply(); + self.executor_data_model.apply(); self.triggers.apply(); - self.permission_schema.apply(); self.account_roles.apply(); self.account_permissions.apply(); self.roles.apply(); @@ -835,18 +821,9 @@ impl WorldTransaction<'_, '_> { Ok(()) } - /// Set new permission token schema. - /// - /// Produces [`PermissionSchemaUpdateEvent`]. - pub fn set_permission_schema(&mut self, schema: PermissionSchema) { - let old_schema: PermissionSchema = - std::mem::replace(&mut self.permission_schema, schema.clone()); - self.emit_events(std::iter::once(DataEvent::Permission( - PermissionSchemaUpdateEvent { - old_schema, - new_schema: schema, - }, - ))) + /// Set executor data model. + pub fn set_executor_data_model(&mut self, executor_data_model: ExecutorDataModel) { + *self.executor_data_model.get_mut() = executor_data_model; } /// Execute trigger with `trigger_id` as id and `authority` as owner @@ -1247,7 +1224,8 @@ impl<'state> StateBlock<'state> { self.block_hashes.push(block_hash); - self.apply_parameters(); + // TODO: apply "core" chain-wide parameters here + self.world.events_buffer.push( BlockEvent { header: block.as_ref().header().clone(), @@ -1331,32 +1309,6 @@ impl<'state> StateBlock<'state> { errors.is_empty().then_some(()).ok_or(errors) } - - fn apply_parameters(&mut self) { - use iroha_data_model::parameter::default::*; - - macro_rules! update_params { - ($($param:expr => $config:expr),+ $(,)?) => { - $(if let Some(param) = self.world.query_param($param) { - $config = param; - })+ - }; - } - - update_params! { - WSV_DOMAIN_METADATA_LIMITS => self.config.domain_metadata_limits, - WSV_ASSET_DEFINITION_METADATA_LIMITS => self.config.asset_definition_metadata_limits, - WSV_ACCOUNT_METADATA_LIMITS => self.config.account_metadata_limits, - WSV_ASSET_METADATA_LIMITS => self.config.asset_metadata_limits, - WSV_TRIGGER_METADATA_LIMITS => self.config.trigger_metadata_limits, - WSV_IDENT_LENGTH_LIMITS => self.config.ident_length_limits, - EXECUTOR_FUEL_LIMIT => self.config.executor_runtime.fuel_limit, - EXECUTOR_MAX_MEMORY => self.config.executor_runtime.max_memory_bytes, - WASM_FUEL_LIMIT => self.config.wasm_runtime.fuel_limit, - WASM_MAX_MEMORY => self.config.wasm_runtime.max_memory_bytes, - TRANSACTION_LIMITS => self.config.transaction_limits, - } - } } impl StateTransaction<'_, '_> { @@ -1589,9 +1541,9 @@ pub(crate) mod deserialize { let mut roles = None; let mut account_permissions = None; let mut account_roles = None; - let mut permission_schema = None; let mut triggers = None; let mut executor = None; + let mut executor_data_model = None; while let Some(key) = map.next_key::<String>()? { match key.as_str() { @@ -1613,9 +1565,6 @@ pub(crate) mod deserialize { "account_roles" => { account_roles = Some(map.next_value()?); } - "permission_schema" => { - permission_schema = Some(map.next_value()?); - } "triggers" => { triggers = Some(map.next_value_seed(self.loader.cast::<TriggerSet>())?); @@ -1625,6 +1574,10 @@ pub(crate) mod deserialize { seed: self.loader.cast::<Executor>(), })?); } + "executor_data_model" => { + executor_data_model = Some(map.next_value()?); + } + _ => { /* Skip unknown fields */ } } } @@ -1642,12 +1595,13 @@ pub(crate) mod deserialize { })?, account_roles: account_roles .ok_or_else(|| serde::de::Error::missing_field("account_roles"))?, - permission_schema: permission_schema - .ok_or_else(|| serde::de::Error::missing_field("permission_schema"))?, triggers: triggers .ok_or_else(|| serde::de::Error::missing_field("triggers"))?, executor: executor .ok_or_else(|| serde::de::Error::missing_field("executor"))?, + executor_data_model: executor_data_model.ok_or_else(|| { + serde::de::Error::missing_field("executor_data_model") + })?, }) } } @@ -1661,9 +1615,9 @@ pub(crate) mod deserialize { "roles", "account_permissions", "account_roles", - "permission_schema", "triggers", "executor", + "executor_data_model", ], WorldVisitor { loader: &self }, ) diff --git a/core/src/sumeragi/main_loop.rs b/core/src/sumeragi/main_loop.rs index 9c0c051b047..462fb7c7f9d 100644 --- a/core/src/sumeragi/main_loop.rs +++ b/core/src/sumeragi/main_loop.rs @@ -342,7 +342,8 @@ impl Sumeragi { Strategy::kura_store_block(&self.kura, block); // Parameters are updated before updating public copy of sumeragi - self.update_params(&state_block); + // TODO: update chain-wide static parameters here, later + self.cache_transaction(&state_block); self.current_topology = new_topology; @@ -355,23 +356,6 @@ impl Sumeragi { state_events.into_iter().for_each(|e| self.send_event(e)); } - fn update_params(&mut self, state_block: &StateBlock<'_>) { - use iroha_data_model::parameter::default::*; - - if let Some(block_time) = state_block.world.query_param(BLOCK_TIME) { - self.block_time = Duration::from_millis(block_time); - } - if let Some(commit_time) = state_block.world.query_param(COMMIT_TIME_LIMIT) { - self.commit_time = Duration::from_millis(commit_time); - } - if let Some(max_txs_in_block) = state_block - .world - .query_param::<u32, _>(MAX_TRANSACTIONS_IN_BLOCK) - { - self.max_txs_in_block = max_txs_in_block as usize; - } - } - fn cache_transaction(&mut self, state_block: &StateBlock<'_>) { self.transaction_cache.retain(|tx| { !state_block.has_transaction(tx.as_ref().hash()) && !self.queue.is_expired(tx) diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index 363d4be93bb..c0cb6eb20c1 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -2,7 +2,7 @@ use core::{fmt::Debug, str::FromStr as _, time::Duration}; #[cfg(debug_assertions)] use std::sync::atomic::AtomicBool; -use std::{collections::BTreeMap, ops::Deref, path::Path, sync::Arc, thread}; +use std::{collections::BTreeMap, num::NonZeroU32, ops::Deref, path::Path, sync::Arc, thread}; use eyre::Result; use futures::{prelude::*, stream::FuturesUnordered}; @@ -92,22 +92,22 @@ impl TestGenesis for GenesisNetwork { let mint_rose_permission = Permission::new( "CanMintAssetWithDefinition".parse().unwrap(), - &json!({ "asset_definition_id": rose_definition_id }), + json!({ "asset_definition_id": rose_definition_id }), ); let burn_rose_permission = Permission::new( "CanBurnAssetWithDefinition".parse().unwrap(), - &json!({ "asset_definition_id": rose_definition_id }), + json!({ "asset_definition_id": rose_definition_id }), ); let unregister_any_peer_permission = - Permission::new("CanUnregisterAnyPeer".parse().unwrap(), &json!(null)); + Permission::new("CanUnregisterAnyPeer".parse().unwrap(), json!(null)); let unregister_any_role_permission = - Permission::new("CanUnregisterAnyRole".parse().unwrap(), &json!(null)); + Permission::new("CanUnregisterAnyRole".parse().unwrap(), json!(null)); let unregister_wonderland_domain = Permission::new( "CanUnregisterDomain".parse().unwrap(), - &json!({ "domain_id": DomainId::from_str("wonderland").unwrap() } ), + json!({ "domain_id": DomainId::from_str("wonderland").unwrap() } ), ); let upgrade_executor_permission = - Permission::new("CanUpgradeExecutor".parse().unwrap(), &json!(null)); + Permission::new("CanUpgradeExecutor".parse().unwrap(), json!(null)); let first_transaction = genesis .first_transaction_mut() @@ -143,6 +143,47 @@ impl TestGenesis for GenesisNetwork { } } +pub struct NetworkOptions { + n_peers: u32, + config: Config, + start_port: Option<u16>, + offline_peers: u32, +} + +impl NetworkOptions { + pub fn with_n_peers(n_peers: u32) -> Self { + let mut config = Config::test(); + config.logger.level = Level::INFO; + + Self { + n_peers, + start_port: None, + offline_peers: 0, + config, + } + } + + pub fn with_start_port(mut self, value: u16) -> Self { + self.start_port = Some(value); + self + } + + pub fn with_offline_peers(mut self, value: u32) -> Self { + self.offline_peers = value; + self + } + + pub fn with_max_txs_in_block(mut self, value: NonZeroU32) -> Self { + self.config.chain_wide.max_transactions_in_block = value; + self + } + + pub fn with_config_mut(mut self, fun: impl Fn(&mut Config)) -> Self { + fun(&mut self.config); + self + } +} + impl Network { /// Collect the freeze handles from all the peers in the network. #[cfg(debug_assertions)] @@ -156,38 +197,20 @@ impl Network { /// Starts network with peers with default configuration and /// specified options in a new async runtime. Returns its info /// and client for connecting to it. - pub fn start_test_with_runtime( - n_peers: u32, - start_port: Option<u16>, - ) -> (Runtime, Self, Client) { + pub fn start_test_with_runtime(options: NetworkOptions) -> (Runtime, Self, Client) { let rt = Runtime::test(); - let (network, client) = rt.block_on(Self::start_test(n_peers, start_port)); + let (network, client) = rt.block_on(Self::start_test(options)); (rt, network, client) } /// Starts network with peers with default configuration and /// specified options. Returns its info and client for connecting /// to it. - pub async fn start_test(n_peers: u32, start_port: Option<u16>) -> (Self, Client) { - Self::start_test_with_offline(n_peers, 0, start_port).await - } - - /// Starts network with peers with default configuration and - /// specified options. Returns its info and client for connecting - /// to it. - pub async fn start_test_with_offline_and_set_n_shifts( - n_peers: u32, - offline_peers: u32, - start_port: Option<u16>, - ) -> (Self, Client) { - let mut config = Config::test(); - config.logger.level = Level::INFO; - let network = - Network::new_with_offline_peers(Some(config), n_peers, offline_peers, start_port) - .await - .expect("Failed to init peers"); + pub async fn start_test(options: NetworkOptions) -> (Self, Client) { + let network = Network::new(options).await.expect("Failed to init peers"); let client = Client::test( - &Network::peers(&network) + &network + .peers() .choose(&mut thread_rng()) .unwrap() .api_address, @@ -195,17 +218,6 @@ impl Network { (network, client) } - /// Starts network with peers with default configuration and - /// specified options. Returns its info and client for connecting - /// to it. - pub async fn start_test_with_offline( - n_peers: u32, - offline_peers: u32, - start_port: Option<u16>, - ) -> (Self, Client) { - Self::start_test_with_offline_and_set_n_shifts(n_peers, offline_peers, start_port).await - } - /// Adds peer to network and waits for it to start block /// synchronization. pub async fn add_peer(&self) -> (Peer, Client) { @@ -245,16 +257,11 @@ impl Network { /// # Errors /// - (RARE) Creating new peers and collecting into a [`HashMap`] fails. /// - Creating new [`Peer`] instance fails. - pub async fn new_with_offline_peers( - default_config: Option<Config>, - n_peers: u32, - offline_peers: u32, - start_port: Option<u16>, - ) -> Result<Self> { + pub async fn new(options: NetworkOptions) -> Result<Self> { let mut builders = core::iter::repeat_with(PeerBuilder::new) .enumerate() .map(|(n, builder)| { - if let Some(port) = start_port { + if let Some(port) = options.start_port { let offset: u16 = (n * 5) .try_into() .expect("The `n_peers` is too large to fit into `u16`"); @@ -264,14 +271,14 @@ impl Network { } }) .map(|(n, builder)| builder.with_into_genesis((n == 0).then(GenesisNetwork::test))) - .take(n_peers as usize) + .take(options.n_peers as usize) .collect::<Vec<_>>(); let mut peers = builders .iter_mut() .map(PeerBuilder::build) .collect::<Result<Vec<_>>>()?; - let mut config = default_config.unwrap_or_else(Config::test); + let mut config = options.config; config.sumeragi.trusted_peers.value_mut().others = UniqueVec::from_iter(peers.iter().map(|peer| peer.id.clone())); @@ -279,7 +286,7 @@ impl Network { let genesis_builder = builders.remove(0).with_config(config.clone()); // Offset by one to account for genesis - let online_peers = n_peers - offline_peers - 1; + let online_peers = options.n_peers - options.offline_peers - 1; let rng = &mut rand::thread_rng(); let futures = FuturesUnordered::new(); @@ -294,7 +301,7 @@ impl Network { } futures.collect::<()>().await; - time::sleep(Duration::from_millis(500) * (n_peers + 1)).await; + time::sleep(Duration::from_millis(500) * (options.n_peers + 1)).await; Ok(Self { genesis: genesis_peer, diff --git a/data_model/src/events/data/events.rs b/data_model/src/events/data/events.rs index 6584e22b9d5..bb6286cc0be 100644 --- a/data_model/src/events/data/events.rs +++ b/data_model/src/events/data/events.rs @@ -89,8 +89,6 @@ mod model { Trigger(trigger::TriggerEvent), /// Role event Role(role::RoleEvent), - /// Permission token event - Permission(permission::PermissionSchemaUpdateEvent), /// Configuration event Configuration(config::ConfigurationEvent), /// Executor event @@ -287,44 +285,6 @@ mod role { } } -mod permission { - //! This module contains [`PermissionSchemaUpdateEvent`] - - pub use self::model::*; - use super::*; - use crate::permission::PermissionSchema; - - #[model] - mod model { - use super::*; - - /// Information about permission tokens update. - /// Only happens when registering new executor - #[derive( - Debug, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Getters, - Decode, - Encode, - Deserialize, - Serialize, - IntoSchema, - )] - #[getset(get = "pub")] - #[ffi_type] - pub struct PermissionSchemaUpdateEvent { - /// Previous set of permission tokens - pub old_schema: PermissionSchema, - /// New set of permission tokens - pub new_schema: PermissionSchema, - } - } -} - mod account { //! This module contains `AccountEvent` and its impls @@ -332,7 +292,6 @@ mod account { pub use self::model::*; use super::*; - use crate::name::Name; type AccountMetadataChanged = MetadataChanged<AccountId>; @@ -414,7 +373,7 @@ mod account { impl AccountPermissionChanged { /// Get permission id - pub fn permission_id(&self) -> &Name { + pub fn permission_id(&self) -> &PermissionId { &self.permission_id } } @@ -535,9 +494,8 @@ mod config { data_event! { #[has_origin(origin = Parameter)] pub enum ConfigurationEvent { - Changed(ParameterId), - Created(ParameterId), - Deleted(ParameterId), + #[has_origin(parameter => ¶meter.id)] + Changed(Parameter), } } } @@ -558,10 +516,10 @@ mod executor { // this is used in no_std #[allow(unused)] use super::*; + use crate::executor::ExecutorDataModel; #[derive( Debug, - Copy, Clone, PartialEq, Eq, @@ -575,11 +533,34 @@ mod executor { EventSet, )] #[non_exhaustive] - #[ffi_type] + #[ffi_type(opaque)] #[serde(untagged)] // Unaffected by #3330, as single unit variant #[repr(transparent)] pub enum ExecutorEvent { - Upgraded, + Upgraded(ExecutorUpgrade), + } + + /// Information about the updated executor data model. + #[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, + Getters, + )] + #[ffi_type] + #[repr(transparent)] + #[getset(get = "pub")] + pub struct ExecutorUpgrade { + /// Updated data model + pub new_data_model: ExecutorDataModel, } } } @@ -616,11 +597,7 @@ impl DataEvent { match self { Self::Domain(event) => Some(event.origin_id()), Self::Trigger(event) => event.origin_id().domain_id.as_ref(), - Self::Peer(_) - | Self::Configuration(_) - | Self::Role(_) - | Self::Permission(_) - | Self::Executor(_) => None, + Self::Peer(_) | Self::Configuration(_) | Self::Role(_) | Self::Executor(_) => None, } } } @@ -635,9 +612,8 @@ pub mod prelude { }, config::{ConfigurationEvent, ConfigurationEventSet}, domain::{DomainEvent, DomainEventSet, DomainOwnerChanged}, - executor::{ExecutorEvent, ExecutorEventSet}, + executor::{ExecutorEvent, ExecutorEventSet, ExecutorUpgrade}, peer::{PeerEvent, PeerEventSet}, - permission::PermissionSchemaUpdateEvent, role::{RoleEvent, RoleEventSet, RolePermissionChanged}, trigger::{TriggerEvent, TriggerEventSet, TriggerNumberOfExecutionsChanged}, DataEvent, HasOrigin, MetadataChanged, diff --git a/data_model/src/events/data/filters.rs b/data_model/src/events/data/filters.rs index 03a2048250b..ab43b561fbd 100644 --- a/data_model/src/events/data/filters.rs +++ b/data_model/src/events/data/filters.rs @@ -47,9 +47,6 @@ mod model { Trigger(TriggerEventFilter), /// Matches [`RoleEvent`]s Role(RoleEventFilter), - /// Matches [`PermissionSchemaUpdateEvent`]s - // nothing to filter for, really - PermissionSchemaUpdate, /// Matches [`ConfigurationEvent`]s Configuration(ConfigurationEventFilter), /// Matches [`ExecutorEvent`]s @@ -226,8 +223,6 @@ mod model { IntoSchema, )] pub struct ConfigurationEventFilter { - /// If specified matches only events originating from this configuration - pub(super) id_matcher: Option<super::ParameterId>, /// Matches only event from this set pub(super) event_set: ConfigurationEventSet, } @@ -601,18 +596,10 @@ impl ConfigurationEventFilter { /// Creates a new [`ConfigurationEventFilter`] accepting all [`ConfigurationEvent`]s. pub const fn new() -> Self { Self { - id_matcher: None, event_set: ConfigurationEventSet::all(), } } - /// Modifies a [`ConfigurationEventFilter`] to accept only [`ConfigurationEvent`]s originating from ids matching `id_matcher`. - #[must_use] - pub fn for_parameter(mut self, id_matcher: ParameterId) -> Self { - self.id_matcher = Some(id_matcher); - self - } - /// Modifies a [`ConfigurationEventFilter`] to accept only [`ConfigurationEvent`]s of types matching `event_set`. #[must_use] pub const fn for_events(mut self, event_set: ConfigurationEventSet) -> Self { @@ -632,12 +619,6 @@ impl super::EventFilter for ConfigurationEventFilter { type Event = super::ConfigurationEvent; fn matches(&self, event: &Self::Event) -> bool { - if let Some(id_matcher) = &self.id_matcher { - if id_matcher != event.origin_id() { - return false; - } - } - if !self.event_set.matches(event) { return false; } @@ -706,7 +687,6 @@ impl EventFilter for DataEventFilter { (DataEvent::Trigger(event), Trigger(filter)) => filter.matches(event), (DataEvent::Role(event), Role(filter)) => filter.matches(event), (DataEvent::Configuration(event), Configuration(filter)) => filter.matches(event), - (DataEvent::Permission(_), PermissionSchemaUpdate) => true, (DataEvent::Executor(event), Executor(filter)) => filter.matches(event), ( @@ -714,7 +694,6 @@ impl EventFilter for DataEventFilter { | DataEvent::Domain(_) | DataEvent::Trigger(_) | DataEvent::Role(_) - | DataEvent::Permission(_) | DataEvent::Configuration(_) | DataEvent::Executor(_), Any, @@ -724,7 +703,6 @@ impl EventFilter for DataEventFilter { | DataEvent::Domain(_) | DataEvent::Trigger(_) | DataEvent::Role(_) - | DataEvent::Permission(_) | DataEvent::Configuration(_) | DataEvent::Executor(_), _, diff --git a/data_model/src/executor.rs b/data_model/src/executor.rs index 8c147cc477b..a97aff64c26 100644 --- a/data_model/src/executor.rs +++ b/data_model/src/executor.rs @@ -1,9 +1,11 @@ //! Structures, traits and impls related to *runtime* `Executor`s. #[cfg(not(feature = "std"))] -use alloc::{format, string::String, vec::Vec}; +use alloc::{collections::BTreeSet, format, string::String, vec::Vec}; +#[cfg(feature = "std")] +use std::collections::BTreeSet; -use derive_more::Constructor; +use derive_more::{Constructor, Display}; use getset::Getters; use iroha_data_model_derive::model; use iroha_schema::IntoSchema; @@ -11,7 +13,9 @@ use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; pub use self::model::*; -use crate::transaction::WasmSmartContract; +use crate::{ + parameter::ParameterId, permission::PermissionId, transaction::WasmSmartContract, JsonString, +}; #[model] mod model { @@ -47,10 +51,69 @@ mod model { pub wasm: WasmSmartContract, } + /// Executor data model. + /// + /// Defined from within the executor, it describes certain structures the executor + /// works with. + /// + /// Executor can define: + /// + /// - Permission tokens (see [`crate::permission::Permission`]) + /// - Configuration parameters (see [`crate::parameter::Parameter`]) + #[derive( + Default, + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Constructor, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, + Display, + )] + #[ffi_type] + #[display(fmt = "{self:?}")] + pub struct ExecutorDataModel { + /// Permission tokens supported by the executor. + /// + /// These IDs refer to the types in the schema. + pub permissions: BTreeSet<PermissionId>, + /// Configuration parameters supported by the executor. + /// + /// These IDs refer to the types in the schema. + pub parameters: BTreeSet<ParameterId>, + /// Data model JSON schema, typically produced by [`IntoSchema`]. + pub schema: JsonString, + } + // TODO: Client doesn't need structures defined inside this macro. When dynamic linking is // implemented use: #[cfg(any(feature = "transparent_api", feature = "ffi_import"))] } +// TODO: derive `Getters` once FFI impl is fixed +// currently it fails for all fields +impl ExecutorDataModel { + /// Getter + pub fn permissions(&self) -> &BTreeSet<PermissionId> { + &self.permissions + } + + /// Getter + pub fn parameters(&self) -> &BTreeSet<ParameterId> { + &self.parameters + } + + /// Getter + pub fn schema(&self) -> &JsonString { + &self.schema + } +} + /// Result type that every executor should return. pub type Result<T = (), E = crate::ValidationFail> = core::result::Result<T, E>; @@ -62,5 +125,5 @@ pub type MigrationResult = Result<(), MigrationError>; pub mod prelude { //! The prelude re-exports most commonly used traits, structs and macros from this crate. - pub use super::Executor; + pub use super::{Executor, ExecutorDataModel}; } diff --git a/data_model/src/isi.rs b/data_model/src/isi.rs index 7ca016b30b2..d272941459a 100644 --- a/data_model/src/isi.rs +++ b/data_model/src/isi.rs @@ -111,8 +111,6 @@ mod model { #[debug(fmt = "{_0:?}")] SetParameter(SetParameter), #[debug(fmt = "{_0:?}")] - NewParameter(NewParameter), - #[debug(fmt = "{_0:?}")] Upgrade(Upgrade), #[debug(fmt = "{_0:?}")] Log(Log), @@ -172,7 +170,6 @@ impl_instruction! { Revoke<RoleId, Account>, Revoke<Permission, Role>, SetParameter, - NewParameter, Upgrade, ExecuteTrigger, Log, @@ -246,7 +243,7 @@ mod transparent { } isi! { - /// Generic instruction for setting a chain-wide config parameter. + /// Setting an executor configuration parameter #[derive(Constructor, Display)] #[display(fmt = "SET `{parameter}`")] #[serde(transparent)] @@ -258,20 +255,6 @@ mod transparent { } } - 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(Constructor, Display)] - #[display(fmt = "SET `{parameter}`")] - #[serde(transparent)] - #[repr(transparent)] - pub struct NewParameter { - /// Parameter to be changed. - #[serde(flatten)] - pub parameter: Parameter, - } - } - isi! { /// Generic instruction to set key value at the object. #[schema(bounds = "O: Identifiable, O::Id: IntoSchema")] @@ -1519,8 +1502,8 @@ pub mod error { pub mod prelude { pub use super::{ AssetTransferBox, Burn, BurnBox, ExecuteTrigger, Fail, Grant, GrantBox, InstructionBox, - Log, Mint, MintBox, NewParameter, Register, RegisterBox, RemoveKeyValue, RemoveKeyValueBox, - Revoke, RevokeBox, SetKeyValue, SetKeyValueBox, SetParameter, Transfer, TransferBox, - Unregister, UnregisterBox, Upgrade, + Log, Mint, MintBox, Register, RegisterBox, RemoveKeyValue, RemoveKeyValueBox, Revoke, + RevokeBox, SetKeyValue, SetKeyValueBox, SetParameter, Transfer, TransferBox, Unregister, + UnregisterBox, Upgrade, }; } diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 301b01ba84e..7a376b3be6a 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -17,17 +17,16 @@ use alloc::{ }; use core::{fmt, fmt::Debug, ops::RangeInclusive, str::FromStr}; -use derive_more::{Constructor, Display, From, FromStr}; +use derive_more::{Constructor, Display, FromStr}; use getset::Getters; use iroha_crypto::PublicKey; -use iroha_data_model_derive::{model, EnumRef, IdEqOrdHash}; +use iroha_data_model_derive::{model, EnumRef}; use iroha_macro::FromVariant; use iroha_schema::IntoSchema; use iroha_version::{declare_versioned, version_with_scale}; use parity_scale_codec::{Decode, Encode}; use prelude::Executable; use serde::{Deserialize, Serialize}; -use serde_with::{DeserializeFromStr, SerializeDisplay}; use strum::FromRepr; pub use self::model::*; @@ -117,7 +116,6 @@ mod seal { Revoke<Permission, Role>, SetParameter, - NewParameter, Upgrade, ExecuteTrigger, Log, @@ -154,7 +152,6 @@ mod seal { FindTransactionsByAccountId, FindTransactionByHash, FindPermissionsByAccountId, - FindPermissionSchema, FindAllActiveTriggerIds, FindTriggerById, FindTriggerKeyValueByIdAndKey, @@ -164,6 +161,7 @@ mod seal { FindRoleByRoleId, FindRolesByAccountId, FindAllParameters, + FindExecutorDataModel } } @@ -212,66 +210,21 @@ impl<EXPECTED, GOT> EnumTryAsError<EXPECTED, GOT> { impl<EXPECTED: Debug, GOT: Debug> std::error::Error for EnumTryAsError<EXPECTED, GOT> {} pub mod parameter { - //! Structures, traits and impls related to `Paramater`s. + //! Executor configuration parameters use core::borrow::Borrow; - use iroha_primitives::numeric::Numeric; + use iroha_data_model_derive::IdEqOrdHash; pub use self::model::*; use super::*; - use crate::isi::InstructionBox; - - /// Set of parameter names currently used by iroha - #[allow(missing_docs)] - pub mod default { - pub const MAX_TRANSACTIONS_IN_BLOCK: &str = "MaxTransactionsInBlock"; - pub const BLOCK_TIME: &str = "BlockTime"; - pub const COMMIT_TIME_LIMIT: &str = "CommitTimeLimit"; - pub const TRANSACTION_LIMITS: &str = "TransactionLimits"; - pub const WSV_DOMAIN_METADATA_LIMITS: &str = "WSVDomainMetadataLimits"; - pub const WSV_ASSET_DEFINITION_METADATA_LIMITS: &str = "WSVAssetDefinitionMetadataLimits"; - pub const WSV_ACCOUNT_METADATA_LIMITS: &str = "WSVAccountMetadataLimits"; - pub const WSV_ASSET_METADATA_LIMITS: &str = "WSVAssetMetadataLimits"; - pub const WSV_TRIGGER_METADATA_LIMITS: &str = "WSVTriggerMetadataLimits"; - pub const WSV_IDENT_LENGTH_LIMITS: &str = "WSVIdentLengthLimits"; - pub const EXECUTOR_FUEL_LIMIT: &str = "ExecutorFuelLimit"; - pub const EXECUTOR_MAX_MEMORY: &str = "ExecutorMaxMemory"; - pub const WASM_FUEL_LIMIT: &str = "WASMFuelLimit"; - pub const WASM_MAX_MEMORY: &str = "WASMMaxMemory"; - } #[model] mod model { use super::*; - #[derive( - Debug, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - FromVariant, - Decode, - Encode, - Deserialize, - Serialize, - IntoSchema, - )] - #[ffi_type(local)] - pub enum ParameterValueBox { - TransactionLimits(transaction::TransactionLimits), - MetadataLimits(metadata::Limits), - LengthLimits(LengthLimits), - Numeric( - #[skip_from] - #[skip_try_from] - Numeric, - ), - } - - /// Identification of a [`Parameter`]. + /// Identifies a global on-chain configuration [`Parameter`]. + /// The executor defines available parameter names. #[derive( Debug, Display, @@ -281,97 +234,61 @@ pub mod parameter { PartialOrd, Ord, Hash, - Getters, + Constructor, FromStr, + Getters, Decode, Encode, Deserialize, Serialize, IntoSchema, )] - #[display(fmt = "{name}")] #[getset(get = "pub")] #[serde(transparent)] #[repr(transparent)] #[ffi_type(opaque)] pub struct ParameterId { - /// [`Name`] unique to a [`Parameter`]. + /// Should be unique. pub name: Name, } + /// Executor configuration parameter. + /// + /// Must be defined in [`crate::executor::ExecutorDataModel`]. #[derive( Debug, Display, Clone, - Constructor, IdEqOrdHash, Decode, Encode, - DeserializeFromStr, - SerializeDisplay, + Deserialize, + Serialize, IntoSchema, + Getters, )] - #[display(fmt = "?{id}={val}")] - /// A chain-wide configuration parameter and its value. + #[display(fmt = "PARAMETER `{id}` = `{payload}`")] #[ffi_type] + #[getset(get = "pub")] pub struct Parameter { - /// Unique [`Id`] of the [`Parameter`]. + /// Refers to a type defined in [`crate::executor::ExecutorDataModel`]. pub id: ParameterId, - /// Current value of the [`Parameter`]. - pub val: ParameterValueBox, - } - } - - // TODO: Maybe derive - impl core::fmt::Display for ParameterValueBox { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::MetadataLimits(v) => core::fmt::Display::fmt(&v, f), - Self::TransactionLimits(v) => core::fmt::Display::fmt(&v, f), - Self::LengthLimits(v) => core::fmt::Display::fmt(&v, f), - Self::Numeric(v) => core::fmt::Display::fmt(&v, f), - } - } - } - - impl<T: Into<Numeric>> From<T> for ParameterValueBox { - fn from(value: T) -> Self { - Self::Numeric(value.into()) - } - } - - impl TryFrom<ParameterValueBox> for u32 { - type Error = iroha_macro::error::ErrorTryFromEnum<ParameterValueBox, Self>; - - fn try_from(value: ParameterValueBox) -> Result<Self, Self::Error> { - use iroha_macro::error::ErrorTryFromEnum; - - let ParameterValueBox::Numeric(numeric) = value else { - return Err(ErrorTryFromEnum::default()); - }; - - numeric.try_into().map_err(|_| ErrorTryFromEnum::default()) - } - } - - impl TryFrom<ParameterValueBox> for u64 { - type Error = iroha_macro::error::ErrorTryFromEnum<ParameterValueBox, Self>; - - fn try_from(value: ParameterValueBox) -> Result<Self, Self::Error> { - use iroha_macro::error::ErrorTryFromEnum; - - let ParameterValueBox::Numeric(numeric) = value else { - return Err(ErrorTryFromEnum::default()); - }; - - numeric.try_into().map_err(|_| ErrorTryFromEnum::default()) + /// Payload containing actual value. + /// + /// It is JSON-encoded, and its structure must correspond to the structure of + /// the type defined in [`crate::executor::ExecutorDataModel`]. + #[getset(skip)] + pub payload: JsonString, } } impl Parameter { - /// Current value of the [`Parameter`]. - pub fn val(&self) -> &ParameterValueBox { - &self.val + /// Constructor + pub fn new(id: ParameterId, payload: impl IntoJsonString) -> Self { + Self { + id, + payload: payload.into_json_string(), + } } } @@ -387,152 +304,11 @@ pub mod parameter { } } - impl FromStr for Parameter { - type Err = ParseError; - - fn from_str(string: &str) -> Result<Self, Self::Err> { - if let Some((parameter_id_candidate, val_candidate)) = string.rsplit_once('=') { - if let Some(parameter_id_candidate) = parameter_id_candidate.strip_prefix('?') { - let param_id: ParameterId = - parameter_id_candidate.parse().map_err(|_| ParseError { - reason: "Failed to parse the `param_id` part of the `Parameter`.", - })?; - if let Some((val, ty)) = val_candidate.rsplit_once('_') { - let val = match ty { - // Shorthand for `LengthLimits` - "LL" => { - let (lower, upper) = val.rsplit_once(',').ok_or( ParseError { - reason: - "Failed to parse the `val` part of the `Parameter` as `LengthLimits`. Two comma-separated values are expected.", - })?; - let lower = lower.parse::<u32>().map_err(|_| ParseError { - reason: - "Failed to parse the `val` part of the `Parameter` as `LengthLimits`. Invalid lower `u32` bound.", - })?; - let upper = upper.parse::<u32>().map_err(|_| ParseError { - reason: - "Failed to parse the `val` part of the `Parameter` as `LengthLimits`. Invalid upper `u32` bound.", - })?; - LengthLimits::new(lower, upper).into() - } - // Shorthand for `TransactionLimits` - "TL" => { - let (max_instr, max_wasm_size) = val.rsplit_once(',').ok_or( ParseError { - reason: - "Failed to parse the `val` part of the `Parameter` as `TransactionLimits`. Two comma-separated values are expected.", - })?; - let max_instr = max_instr.parse::<u64>().map_err(|_| ParseError { - reason: - "Failed to parse the `val` part of the `Parameter` as `TransactionLimits`. `max_instruction_number` field should be a valid `u64`.", - })?; - let max_wasm_size = max_wasm_size.parse::<u64>().map_err(|_| ParseError { - reason: - "Failed to parse the `val` part of the `Parameter` as `TransactionLimits`. `max_wasm_size_bytes` field should be a valid `u64`.", - })?; - transaction::TransactionLimits::new( - max_instr, - max_wasm_size, - ).into() - } - // Shorthand for `MetadataLimits` - "ML" => { - let (lower, upper) = val.rsplit_once(',').ok_or( ParseError { - reason: - "Failed to parse the `val` part of the `Parameter` as `MetadataLimits`. Two comma-separated values are expected.", - })?; - let lower = lower.parse::<u32>().map_err(|_| ParseError { - reason: - "Failed to parse the `val` part of the `Parameter` as `MetadataLimits`. Invalid `u32` in `capacity` field.", - })?; - let upper = upper.parse::<u32>().map_err(|_| ParseError { - reason: - "Failed to parse the `val` part of the `Parameter` as `MetadataLimits`. Invalid `u32` in `max_entry_len` field.", - })?; - metadata::Limits::new(lower, upper).into() - } - _ => return Err(ParseError { - reason: - "Unsupported type provided for the `val` part of the `Parameter`.", - }), - }; - Ok(Self::new(param_id, val)) - } else { - let val = val_candidate.parse::<Numeric>().map_err(|_| ParseError { - reason: - "Failed to parse the `val` part of the `Parameter` as `Numeric`.", - })?; - - Ok(Self::new(param_id, val.into())) - } - } else { - Err(ParseError { - reason: "`param_id` part of `Parameter` must start with `?`", - }) - } - } else { - Err(ParseError { - reason: "The `Parameter` string did not contain the `=` character.", - }) - } - } - } - - /// Convenience tool for setting parameters - #[derive(Default)] - #[must_use] - pub struct ParametersBuilder { - parameters: Vec<Parameter>, - } - - /// Error associated with parameters builder - #[derive(From, Debug, Display, Copy, Clone)] - pub enum ParametersBuilderError { - /// Error emerged during parsing of parameter id - Parse(ParseError), - } - - #[cfg(feature = "std")] - impl std::error::Error for ParametersBuilderError {} - - impl ParametersBuilder { - /// Construct [`Self`] - pub fn new() -> Self { - Self::default() - } - - /// Add [`Parameter`] to self - /// - /// # Errors - /// - [`ParameterId`] parsing failed - pub fn add_parameter( - mut self, - parameter_id: &str, - val: impl Into<ParameterValueBox>, - ) -> Result<Self, ParametersBuilderError> { - let parameter = Parameter { - id: parameter_id.parse()?, - val: val.into(), - }; - self.parameters.push(parameter); - Ok(self) - } - - /// Create sequence isi for setting parameters - pub fn into_set_parameters(self) -> Vec<InstructionBox> { - self.parameters - .into_iter() - .map(isi::SetParameter::new) - .map(Into::into) - .collect() - } - - /// Create sequence isi for creating parameters - pub fn into_create_parameters(self) -> Vec<InstructionBox> { - self.parameters - .into_iter() - .map(isi::NewParameter::new) - .map(Into::into) - .collect() + impl Parameter { + /// Getter + // TODO: derive with getset once FFI impl is fixed + pub fn payload(&self) -> &JsonString { + &self.payload } } @@ -541,82 +317,13 @@ pub mod parameter { pub use super::{Parameter, ParameterId}; } - - #[cfg(test)] - mod tests { - use super::*; - use crate::{ - prelude::{numeric, MetadataLimits}, - transaction::TransactionLimits, - }; - - const INVALID_PARAM: [&str; 4] = [ - "", - "Block?SyncGossipPeriod=20000", - "?BlockSyncGossipPeriod20000", - "?BlockSyncGossipPeriod=20000_u32", - ]; - - #[test] - fn test_invalid_parameter_str() { - assert!(matches!( - parameter::Parameter::from_str(INVALID_PARAM[0]), - Err(err) if err.reason == "The `Parameter` string did not contain the `=` character." - )); - assert!(matches!( - parameter::Parameter::from_str(INVALID_PARAM[1]), - Err(err) if err.reason == "`param_id` part of `Parameter` must start with `?`" - )); - assert!(matches!( - parameter::Parameter::from_str(INVALID_PARAM[2]), - Err(err) if err.to_string() == "The `Parameter` string did not contain the `=` character." - )); - assert!(matches!( - parameter::Parameter::from_str(INVALID_PARAM[3]), - Err(err) if err.to_string() == "Unsupported type provided for the `val` part of the `Parameter`." - )); - } - - #[test] - fn test_parameter_serialize_deserialize_consistent() { - let parameters = [ - Parameter::new( - ParameterId::from_str("TransactionLimits") - .expect("Failed to parse `ParameterId`"), - TransactionLimits::new(42, 24).into(), - ), - Parameter::new( - ParameterId::from_str("MetadataLimits").expect("Failed to parse `ParameterId`"), - MetadataLimits::new(42, 24).into(), - ), - Parameter::new( - ParameterId::from_str("LengthLimits").expect("Failed to parse `ParameterId`"), - LengthLimits::new(24, 42).into(), - ), - Parameter::new( - ParameterId::from_str("Int").expect("Failed to parse `ParameterId`"), - numeric!(42).into(), - ), - ]; - - for parameter in parameters { - assert_eq!( - parameter, - serde_json::to_string(¶meter) - .and_then(|parameter| serde_json::from_str(¶meter)) - .unwrap_or_else(|_| panic!( - "Failed to de/serialize parameter {:?}", - ¶meter - )) - ); - } - } - } } #[model] #[allow(clippy::redundant_pub_crate)] mod model { + use iroha_schema::TypeId; + use super::*; /// Unique id of blockchain @@ -675,7 +382,7 @@ mod model { TriggerId(trigger::TriggerId), /// [`RoleId`](`role::RoleId`) variant. RoleId(role::RoleId), - /// [`Permission`](`permission::Permission`) variant. + /// [`PermissionId`](`permission::PermissionId`) variant. PermissionId(permission::PermissionId), /// [`ParameterId`](`parameter::ParameterId`) variant. ParameterId(parameter::ParameterId), @@ -864,6 +571,106 @@ mod model { /// in the next request to continue fetching results of the original query pub cursor: crate::query::cursor::ForwardCursor, } + + /// String containing serialized valid JSON. + /// + /// This string is guaranteed to be parsed as JSON. + #[derive(Display, Default, Debug, Clone, Eq, Encode, Decode, TypeId, Ord, PartialOrd)] + #[ffi_type(unsafe {robust})] + #[repr(transparent)] + #[display(fmt = "{}", "0")] + pub struct JsonString(pub(super) String); +} + +/// A helper trait for polymorphism, implemented for various types +pub trait IntoJsonString { + /// Converts self into [`JsonString`] + fn into_json_string(self) -> JsonString; +} + +impl IntoJsonString for JsonString { + fn into_json_string(self) -> JsonString { + self + } +} + +impl IntoJsonString for &serde_json::Value { + fn into_json_string(self) -> JsonString { + JsonString::from(self) + } +} + +impl IntoJsonString for serde_json::Value { + fn into_json_string(self) -> JsonString { + (&self).into_json_string() + } +} + +impl JsonString { + /// Deserialize JSON into something + /// # Errors + /// See [`serde_json::from_str`]. + pub fn deserialize<'a, T>(&'a self) -> serde_json::Result<T> + where + T: Deserialize<'a>, + { + serde_json::from_str(&self.0) + } + + /// Serializes a value into [`JsonString`] + /// # Errors + /// See [`serde_json::to_string`]. + pub fn serialize<T: serde::Serialize>(value: &T) -> serde_json::Result<Self> { + let serialized = serde_json::to_string(value)?; + // the string was obtained from serde_json serialization, + // so it should be a valid JSON string + Ok(Self(serialized)) + } +} + +impl From<&serde_json::Value> for JsonString { + fn from(value: &serde_json::Value) -> Self { + Self(value.to_string()) + } +} + +impl PartialEq for JsonString { + fn eq(&self, other: &Self) -> bool { + serde_json::from_str::<serde_json::Value>(&self.0).unwrap() + == serde_json::from_str::<serde_json::Value>(&other.0).unwrap() + } +} + +impl<'de> serde::de::Deserialize<'de> for JsonString { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + let json = serde_json::Value::deserialize(deserializer)?; + Ok(Self::from(&json)) + } +} + +impl serde::ser::Serialize for JsonString { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + let json = serde_json::Value::from_str(&self.0).map_err(serde::ser::Error::custom)?; + json.serialize(serializer) + } +} + +impl IntoSchema for JsonString { + fn type_name() -> iroha_schema::Ident { + <Self as iroha_schema::TypeId>::id() + } + + fn update_schema_map(map: &mut iroha_schema::MetaMap) { + if !map.contains_key::<Self>() { + map.insert::<Self>(iroha_schema::Metadata::String); + } + } } macro_rules! impl_encode_as_id_box { diff --git a/data_model/src/permission.rs b/data_model/src/permission.rs index e5c24fe2ea5..4651554585c 100644 --- a/data_model/src/permission.rs +++ b/data_model/src/permission.rs @@ -1,6 +1,7 @@ //! Permission Token and related impls #[cfg(not(feature = "std"))] -use alloc::{borrow::ToOwned as _, collections::BTreeSet, format, string::String, vec::Vec}; +use alloc::{collections::BTreeSet, format, string::String, vec::Vec}; +use core::borrow::Borrow; #[cfg(feature = "std")] use std::collections::BTreeSet; @@ -17,196 +18,101 @@ pub type Permissions = BTreeSet<Permission>; use super::*; -/// Unique id of [`Permission`] -pub type PermissionId = Name; - #[model] mod model { use super::*; - /// Stored proof of the account having a permission for a certain action. - /// - /// Since permission token is represented opaque to core - /// either executor or client should make sure that tokens are represented uniformly. - /// - /// So that: - /// - payload A is equal to payload B then token A must be equal to token B - /// - and if payload A is't equal to B then token A mustn't be equal to token B + /// Identifies a [`Permission`]. + /// The executor defines available permission names. #[derive( Debug, + Display, Clone, PartialEq, Eq, PartialOrd, Ord, + Hash, + Constructor, + FromStr, + Getters, Decode, Encode, Deserialize, Serialize, IntoSchema, )] - #[ffi_type] - pub struct Permission { - /// Token identifier - pub definition_id: PermissionId, - /// JSON encoded token payload - pub payload: JsonString, + #[getset(get = "pub")] + #[serde(transparent)] + #[repr(transparent)] + #[ffi_type(opaque)] + pub struct PermissionId { + /// Should be unique. + pub name: Name, } - /// Description of tokens defined in the executor + /// Stored proof of the account having a permission for a certain action. #[derive( Debug, - Display, Clone, PartialEq, Eq, PartialOrd, Ord, - Default, Decode, Encode, Deserialize, Serialize, IntoSchema, + Display, + Getters, )] - #[display(fmt = "{token_ids:#?}")] #[ffi_type] - pub struct PermissionSchema { - /// Ids of all permission tokens, sorted. - pub token_ids: Vec<PermissionId>, - /// Type schema of permission tokens + #[display(fmt = "PERMISSION `{id}` = `{payload}`")] + #[getset(get = "pub")] + pub struct Permission { + /// Refers to a type defined in [`crate::executor::ExecutorDataModel`]. + pub id: PermissionId, + /// Payload containing actual value. /// - /// At the time of writing this doc a complete schema is returned but it's - /// possible that in the future this field will contain references to types - /// defined in the Iroha schema without defining them itself - pub schema: String, - } - - /// String containing serialized valid JSON. - /// This string is guaranteed to parse as JSON - #[derive(Debug, Clone, Eq, Encode, Decode)] - pub struct JsonString(pub(super) String); -} - -// TODO: Use getset to derive this -impl PermissionSchema { - /// Construct new [`PermissionSchema`] - pub fn new(token_ids: Vec<PermissionId>, schema: String) -> Self { - Self { token_ids, schema } - } - - /// Return id of this token - pub fn permissions(&self) -> &[PermissionId] { - &self.token_ids + /// It is JSON-encoded, and its structure must correspond to the structure of + /// the type defined in [`crate::executor::ExecutorDataModel`]. + #[getset(skip)] + pub payload: JsonString, } } impl Permission { - /// Construct [`Self`] from a raw string slice. The caller of the function - /// must make sure that the given string slice can be parsed as valid JSON. - /// - /// Only used in tests - #[cfg(debug_assertions)] - // TODO: Remove after integration tests have been moved to python tests - #[deprecated(note = "Will be removed after integration tests are removed from iroha_client")] - pub fn from_str_unchecked(definition_id: PermissionId, payload: &str) -> Self { + /// Constructor + pub fn new(id: PermissionId, payload: impl IntoJsonString) -> Self { Self { - definition_id, - payload: JsonString(payload.to_owned()), + id, + payload: payload.into_json_string(), } } - - /// Construct [`Self`] - pub fn new(definition_id: PermissionId, payload: &serde_json::Value) -> Self { - Self { - definition_id, - payload: JsonString::new(payload), - } - } - - /// Return id of this token - // TODO: Use getset to derive this after fixes in FFI - pub fn definition_id(&self) -> &Name { - &self.definition_id - } - - /// Payload of this token - // TODO: Use getset to derive this after fixes in FFI - pub fn payload(&self) -> &String { - &self.payload.0 - } -} - -impl core::fmt::Display for Permission { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.definition_id) - } -} - -impl JsonString { - /// Construct [`JsonString`] - pub fn new(payload: &serde_json::Value) -> Self { - Self(payload.to_string()) - } -} -impl PartialEq for JsonString { - fn eq(&self, other: &Self) -> bool { - serde_json::from_str::<serde_json::Value>(&self.0).unwrap() - == serde_json::from_str::<serde_json::Value>(&other.0).unwrap() - } } -impl<'de> serde::de::Deserialize<'de> for JsonString { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: serde::Deserializer<'de>, - { - let json = serde_json::Value::deserialize(deserializer)?; - Ok(Self::new(&json)) +impl Borrow<str> for PermissionId { + fn borrow(&self) -> &str { + self.name.borrow() } } -impl serde::ser::Serialize for JsonString { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: serde::Serializer, - { - let json = serde_json::Value::from_str(&self.0).map_err(serde::ser::Error::custom)?; - json.serialize(serializer) +impl Borrow<str> for Permission { + fn borrow(&self) -> &str { + self.id.borrow() } } -impl iroha_schema::TypeId for JsonString { - fn id() -> iroha_schema::Ident { - "JsonString".to_owned() - } -} - -impl IntoSchema for JsonString { - fn type_name() -> iroha_schema::Ident { - <Self as iroha_schema::TypeId>::id() - } - - fn update_schema_map(map: &mut iroha_schema::MetaMap) { - if !map.contains_key::<Self>() { - map.insert::<Self>(iroha_schema::Metadata::String); - } - } -} - -impl PartialOrd for JsonString { - fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for JsonString { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.0.cmp(&other.0) +impl Permission { + /// Getter + // TODO: derive with getset once FFI impl is fixed + pub fn payload(&self) -> &JsonString { + &self.payload } } pub mod prelude { //! The prelude re-exports most commonly used traits, structs and macros from this crate. - pub use super::{Permission, PermissionId, PermissionSchema}; + pub use super::{Permission, PermissionId}; } diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index ae99fc9fa2e..ca450c6b9c4 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -26,8 +26,8 @@ pub use sorting::Sorting; pub use self::model::*; use self::{ - account::*, asset::*, block::*, domain::*, peer::*, permission::*, predicate::*, role::*, - transaction::*, trigger::*, + account::*, asset::*, block::*, domain::*, executor::*, peer::*, permission::*, predicate::*, + role::*, transaction::*, trigger::*, }; use crate::{ account::{Account, AccountId}, @@ -188,7 +188,6 @@ mod model { FindTransactionsByAccountId(FindTransactionsByAccountId), FindTransactionByHash(FindTransactionByHash), FindPermissionsByAccountId(FindPermissionsByAccountId), - FindPermissionSchema(FindPermissionSchema), FindAllActiveTriggerIds(FindAllActiveTriggerIds), FindTriggerById(FindTriggerById), FindTriggerKeyValueByIdAndKey(FindTriggerKeyValueByIdAndKey), @@ -198,6 +197,7 @@ mod model { FindRoleByRoleId(FindRoleByRoleId), FindRolesByAccountId(FindRolesByAccountId), FindAllParameters(FindAllParameters), + FindExecutorDataModel(FindExecutorDataModel), } /// Sized container for all possible [`Query::Output`]s @@ -221,11 +221,11 @@ mod model { Identifiable(IdentifiableBox), Transaction(TransactionQueryOutput), Permission(crate::permission::Permission), - PermissionSchema(crate::permission::PermissionSchema), LimitedMetadata(MetadataValueBox), Numeric(Numeric), BlockHeader(BlockHeader), Block(crate::block::SignedBlock), + ExecutorDataModel(crate::executor::ExecutorDataModel), Vec( #[skip_from] @@ -359,7 +359,6 @@ impl_query! { FindAllRoleIds => Vec<crate::role::RoleId>, FindRolesByAccountId => Vec<crate::role::RoleId>, FindRoleByRoleId => crate::role::Role, - FindPermissionSchema => crate::permission::PermissionSchema, FindPermissionsByAccountId => Vec<crate::permission::Permission>, FindAllAccounts => Vec<crate::account::Account>, FindAccountById => crate::account::Account, @@ -394,6 +393,7 @@ impl_query! { FindAllBlocks => Vec<SignedBlock>, FindAllBlockHeaders => Vec<crate::block::BlockHeader>, FindBlockHeaderByHash => crate::block::BlockHeader, + FindExecutorDataModel => crate::executor::ExecutorDataModel } impl Query for QueryBox { @@ -412,11 +412,11 @@ impl core::fmt::Display for QueryOutputBox { QueryOutputBox::Identifiable(v) => core::fmt::Display::fmt(&v, f), QueryOutputBox::Transaction(_) => write!(f, "TransactionQueryOutput"), QueryOutputBox::Permission(v) => core::fmt::Display::fmt(&v, f), - QueryOutputBox::PermissionSchema(v) => core::fmt::Display::fmt(&v, f), QueryOutputBox::Block(v) => core::fmt::Display::fmt(&v, f), QueryOutputBox::BlockHeader(v) => core::fmt::Display::fmt(&v, f), QueryOutputBox::Numeric(v) => core::fmt::Display::fmt(&v, f), QueryOutputBox::LimitedMetadata(v) => core::fmt::Display::fmt(&v, f), + QueryOutputBox::ExecutorDataModel(v) => core::fmt::Display::fmt(&v, f), QueryOutputBox::Vec(v) => { // TODO: Remove so we can derive. @@ -621,17 +621,9 @@ pub mod permission { use parity_scale_codec::Encode; use super::{Query, QueryType}; - use crate::{ - permission::{self, PermissionSchema}, - prelude::*, - }; + use crate::prelude::*; queries! { - /// Finds all registered permission tokens - #[derive(Copy, Display)] - #[ffi_type] - pub struct FindPermissionSchema; - /// [`FindPermissionsByAccountId`] Iroha Query finds all [`Permission`]s /// for a specified account. #[derive(Display)] @@ -647,7 +639,7 @@ pub mod permission { /// The prelude re-exports most commonly used traits, structs and macros from this module. pub mod prelude { - pub use super::{FindPermissionSchema, FindPermissionsByAccountId}; + pub use super::FindPermissionsByAccountId; } } @@ -954,7 +946,7 @@ pub mod domain { } pub mod peer { - //! Queries related to [`Domain`](crate::domain::Domain). + //! Queries related to [`crate::peer`]. #[cfg(not(feature = "std"))] use alloc::{format, string::String, vec::Vec}; @@ -970,18 +962,39 @@ pub mod peer { #[display(fmt = "Find all peers")] #[ffi_type] pub struct FindAllPeers; + } + + /// The prelude re-exports most commonly used traits, structs and macros from this crate. + pub mod prelude { + pub use super::FindAllPeers; + } +} + +pub mod executor { + //! Queries related to [`crate::executor`]. + + #[cfg(not(feature = "std"))] + use alloc::{format, string::String, vec::Vec}; + + use derive_more::Display; + + queries! { + /// [`FindExecutorDataModel`] Iroha Query finds the data model of the current executor. + #[derive(Copy, Display)] + #[display(fmt = "Find executor data model")] + #[ffi_type] + pub struct FindExecutorDataModel; - /// [`FindAllParameters`] Iroha Query finds all [`Peer`]s parameters. + /// [`FindAllParameters`] Iroha Query finds all defined executor configuration parameters. #[derive(Copy, Display)] #[display(fmt = "Find all peers parameters")] - // TODO: Unused query. Remove? #[ffi_type] pub struct FindAllParameters; } /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { - pub use super::{FindAllParameters, FindAllPeers}; + pub use super::{FindAllParameters, FindExecutorDataModel}; } } @@ -1495,7 +1508,8 @@ pub mod prelude { pub use super::http::*; pub use super::{ account::prelude::*, asset::prelude::*, block::prelude::*, domain::prelude::*, - peer::prelude::*, permission::prelude::*, predicate::PredicateTrait, role::prelude::*, - transaction::*, trigger::prelude::*, FetchSize, QueryBox, QueryId, TransactionQueryOutput, + executor::prelude::*, peer::prelude::*, permission::prelude::*, predicate::PredicateTrait, + role::prelude::*, transaction::prelude::*, trigger::prelude::*, FetchSize, QueryBox, + QueryId, TransactionQueryOutput, }; } diff --git a/data_model/src/role.rs b/data_model/src/role.rs index 45c6b53732a..d7479db5959 100644 --- a/data_model/src/role.rs +++ b/data_model/src/role.rs @@ -44,7 +44,7 @@ mod model { #[repr(transparent)] #[ffi_type(opaque)] pub struct RoleId { - /// Role name, should be unique . + /// Role name. Should be unique. pub name: Name, } diff --git a/data_model/src/transaction.rs b/data_model/src/transaction.rs index 081e0a514f9..ace8cd328d4 100644 --- a/data_model/src/transaction.rs +++ b/data_model/src/transaction.rs @@ -580,7 +580,6 @@ pub mod error { Revoke(_) => "revoke", ExecuteTrigger(_) => "execute trigger", SetParameter(_) => "set parameter", - NewParameter(_) => "new parameter", Upgrade(_) => "upgrade", Log(_) => "log", }; diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index 754ee8368c6..4d5be970008 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -40,7 +40,6 @@ pub trait Visit { visit_upgrade(&Upgrade), visit_execute_trigger(&ExecuteTrigger), - visit_new_parameter(&NewParameter), visit_set_parameter(&SetParameter), visit_log(&Log), @@ -58,7 +57,6 @@ pub trait Visit { visit_find_all_domains(&FindAllDomains), visit_find_all_parameters(&FindAllParameters), visit_find_all_peers(&FindAllPeers), - visit_find_permission_schema(&FindPermissionSchema), visit_find_all_role_ids(&FindAllRoleIds), visit_find_all_roles(&FindAllRoles), visit_find_all_transactions(&FindAllTransactions), @@ -84,6 +82,7 @@ pub trait Visit { visit_find_trigger_by_id(&FindTriggerById), visit_find_trigger_key_value_by_id_and_key(&FindTriggerKeyValueByIdAndKey), visit_find_triggers_by_domain_id(&FindTriggersByDomainId), + visit_find_executor_data_model(&FindExecutorDataModel), // Visit RegisterBox visit_register_peer(&Register<Peer>), @@ -183,7 +182,6 @@ pub fn visit_query<V: Visit + ?Sized>(visitor: &mut V, authority: &AccountId, qu visit_find_all_domains(FindAllDomains), visit_find_all_parameters(FindAllParameters), visit_find_all_peers(FindAllPeers), - visit_find_permission_schema(FindPermissionSchema), visit_find_all_role_ids(FindAllRoleIds), visit_find_all_roles(FindAllRoles), visit_find_all_transactions(FindAllTransactions), @@ -209,6 +207,7 @@ pub fn visit_query<V: Visit + ?Sized>(visitor: &mut V, authority: &AccountId, qu visit_find_trigger_by_id(FindTriggerById), visit_find_trigger_key_value_by_id_and_key(FindTriggerKeyValueByIdAndKey), visit_find_triggers_by_domain_id(FindTriggersByDomainId), + visit_find_executor_data_model(FindExecutorDataModel), } } @@ -230,9 +229,6 @@ pub fn visit_instruction<V: Visit + ?Sized>( isi: &InstructionBox, ) { match isi { - InstructionBox::NewParameter(variant_value) => { - visitor.visit_new_parameter(authority, variant_value) - } InstructionBox::SetParameter(variant_value) => { visitor.visit_set_parameter(authority, variant_value) } @@ -424,7 +420,6 @@ leaf_visitors! { visit_mint_trigger_repetitions(&Mint<u32, Trigger>), visit_burn_trigger_repetitions(&Burn<u32, Trigger>), visit_upgrade(&Upgrade), - visit_new_parameter(&NewParameter), visit_set_parameter(&SetParameter), visit_execute_trigger(&ExecuteTrigger), visit_fail(&Fail), @@ -444,7 +439,6 @@ leaf_visitors! { visit_find_all_domains(&FindAllDomains), visit_find_all_parameters(&FindAllParameters), visit_find_all_peers(&FindAllPeers), - visit_find_permission_schema(&FindPermissionSchema), visit_find_all_role_ids(&FindAllRoleIds), visit_find_all_roles(&FindAllRoles), visit_find_all_transactions(&FindAllTransactions), @@ -470,4 +464,5 @@ leaf_visitors! { visit_find_trigger_by_id(&FindTriggerById), visit_find_trigger_key_value_by_id_and_key(&FindTriggerKeyValueByIdAndKey), visit_find_triggers_by_domain_id(&FindTriggersByDomainId), + visit_find_executor_data_model(&FindExecutorDataModel), } diff --git a/default_executor/src/lib.rs b/default_executor/src/lib.rs index 26b3593f753..546a6cab359 100644 --- a/default_executor/src/lib.rs +++ b/default_executor/src/lib.rs @@ -8,7 +8,7 @@ extern crate panic_halt; use alloc::borrow::ToOwned as _; -use iroha_executor::{default::default_permission_schema, prelude::*}; +use iroha_executor::{prelude::*, DataModelBuilder}; use lol_alloc::{FreeListAllocator, LockedAllocator}; #[global_allocator] @@ -52,11 +52,7 @@ impl Executor { pub fn migrate(block_height: u64) -> MigrationResult { Executor::ensure_genesis(block_height)?; - let schema = default_permission_schema(); - let (token_ids, schema_str) = schema.serialize(); - iroha_executor::set_permission_schema( - &iroha_executor::data_model::permission::PermissionSchema::new(token_ids, schema_str), - ); + DataModelBuilder::with_default_permissions().set(); Ok(()) } diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index 3428213f02e..81fd7f6e7e8 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -157,7 +157,7 @@ }, { "name": "permission_id", - "type": "Name" + "type": "PermissionId" } ] }, @@ -769,26 +769,12 @@ { "tag": "Changed", "discriminant": 0, - "type": "ParameterId" - }, - { - "tag": "Created", - "discriminant": 1, - "type": "ParameterId" - }, - { - "tag": "Deleted", - "discriminant": 2, - "type": "ParameterId" + "type": "Parameter" } ] }, "ConfigurationEventFilter": { "Struct": [ - { - "name": "id_matcher", - "type": "Option<ParameterId>" - }, { "name": "event_set", "type": "ConfigurationEventSet" @@ -802,14 +788,6 @@ { "name": "Changed", "mask": 1 - }, - { - "name": "Created", - "mask": 2 - }, - { - "name": "Deleted", - "mask": 4 } ] } @@ -855,19 +833,14 @@ "discriminant": 3, "type": "RoleEvent" }, - { - "tag": "Permission", - "discriminant": 4, - "type": "PermissionSchemaUpdateEvent" - }, { "tag": "Configuration", - "discriminant": 5, + "discriminant": 4, "type": "ConfigurationEvent" }, { "tag": "Executor", - "discriminant": 6, + "discriminant": 5, "type": "ExecutorEvent" } ] @@ -913,18 +886,14 @@ "discriminant": 7, "type": "RoleEventFilter" }, - { - "tag": "PermissionSchemaUpdate", - "discriminant": 8 - }, { "tag": "Configuration", - "discriminant": 9, + "discriminant": 8, "type": "ConfigurationEventFilter" }, { "tag": "Executor", - "discriminant": 10, + "discriminant": 9, "type": "ExecutorEventFilter" } ] @@ -1200,11 +1169,28 @@ } ] }, + "ExecutorDataModel": { + "Struct": [ + { + "name": "permissions", + "type": "SortedVec<PermissionId>" + }, + { + "name": "parameters", + "type": "SortedVec<ParameterId>" + }, + { + "name": "schema", + "type": "JsonString" + } + ] + }, "ExecutorEvent": { "Enum": [ { "tag": "Upgraded", - "discriminant": 0 + "discriminant": 0, + "type": "ExecutorUpgrade" } ] }, @@ -1227,6 +1213,14 @@ ] } }, + "ExecutorUpgrade": { + "Struct": [ + { + "name": "new_data_model", + "type": "ExecutorDataModel" + } + ] + }, "Fail": { "Struct": [ { @@ -1466,7 +1460,7 @@ { "tag": "Permission", "discriminant": 10, - "type": "Name" + "type": "PermissionId" }, { "tag": "Parameter", @@ -1480,7 +1474,7 @@ } ] }, - "FindPermissionSchema": null, + "FindExecutorDataModel": null, "FindPermissionsByAccountId": { "Struct": [ { @@ -1692,7 +1686,7 @@ { "tag": "PermissionId", "discriminant": 7, - "type": "Name" + "type": "PermissionId" }, { "tag": "ParameterId", @@ -1822,24 +1816,19 @@ "discriminant": 10, "type": "SetParameter" }, - { - "tag": "NewParameter", - "discriminant": 11, - "type": "NewParameter" - }, { "tag": "Upgrade", - "discriminant": 12, + "discriminant": 11, "type": "Upgrade" }, { "tag": "Log", - "discriminant": 13, + "discriminant": 12, "type": "Log" }, { "tag": "Fail", - "discriminant": 14, + "discriminant": 13, "type": "Fail" } ] @@ -1980,21 +1969,17 @@ "tag": "SetParameter", "discriminant": 10 }, - { - "tag": "NewParameter", - "discriminant": 11 - }, { "tag": "Upgrade", - "discriminant": 12 + "discriminant": 11 }, { "tag": "Log", - "discriminant": 13 + "discriminant": 12 }, { "tag": "Fail", - "discriminant": 14 + "discriminant": 13 } ] }, @@ -2019,18 +2004,6 @@ "Ipv4Addr": "Array<u8, 4>", "Ipv6Addr": "Array<u16, 8>", "JsonString": "String", - "LengthLimits": { - "Struct": [ - { - "name": "min", - "type": "u32" - }, - { - "name": "max", - "type": "u32" - } - ] - }, "Level": { "Enum": [ { @@ -2394,14 +2367,6 @@ } ] }, - "NewParameter": { - "Struct": [ - { - "name": "parameter", - "type": "Parameter" - } - ] - }, "NewRole": { "Struct": [ { @@ -2475,9 +2440,6 @@ "Option<Option<u64>>": { "Option": "Option<u64>" }, - "Option<ParameterId>": { - "Option": "ParameterId" - }, "Option<PeerId>": { "Option": "PeerId" }, @@ -2527,8 +2489,8 @@ "type": "ParameterId" }, { - "name": "val", - "type": "ParameterValueBox" + "name": "payload", + "type": "JsonString" } ] }, @@ -2540,30 +2502,6 @@ } ] }, - "ParameterValueBox": { - "Enum": [ - { - "tag": "TransactionLimits", - "discriminant": 0, - "type": "TransactionLimits" - }, - { - "tag": "MetadataLimits", - "discriminant": 1, - "type": "Limits" - }, - { - "tag": "LengthLimits", - "discriminant": 2, - "type": "LengthLimits" - }, - { - "tag": "Numeric", - "discriminant": 3, - "type": "Numeric" - } - ] - }, "Peer": { "Struct": [ { @@ -2628,8 +2566,8 @@ "Permission": { "Struct": [ { - "name": "definition_id", - "type": "Name" + "name": "id", + "type": "PermissionId" }, { "name": "payload", @@ -2637,27 +2575,11 @@ } ] }, - "PermissionSchema": { - "Struct": [ - { - "name": "token_ids", - "type": "Vec<Name>" - }, - { - "name": "schema", - "type": "String" - } - ] - }, - "PermissionSchemaUpdateEvent": { + "PermissionId": { "Struct": [ { - "name": "old_schema", - "type": "PermissionSchema" - }, - { - "name": "new_schema", - "type": "PermissionSchema" + "name": "name", + "type": "Name" } ] }, @@ -2848,55 +2770,55 @@ "discriminant": 28, "type": "FindPermissionsByAccountId" }, - { - "tag": "FindPermissionSchema", - "discriminant": 29, - "type": "FindPermissionSchema" - }, { "tag": "FindAllActiveTriggerIds", - "discriminant": 30, + "discriminant": 29, "type": "FindAllActiveTriggerIds" }, { "tag": "FindTriggerById", - "discriminant": 31, + "discriminant": 30, "type": "FindTriggerById" }, { "tag": "FindTriggerKeyValueByIdAndKey", - "discriminant": 32, + "discriminant": 31, "type": "FindTriggerKeyValueByIdAndKey" }, { "tag": "FindTriggersByDomainId", - "discriminant": 33, + "discriminant": 32, "type": "FindTriggersByDomainId" }, { "tag": "FindAllRoles", - "discriminant": 34, + "discriminant": 33, "type": "FindAllRoles" }, { "tag": "FindAllRoleIds", - "discriminant": 35, + "discriminant": 34, "type": "FindAllRoleIds" }, { "tag": "FindRoleByRoleId", - "discriminant": 36, + "discriminant": 35, "type": "FindRoleByRoleId" }, { "tag": "FindRolesByAccountId", - "discriminant": 37, + "discriminant": 36, "type": "FindRolesByAccountId" }, { "tag": "FindAllParameters", - "discriminant": 38, + "discriminant": 37, "type": "FindAllParameters" + }, + { + "tag": "FindExecutorDataModel", + "discriminant": 38, + "type": "FindExecutorDataModel" } ] }, @@ -2953,31 +2875,31 @@ "discriminant": 3, "type": "Permission" }, - { - "tag": "PermissionSchema", - "discriminant": 4, - "type": "PermissionSchema" - }, { "tag": "LimitedMetadata", - "discriminant": 5, + "discriminant": 4, "type": "MetadataValueBox" }, { "tag": "Numeric", - "discriminant": 6, + "discriminant": 5, "type": "Numeric" }, { "tag": "BlockHeader", - "discriminant": 7, + "discriminant": 6, "type": "BlockHeader" }, { "tag": "Block", - "discriminant": 8, + "discriminant": 7, "type": "SignedBlock" }, + { + "tag": "ExecutorDataModel", + "discriminant": 8, + "type": "ExecutorDataModel" + }, { "tag": "Vec", "discriminant": 9, @@ -3369,7 +3291,7 @@ }, { "name": "permission_id", - "type": "Name" + "type": "PermissionId" } ] }, @@ -3718,9 +3640,15 @@ "value": "MetadataValueBox" } }, + "SortedVec<ParameterId>": { + "Vec": "ParameterId" + }, "SortedVec<Permission>": { "Vec": "Permission" }, + "SortedVec<PermissionId>": { + "Vec": "PermissionId" + }, "SortedVec<SignatureOf<BlockPayload>>": { "Vec": "SignatureOf<BlockPayload>" }, @@ -3822,18 +3750,6 @@ } ] }, - "TransactionLimits": { - "Struct": [ - { - "name": "max_instruction_number", - "type": "u64" - }, - { - "name": "max_wasm_size_bytes", - "type": "u64" - } - ] - }, "TransactionPayload": { "Struct": [ { @@ -4364,9 +4280,6 @@ "Vec<MetadataValueBox>": { "Vec": "MetadataValueBox" }, - "Vec<Name>": { - "Vec": "Name" - }, "Vec<PeerId>": { "Vec": "PeerId" }, diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index ff6b9888da7..bfae67733b1 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -137,6 +137,8 @@ types!( ExecutorEvent, ExecutorEventFilter, ExecutorEventSet, + ExecutorUpgrade, + ExecutorDataModel, Fail, EventFilterBox, FetchSize, @@ -170,7 +172,6 @@ types!( FindDomainById, FindDomainKeyValueByIdAndKey, FindError, - FindPermissionSchema, FindPermissionsByAccountId, FindRoleByRoleId, FindRolesByAccountId, @@ -224,7 +225,6 @@ types!( NewAccount, NewAssetDefinition, NewDomain, - NewParameter, NewRole, NonTrivial<PredicateBox>, NonZeroU32, @@ -247,7 +247,6 @@ types!( Option<NonZeroU32>, Option<NonZeroU64>, Option<Option<u64>>, - Option<ParameterId>, Option<PeerId>, Option<RoleId>, Option<String>, @@ -259,7 +258,6 @@ types!( Pagination, Parameter, ParameterId, - ParameterValueBox, Peer, PeerEvent, PeerEventFilter, @@ -267,8 +265,6 @@ types!( PeerId, RolePermissionChanged, Permission, - PermissionSchema, - PermissionSchemaUpdateEvent, PipelineEventBox, PipelineEventFilterBox, PredicateBox, @@ -396,16 +392,17 @@ types!( u8, ); -#[cfg(test)] -mod tests { - use core::num::{NonZeroU32, NonZeroU64}; - use std::{ +pub mod complete_data_model { + //! Complete set of types participating in the schema + + pub use core::num::{NonZeroU32, NonZeroU64}; + pub use std::{ collections::{BTreeMap, BTreeSet, HashMap, HashSet}, time::Duration, }; - use iroha_crypto::*; - use iroha_data_model::{ + pub use iroha_crypto::*; + pub use iroha_data_model::{ account::NewAccount, asset::NewAssetDefinition, block::{ @@ -425,8 +422,6 @@ mod tests { InstructionType, }, metadata::{MetadataError, MetadataValueBox, SizeError}, - parameter::ParameterValueBox, - permission::JsonString, prelude::*, query::{ error::{FindError, QueryExecutionFail}, @@ -442,17 +437,20 @@ mod tests { error::TransactionLimitError, SignedTransactionV1, TransactionLimits, TransactionPayload, }, - BatchedResponse, BatchedResponseV1, Level, + BatchedResponse, BatchedResponseV1, JsonString, Level, }; - use iroha_primitives::{ + pub use iroha_primitives::{ addr::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrHost, SocketAddrV4, SocketAddrV6}, const_vec::ConstVec, conststr::ConstString, unique_vec::UniqueVec, }; - use iroha_schema::Compact; + pub use iroha_schema::Compact; +} - use super::IntoSchema; +#[cfg(test)] +mod tests { + use super::{complete_data_model::*, IntoSchema}; fn is_const_generic(generic: &str) -> bool { generic.parse::<usize>().is_ok() diff --git a/smart_contract/executor/derive/src/default.rs b/smart_contract/executor/derive/src/default.rs index 14b58d0bd73..492fe0787f2 100644 --- a/smart_contract/executor/derive/src/default.rs +++ b/smart_contract/executor/derive/src/default.rs @@ -142,21 +142,20 @@ pub fn impl_derive_visit(emitter: &mut Emitter, input: &syn::DeriveInput) -> Tok "fn visit_transfer_asset_definition(operation: &Transfer<Account, AssetDefinitionId, Account>)", "fn visit_set_asset_definition_key_value(operation: &SetKeyValue<AssetDefinition>)", "fn visit_remove_asset_definition_key_value(operation: &RemoveKeyValue<AssetDefinition>)", - "fn visit_grant_account_permission(operation: &Grant<Permission, Account>)", - "fn visit_revoke_account_permission(operation: &Revoke<Permission, Account>)", + "fn visit_grant_account_permission(operation: &Grant<PermissionObject, Account>)", + "fn visit_revoke_account_permission(operation: &Revoke<PermissionObject, Account>)", "fn visit_register_role(operation: &Register<Role>)", "fn visit_unregister_role(operation: &Unregister<Role>)", "fn visit_grant_account_role(operation: &Grant<RoleId, Account>)", "fn visit_revoke_account_role(operation: &Revoke<RoleId, Account>)", - "fn visit_grant_role_permission(operation: &Grant<Permission, Role>)", - "fn visit_revoke_role_permission(operation: &Revoke<Permission, Role>)", + "fn visit_grant_role_permission(operation: &Grant<PermissionObject, Role>)", + "fn visit_revoke_role_permission(operation: &Revoke<PermissionObject, Role>)", "fn visit_register_trigger(operation: &Register<Trigger>)", "fn visit_unregister_trigger(operation: &Unregister<Trigger>)", "fn visit_mint_trigger_repetitions(operation: &Mint<u32, Trigger>)", "fn visit_burn_trigger_repetitions(operation: &Burn<u32, Trigger>)", "fn visit_execute_trigger(operation: &ExecuteTrigger)", "fn visit_set_parameter(operation: &SetParameter)", - "fn visit_new_parameter(operation: &NewParameter)", "fn visit_upgrade(operation: &Upgrade)", "fn visit_log(operation: &Log)", "fn visit_fail(operation: &Fail)", diff --git a/smart_contract/executor/derive/src/entrypoint.rs b/smart_contract/executor/derive/src/entrypoint.rs index 84b685bd64e..646fb0c281f 100644 --- a/smart_contract/executor/derive/src/entrypoint.rs +++ b/smart_contract/executor/derive/src/entrypoint.rs @@ -144,6 +144,7 @@ fn impl_migrate_entrypoint(fn_item: syn::ItemFn) -> TokenStream { let migrate_fn_name = syn::Ident::new(export::EXECUTOR_MIGRATE, proc_macro2::Span::call_site()); + // FIXME: is doc accurate? quote! { /// Executor `permission_schema` entrypoint /// diff --git a/smart_contract/executor/derive/src/lib.rs b/smart_contract/executor/derive/src/lib.rs index fa4a4318c8b..7a431e3d15b 100644 --- a/smart_contract/executor/derive/src/lib.rs +++ b/smart_contract/executor/derive/src/lib.rs @@ -7,7 +7,7 @@ use proc_macro2::TokenStream; mod conversion; mod default; mod entrypoint; -mod token; +mod permission; mod validate; /// Annotate the user-defined function that starts the execution of a executor. @@ -64,14 +64,14 @@ pub fn entrypoint(attr: TokenStream, item: TokenStream) -> TokenStream { emitter.finish_token_stream_with(result) } -/// Derive macro for `Token` trait. +/// Derive macro for `Permission` trait. /// /// # Example /// /// ```ignore /// use iroha_executor::{permission, prelude::*}; /// -/// #[derive(Token, ValidateGrantRevoke, permission::derive_conversions::asset::Owner)] +/// #[derive(Permission, ValidateGrantRevoke, permission::derive_conversions::asset::Owner)] /// #[validate(permission::asset::Owner)] /// struct CanDoSomethingWithAsset { /// some_data: String, @@ -93,11 +93,11 @@ pub fn entrypoint(attr: TokenStream, item: TokenStream) -> TokenStream { /// } /// ``` #[manyhow] -#[proc_macro_derive(Token)] -pub fn derive_token(input: TokenStream) -> Result<TokenStream> { +#[proc_macro_derive(Permission)] +pub fn derive_permission(input: TokenStream) -> Result<TokenStream> { let input = syn::parse2(input)?; - Ok(token::impl_derive_token(&input)) + Ok(permission::impl_derive_permission(&input)) } /// Derive macro for `ValidateGrantRevoke` trait. @@ -149,13 +149,13 @@ pub fn derive_token(input: TokenStream) -> Result<TokenStream> { /// /// # Example /// -/// See [`Token`] derive macro example. +/// See [`Permission`] derive macro example. // // TODO: Add combinators (#3255). // Example: // // ``` -// #[derive(Token, ValidateGrantRevoke)] +// #[derive(Permission, ValidateGrantRevoke)] // #[validate(Creator || Admin)] // pub struct CanDoSomethingWithAsset { // ... diff --git a/smart_contract/executor/derive/src/permission.rs b/smart_contract/executor/derive/src/permission.rs new file mode 100644 index 00000000000..82c6a51fb14 --- /dev/null +++ b/smart_contract/executor/derive/src/permission.rs @@ -0,0 +1,34 @@ +//! Module with [`derive_permission`](crate::derive_permission) macro implementation + +use proc_macro2::TokenStream; +use quote::quote; + +/// [`derive_permission`](crate::derive_permission()) macro implementation +pub fn impl_derive_permission(input: &syn::DeriveInput) -> TokenStream { + let generics = &input.generics; + let ident = &input.ident; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + quote! { + impl #impl_generics ::iroha_executor::permission::Permission for #ident #ty_generics #where_clause { + fn is_owned_by(&self, account_id: &::iroha_executor::data_model::account::AccountId) -> bool { + let account_tokens_cursor = + ::iroha_executor::smart_contract::ExecuteQueryOnHost::execute( + &::iroha_executor::data_model::query::permission::FindPermissionsByAccountId::new( + account_id.clone(), + ) + ) + .expect("`FindPermissionsByAccountId` query should never fail, it's a bug"); + + account_tokens_cursor + .into_iter() + .map(|res| ::iroha_executor::smart_contract::debug::DebugExpectExt::dbg_expect( + res, + "Failed to get permission token from cursor" + )) + .filter_map(|token| Self::try_from_object(&token).ok()) + .any(|token| self == &token) + } + } + } +} diff --git a/smart_contract/executor/derive/src/token.rs b/smart_contract/executor/derive/src/token.rs deleted file mode 100644 index c2ca5adea29..00000000000 --- a/smart_contract/executor/derive/src/token.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! Module with [`derive_token`](crate::derive_token) macro implementation - -use proc_macro2::TokenStream; -use quote::quote; - -/// [`derive_token`](crate::derive_token()) macro implementation -pub fn impl_derive_token(input: &syn::DeriveInput) -> TokenStream { - let generics = &input.generics; - let ident = &input.ident; - - let impl_token = impl_token(ident, generics); - let impl_try_from_permission = impl_try_from_permission(ident, generics); - - quote! { - #impl_token - #impl_try_from_permission - } -} - -fn impl_token(ident: &syn::Ident, generics: &syn::Generics) -> proc_macro2::TokenStream { - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - - quote! { - impl #impl_generics ::iroha_executor::permission::Token for #ident #ty_generics #where_clause { - fn is_owned_by(&self, account_id: &::iroha_executor::data_model::account::AccountId) -> bool { - let account_tokens_cursor = ::iroha_executor::smart_contract::debug::DebugExpectExt::dbg_expect( - ::iroha_executor::smart_contract::ExecuteQueryOnHost::execute( - &::iroha_executor::data_model::query::permission::FindPermissionsByAccountId::new( - account_id.clone(), - ) - ), - "Failed to execute `FindPermissionsByAccountId` query" - ); - - account_tokens_cursor - .into_iter() - .map(|res| ::iroha_executor::smart_contract::debug::DebugExpectExt::dbg_expect( - res, - "Failed to get permission token from cursor" - )) - .filter_map(|token| Self::try_from(&token).ok()) - .any(|token| self == &token) - } - } - } -} - -fn impl_try_from_permission(ident: &syn::Ident, generics: &syn::Generics) -> TokenStream { - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let token_id = quote! { <#ident #ty_generics as ::iroha_executor::permission::Token>::name() }; - - quote! { - impl #impl_generics ::core::convert::TryFrom<&::iroha_executor::data_model::permission::Permission> for #ident #ty_generics #where_clause { - type Error = ::iroha_executor::permission::PermissionConversionError; - - fn try_from(token: &::iroha_executor::data_model::permission::Permission) -> ::core::result::Result<Self, Self::Error> { - if #token_id != *token.definition_id() { - return Err(::iroha_executor::permission::PermissionConversionError::Id( - ToOwned::to_owned(token.definition_id()) - )); - } - ::serde_json::from_str::<Self>(token.payload()) - .map_err(::iroha_executor::permission::PermissionConversionError::Deserialize) - } - } - - impl #impl_generics ::core::convert::From<#ident #ty_generics> for ::iroha_executor::data_model::permission::Permission #where_clause { - fn from(token: #ident #ty_generics) -> Self { - let definition_id = #token_id; - - let payload = ::iroha_executor::smart_contract::debug::DebugExpectExt::dbg_expect( - ::serde_json::to_value::<#ident #ty_generics>(token), - "failed to serialize concrete permission token type. This is a bug." - ); - - ::iroha_executor::data_model::permission::Permission::new(definition_id, &payload) - } - } - } -} diff --git a/smart_contract/executor/src/default.rs b/smart_contract/executor/src/default.rs index e2a4e827b9e..5d583ce5a00 100644 --- a/smart_contract/executor/src/default.rs +++ b/smart_contract/executor/src/default.rs @@ -1,7 +1,7 @@ //! Definition of Iroha default executor and accompanying validation functions #![allow(missing_docs, clippy::missing_errors_doc)] -pub mod tokens; +pub mod permissions; use alloc::format; @@ -27,9 +27,10 @@ pub use executor::visit_upgrade; pub use fail::visit_fail; use iroha_smart_contract::data_model::isi::InstructionBox; pub use log::visit_log; -pub use parameter::{visit_new_parameter, visit_set_parameter}; +pub use parameter::visit_set_parameter; pub use peer::{visit_register_peer, visit_unregister_peer}; pub use permission::{visit_grant_account_permission, visit_revoke_account_permission}; +use permissions::AnyPermission; pub use role::{ visit_grant_account_role, visit_grant_role_permission, visit_register_role, visit_revoke_account_role, visit_revoke_role_permission, visit_unregister_role, @@ -40,21 +41,7 @@ pub use trigger::{ visit_unregister_trigger, }; -use crate::{permission::Token as _, prelude::*}; - -pub fn default_permission_schema() -> PermissionSchema { - let mut schema = iroha_executor::PermissionSchema::default(); - - macro_rules! add_to_schema { - ($token_ty:ty) => { - schema.insert::<$token_ty>(); - }; - } - - tokens::map_token_type!(add_to_schema); - - schema -} +use crate::{permission::Permission as _, prelude::*}; // NOTE: If any new `visit_..` functions are introduced in this module, one should // not forget to update the default executor boilerplate too, specifically the @@ -95,9 +82,6 @@ pub fn visit_instruction<V: Validate + Visit + ?Sized>( isi: &InstructionBox, ) { match isi { - InstructionBox::NewParameter(isi) => { - executor.visit_new_parameter(authority, isi); - } InstructionBox::SetParameter(isi) => { executor.visit_set_parameter(authority, isi); } @@ -163,7 +147,7 @@ pub mod peer { if is_genesis(executor) { execute!(executor, isi); } - if tokens::peer::CanUnregisterAnyPeer.is_owned_by(authority) { + if permissions::peer::CanUnregisterAnyPeer.is_owned_by(authority) { execute!(executor, isi); } @@ -172,8 +156,7 @@ pub mod peer { } pub mod domain { - use iroha_smart_contract::data_model::{domain::DomainId, permission::Permission}; - use tokens::AnyPermission; + use iroha_smart_contract::data_model::domain::DomainId; use super::*; use crate::permission::{ @@ -201,7 +184,7 @@ pub mod domain { Ok(is_domain_owner) => is_domain_owner, } || { - let can_unregister_domain_token = tokens::domain::CanUnregisterDomain { + let can_unregister_domain_token = permissions::domain::CanUnregisterDomain { domain_id: domain_id.clone(), }; can_unregister_domain_token.is_owned_by(authority) @@ -268,7 +251,7 @@ pub mod domain { Ok(true) => execute!(executor, isi), Ok(false) => {} } - let can_set_key_value_in_domain_token = tokens::domain::CanSetKeyValueInDomain { + let can_set_key_value_in_domain_token = permissions::domain::CanSetKeyValueInDomain { domain_id: domain_id.clone(), }; if can_set_key_value_in_domain_token.is_owned_by(authority) { @@ -293,7 +276,7 @@ pub mod domain { Ok(true) => execute!(executor, isi), Ok(false) => {} } - let can_remove_key_value_in_domain_token = tokens::domain::CanRemoveKeyValueInDomain { + let can_remove_key_value_in_domain_token = permissions::domain::CanRemoveKeyValueInDomain { domain_id: domain_id.clone(), }; if can_remove_key_value_in_domain_token.is_owned_by(authority) { @@ -304,7 +287,7 @@ pub mod domain { } #[allow(clippy::too_many_lines)] - fn is_token_domain_associated(permission: &Permission, domain_id: &DomainId) -> bool { + fn is_token_domain_associated(permission: &PermissionObject, domain_id: &DomainId) -> bool { let Ok(permission) = AnyPermission::try_from(permission) else { return false; }; @@ -421,9 +404,6 @@ pub mod domain { } pub mod account { - use iroha_smart_contract::data_model::permission::Permission; - use tokens::AnyPermission; - use super::*; use crate::permission::{account::is_account_owner, accounts_permissions, roles_permissions}; @@ -440,7 +420,7 @@ pub mod account { Ok(false) => {} } - let can_register_account_in_domain = tokens::domain::CanRegisterAccountInDomain { + let can_register_account_in_domain = permissions::domain::CanRegisterAccountInDomain { domain_id: domain_id.clone(), }; if can_register_account_in_domain.is_owned_by(authority) { @@ -466,7 +446,7 @@ pub mod account { Ok(is_account_owner) => is_account_owner, } || { - let can_unregister_user_account = tokens::account::CanUnregisterAccount { + let can_unregister_user_account = permissions::account::CanUnregisterAccount { account_id: account_id.clone(), }; can_unregister_user_account.is_owned_by(authority) @@ -508,9 +488,10 @@ pub mod account { Ok(true) => execute!(executor, isi), Ok(false) => {} } - let can_set_key_value_in_user_account_token = tokens::account::CanSetKeyValueInAccount { - account_id: account_id.clone(), - }; + let can_set_key_value_in_user_account_token = + permissions::account::CanSetKeyValueInAccount { + account_id: account_id.clone(), + }; if can_set_key_value_in_user_account_token.is_owned_by(authority) { execute!(executor, isi); } @@ -537,7 +518,7 @@ pub mod account { Ok(false) => {} } let can_remove_key_value_in_user_account_token = - tokens::account::CanRemoveKeyValueInAccount { + permissions::account::CanRemoveKeyValueInAccount { account_id: account_id.clone(), }; if can_remove_key_value_in_user_account_token.is_owned_by(authority) { @@ -550,7 +531,7 @@ pub mod account { ); } - fn is_token_account_associated(permission: &Permission, account_id: &AccountId) -> bool { + fn is_token_account_associated(permission: &PermissionObject, account_id: &AccountId) -> bool { let Ok(permission) = AnyPermission::try_from(permission) else { return false; }; @@ -627,8 +608,7 @@ pub mod account { } pub mod asset_definition { - use iroha_smart_contract::data_model::{asset::AssetDefinitionId, permission::Permission}; - use tokens::AnyPermission; + use iroha_smart_contract::data_model::asset::AssetDefinitionId; use super::*; use crate::permission::{ @@ -650,7 +630,7 @@ pub mod asset_definition { } let can_register_asset_definition_in_domain_token = - tokens::domain::CanRegisterAssetDefinitionInDomain { + permissions::domain::CanRegisterAssetDefinitionInDomain { domain_id: domain_id.clone(), }; if can_register_asset_definition_in_domain_token.is_owned_by(authority) { @@ -677,7 +657,7 @@ pub mod asset_definition { } || { let can_unregister_asset_definition_token = - tokens::asset_definition::CanUnregisterAssetDefinition { + permissions::asset_definition::CanUnregisterAssetDefinition { asset_definition_id: asset_definition_id.clone(), }; can_unregister_asset_definition_token.is_owned_by(authority) @@ -751,7 +731,7 @@ pub mod asset_definition { Ok(false) => {} } let can_set_key_value_in_asset_definition_token = - tokens::asset_definition::CanSetKeyValueInAssetDefinition { + permissions::asset_definition::CanSetKeyValueInAssetDefinition { asset_definition_id: asset_definition_id.clone(), }; if can_set_key_value_in_asset_definition_token.is_owned_by(authority) { @@ -780,7 +760,7 @@ pub mod asset_definition { Ok(false) => {} } let can_remove_key_value_in_asset_definition_token = - tokens::asset_definition::CanRemoveKeyValueInAssetDefinition { + permissions::asset_definition::CanRemoveKeyValueInAssetDefinition { asset_definition_id: asset_definition_id.clone(), }; if can_remove_key_value_in_asset_definition_token.is_owned_by(authority) { @@ -794,7 +774,7 @@ pub mod asset_definition { } fn is_token_asset_definition_associated( - permission: &Permission, + permission: &PermissionObject, asset_definition_id: &AssetDefinitionId, ) -> bool { let Ok(permission) = AnyPermission::try_from(permission) else { @@ -899,7 +879,7 @@ pub mod asset { Ok(false) => {} } let can_register_assets_with_definition_token = - tokens::asset::CanRegisterAssetWithDefinition { + permissions::asset::CanRegisterAssetWithDefinition { asset_definition_id: asset.id().definition_id().clone(), }; if can_register_assets_with_definition_token.is_owned_by(authority) { @@ -933,13 +913,13 @@ pub mod asset { Ok(false) => {} } let can_unregister_assets_with_definition_token = - tokens::asset::CanUnregisterAssetWithDefinition { + permissions::asset::CanUnregisterAssetWithDefinition { asset_definition_id: asset_id.definition_id().clone(), }; if can_unregister_assets_with_definition_token.is_owned_by(authority) { execute!(executor, isi); } - let can_unregister_user_asset_token = tokens::asset::CanUnregisterUserAsset { + let can_unregister_user_asset_token = permissions::asset::CanUnregisterUserAsset { asset_id: asset_id.clone(), }; if can_unregister_user_asset_token.is_owned_by(authority) { @@ -964,13 +944,14 @@ pub mod asset { Ok(true) => execute!(executor, isi), Ok(false) => {} } - let can_mint_assets_with_definition_token = tokens::asset::CanMintAssetWithDefinition { - asset_definition_id: asset_id.definition_id().clone(), - }; + let can_mint_assets_with_definition_token = + permissions::asset::CanMintAssetWithDefinition { + asset_definition_id: asset_id.definition_id().clone(), + }; if can_mint_assets_with_definition_token.is_owned_by(authority) { execute!(executor, isi); } - let can_mint_user_asset_token = tokens::asset::CanMintUserAsset { + let can_mint_user_asset_token = permissions::asset::CanMintUserAsset { asset_id: asset_id.clone(), }; if can_mint_user_asset_token.is_owned_by(authority) { @@ -1011,13 +992,14 @@ pub mod asset { Ok(true) => execute!(executor, isi), Ok(false) => {} } - let can_burn_assets_with_definition_token = tokens::asset::CanBurnAssetWithDefinition { - asset_definition_id: asset_id.definition_id().clone(), - }; + let can_burn_assets_with_definition_token = + permissions::asset::CanBurnAssetWithDefinition { + asset_definition_id: asset_id.definition_id().clone(), + }; if can_burn_assets_with_definition_token.is_owned_by(authority) { execute!(executor, isi); } - let can_burn_user_asset_token = tokens::asset::CanBurnUserAsset { + let can_burn_user_asset_token = permissions::asset::CanBurnUserAsset { asset_id: asset_id.clone(), }; if can_burn_user_asset_token.is_owned_by(authority) { @@ -1059,13 +1041,13 @@ pub mod asset { Ok(false) => {} } let can_transfer_assets_with_definition_token = - tokens::asset::CanTransferAssetWithDefinition { + permissions::asset::CanTransferAssetWithDefinition { asset_definition_id: asset_id.definition_id().clone(), }; if can_transfer_assets_with_definition_token.is_owned_by(authority) { execute!(executor, isi); } - let can_transfer_user_asset_token = tokens::asset::CanTransferUserAsset { + let can_transfer_user_asset_token = permissions::asset::CanTransferUserAsset { asset_id: asset_id.clone(), }; if can_transfer_user_asset_token.is_owned_by(authority) { @@ -1107,7 +1089,7 @@ pub mod asset { Ok(false) => {} } - let can_set_key_value_in_user_asset_token = tokens::asset::CanSetKeyValueInUserAsset { + let can_set_key_value_in_user_asset_token = permissions::asset::CanSetKeyValueInUserAsset { asset_id: asset_id.clone(), }; if can_set_key_value_in_user_asset_token.is_owned_by(authority) { @@ -1136,7 +1118,7 @@ pub mod asset { Ok(false) => {} } let can_remove_key_value_in_user_asset_token = - tokens::asset::CanRemoveKeyValueInUserAsset { + permissions::asset::CanRemoveKeyValueInUserAsset { asset_id: asset_id.clone(), }; if can_remove_key_value_in_user_asset_token.is_owned_by(authority) { @@ -1153,25 +1135,6 @@ pub mod asset { pub mod parameter { use super::*; - #[allow(clippy::needless_pass_by_value)] - pub fn visit_new_parameter<V: Validate + Visit + ?Sized>( - executor: &mut V, - authority: &AccountId, - isi: &NewParameter, - ) { - if is_genesis(executor) { - execute!(executor, isi); - } - if tokens::parameter::CanCreateParameters.is_owned_by(authority) { - execute!(executor, isi); - } - - deny!( - executor, - "Can't create new configuration parameters outside genesis without permission" - ); - } - #[allow(clippy::needless_pass_by_value)] pub fn visit_set_parameter<V: Validate + Visit + ?Sized>( executor: &mut V, @@ -1181,20 +1144,20 @@ pub mod parameter { if is_genesis(executor) { execute!(executor, isi); } - if tokens::parameter::CanSetParameters.is_owned_by(authority) { + if permissions::parameter::CanSetParameters.is_owned_by(authority) { execute!(executor, isi); } deny!( executor, - "Can't set configuration parameters without permission" + "Can't set executor configuration parameters without permission" ); } } pub mod role { use iroha_smart_contract::data_model::role::Role; - use role::tokens::AnyPermission; + use role::permissions::AnyPermission; use super::*; @@ -1242,7 +1205,7 @@ pub mod role { let token = $isi.object(); if let Ok(any_token) = AnyPermission::try_from(token) { - let token = Permission::from(any_token.clone()); + let token = PermissionObject::from(any_token.clone()); let isi = <$isi_type>::role_permission(token, role_id); if is_genesis($executor) { execute!($executor, isi); @@ -1280,7 +1243,7 @@ pub mod role { iroha_smart_contract::debug!(&format!("Checking `{token:?}`")); if let Ok(any_token) = AnyPermission::try_from(token) { - let token = Permission::from(any_token); + let token = PermissionObject::from(any_token); new_role = new_role.add_permission(token); continue; } @@ -1310,7 +1273,7 @@ pub mod role { if is_genesis(executor) { execute!(executor, isi); } - if tokens::role::CanUnregisterAnyRole.is_owned_by(authority) { + if permissions::role::CanUnregisterAnyRole.is_owned_by(authority) { execute!(executor, isi); } @@ -1336,28 +1299,29 @@ pub mod role { pub fn visit_grant_role_permission<V: Validate + Visit + ?Sized>( executor: &mut V, authority: &AccountId, - isi: &Grant<Permission, Role>, + isi: &Grant<PermissionObject, Role>, ) { - impl_validate_grant_revoke_role_permission!(executor, isi, authority, validate_grant, Grant<Permission, Role>); + impl_validate_grant_revoke_role_permission!(executor, isi, authority, validate_grant, Grant<PermissionObject, Role>); } pub fn visit_revoke_role_permission<V: Validate + Visit + ?Sized>( executor: &mut V, authority: &AccountId, - isi: &Revoke<Permission, Role>, + isi: &Revoke<PermissionObject, Role>, ) { - impl_validate_grant_revoke_role_permission!(executor, isi, authority, validate_revoke, Revoke<Permission, Role>); + impl_validate_grant_revoke_role_permission!(executor, isi, authority, validate_revoke, Revoke<PermissionObject, Role>); } } pub mod trigger { - use iroha_executor::permission::trigger::find_trigger; - use iroha_smart_contract::data_model::{permission::Permission, trigger::Trigger}; - use tokens::AnyPermission; + use iroha_smart_contract::data_model::trigger::Trigger; use super::*; use crate::permission::{ - accounts_permissions, domain::is_domain_owner, roles_permissions, trigger::is_trigger_owner, + accounts_permissions, + domain::is_domain_owner, + roles_permissions, + trigger::{find_trigger, is_trigger_owner}, }; pub fn visit_register_trigger<V: Validate + Visit + ?Sized>( @@ -1375,9 +1339,10 @@ pub mod trigger { } } || { - let can_register_user_trigger_token = tokens::trigger::CanRegisterUserTrigger { - account_id: isi.object().action().authority().clone(), - }; + let can_register_user_trigger_token = + permissions::trigger::CanRegisterUserTrigger { + account_id: isi.object().action().authority().clone(), + }; can_register_user_trigger_token.is_owned_by(authority) } { @@ -1399,13 +1364,14 @@ pub mod trigger { Ok(is_trigger_owner) => is_trigger_owner, } || { - let can_unregister_user_trigger_token = tokens::trigger::CanUnregisterUserTrigger { - account_id: find_trigger(trigger_id) - .unwrap() - .action() - .authority() - .clone(), - }; + let can_unregister_user_trigger_token = + permissions::trigger::CanUnregisterUserTrigger { + account_id: find_trigger(trigger_id) + .unwrap() + .action() + .authority() + .clone(), + }; can_unregister_user_trigger_token.is_owned_by(authority) } { @@ -1448,7 +1414,7 @@ pub mod trigger { Ok(true) => execute!(executor, isi), Ok(false) => {} } - let can_mint_user_trigger_token = tokens::trigger::CanMintUserTrigger { + let can_mint_user_trigger_token = permissions::trigger::CanMintUserTrigger { trigger_id: trigger_id.clone(), }; if can_mint_user_trigger_token.is_owned_by(authority) { @@ -1476,7 +1442,7 @@ pub mod trigger { Ok(true) => execute!(executor, isi), Ok(false) => {} } - let can_mint_user_trigger_token = tokens::trigger::CanBurnUserTrigger { + let can_mint_user_trigger_token = permissions::trigger::CanBurnUserTrigger { trigger_id: trigger_id.clone(), }; if can_mint_user_trigger_token.is_owned_by(authority) { @@ -1504,7 +1470,7 @@ pub mod trigger { Ok(true) => execute!(executor, isi), Ok(false) => {} } - let can_execute_trigger_token = tokens::trigger::CanExecuteUserTrigger { + let can_execute_trigger_token = permissions::trigger::CanExecuteUserTrigger { trigger_id: trigger_id.clone(), }; if can_execute_trigger_token.is_owned_by(authority) { @@ -1529,9 +1495,10 @@ pub mod trigger { Ok(true) => execute!(executor, isi), Ok(false) => {} } - let can_set_key_value_in_user_trigger_token = tokens::trigger::CanSetKeyValueInTrigger { - trigger_id: trigger_id.clone(), - }; + let can_set_key_value_in_user_trigger_token = + permissions::trigger::CanSetKeyValueInTrigger { + trigger_id: trigger_id.clone(), + }; if can_set_key_value_in_user_trigger_token.is_owned_by(authority) { execute!(executor, isi); } @@ -1557,9 +1524,10 @@ pub mod trigger { Ok(true) => execute!(executor, isi), Ok(false) => {} } - let can_remove_key_value_in_trigger_token = tokens::trigger::CanRemoveKeyValueInTrigger { - trigger_id: trigger_id.clone(), - }; + let can_remove_key_value_in_trigger_token = + permissions::trigger::CanRemoveKeyValueInTrigger { + trigger_id: trigger_id.clone(), + }; if can_remove_key_value_in_trigger_token.is_owned_by(authority) { execute!(executor, isi); } @@ -1570,7 +1538,7 @@ pub mod trigger { ); } - fn is_token_trigger_associated(permission: &Permission, trigger_id: &TriggerId) -> bool { + fn is_token_trigger_associated(permission: &PermissionObject, trigger_id: &TriggerId) -> bool { let Ok(permission) = AnyPermission::try_from(permission) else { return false; }; @@ -1627,8 +1595,6 @@ pub mod trigger { } pub mod permission { - use tokens::AnyPermission; - use super::*; macro_rules! impl_validate { @@ -1637,7 +1603,7 @@ pub mod permission { let token = $isi.object(); if let Ok(any_token) = AnyPermission::try_from(token) { - let token = Permission::from(any_token.clone()); + let token = PermissionObject::from(any_token.clone()); let isi = <$isi_type>::permission(token, account_id); if is_genesis($executor) { execute!($executor, isi); @@ -1663,28 +1629,28 @@ pub mod permission { pub fn visit_grant_account_permission<V: Validate + Visit + ?Sized>( executor: &mut V, authority: &AccountId, - isi: &Grant<Permission, Account>, + isi: &Grant<PermissionObject, Account>, ) { impl_validate!( executor, authority, isi, validate_grant, - Grant<Permission, Account> + Grant<PermissionObject, Account> ); } pub fn visit_revoke_account_permission<V: Validate + Visit + ?Sized>( executor: &mut V, authority: &AccountId, - isi: &Revoke<Permission, Account>, + isi: &Revoke<PermissionObject, Account>, ) { impl_validate!( executor, authority, isi, validate_revoke, - Revoke<Permission, Account> + Revoke<PermissionObject, Account> ); } } @@ -1701,7 +1667,7 @@ pub mod executor { if is_genesis(executor) { execute!(executor, isi); } - if tokens::executor::CanUpgradeExecutor.is_owned_by(authority) { + if permissions::executor::CanUpgradeExecutor.is_owned_by(authority) { execute!(executor, isi); } diff --git a/smart_contract/executor/src/default/tokens.rs b/smart_contract/executor/src/default/permissions.rs similarity index 77% rename from smart_contract/executor/src/default/tokens.rs rename to smart_contract/executor/src/default/permissions.rs index 283b48858ae..8406a9afe2c 100644 --- a/smart_contract/executor/src/default/tokens.rs +++ b/smart_contract/executor/src/default/permissions.rs @@ -6,7 +6,7 @@ use alloc::{borrow::ToOwned, format, string::String, vec::Vec}; use iroha_executor_derive::ValidateGrantRevoke; use iroha_smart_contract::data_model::{executor::Result, prelude::*}; -use crate::permission::{self, Token as _}; +use crate::permission::{self, Permission as _}; /// Declare token types of current module. Use it with a full path to the token. /// Used to iterate over tokens to validate `Grant` and `Revoke` instructions. @@ -27,9 +27,9 @@ use crate::permission::{self, Token as _}; /// pub struct MyToken; /// } /// ``` -macro_rules! declare_tokens { +macro_rules! declare_permissions { ($($($token_path:ident ::)+ { $token_ty:ident }),+ $(,)?) => { - macro_rules! map_token_type { + macro_rules! map_default_permissions { ($callback:ident) => { $( $callback!($($token_path::)+$token_ty); )+ }; @@ -43,15 +43,15 @@ macro_rules! declare_tokens { } impl TryFrom<&$crate::data_model::permission::Permission> for AnyPermission { - type Error = $crate::permission::PermissionConversionError; + type Error = $crate::TryFromDataModelObjectError; fn try_from(token: &$crate::data_model::permission::Permission) -> Result<Self, Self::Error> { - match token.definition_id().as_ref() { $( + match token.id().name().as_ref() { $( stringify!($token_ty) => { - let token = <$($token_path::)+$token_ty>::try_from(token)?; + let token = <$($token_path::)+$token_ty>::try_from_object(token)?; Ok(Self::$token_ty(token)) } )+ - _ => Err(Self::Error::Id(token.definition_id().clone())) + _ => Err(Self::Error::Id(token.id().name().clone())) } } } @@ -59,7 +59,7 @@ macro_rules! declare_tokens { impl From<AnyPermission> for $crate::data_model::permission::Permission { fn from(token: AnyPermission) -> Self { match token { $( - AnyPermission::$token_ty(token) => Self::from(token), )* + AnyPermission::$token_ty(token) => token.to_object(), )* } } } @@ -78,76 +78,76 @@ macro_rules! declare_tokens { } } - pub(crate) use map_token_type; + pub(crate) use map_default_permissions; }; } -macro_rules! token { +macro_rules! permission { ($($meta:meta)* $item:item) => { #[derive(PartialEq, Eq, serde::Serialize, serde::Deserialize)] - #[derive(Clone, iroha_executor_derive::Token)] + #[derive(Clone, iroha_executor_derive::Permission)] #[derive(iroha_schema::IntoSchema)] $($meta)* $item }; } -declare_tokens! { - crate::default::tokens::peer::{CanUnregisterAnyPeer}, - - crate::default::tokens::domain::{CanUnregisterDomain}, - crate::default::tokens::domain::{CanSetKeyValueInDomain}, - crate::default::tokens::domain::{CanRemoveKeyValueInDomain}, - crate::default::tokens::domain::{CanRegisterAccountInDomain}, - crate::default::tokens::domain::{CanRegisterAssetDefinitionInDomain}, - - crate::default::tokens::account::{CanUnregisterAccount}, - crate::default::tokens::account::{CanMintUserPublicKeys}, - crate::default::tokens::account::{CanBurnUserPublicKeys}, - crate::default::tokens::account::{CanMintUserSignatureCheckConditions}, - crate::default::tokens::account::{CanSetKeyValueInAccount}, - crate::default::tokens::account::{CanRemoveKeyValueInAccount}, - - crate::default::tokens::asset_definition::{CanUnregisterAssetDefinition}, - crate::default::tokens::asset_definition::{CanSetKeyValueInAssetDefinition}, - crate::default::tokens::asset_definition::{CanRemoveKeyValueInAssetDefinition}, - - crate::default::tokens::asset::{CanRegisterAssetWithDefinition}, - crate::default::tokens::asset::{CanUnregisterAssetWithDefinition}, - crate::default::tokens::asset::{CanUnregisterUserAsset}, - crate::default::tokens::asset::{CanBurnAssetWithDefinition}, - crate::default::tokens::asset::{CanMintAssetWithDefinition}, - crate::default::tokens::asset::{CanMintUserAsset}, - crate::default::tokens::asset::{CanBurnUserAsset}, - crate::default::tokens::asset::{CanTransferAssetWithDefinition}, - crate::default::tokens::asset::{CanTransferUserAsset}, - crate::default::tokens::asset::{CanSetKeyValueInUserAsset}, - crate::default::tokens::asset::{CanRemoveKeyValueInUserAsset}, - - crate::default::tokens::parameter::{CanGrantPermissionToCreateParameters}, - crate::default::tokens::parameter::{CanRevokePermissionToCreateParameters}, - crate::default::tokens::parameter::{CanCreateParameters}, - crate::default::tokens::parameter::{CanGrantPermissionToSetParameters}, - crate::default::tokens::parameter::{CanRevokePermissionToSetParameters}, - crate::default::tokens::parameter::{CanSetParameters}, - - crate::default::tokens::role::{CanUnregisterAnyRole}, - - crate::default::tokens::trigger::{CanRegisterUserTrigger}, - crate::default::tokens::trigger::{CanExecuteUserTrigger}, - crate::default::tokens::trigger::{CanUnregisterUserTrigger}, - crate::default::tokens::trigger::{CanMintUserTrigger}, - crate::default::tokens::trigger::{CanBurnUserTrigger}, - crate::default::tokens::trigger::{CanSetKeyValueInTrigger}, - crate::default::tokens::trigger::{CanRemoveKeyValueInTrigger}, - - crate::default::tokens::executor::{CanUpgradeExecutor}, +declare_permissions! { + crate::default::permissions::peer::{CanUnregisterAnyPeer}, + + crate::default::permissions::domain::{CanUnregisterDomain}, + crate::default::permissions::domain::{CanSetKeyValueInDomain}, + crate::default::permissions::domain::{CanRemoveKeyValueInDomain}, + crate::default::permissions::domain::{CanRegisterAccountInDomain}, + crate::default::permissions::domain::{CanRegisterAssetDefinitionInDomain}, + + crate::default::permissions::account::{CanUnregisterAccount}, + crate::default::permissions::account::{CanMintUserPublicKeys}, + crate::default::permissions::account::{CanBurnUserPublicKeys}, + crate::default::permissions::account::{CanMintUserSignatureCheckConditions}, + crate::default::permissions::account::{CanSetKeyValueInAccount}, + crate::default::permissions::account::{CanRemoveKeyValueInAccount}, + + crate::default::permissions::asset_definition::{CanUnregisterAssetDefinition}, + crate::default::permissions::asset_definition::{CanSetKeyValueInAssetDefinition}, + crate::default::permissions::asset_definition::{CanRemoveKeyValueInAssetDefinition}, + + crate::default::permissions::asset::{CanRegisterAssetWithDefinition}, + crate::default::permissions::asset::{CanUnregisterAssetWithDefinition}, + crate::default::permissions::asset::{CanUnregisterUserAsset}, + crate::default::permissions::asset::{CanBurnAssetWithDefinition}, + crate::default::permissions::asset::{CanMintAssetWithDefinition}, + crate::default::permissions::asset::{CanMintUserAsset}, + crate::default::permissions::asset::{CanBurnUserAsset}, + crate::default::permissions::asset::{CanTransferAssetWithDefinition}, + crate::default::permissions::asset::{CanTransferUserAsset}, + crate::default::permissions::asset::{CanSetKeyValueInUserAsset}, + crate::default::permissions::asset::{CanRemoveKeyValueInUserAsset}, + + crate::default::permissions::parameter::{CanGrantPermissionToCreateParameters}, + crate::default::permissions::parameter::{CanRevokePermissionToCreateParameters}, + crate::default::permissions::parameter::{CanCreateParameters}, + crate::default::permissions::parameter::{CanGrantPermissionToSetParameters}, + crate::default::permissions::parameter::{CanRevokePermissionToSetParameters}, + crate::default::permissions::parameter::{CanSetParameters}, + + crate::default::permissions::role::{CanUnregisterAnyRole}, + + crate::default::permissions::trigger::{CanRegisterUserTrigger}, + crate::default::permissions::trigger::{CanExecuteUserTrigger}, + crate::default::permissions::trigger::{CanUnregisterUserTrigger}, + crate::default::permissions::trigger::{CanMintUserTrigger}, + crate::default::permissions::trigger::{CanBurnUserTrigger}, + crate::default::permissions::trigger::{CanSetKeyValueInTrigger}, + crate::default::permissions::trigger::{CanRemoveKeyValueInTrigger}, + + crate::default::permissions::executor::{CanUpgradeExecutor}, } pub mod peer { use super::*; - token! { + permission! { #[derive(Copy, ValidateGrantRevoke)] #[validate(permission::OnlyGenesis)] pub struct CanUnregisterAnyPeer; @@ -157,7 +157,7 @@ pub mod peer { pub mod domain { use super::*; - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::domain::Owner)] #[validate(permission::domain::Owner)] pub struct CanUnregisterDomain { @@ -165,7 +165,7 @@ pub mod domain { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::domain::Owner)] #[validate(permission::domain::Owner)] pub struct CanSetKeyValueInDomain { @@ -173,7 +173,7 @@ pub mod domain { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::domain::Owner)] #[validate(permission::domain::Owner)] pub struct CanRemoveKeyValueInDomain { @@ -181,7 +181,7 @@ pub mod domain { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::domain::Owner)] #[validate(permission::domain::Owner)] pub struct CanRegisterAccountInDomain { @@ -189,7 +189,7 @@ pub mod domain { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::domain::Owner)] #[validate(permission::domain::Owner)] pub struct CanRegisterAssetDefinitionInDomain { @@ -201,42 +201,42 @@ pub mod domain { pub mod account { use super::*; - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::account::Owner)] #[validate(permission::account::Owner)] pub struct CanUnregisterAccount { pub account_id: AccountId, } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::account::Owner)] #[validate(permission::account::Owner)] pub struct CanMintUserPublicKeys { pub account_id: AccountId, } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::account::Owner)] #[validate(permission::account::Owner)] pub struct CanBurnUserPublicKeys { pub account_id: AccountId, } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::account::Owner)] #[validate(permission::account::Owner)] pub struct CanMintUserSignatureCheckConditions { pub account_id: AccountId, } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::account::Owner)] #[validate(permission::account::Owner)] pub struct CanSetKeyValueInAccount { pub account_id: AccountId, } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::account::Owner)] #[validate(permission::account::Owner)] pub struct CanRemoveKeyValueInAccount { @@ -248,7 +248,7 @@ pub mod account { pub mod asset_definition { use super::*; - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset_definition::Owner)] #[validate(permission::asset_definition::Owner)] pub struct CanUnregisterAssetDefinition { @@ -256,7 +256,7 @@ pub mod asset_definition { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset_definition::Owner)] #[validate(permission::asset_definition::Owner)] pub struct CanSetKeyValueInAssetDefinition { @@ -264,7 +264,7 @@ pub mod asset_definition { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset_definition::Owner)] #[validate(permission::asset_definition::Owner)] pub struct CanRemoveKeyValueInAssetDefinition { @@ -276,7 +276,7 @@ pub mod asset_definition { pub mod asset { use super::*; - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset_definition::Owner)] #[validate(permission::asset_definition::Owner)] pub struct CanRegisterAssetWithDefinition { @@ -284,7 +284,7 @@ pub mod asset { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset_definition::Owner)] #[validate(permission::asset_definition::Owner)] pub struct CanUnregisterAssetWithDefinition { @@ -292,7 +292,7 @@ pub mod asset { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset::Owner)] #[validate(permission::asset::Owner)] pub struct CanUnregisterUserAsset { @@ -300,7 +300,7 @@ pub mod asset { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset_definition::Owner)] #[validate(permission::asset_definition::Owner)] pub struct CanBurnAssetWithDefinition { @@ -308,7 +308,7 @@ pub mod asset { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset::Owner)] #[validate(permission::asset::Owner)] pub struct CanBurnUserAsset { @@ -316,7 +316,7 @@ pub mod asset { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset_definition::Owner)] #[validate(permission::asset_definition::Owner)] pub struct CanMintAssetWithDefinition { @@ -324,7 +324,7 @@ pub mod asset { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset::Owner)] #[validate(permission::asset::Owner)] pub struct CanMintUserAsset { @@ -332,7 +332,7 @@ pub mod asset { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset_definition::Owner)] #[validate(permission::asset_definition::Owner)] pub struct CanTransferAssetWithDefinition { @@ -340,7 +340,7 @@ pub mod asset { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset::Owner)] #[validate(permission::asset::Owner)] pub struct CanTransferUserAsset { @@ -348,7 +348,7 @@ pub mod asset { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset::Owner)] #[validate(permission::asset::Owner)] pub struct CanSetKeyValueInUserAsset { @@ -356,7 +356,7 @@ pub mod asset { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::asset::Owner)] #[validate(permission::asset::Owner)] pub struct CanRemoveKeyValueInUserAsset { @@ -370,36 +370,36 @@ pub mod parameter { use super::*; - token! { + permission! { #[derive(Copy, ValidateGrantRevoke)] #[validate(permission::OnlyGenesis)] pub struct CanGrantPermissionToCreateParameters; } - token! { + permission! { #[derive(Copy, ValidateGrantRevoke)] #[validate(permission::OnlyGenesis)] pub struct CanRevokePermissionToCreateParameters; } - token! { + permission! { #[derive(Copy)] pub struct CanCreateParameters; } - token! { + permission! { #[derive(Copy, ValidateGrantRevoke)] #[validate(permission::OnlyGenesis)] pub struct CanGrantPermissionToSetParameters; } - token! { + permission! { #[derive(Copy, ValidateGrantRevoke)] #[validate(permission::OnlyGenesis)] pub struct CanRevokePermissionToSetParameters; } - token! { + permission! { #[derive(Copy)] pub struct CanSetParameters; } @@ -456,7 +456,7 @@ pub mod parameter { pub mod role { use super::*; - token! { + permission! { #[derive(Copy, ValidateGrantRevoke)] #[validate(permission::OnlyGenesis)] pub struct CanUnregisterAnyRole; @@ -478,7 +478,7 @@ pub mod trigger { )+}; } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::account::Owner)] #[validate(permission::account::Owner)] pub struct CanRegisterUserTrigger { @@ -486,7 +486,7 @@ pub mod trigger { } } - token! { + permission! { #[derive(ValidateGrantRevoke)] #[validate(permission::trigger::Owner)] pub struct CanExecuteUserTrigger { @@ -494,7 +494,7 @@ pub mod trigger { } } - token! { + permission! { #[derive(ValidateGrantRevoke, permission::derive_conversions::account::Owner)] #[validate(permission::account::Owner)] pub struct CanUnregisterUserTrigger { @@ -502,7 +502,7 @@ pub mod trigger { } } - token! { + permission! { #[derive(ValidateGrantRevoke)] #[validate(permission::trigger::Owner)] pub struct CanMintUserTrigger { @@ -510,7 +510,7 @@ pub mod trigger { } } - token! { + permission! { #[derive(ValidateGrantRevoke)] #[validate(permission::trigger::Owner)] pub struct CanBurnUserTrigger { @@ -518,7 +518,7 @@ pub mod trigger { } } - token! { + permission! { #[derive(ValidateGrantRevoke)] #[validate(permission::trigger::Owner)] pub struct CanSetKeyValueInTrigger { @@ -526,7 +526,7 @@ pub mod trigger { } } - token! { + permission! { #[derive(ValidateGrantRevoke)] #[validate(permission::trigger::Owner)] pub struct CanRemoveKeyValueInTrigger { @@ -546,7 +546,7 @@ pub mod trigger { pub mod executor { use super::*; - token! { + permission! { #[derive(Copy, ValidateGrantRevoke)] #[validate(permission::OnlyGenesis)] pub struct CanUpgradeExecutor; diff --git a/smart_contract/executor/src/lib.rs b/smart_contract/executor/src/lib.rs index 1e26b7b5c9e..fac1d112b8f 100644 --- a/smart_contract/executor/src/lib.rs +++ b/smart_contract/executor/src/lib.rs @@ -5,9 +5,9 @@ extern crate alloc; extern crate self as iroha_executor; -use alloc::vec::Vec; +use alloc::collections::BTreeSet; -use data_model::{executor::Result, permission::PermissionId, ValidationFail}; +use data_model::{executor::Result, ValidationFail}; #[cfg(not(test))] use data_model::{prelude::*, smart_contract::payloads}; pub use iroha_schema::MetaMap; @@ -18,6 +18,7 @@ use iroha_smart_contract_utils::{decode_with_length_prefix_from_raw, encode_and_ pub use smart_contract::{data_model, parse, stub_getrandom}; pub mod default; +pub mod parameter; pub mod permission; pub mod utils { @@ -78,7 +79,11 @@ pub fn get_migrate_payload() -> payloads::Migrate { unsafe { decode_with_length_prefix_from_raw(host::get_migrate_payload()) } } -/// Set new [`PermissionSchema`]. +// pub trait IntoDataModel { +// fn into_data_model(&self) -> &ExecutorDataModel; +// } + +/// Set new [`ExecutorDataModel`]. /// /// # Errors /// @@ -89,9 +94,9 @@ pub fn get_migrate_payload() -> payloads::Migrate { /// Host side will generate a trap if this function was not called from a /// executor's `migrate()` entrypoint. #[cfg(not(test))] -pub fn set_permission_schema(schema: &data_model::permission::PermissionSchema) { +pub fn set_data_model(data_model: &ExecutorDataModel) { // Safety: - ownership of the returned result is transferred into `_decode_from_raw` - unsafe { encode_and_execute(&schema, host::set_permission_schema) } + unsafe { encode_and_execute(&data_model, host::set_data_model) } } #[cfg(not(test))] @@ -126,8 +131,8 @@ mod host { /// This function does transfer ownership of the result to the caller pub(super) fn get_migrate_payload() -> *const u8; - /// Set new [`PermissionSchema`]. - pub(super) fn set_permission_schema(ptr: *const u8, len: usize); + /// Set new [`ExecutorDataModel`]. + pub(super) fn set_data_model(ptr: *const u8, len: usize); } } @@ -172,35 +177,96 @@ macro_rules! deny { }}; } -/// Collection of all permission tokens defined by the executor -#[derive(Debug, Clone, Default)] -pub struct PermissionSchema(Vec<PermissionId>, MetaMap); +/// An error that might occur while converting a data model object (with id and payload) +/// into a native executor type. +/// +/// Such objects are [`data_model::prelude::Permission`] and [`data_model::prelude::Parameter`]. +#[derive(Debug)] +pub enum TryFromDataModelObjectError { + /// Unexpected object id + Id(data_model::prelude::Name), + /// Failed to deserialize object payload + Deserialize(serde_json::Error), +} + +/// A convenience to build [`ExecutorDataModel`] from within the executor +#[derive(Debug, Clone)] +pub struct DataModelBuilder { + schema: MetaMap, + permissions: BTreeSet<prelude::PermissionId>, + parameters: BTreeSet<prelude::ParameterId>, +} + +impl DataModelBuilder { + /// Constructor + // we don't need to confuse with `with_default_permissions` + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Self { + schema: <_>::default(), + permissions: <_>::default(), + parameters: <_>::default(), + } + } -impl PermissionSchema { - /// Remove permission token from this collection - pub fn remove<T: permission::Token>(&mut self) { - let to_remove = <T as permission::Token>::name(); + /// Creates a data model with default permissions preset (defined in [`default::permissions`]) + #[must_use] + pub fn with_default_permissions() -> Self { + let mut builder = Self::new(); - if let Some(pos) = self.0.iter().position(|token_id| *token_id == to_remove) { - self.0.remove(pos); - <T as iroha_schema::IntoSchema>::remove_from_schema(&mut self.1); + macro_rules! add_to_schema { + ($token_ty:ty) => { + builder = builder.add_permission::<$token_ty>(); + }; } + + default::permissions::map_default_permissions!(add_to_schema); + + builder + } + + /// Define a permission in the data model + #[must_use] + pub fn add_permission<T: permission::Permission>(mut self) -> Self { + <T as iroha_schema::IntoSchema>::update_schema_map(&mut self.schema); + self.permissions.insert(<T as permission::Permission>::id()); + self } - /// Insert new permission token into this collection - pub fn insert<T: permission::Token>(&mut self) { - <T as iroha_schema::IntoSchema>::update_schema_map(&mut self.1); - self.0.push(<T as permission::Token>::name()); + /// Remove a permission from the data model + #[must_use] + pub fn remove_permission<T: permission::Permission>(mut self) -> Self { + <T as iroha_schema::IntoSchema>::remove_from_schema(&mut self.schema); + self.permissions + .remove(&<T as permission::Permission>::id()); + self } - /// Serializes schema into a JSON string representation - pub fn serialize(mut self) -> (Vec<PermissionId>, alloc::string::String) { - self.0.sort(); + /// Define a configuration parameter in the data model + #[must_use] + pub fn add_parameter<T: parameter::Parameter>(mut self) -> Self { + <T as iroha_schema::IntoSchema>::update_schema_map(&mut self.schema); + self.parameters.insert(<T as parameter::Parameter>::id()); + self + } + + /// Remove a configuration parameter from the data model + #[must_use] + pub fn remove_parameter<T: parameter::Parameter>(mut self) -> Self { + <T as iroha_schema::IntoSchema>::remove_from_schema(&mut self.schema); + self.parameters.remove(&<T as parameter::Parameter>::id()); + self + } - ( - self.0, - serde_json::to_string(&self.1).expect("schema serialization must not fail"), - ) + /// Set the data model of the executor via [`set_data_model`] + #[cfg(not(test))] + pub fn set(self) { + set_data_model(&ExecutorDataModel::new( + self.permissions, + self.parameters, + data_model::JsonString::serialize(&self.schema) + .expect("schema serialization must not fail"), + )) } } @@ -222,9 +288,12 @@ pub mod prelude { pub use alloc::vec::Vec; pub use iroha_executor_derive::{ - entrypoint, Constructor, Token, Validate, ValidateEntrypoints, ValidateGrantRevoke, Visit, + entrypoint, Constructor, Permission, Validate, ValidateEntrypoints, ValidateGrantRevoke, + Visit, + }; + pub use iroha_smart_contract::prelude::{ + Parameter as ParameterObject, Permission as PermissionObject, *, }; - pub use iroha_smart_contract::prelude::*; pub use super::{ data_model::{ @@ -232,6 +301,9 @@ pub mod prelude { visit::Visit, ValidationFail, }, - deny, execute, PermissionSchema, Validate, + deny, execute, + parameter::Parameter, + permission::Permission, + DataModelBuilder, Validate, }; } diff --git a/smart_contract/executor/src/parameter.rs b/smart_contract/executor/src/parameter.rs new file mode 100644 index 00000000000..805868de2a0 --- /dev/null +++ b/smart_contract/executor/src/parameter.rs @@ -0,0 +1,59 @@ +//! Executor-defined configuration parameters + +use iroha_executor::prelude::{ParameterId, ParameterObject}; +use iroha_schema::IntoSchema; +use iroha_smart_contract_utils::debug::DebugExpectExt; +use serde::{de::DeserializeOwned, Serialize}; + +use crate::{data_model::JsonString, TryFromDataModelObjectError}; + +/// Marker trait for parameters. +/// +/// A parameter could be defined in the following way: +/// +/// ``` +/// use iroha_executor::parameter::Parameter; +/// use iroha_schema::IntoSchema; +/// use serde::{Deserialize, Serialize}; +/// +/// #[derive(IntoSchema, Serialize, Deserialize)] +/// struct DomainPrefix { +/// prefix: String, +/// } +/// +/// impl Parameter for DomainPrefix {} +/// ``` +pub trait Parameter: Serialize + DeserializeOwned + IntoSchema { + /// Parameter id, according to [`IntoSchema`]. + fn id() -> ParameterId { + ParameterId::new( + <Self as iroha_schema::IntoSchema>::type_name() + .parse() + .dbg_expect("Failed to parse parameter id as `Name`"), + ) + } + + /// Try to convert from [`ParameterObject`] + /// # Errors + /// See [`TryFromDataModelObjectError`] + fn try_from_object( + object: &ParameterObject, + ) -> crate::prelude::Result<Self, TryFromDataModelObjectError> { + if *object.id() != <Self as Parameter>::id() { + return Err(TryFromDataModelObjectError::Id(object.id().name().clone())); + } + object + .payload() + .deserialize() + .map_err(TryFromDataModelObjectError::Deserialize) + } + + /// Convert into [`ParameterObject`] + fn to_object(&self) -> ParameterObject { + ParameterObject::new( + <Self as Parameter>::id(), + JsonString::serialize(&self) + .expect("failed to serialize concrete data model entity; this is a bug"), + ) + } +} diff --git a/smart_contract/executor/src/permission.rs b/smart_contract/executor/src/permission.rs index 67f2f6a689a..313fe38dd48 100644 --- a/smart_contract/executor/src/permission.rs +++ b/smart_contract/executor/src/permission.rs @@ -3,27 +3,49 @@ use alloc::borrow::ToOwned as _; use iroha_schema::IntoSchema; -use iroha_smart_contract::{data_model::permission::Permission, QueryOutputCursor}; +use iroha_smart_contract::{data_model::JsonString, QueryOutputCursor}; use iroha_smart_contract_utils::debug::DebugExpectExt as _; use serde::{de::DeserializeOwned, Serialize}; -use crate::{data_model::prelude::*, prelude::*}; +use crate::{prelude::*, TryFromDataModelObjectError}; -/// [`Token`] trait is used to check if the token is owned by the account. -pub trait Token: +/// Is used to check if the permission token is owned by the account. +pub trait Permission: Serialize + DeserializeOwned + IntoSchema + PartialEq<Self> + ValidateGrantRevoke -where - for<'a> Self: TryFrom<&'a Permission, Error = PermissionConversionError>, { - /// Return name of this permission token - fn name() -> Name { - <Self as iroha_schema::IntoSchema>::type_name() - .parse() - .dbg_expect("Failed to parse permission token as `Name`") + /// Check if the account owns this token + fn is_owned_by(&self, account_id: &AccountId) -> bool; + + /// Permission id, according to [`IntoSchema`]. + fn id() -> PermissionId { + PermissionId::new( + <Self as iroha_schema::IntoSchema>::type_name() + .parse() + .dbg_expect("Failed to parse permission id as `Name`"), + ) } - /// Check if token is owned by the account - fn is_owned_by(&self, account_id: &AccountId) -> bool; + /// Try to convert from [`PermissionObject`] + /// # Errors + /// See [`TryFromDataModelObjectError`] + fn try_from_object(object: &PermissionObject) -> Result<Self, TryFromDataModelObjectError> { + if *object.id() != <Self as Permission>::id() { + return Err(TryFromDataModelObjectError::Id(object.id().name().clone())); + } + object + .payload() + .deserialize() + .map_err(TryFromDataModelObjectError::Deserialize) + } + + /// Convert into [`PermissionObject`] + fn to_object(&self) -> PermissionObject { + PermissionObject::new( + <Self as Permission>::id(), + JsonString::serialize(&self) + .expect("failed to serialize concrete data model entity; this is a bug"), + ) + } } /// Trait that should be implemented for all permission tokens. @@ -43,15 +65,6 @@ pub trait PassCondition { fn validate(&self, authority: &AccountId, block_height: u64) -> Result; } -/// Error type for `TryFrom<Permission>` implementations. -#[derive(Debug)] -pub enum PermissionConversionError { - /// Unexpected token id. - Id(PermissionId), - /// Failed to deserialize JSON - Deserialize(serde_json::Error), -} - pub mod derive_conversions { //! Module with derive macros to generate conversion from custom strongly-typed token //! to some pass condition to successfully derive [`ValidateGrantRevoke`](iroha_executor_derive::ValidateGrantRevoke) @@ -307,7 +320,7 @@ impl PassCondition for AlwaysPass { } } -impl<T: Token> From<&T> for AlwaysPass { +impl<T: Permission> From<&T> for AlwaysPass { fn from(_: &T) -> Self { Self } @@ -331,14 +344,14 @@ impl PassCondition for OnlyGenesis { } } -impl<T: Token> From<&T> for OnlyGenesis { +impl<T: Permission> From<&T> for OnlyGenesis { fn from(_: &T) -> Self { Self } } /// Iterator over all accounts and theirs permission tokens -pub(crate) fn accounts_permissions() -> impl Iterator<Item = (AccountId, Permission)> { +pub(crate) fn accounts_permissions() -> impl Iterator<Item = (AccountId, PermissionObject)> { FindAllAccounts .execute() .dbg_expect("failed to query all accounts") @@ -355,7 +368,7 @@ pub(crate) fn accounts_permissions() -> impl Iterator<Item = (AccountId, Permiss } /// Iterator over all roles and theirs permission tokens -pub(crate) fn roles_permissions() -> impl Iterator<Item = (RoleId, Permission)> { +pub(crate) fn roles_permissions() -> impl Iterator<Item = (RoleId, PermissionObject)> { FindAllRoles .execute() .dbg_expect("failed to query all accounts") @@ -369,3 +382,32 @@ pub(crate) fn roles_permissions() -> impl Iterator<Item = (RoleId, Permission)> .map(move |token| (role.id().clone(), token)) }) } + +#[cfg(test)] +mod tests { + use alloc::{format, string::String}; + + use serde::Deserialize; + use serde_json::json; + + use super::*; + + #[test] + fn convert_token() { + #[derive( + Serialize, Deserialize, IntoSchema, PartialEq, ValidateGrantRevoke, Permission, + )] + #[validate(AlwaysPass)] + struct SampleToken { + can_do_whatever: bool, + } + + let object = PermissionObject::new( + "SampleToken".parse().unwrap(), + json!({ "can_do_whatever": false }), + ); + let parsed = SampleToken::try_from_object(&object).expect("valid"); + + assert!(!parsed.can_do_whatever); + } +} diff --git a/tools/kagami/Cargo.toml b/tools/kagami/Cargo.toml index 1f076c54b85..c35098ccb09 100644 --- a/tools/kagami/Cargo.toml +++ b/tools/kagami/Cargo.toml @@ -13,7 +13,7 @@ license.workspace = true workspace = true [dependencies] -iroha_crypto = { workspace = true } +iroha_crypto = { workspace = true, features = ["rand"] } iroha_config = { workspace = true } iroha_data_model = { workspace = true } iroha_schema_gen = { workspace = true } diff --git a/tools/kagami/src/genesis.rs b/tools/kagami/src/genesis.rs index 4f5b6203c66..da43396a715 100644 --- a/tools/kagami/src/genesis.rs +++ b/tools/kagami/src/genesis.rs @@ -1,11 +1,9 @@ use std::path::PathBuf; use clap::{Parser, Subcommand}; -use iroha_config::parameters::defaults::chain_wide as chain_wide_defaults; use iroha_data_model::{ asset::{AssetDefinitionId, AssetValueType}, metadata::Limits, - parameter::{default::*, ParametersBuilder}, prelude::AssetId, }; use iroha_genesis::{ @@ -142,62 +140,6 @@ pub fn generate_default( ) .into(); - let parameter_defaults = ParametersBuilder::new() - .add_parameter( - MAX_TRANSACTIONS_IN_BLOCK, - Numeric::new(chain_wide_defaults::MAX_TXS.get().into(), 0), - )? - .add_parameter( - BLOCK_TIME, - Numeric::new(chain_wide_defaults::BLOCK_TIME.as_millis(), 0), - )? - .add_parameter( - COMMIT_TIME_LIMIT, - Numeric::new(chain_wide_defaults::COMMIT_TIME.as_millis(), 0), - )? - .add_parameter(TRANSACTION_LIMITS, chain_wide_defaults::TRANSACTION_LIMITS)? - .add_parameter( - WSV_DOMAIN_METADATA_LIMITS, - chain_wide_defaults::METADATA_LIMITS, - )? - .add_parameter( - WSV_ASSET_DEFINITION_METADATA_LIMITS, - chain_wide_defaults::METADATA_LIMITS, - )? - .add_parameter( - WSV_ACCOUNT_METADATA_LIMITS, - chain_wide_defaults::METADATA_LIMITS, - )? - .add_parameter( - WSV_ASSET_METADATA_LIMITS, - chain_wide_defaults::METADATA_LIMITS, - )? - .add_parameter( - WSV_TRIGGER_METADATA_LIMITS, - chain_wide_defaults::METADATA_LIMITS, - )? - .add_parameter( - WSV_IDENT_LENGTH_LIMITS, - chain_wide_defaults::IDENT_LENGTH_LIMITS, - )? - .add_parameter( - EXECUTOR_FUEL_LIMIT, - Numeric::new(chain_wide_defaults::WASM_FUEL_LIMIT.into(), 0), - )? - .add_parameter( - EXECUTOR_MAX_MEMORY, - Numeric::new(chain_wide_defaults::WASM_MAX_MEMORY_BYTES.into(), 0), - )? - .add_parameter( - WASM_FUEL_LIMIT, - Numeric::new(chain_wide_defaults::WASM_FUEL_LIMIT.into(), 0), - )? - .add_parameter( - WASM_MAX_MEMORY, - Numeric::new(chain_wide_defaults::WASM_MAX_MEMORY_BYTES.into(), 0), - )? - .into_create_parameters(); - let first_tx = genesis .first_transaction_mut() .expect("At least one transaction is expected"); @@ -209,7 +151,6 @@ pub fn generate_default( grant_permission_to_set_parameters.into(), ] .into_iter() - .chain(parameter_defaults.into_iter()) .chain(std::iter::once(register_user_metadata_access)) { first_tx.append_instruction(isi); diff --git a/tools/parity_scale_cli/src/main.rs b/tools/parity_scale_cli/src/main.rs index 9d7f8457a4d..b47530cb08c 100644 --- a/tools/parity_scale_cli/src/main.rs +++ b/tools/parity_scale_cli/src/main.rs @@ -15,51 +15,7 @@ use std::{ use clap::Parser; use colored::*; use eyre::{eyre, Result}; -use iroha_crypto::*; -use iroha_data_model::{ - account::NewAccount, - asset::NewAssetDefinition, - block::{ - error::BlockRejectionReason, - stream::{BlockMessage, BlockSubscriptionRequest}, - BlockHeader, BlockPayload, SignedBlock, SignedBlockV1, - }, - domain::NewDomain, - events::pipeline::{BlockEventFilter, TransactionEventFilter}, - executor::Executor, - ipfs::IpfsPath, - isi::{ - error::{ - InstructionEvaluationError, InstructionExecutionError, InvalidParameterError, - MathError, MintabilityError, Mismatch, RepetitionError, TypeError, - }, - InstructionType, - }, - metadata::{MetadataError, MetadataValueBox, SizeError}, - parameter::ParameterValueBox, - permission::JsonString, - prelude::*, - query::{ - error::{FindError, QueryExecutionFail}, - predicate::{ - numerical::{SemiInterval, SemiRange}, - string::StringPredicate, - value::{AtIndex, Container, QueryOutputPredicate}, - GenericPredicateBox, NonTrivial, PredicateBox, - }, - ForwardCursor, Pagination, QueryOutputBox, Sorting, - }, - transaction::{ - error::TransactionLimitError, SignedTransactionV1, TransactionLimits, TransactionPayload, - }, - BatchedResponse, BatchedResponseV1, Level, -}; -use iroha_primitives::{ - addr::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrHost, SocketAddrV4, SocketAddrV6}, - const_vec::ConstVec, - conststr::ConstString, - unique_vec::UniqueVec, -}; +use iroha_schema_gen::complete_data_model::*; use parity_scale_codec::{DecodeAll, Encode}; use serde::{de::DeserializeOwned, Serialize}; From 79e49166f385927ab47e764a106365628c485f62 Mon Sep 17 00:00:00 2001 From: 0x009922 <43530070+0x009922@users.noreply.github.com> Date: Thu, 23 May 2024 19:09:44 +0900 Subject: [PATCH 2/4] test: expand messages Signed-off-by: 0x009922 <43530070+0x009922@users.noreply.github.com> --- .../executor_with_custom_parameter/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/tests/integration/smartcontracts/executor_with_custom_parameter/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_custom_parameter/src/lib.rs index 4f7a9f391d8..b1f607f50f8 100644 --- a/client/tests/integration/smartcontracts/executor_with_custom_parameter/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_custom_parameter/src/lib.rs @@ -30,12 +30,13 @@ fn visit_set_parameter(executor: &mut Executor, _authority: &AccountId, isi: &Se } fn visit_register_domain(executor: &mut Executor, _authority: &AccountId, isi: &Register<Domain>) { - // FIXME: unwrap is ok here? let required_prefix = FindAllParameters .execute() - .unwrap() + .expect("Iroha should not fail to provide parameters, it is a bug") .into_iter() - .map(Result::unwrap) + .map(|result| { + result.expect("each parameter retrieval should not fail as well, it is a bug") + }) .find_map(|parameter| EnforceDomainPrefix::try_from_object(¶meter).ok()); if let Some(EnforceDomainPrefix { prefix }) = required_prefix { From c1fe4aba9478f264dfe1ba9d4c1d215c30ee096b Mon Sep 17 00:00:00 2001 From: 0x009922 <43530070+0x009922@users.noreply.github.com> Date: Fri, 24 May 2024 17:31:51 +0900 Subject: [PATCH 3/4] refactor: apply suggestions from code review Signed-off-by: 0x009922 <43530070+0x009922@users.noreply.github.com> --- client/tests/integration/permissions.rs | 8 +++++++- .../executor_with_custom_permission/src/lib.rs | 9 +++------ client_cli/src/main.rs | 12 ++++++------ data_model/src/lib.rs | 7 +++++++ smart_contract/executor/derive/src/default.rs | 8 ++++---- smart_contract/executor/derive/src/entrypoint.rs | 3 +-- smart_contract/executor/src/default.rs | 5 ++++- smart_contract/executor/src/lib.rs | 12 +++--------- smart_contract/executor/src/parameter.rs | 11 ++++++----- smart_contract/executor/src/permission.rs | 5 ++++- 10 files changed, 45 insertions(+), 35 deletions(-) diff --git a/client/tests/integration/permissions.rs b/client/tests/integration/permissions.rs index 7aebf8f5e35..d2bc825b8c3 100644 --- a/client/tests/integration/permissions.rs +++ b/client/tests/integration/permissions.rs @@ -8,6 +8,7 @@ use iroha_client::{ }; use iroha_data_model::{ permission::Permission, role::RoleId, transaction::error::TransactionRejectionReason, + JsonString, }; use iroha_genesis::GenesisNetwork; use serde_json::json; @@ -317,7 +318,12 @@ fn stored_vs_granted_token_payload() -> Result<()> { let allow_alice_to_set_key_value_in_mouse_asset = Grant::permission( Permission::new( "CanSetKeyValueInUserAsset".parse().unwrap(), - json!({ "asset_id": format!("xor#wonderland#{mouse_id}") }), + JsonString::from_json_string_unchecked(format!( + // Introducing some whitespaces + // This way, if the executor compares just JSON strings, this test would fail + r##"{{ "asset_id" : "xor#wonderland#{}" }}"##, + mouse_id + )), ), alice_id, ); diff --git a/client/tests/integration/smartcontracts/executor_with_custom_permission/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_custom_permission/src/lib.rs index af0c6f04392..1fb8612595f 100644 --- a/client/tests/integration/smartcontracts/executor_with_custom_permission/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_custom_permission/src/lib.rs @@ -19,7 +19,7 @@ extern crate panic_halt; use alloc::string::String; use anyhow::anyhow; -use iroha_executor::{permission::Permission as _, prelude::*, DataModelBuilder}; +use iroha_executor::{prelude::*, DataModelBuilder}; use iroha_schema::IntoSchema; use lol_alloc::{FreeListAllocator, LockedAllocator}; use parity_scale_codec::{Decode, Encode}; @@ -118,7 +118,7 @@ impl Executor { .iter() .try_for_each(|(account, domain_id)| { Revoke::permission( - PermissionObject::new( + Permission::new( can_unregister_domain_definition_id.clone(), &json!({ "domain_id": domain_id }), ), @@ -137,10 +137,7 @@ impl Executor { })?; Grant::permission( - PermissionObject::new( - can_control_domain_lives_definition_id.clone(), - &json!(null), - ), + Permission::new(can_control_domain_lives_definition_id.clone(), &json!(null)), account.id().clone(), ) .execute() diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index 6e93284efc9..d2753792d2e 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -522,7 +522,7 @@ mod account { use iroha_client::client::{self}; - use super::{Permission as PermissionObject, *}; + use super::*; /// subcommands for account subcommand #[derive(clap::Subcommand, Debug)] @@ -603,22 +603,22 @@ mod account { pub id: AccountId, /// The JSON/JSON5 file with a permission token #[arg(short, long)] - pub permission: Permission, + pub permission: PermissionWrap, #[command(flatten)] pub metadata: MetadataArgs, } - /// [`PermissionObject`] wrapper implementing [`FromStr`] + /// [`Permission`] wrapper implementing [`FromStr`] #[derive(Debug, Clone)] - pub struct Permission(PermissionObject); + pub struct PermissionWrap(Permission); - impl FromStr for Permission { + impl FromStr for PermissionWrap { type Err = Error; fn from_str(s: &str) -> Result<Self> { let content = fs::read_to_string(s) .wrap_err(format!("Failed to read the permission token file {}", &s))?; - let permission: PermissionObject = json5::from_str(&content).wrap_err(format!( + let permission: Permission = json5::from_str(&content).wrap_err(format!( "Failed to deserialize the permission token from file {}", &s ))?; diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 7a376b3be6a..0e763c42dd2 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -626,6 +626,13 @@ impl JsonString { // so it should be a valid JSON string Ok(Self(serialized)) } + + /// Create without checking whether the input is a valid JSON string. + /// + /// The caller must guarantee that the value is valid. + pub fn from_json_string_unchecked(value: String) -> Self { + Self(value) + } } impl From<&serde_json::Value> for JsonString { diff --git a/smart_contract/executor/derive/src/default.rs b/smart_contract/executor/derive/src/default.rs index 492fe0787f2..d85b25c720a 100644 --- a/smart_contract/executor/derive/src/default.rs +++ b/smart_contract/executor/derive/src/default.rs @@ -142,14 +142,14 @@ pub fn impl_derive_visit(emitter: &mut Emitter, input: &syn::DeriveInput) -> Tok "fn visit_transfer_asset_definition(operation: &Transfer<Account, AssetDefinitionId, Account>)", "fn visit_set_asset_definition_key_value(operation: &SetKeyValue<AssetDefinition>)", "fn visit_remove_asset_definition_key_value(operation: &RemoveKeyValue<AssetDefinition>)", - "fn visit_grant_account_permission(operation: &Grant<PermissionObject, Account>)", - "fn visit_revoke_account_permission(operation: &Revoke<PermissionObject, Account>)", + "fn visit_grant_account_permission(operation: &Grant<Permission, Account>)", + "fn visit_revoke_account_permission(operation: &Revoke<Permission, Account>)", "fn visit_register_role(operation: &Register<Role>)", "fn visit_unregister_role(operation: &Unregister<Role>)", "fn visit_grant_account_role(operation: &Grant<RoleId, Account>)", "fn visit_revoke_account_role(operation: &Revoke<RoleId, Account>)", - "fn visit_grant_role_permission(operation: &Grant<PermissionObject, Role>)", - "fn visit_revoke_role_permission(operation: &Revoke<PermissionObject, Role>)", + "fn visit_grant_role_permission(operation: &Grant<Permission, Role>)", + "fn visit_revoke_role_permission(operation: &Revoke<Permission, Role>)", "fn visit_register_trigger(operation: &Register<Trigger>)", "fn visit_unregister_trigger(operation: &Unregister<Trigger>)", "fn visit_mint_trigger_repetitions(operation: &Mint<u32, Trigger>)", diff --git a/smart_contract/executor/derive/src/entrypoint.rs b/smart_contract/executor/derive/src/entrypoint.rs index 646fb0c281f..0b914e825fd 100644 --- a/smart_contract/executor/derive/src/entrypoint.rs +++ b/smart_contract/executor/derive/src/entrypoint.rs @@ -144,9 +144,8 @@ fn impl_migrate_entrypoint(fn_item: syn::ItemFn) -> TokenStream { let migrate_fn_name = syn::Ident::new(export::EXECUTOR_MIGRATE, proc_macro2::Span::call_site()); - // FIXME: is doc accurate? quote! { - /// Executor `permission_schema` entrypoint + /// Executor `data_model_schema` entrypoint /// /// # Memory safety /// diff --git a/smart_contract/executor/src/default.rs b/smart_contract/executor/src/default.rs index 5d583ce5a00..c90a4cec724 100644 --- a/smart_contract/executor/src/default.rs +++ b/smart_contract/executor/src/default.rs @@ -41,7 +41,10 @@ pub use trigger::{ visit_unregister_trigger, }; -use crate::{permission::Permission as _, prelude::*}; +use crate::{ + permission::Permission as _, + prelude::{Permission as PermissionObject, *}, +}; // NOTE: If any new `visit_..` functions are introduced in this module, one should // not forget to update the default executor boilerplate too, specifically the diff --git a/smart_contract/executor/src/lib.rs b/smart_contract/executor/src/lib.rs index fac1d112b8f..dde70e5690a 100644 --- a/smart_contract/executor/src/lib.rs +++ b/smart_contract/executor/src/lib.rs @@ -79,10 +79,6 @@ pub fn get_migrate_payload() -> payloads::Migrate { unsafe { decode_with_length_prefix_from_raw(host::get_migrate_payload()) } } -// pub trait IntoDataModel { -// fn into_data_model(&self) -> &ExecutorDataModel; -// } - /// Set new [`ExecutorDataModel`]. /// /// # Errors @@ -291,9 +287,7 @@ pub mod prelude { entrypoint, Constructor, Permission, Validate, ValidateEntrypoints, ValidateGrantRevoke, Visit, }; - pub use iroha_smart_contract::prelude::{ - Parameter as ParameterObject, Permission as PermissionObject, *, - }; + pub use iroha_smart_contract::prelude::*; pub use super::{ data_model::{ @@ -302,8 +296,8 @@ pub mod prelude { ValidationFail, }, deny, execute, - parameter::Parameter, - permission::Permission, + parameter::Parameter as ParameterTrait, + permission::Permission as PermissionTrait, DataModelBuilder, Validate, }; } diff --git a/smart_contract/executor/src/parameter.rs b/smart_contract/executor/src/parameter.rs index 805868de2a0..b6e887054cb 100644 --- a/smart_contract/executor/src/parameter.rs +++ b/smart_contract/executor/src/parameter.rs @@ -1,11 +1,14 @@ //! Executor-defined configuration parameters -use iroha_executor::prelude::{ParameterId, ParameterObject}; use iroha_schema::IntoSchema; use iroha_smart_contract_utils::debug::DebugExpectExt; use serde::{de::DeserializeOwned, Serialize}; -use crate::{data_model::JsonString, TryFromDataModelObjectError}; +use crate::{ + data_model::JsonString, + prelude::{Parameter as ParameterObject, *}, + TryFromDataModelObjectError, +}; /// Marker trait for parameters. /// @@ -36,9 +39,7 @@ pub trait Parameter: Serialize + DeserializeOwned + IntoSchema { /// Try to convert from [`ParameterObject`] /// # Errors /// See [`TryFromDataModelObjectError`] - fn try_from_object( - object: &ParameterObject, - ) -> crate::prelude::Result<Self, TryFromDataModelObjectError> { + fn try_from_object(object: &ParameterObject) -> Result<Self, TryFromDataModelObjectError> { if *object.id() != <Self as Parameter>::id() { return Err(TryFromDataModelObjectError::Id(object.id().name().clone())); } diff --git a/smart_contract/executor/src/permission.rs b/smart_contract/executor/src/permission.rs index 313fe38dd48..5672b4a7114 100644 --- a/smart_contract/executor/src/permission.rs +++ b/smart_contract/executor/src/permission.rs @@ -7,7 +7,10 @@ use iroha_smart_contract::{data_model::JsonString, QueryOutputCursor}; use iroha_smart_contract_utils::debug::DebugExpectExt as _; use serde::{de::DeserializeOwned, Serialize}; -use crate::{prelude::*, TryFromDataModelObjectError}; +use crate::{ + prelude::{Permission as PermissionObject, *}, + TryFromDataModelObjectError, +}; /// Is used to check if the permission token is owned by the account. pub trait Permission: From 48363e92b22bf6cb1f3668af646d303cef6a5bba Mon Sep 17 00:00:00 2001 From: 0x009922 <43530070+0x009922@users.noreply.github.com> Date: Mon, 27 May 2024 08:52:51 +0900 Subject: [PATCH 4/4] test: change port Signed-off-by: 0x009922 <43530070+0x009922@users.noreply.github.com> --- client/tests/integration/upgrade.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/tests/integration/upgrade.rs b/client/tests/integration/upgrade.rs index 637a6ea879a..2d1f2b5c1ac 100644 --- a/client/tests/integration/upgrade.rs +++ b/client/tests/integration/upgrade.rs @@ -199,7 +199,7 @@ fn executor_upgrade_should_revoke_removed_permissions() -> Result<()> { #[test] fn migration_fail_should_not_cause_any_effects() { - let (_rt, _peer, client) = <PeerBuilder>::new().with_port(10_995).start_with_runtime(); + let (_rt, _peer, client) = <PeerBuilder>::new().with_port(10_999).start_with_runtime(); wait_for_genesis_committed(&vec![client.clone()], 0); let assert_domain_does_not_exist = |client: &Client, domain_id: &DomainId| {