From cf7170b1f9c5be176b2317afe9830f5e87343c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Wed, 3 Jul 2024 21:45:41 +0200 Subject: [PATCH] refactor!: rename wasm to smart contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- cli/src/lib.rs | 2 +- cli/src/samples.rs | 2 +- client/benches/tps/utils.rs | 2 +- client/examples/register_1000_triggers.rs | 2 +- client/src/client.rs | 9 +- client/tests/integration/asset_propagation.rs | 4 +- client/tests/integration/events/data.rs | 4 +- client/tests/integration/events/pipeline.rs | 4 +- .../multiple_blocks_created.rs | 4 +- .../integration/extra_functional/normal.rs | 4 +- .../extra_functional/unregister_peer.rs | 4 +- .../extra_functional/unstable_network.rs | 9 +- client/tests/integration/multisig.rs | 4 +- .../integration/queries/smart_contract.rs | 16 ++- .../multisig_register/src/lib.rs | 7 +- .../integration/triggers/by_call_trigger.rs | 8 +- .../integration/triggers/time_trigger.rs | 6 +- client/tests/integration/upgrade.rs | 7 +- client_cli/README.md | 36 ++--- client_cli/src/main.rs | 21 +-- configs/swarm/executor.wasm | Bin 486804 -> 486463 bytes core/benches/blocks/common.rs | 4 +- core/benches/validation.rs | 6 +- core/src/executor.rs | 2 +- core/src/smartcontracts/isi/triggers/mod.rs | 2 +- core/src/smartcontracts/isi/triggers/set.rs | 132 +++++++++--------- .../isi/triggers/specialized.rs | 4 +- core/src/smartcontracts/isi/world.rs | 4 +- core/src/smartcontracts/wasm.rs | 4 +- core/src/state.rs | 4 +- core/src/tx.rs | 20 +-- data_model/src/executor.rs | 6 +- data_model/src/isi.rs | 24 +++- data_model/src/lib.rs | 5 +- data_model/src/parameter.rs | 16 ++- data_model/src/query/mod.rs | 6 +- data_model/src/transaction.rs | 54 +++---- data_model/src/visit.rs | 10 +- docs/source/references/schema.json | 34 ++--- genesis/src/lib.rs | 8 +- schema/gen/src/lib.rs | 4 +- smart_contract/README.md | 8 +- smart_contract/derive/src/entrypoint.rs | 2 +- .../data_model/derive/src/parameter.rs | 8 +- .../executor/data_model/src/parameter.rs | 1 - .../executor/derive/src/entrypoint.rs | 2 +- smart_contract/executor/src/default.rs | 6 +- smart_contract/executor/src/lib.rs | 2 +- smart_contract/src/lib.rs | 2 +- .../trigger/derive/src/entrypoint.rs | 2 +- smart_contract/trigger/src/lib.rs | 2 +- smart_contract/utils/src/debug.rs | 16 +-- smart_contract/utils/src/lib.rs | 5 +- smart_contract/utils/src/log.rs | 8 +- 54 files changed, 295 insertions(+), 273 deletions(-) diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 63e00eeddb1..676d7a689d8 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -826,7 +826,7 @@ mod tests { } fn dummy_executor() -> Executor { - Executor::new(WasmSmartContract::from_compiled(vec![1, 2, 3])) + Executor::new(SmartContract::from_compiled(vec![1, 2, 3])) } #[test] diff --git a/cli/src/samples.rs b/cli/src/samples.rs index dccce0fe4fa..9b977758968 100644 --- a/cli/src/samples.rs +++ b/cli/src/samples.rs @@ -115,5 +115,5 @@ where .optimize()? .into_bytes()?; - Ok(Executor::new(WasmSmartContract::from_compiled(wasm_blob))) + Ok(Executor::new(SmartContract::from_compiled(wasm_blob))) } diff --git a/client/benches/tps/utils.rs b/client/benches/tps/utils.rs index cca409724ae..fa2c4baf335 100644 --- a/client/benches/tps/utils.rs +++ b/client/benches/tps/utils.rs @@ -51,7 +51,7 @@ impl Config { let clients = network.clients(); wait_for_genesis_committed_with_max_retries(&clients, 0, self.genesis_max_retries); - client.submit_blocking(SetParameter::new(Parameter::Block(self.block_limits)))?; + client.submit_blocking(SetParameter::new(self.block_limits))?; let unit_names = (UnitName::MIN..).take(self.peers as usize); let units = clients diff --git a/client/examples/register_1000_triggers.rs b/client/examples/register_1000_triggers.rs index a7f31bd2962..bda2d4ff1a3 100644 --- a/client/examples/register_1000_triggers.rs +++ b/client/examples/register_1000_triggers.rs @@ -40,7 +40,7 @@ fn generate_genesis( .build()? .optimize()? .into_bytes()?; - let wasm = WasmSmartContract::from_compiled(wasm); + let wasm = SmartContract::from_compiled(wasm); let (account_id, _account_keypair) = gen_account_in("wonderland"); let build_trigger = |trigger_id: TriggerId| { diff --git a/client/src/client.rs b/client/src/client.rs index 6902b054f0a..ee653f0a20c 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -16,7 +16,6 @@ use futures_util::StreamExt; use http_default::{AsyncWebSocketStream, WebSocketStream}; pub use iroha_config::client_api::ConfigDTO; use iroha_logger::prelude::*; -use iroha_primitives::json; use iroha_telemetry::metrics::Status; use iroha_torii_const::uri as torii_uri; use iroha_version::prelude::*; @@ -327,7 +326,7 @@ impl_query_output! { crate::data_model::account::Account, crate::data_model::domain::Domain, crate::data_model::block::BlockHeader, - json::JsonString, + crate::data_model::prelude::JsonString, crate::data_model::query::TransactionQueryOutput, crate::data_model::executor::ExecutorDataModel, crate::data_model::trigger::Trigger, @@ -447,7 +446,7 @@ impl Client { } } - /// Builds transaction out of supplied instructions or wasm. + /// Builds transaction out of supplied instructions or smart contract. /// /// # Errors /// Fails if signing transaction fails @@ -460,7 +459,9 @@ impl Client { let mut tx_builder = match instructions.into() { Executable::Instructions(instructions) => tx_builder.with_instructions(instructions), - Executable::Wasm(wasm) => tx_builder.with_wasm(wasm), + Executable::SmartContract(smart_contract) => { + tx_builder.with_smart_contract(smart_contract) + } }; if let Some(transaction_ttl) = self.transaction_ttl { diff --git a/client/tests/integration/asset_propagation.rs b/client/tests/integration/asset_propagation.rs index c191c5fdb82..75994e92b45 100644 --- a/client/tests/integration/asset_propagation.rs +++ b/client/tests/integration/asset_propagation.rs @@ -20,8 +20,8 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount_on_a wait_for_genesis_committed(&network.clients(), 0); let pipeline_time = Config::pipeline_time(); - client.submit_blocking(SetParameter::new(Parameter::Block( - BlockParameter::MaxTransactions(nonzero!(1_u64)), + client.submit_blocking(SetParameter::new(BlockParameter::MaxTransactions( + nonzero!(1_u64), )))?; let create_domain = Register::domain(Domain::new(DomainId::from_str("domain")?)); diff --git a/client/tests/integration/events/data.rs b/client/tests/integration/events/data.rs index 4c9e32e6e2a..31407295a8c 100644 --- a/client/tests/integration/events/data.rs +++ b/client/tests/integration/events/data.rs @@ -1,7 +1,7 @@ use std::{fmt::Write as _, sync::mpsc, thread}; use eyre::Result; -use iroha::data_model::{prelude::*, transaction::WasmSmartContract}; +use iroha::data_model::{prelude::*, transaction::SmartContract}; use iroha_executor_data_model::permission::account::{ CanRemoveKeyValueInAccount, CanSetKeyValueInAccount, }; @@ -125,7 +125,7 @@ fn wasm_execution_should_produce_events() -> Result<()> { ); transaction_execution_should_produce_events( - WasmSmartContract::from_compiled(wat.into_bytes()), + SmartContract::from_compiled(wat.into_bytes()), 10_615, ) } diff --git a/client/tests/integration/events/pipeline.rs b/client/tests/integration/events/pipeline.rs index f57d4382563..dd34a74d83a 100644 --- a/client/tests/integration/events/pipeline.rs +++ b/client/tests/integration/events/pipeline.rs @@ -57,8 +57,8 @@ fn test_with_instruction_and_status_and_port( wait_for_genesis_committed(&clients, 0); let pipeline_time = Config::pipeline_time(); - client.submit_blocking(SetParameter::new(Parameter::Block( - BlockParameter::MaxTransactions(nonzero!(1_u64)), + client.submit_blocking(SetParameter::new(BlockParameter::MaxTransactions( + nonzero!(1_u64), )))?; // Given diff --git a/client/tests/integration/extra_functional/multiple_blocks_created.rs b/client/tests/integration/extra_functional/multiple_blocks_created.rs index 78d10cae935..fb228b75920 100644 --- a/client/tests/integration/extra_functional/multiple_blocks_created.rs +++ b/client/tests/integration/extra_functional/multiple_blocks_created.rs @@ -20,8 +20,8 @@ fn long_multiple_blocks_created() -> Result<()> { wait_for_genesis_committed(&network.clients(), 0); let pipeline_time = Config::pipeline_time(); - client.submit_blocking(SetParameter::new(Parameter::Block( - BlockParameter::MaxTransactions(nonzero!(1_u64)), + client.submit_blocking(SetParameter::new(BlockParameter::MaxTransactions( + nonzero!(1_u64), )))?; let create_domain = Register::domain(Domain::new("domain".parse()?)); diff --git a/client/tests/integration/extra_functional/normal.rs b/client/tests/integration/extra_functional/normal.rs index 401d3b22626..b8b364aef45 100644 --- a/client/tests/integration/extra_functional/normal.rs +++ b/client/tests/integration/extra_functional/normal.rs @@ -10,8 +10,8 @@ fn tranasctions_should_be_applied() { let (_rt, network, iroha) = NetworkBuilder::new(4, Some(11_300)).create_with_runtime(); wait_for_genesis_committed(&network.clients(), 0); iroha - .submit_blocking(SetParameter::new(Parameter::Block( - BlockParameter::MaxTransactions(nonzero!(1_u64)), + .submit_blocking(SetParameter::new(BlockParameter::MaxTransactions( + nonzero!(1_u64), ))) .unwrap(); diff --git a/client/tests/integration/extra_functional/unregister_peer.rs b/client/tests/integration/extra_functional/unregister_peer.rs index ebd9ff458a9..082037f4648 100644 --- a/client/tests/integration/extra_functional/unregister_peer.rs +++ b/client/tests/integration/extra_functional/unregister_peer.rs @@ -116,9 +116,7 @@ fn init() -> Result<( let pipeline_time = Config::pipeline_time(); iroha_logger::info!("Started"); - let set_max_txns_in_block = SetParameter::new(Parameter::Block( - BlockParameter::MaxTransactions(nonzero!(1_u64)), - )); + let set_max_txns_in_block = SetParameter::new(BlockParameter::MaxTransactions(nonzero!(1_u64))); let create_domain = Register::domain(Domain::new("domain".parse()?)); let (account_id, _account_keypair) = gen_account_in("domain"); diff --git a/client/tests/integration/extra_functional/unstable_network.rs b/client/tests/integration/extra_functional/unstable_network.rs index c917b85580d..f3364f15c99 100644 --- a/client/tests/integration/extra_functional/unstable_network.rs +++ b/client/tests/integration/extra_functional/unstable_network.rs @@ -2,10 +2,7 @@ use std::thread; use iroha::{ client::{self, QueryResult}, - data_model::{ - parameter::{BlockParameter, Parameter}, - prelude::*, - }, + data_model::{parameter::BlockParameter, prelude::*}, }; use iroha_config::parameters::actual::Root as Config; use nonzero_ext::nonzero; @@ -64,8 +61,8 @@ fn unstable_network( .create_with_runtime(); wait_for_genesis_committed(&network.clients(), n_offline_peers); iroha - .submit_blocking(SetParameter::new(Parameter::Block( - BlockParameter::MaxTransactions(nonzero!(5_u64)), + .submit_blocking(SetParameter::new(BlockParameter::MaxTransactions( + nonzero!(5_u64), ))) .unwrap(); diff --git a/client/tests/integration/multisig.rs b/client/tests/integration/multisig.rs index c7fd8b0bb0c..b6fdcd4c321 100644 --- a/client/tests/integration/multisig.rs +++ b/client/tests/integration/multisig.rs @@ -7,7 +7,7 @@ use iroha::{ crypto::KeyPair, data_model::{ prelude::*, - transaction::{TransactionBuilder, WasmSmartContract}, + transaction::{SmartContract, TransactionBuilder}, }, }; use iroha_data_model::parameter::SmartContractParameter; @@ -38,7 +38,7 @@ fn mutlisig() -> Result<()> { .build()? .optimize()? .into_bytes()?; - let wasm = WasmSmartContract::from_compiled(wasm); + let wasm = SmartContract::from_compiled(wasm); let trigger = Trigger::new( multisig_register_trigger_id.clone(), diff --git a/client/tests/integration/queries/smart_contract.rs b/client/tests/integration/queries/smart_contract.rs index e41c4bd985a..9eda4b7887a 100644 --- a/client/tests/integration/queries/smart_contract.rs +++ b/client/tests/integration/queries/smart_contract.rs @@ -12,7 +12,7 @@ fn live_query_is_dropped_after_smart_contract_end() -> Result<()> { let (_rt, _peer, client) = ::new().with_port(11_140).start_with_runtime(); wait_for_genesis_committed(&[client.clone()], 0); - let wasm = iroha_wasm_builder::Builder::new( + let smart_contract = iroha_wasm_builder::Builder::new( "tests/integration/smartcontracts/query_assets_and_save_cursor", ) .show_output() @@ -20,8 +20,10 @@ fn live_query_is_dropped_after_smart_contract_end() -> Result<()> { .optimize()? .into_bytes()?; - let transaction = - client.build_transaction(WasmSmartContract::from_compiled(wasm), Metadata::default()); + let transaction = client.build_transaction( + SmartContract::from_compiled(smart_contract), + Metadata::default(), + ); client.submit_transaction_blocking(&transaction)?; let metadata_value: JsonString = client.request(FindAccountKeyValueByIdAndKey::new( @@ -49,7 +51,7 @@ fn smart_contract_can_filter_queries() -> Result<()> { let (_rt, _peer, client) = ::new().with_port(11_260).start_with_runtime(); wait_for_genesis_committed(&[client.clone()], 0); - let wasm = iroha_wasm_builder::Builder::new( + let smart_contract = iroha_wasm_builder::Builder::new( "tests/integration/smartcontracts/smart_contract_can_filter_queries", ) .show_output() @@ -57,8 +59,10 @@ fn smart_contract_can_filter_queries() -> Result<()> { .optimize()? .into_bytes()?; - let transaction = - client.build_transaction(WasmSmartContract::from_compiled(wasm), Metadata::default()); + let transaction = client.build_transaction( + SmartContract::from_compiled(smart_contract), + Metadata::default(), + ); client.submit_transaction_blocking(&transaction)?; Ok(()) diff --git a/client/tests/integration/smartcontracts/multisig_register/src/lib.rs b/client/tests/integration/smartcontracts/multisig_register/src/lib.rs index f3f2dfb6530..40f299a790d 100644 --- a/client/tests/integration/smartcontracts/multisig_register/src/lib.rs +++ b/client/tests/integration/smartcontracts/multisig_register/src/lib.rs @@ -18,8 +18,9 @@ static ALLOC: LockedAllocator = LockedAllocator::new(FreeList getrandom::register_custom_getrandom!(iroha_trigger::stub_getrandom); -// Trigger wasm code for handling multisig logic -const WASM: &[u8] = core::include_bytes!(concat!(core::env!("OUT_DIR"), "/multisig.wasm")); +// Trigger for handling multisig logic +const SMART_CONTRACT: &[u8] = + core::include_bytes!(concat!(core::env!("OUT_DIR"), "/multisig.wasm")); #[iroha_trigger::main] fn main(_id: TriggerId, _owner: AccountId, event: EventBox) { @@ -46,7 +47,7 @@ fn main(_id: TriggerId, _owner: AccountId, event: EventBox) { .parse() .dbg_expect("failed to parse trigger id"); - let payload = WasmSmartContract::from_compiled(WASM.to_vec()); + let payload = SmartContract::from_compiled(SMART_CONTRACT.to_vec()); let trigger = Trigger::new( trigger_id.clone(), Action::new( diff --git a/client/tests/integration/triggers/by_call_trigger.rs b/client/tests/integration/triggers/by_call_trigger.rs index 293982cee0e..1cdc6bece7e 100644 --- a/client/tests/integration/triggers/by_call_trigger.rs +++ b/client/tests/integration/triggers/by_call_trigger.rs @@ -8,7 +8,7 @@ use iroha::{ data_model::{ prelude::*, query::error::{FindError, QueryExecutionFail}, - transaction::{Executable, WasmSmartContract}, + transaction::{Executable, SmartContract}, }, }; use iroha_executor_data_model::permission::trigger::CanRegisterUserTrigger; @@ -430,7 +430,7 @@ fn trigger_in_genesis_using_base64() -> Result<()> { let trigger = Trigger::new( trigger_id.clone(), Action::new( - serde_json::from_str::(&wasm_base64) + serde_json::from_str::(&wasm_base64) .wrap_err("Can't deserialize wasm using base64")?, Repeats::Indefinitely, account_id.clone(), @@ -585,7 +585,7 @@ fn unregistering_one_of_two_triggers_with_identical_wasm_should_not_cause_origin .build()? .optimize()? .into_bytes()?; - let wasm = WasmSmartContract::from_compiled(wasm); + let wasm = SmartContract::from_compiled(wasm); let build_trigger = |trigger_id: TriggerId| { Trigger::new( @@ -667,7 +667,7 @@ fn call_execute_trigger_with_args() -> Result<()> { .build()? .optimize()? .into_bytes()?; - let wasm = WasmSmartContract::from_compiled(wasm); + let wasm = SmartContract::from_compiled(wasm); let trigger = Trigger::new( trigger_id.clone(), Action::new( diff --git a/client/tests/integration/triggers/time_trigger.rs b/client/tests/integration/triggers/time_trigger.rs index c77ca97eea9..a9daa99b74a 100644 --- a/client/tests/integration/triggers/time_trigger.rs +++ b/client/tests/integration/triggers/time_trigger.rs @@ -8,7 +8,7 @@ use iroha::{ events::pipeline::{BlockEventFilter, BlockStatus}, parameter::SumeragiParameters, prelude::*, - transaction::WasmSmartContract, + transaction::SmartContract, Level, }, }; @@ -228,7 +228,7 @@ fn mint_nft_for_every_user_every_1_sec() -> Result<()> { .optimize()? .into_bytes()?; - info!("WASM size is {} bytes", wasm.len()); + info!("Smart contract size is {} bytes", wasm.len()); let (_rt, _peer, mut test_client) = ::new().with_port(10_780).start_with_runtime(); wait_for_genesis_committed(&vec![test_client.clone()], 0); @@ -265,7 +265,7 @@ fn mint_nft_for_every_user_every_1_sec() -> Result<()> { let register_trigger = Register::trigger(Trigger::new( "mint_nft_for_all".parse()?, Action::new( - WasmSmartContract::from_compiled(wasm), + SmartContract::from_compiled(wasm), Repeats::Indefinitely, alice_id.clone(), filter, diff --git a/client/tests/integration/upgrade.rs b/client/tests/integration/upgrade.rs index 2ce4f3e85fa..473b0a88b25 100644 --- a/client/tests/integration/upgrade.rs +++ b/client/tests/integration/upgrade.rs @@ -406,8 +406,7 @@ fn define_custom_parameter() -> Result<()> { let parameter = DomainLimits { id_len: 2_u32.pow(6), - } - .into(); + }; let set_param_isi = SetParameter::new(parameter); client.submit_all_blocking::([set_param_isi.into(), create_domain.into()])?; @@ -423,9 +422,9 @@ fn upgrade_executor(client: &Client, executor: impl AsRef) -> Result<()> { .optimize()? .into_bytes()?; - info!("WASM size is {} bytes", wasm.len()); + info!("Smart contract size is {} bytes", wasm.len()); - let upgrade_executor = Upgrade::new(Executor::new(WasmSmartContract::from_compiled(wasm))); + let upgrade_executor = Upgrade::executor(Executor::new(SmartContract::from_compiled(wasm))); client.submit_blocking(upgrade_executor)?; Ok(()) diff --git a/client_cli/README.md b/client_cli/README.md index 08c4494f3d2..ce24f2ba14d 100644 --- a/client_cli/README.md +++ b/client_cli/README.md @@ -38,17 +38,17 @@ iroha [OPTIONS] ### Subcommands -| Command | Description | -| --------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -| `account` | Execute commands related to accounts: register a new one, list all accounts, grant a permission to an account, list all account permissions | -| `asset` | Execute commands related to assets: register a new one, mint or transfer assets, get info about an asset, list all assets | -| `blocks` | Get block stream from Iroha peer | -| `domain` | Execute commands related to domains: register a new one, list all domains | -| `events` | Get event stream from Iroha peer | -| `json` | Submit multi-instructions or request query as JSON | -| `peer` | Execute commands related to peer administration and networking | -| `wasm` | Execute commands related to WASM | -| `help` | Print the help message for `iroha` and/or the current subcommand other than `help` subcommand | +| Command | Description | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `account` | Execute commands related to accounts: register a new one, list all accounts, grant a permission to an account, list all account permissions | +| `asset` | Execute commands related to assets: register a new one, mint or transfer assets, get info about an asset, list all assets | +| `blocks` | Get block stream from Iroha peer | +| `domain` | Execute commands related to domains: register a new one, list all domains | +| `events` | Get event stream from Iroha peer | +| `json` | Submit multi-instructions or request query as JSON | +| `peer` | Execute commands related to peer administration and networking | +| `smart-contract` | Execute commands related to smart contracts | +| `help` | Print the help message for `iroha` and/or the current subcommand other than `help` subcommand | Refer to [Iroha Special Instructions](https://hyperledger.github.io/iroha-2-docs/guide/blockchain/instructions.html) for more information about Iroha instructions such as register, mint, grant, and so on. @@ -79,7 +79,7 @@ In this section we will show you how to use Iroha CLI Client to do the following - [Create new Account](#create-new-account) - [Mint Asset to Account](#mint-asset-to-account) - [Query Account Assets Quantity](#query-account-assets-quantity) - - [Execute WASM transaction](#execute-wasm-transaction) + - [Execute smart contract](#execute-smart-contract) - [Execute Multi-instruction Transactions](#execute-multi-instruction-transactions) ### Create new Domain @@ -160,21 +160,21 @@ Examples: ./iroha asset list filter '{"Or": [{"Identifiable": {"Contains": "#wonderland#"}}, {"And": [{"Identifiable": {"Contains": "##"}}, {"Identifiable": {"EndsWith": "@wonderland"}}]}]}' ``` -### Execute WASM transaction +### Execute smart contract -Use `--file` to specify a path to the WASM file: +Use `--file` to specify a path to the smart contract file: ```bash -./iroha wasm --file=/path/to/file.wasm +./iroha smart-contract --file=/path/to/file.wasm ``` -Or skip `--file` to read WASM from standard input: +Or skip `--file` to read smart contract from standard input: ```bash -cat /path/to/file.wasm | ./iroha wasm +cat /path/to/file.wasm | ./iroha smart-contract ``` -These subcommands submit the provided wasm binary as an `Executable` to be executed outside a trigger context. +These subcommands submit the provided smart contract binary as an `Executable` to be executed outside a trigger context. ### Execute Multi-instruction Transactions diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index 40f78a224bc..3d357122693 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -108,8 +108,8 @@ enum Subcommand { /// The subcommand related to event streaming #[clap(subcommand)] Events(events::Args), - /// The subcommand related to Wasm - Wasm(wasm::Args), + /// The subcommand related to smart contracts + SmartContract(smart_contract::Args), /// The subcommand related to block streaming Blocks(blocks::Args), /// The subcommand related to multi-instructions as Json or Json5 @@ -169,7 +169,7 @@ macro_rules! match_all { impl RunArgs for Subcommand { fn run(self, context: &mut dyn RunContext) -> Result<()> { use Subcommand::*; - match_all!((self, context), { Domain, Account, Asset, Peer, Events, Wasm, Blocks, Json }) + match_all!((self, context), { Domain, Account, Asset, Peer, Events, SmartContract, Blocks, Json }) } } @@ -1060,15 +1060,15 @@ mod peer { } } -mod wasm { +mod smart_contract { use std::{io::Read, path::PathBuf}; use super::*; - /// Subcommand for dealing with Wasm + /// Subcommand for dealing with smart contracts #[derive(Debug, clap::Args)] pub struct Args { - /// Specify a path to the Wasm file or skip this flag to read from stdin + /// Specify a path to the smart contract file or skip this flag to read from stdin #[arg(short, long)] path: Option, } @@ -1076,21 +1076,22 @@ mod wasm { impl RunArgs for Args { fn run(self, context: &mut dyn RunContext) -> Result<()> { let raw_data = if let Some(path) = self.path { - read_file(path).wrap_err("Failed to read a Wasm from the file into the buffer")? + read_file(path) + .wrap_err("Failed to read a smart contract from the file into the buffer")? } else { let mut buf = Vec::::new(); stdin() .read_to_end(&mut buf) - .wrap_err("Failed to read a Wasm from stdin into the buffer")?; + .wrap_err("Failed to read a smart contract from stdin into the buffer")?; buf }; submit( - WasmSmartContract::from_compiled(raw_data), + SmartContract::from_compiled(raw_data), Metadata::default(), context, ) - .wrap_err("Failed to submit a Wasm smart contract") + .wrap_err("Failed to submit a smart contract") } } } diff --git a/configs/swarm/executor.wasm b/configs/swarm/executor.wasm index 7bff907546dc02ce0ce0bbc275f51825e3b4c6d5..92c3676af6730d14779080939d69e62b602bfed2 100644 GIT binary patch delta 81032 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 diff --git a/core/benches/blocks/common.rs b/core/benches/blocks/common.rs index 96c408281a5..e357ddd7098 100644 --- a/core/benches/blocks/common.rs +++ b/core/benches/blocks/common.rs @@ -208,8 +208,8 @@ pub fn build_state(rt: &tokio::runtime::Handle, account_id: &AccountId) -> State .join("../configs/swarm/executor.wasm"); let wasm = std::fs::read(&path_to_executor) .unwrap_or_else(|_| panic!("Failed to read file: {}", path_to_executor.display())); - let executor = Executor::new(WasmSmartContract::from_compiled(wasm)); - Upgrade::new(executor) + let executor = Executor::new(SmartContract::from_compiled(wasm)); + Upgrade::executor(executor) .execute(account_id, &mut state_transaction) .expect("Failed to load executor"); diff --git a/core/benches/validation.rs b/core/benches/validation.rs index 3f010144574..e2391e6bb79 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -61,11 +61,11 @@ fn build_test_and_transient_state() -> State { let mut state_transaction = state_block.transaction(); let path_to_executor = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("../configs/swarm/executor.wasm"); - let wasm = std::fs::read(&path_to_executor) + let smart_contract = std::fs::read(&path_to_executor) .unwrap_or_else(|_| panic!("Failed to read file: {}", path_to_executor.display())); - let executor = Executor::new(WasmSmartContract::from_compiled(wasm)); + let executor = Executor::new(SmartContract::from_compiled(smart_contract)); let (authority, _authority_keypair) = gen_account_in("genesis"); - Upgrade::new(executor) + Upgrade::executor(executor) .execute(&authority, &mut state_transaction) .expect("Failed to load executor"); state_transaction.apply(); diff --git a/core/src/executor.rs b/core/src/executor.rs index 0894b290639..78602156c24 100644 --- a/core/src/executor.rs +++ b/core/src/executor.rs @@ -278,7 +278,7 @@ impl LoadedExecutor { raw_executor: data_model_executor::Executor, ) -> Result { Ok(Self { - module: wasm::load_module(engine, &raw_executor.wasm)?, + module: wasm::load_module(engine, &raw_executor.smart_contract)?, raw_executor, }) } diff --git a/core/src/smartcontracts/isi/triggers/mod.rs b/core/src/smartcontracts/isi/triggers/mod.rs index 62e2d1d259c..21a80e50c59 100644 --- a/core/src/smartcontracts/isi/triggers/mod.rs +++ b/core/src/smartcontracts/isi/triggers/mod.rs @@ -98,7 +98,7 @@ pub mod isi { .map_err(|e: &str| Error::Conversion(e.to_owned()))?, ), } - .map_err(|e| InvalidParameterError::Wasm(e.to_string()))?; + .map_err(|e| InvalidParameterError::SmartContract(e.to_string()))?; if !success { return Err(RepetitionError { diff --git a/core/src/smartcontracts/isi/triggers/set.rs b/core/src/smartcontracts/isi/triggers/set.rs index d7781f7acb2..7461fa51a9a 100644 --- a/core/src/smartcontracts/isi/triggers/set.rs +++ b/core/src/smartcontracts/isi/triggers/set.rs @@ -17,7 +17,7 @@ use iroha_data_model::{ isi::error::{InstructionExecutionError, MathError}, prelude::*, query::error::FindError, - transaction::WasmSmartContract, + transaction::SmartContract, }; use serde::{ de::{DeserializeSeed, MapAccess, Visitor}, @@ -45,22 +45,20 @@ use crate::{ /// Error type for [`Set`] operations. #[derive(Debug, Error, displaydoc::Display)] pub enum Error { - /// Failed to preload wasm trigger + /// Failed to preload smart contract trigger Preload(#[from] wasm::error::Error), } /// Result type for [`Set`] operations. pub type Result = core::result::Result; -/// [`WasmSmartContract`]s by [`TriggerId`]. -/// Stored together with number to count triggers with identical [`WasmSmartContract`]. -type WasmSmartContractMap = Storage, WasmSmartContractEntry>; -type WasmSmartContractMapBlock<'set> = - StorageBlock<'set, HashOf, WasmSmartContractEntry>; -type WasmSmartContractMapTransaction<'block, 'set> = - StorageTransaction<'block, 'set, HashOf, WasmSmartContractEntry>; -type WasmSmartContractMapView<'set> = - StorageView<'set, HashOf, WasmSmartContractEntry>; +/// [`SmartContract`]s by [`TriggerId`]. +/// Stored together with number to count triggers with identical [`SmartContract`]. +type SmartContractMap = Storage, SmartContractEntry>; +type SmartContractMapBlock<'set> = StorageBlock<'set, HashOf, SmartContractEntry>; +type SmartContractMapTransaction<'block, 'set> = + StorageTransaction<'block, 'set, HashOf, SmartContractEntry>; +type SmartContractMapView<'set> = StorageView<'set, HashOf, SmartContractEntry>; /// Specialized structure that maps event filters to Triggers. // NB: `Set` has custom `Serialize` and `DeserializeSeed` implementations @@ -77,12 +75,12 @@ pub struct Set { by_call_triggers: Storage>, /// Trigger ids with type of events they process ids: Storage, - /// [`WasmSmartContract`]s map by wasm blob hash. + /// [`SmartContract`]s map by smart contract blob hash. /// This map serves multiple purposes: - /// 1. Querying original wasm blob of trigger + /// 1. Querying original smart contract blob of trigger /// 2. Getting compiled by wasmtime module for execution - /// 3. Deduplicating triggers with the same wasm blob - contracts: WasmSmartContractMap, + /// 3. Deduplicating triggers with the same smart contract blob + contracts: SmartContractMap, /// List of actions that should be triggered by events provided by `handle_*` methods. /// Vector is used to save the exact triggers order. // NOTE: Cell is used because matched_ids changed as whole (not granularly) @@ -101,8 +99,8 @@ pub struct SetBlock<'set> { by_call_triggers: StorageBlock<'set, TriggerId, LoadedAction>, /// Trigger ids with type of events they process ids: StorageBlock<'set, TriggerId, TriggeringEventType>, - /// Original [`WasmSmartContract`]s by [`TriggerId`] for querying purposes. - contracts: WasmSmartContractMapBlock<'set>, + /// Original [`SmartContract`]s by [`TriggerId`] for querying purposes. + contracts: SmartContractMapBlock<'set>, /// List of actions that should be triggered by events provided by `handle_*` methods. /// Vector is used to save the exact triggers order. matched_ids: CellBlock<'set, Vec<(EventBox, TriggerId)>>, @@ -122,8 +120,8 @@ pub struct SetTransaction<'block, 'set> { StorageTransaction<'block, 'set, TriggerId, LoadedAction>, /// Trigger ids with type of events they process ids: StorageTransaction<'block, 'set, TriggerId, TriggeringEventType>, - /// Original [`WasmSmartContract`]s by [`TriggerId`] for querying purposes. - contracts: WasmSmartContractMapTransaction<'block, 'set>, + /// Original [`SmartContract`]s by [`TriggerId`] for querying purposes. + contracts: SmartContractMapTransaction<'block, 'set>, /// List of actions that should be triggered by events provided by `handle_*` methods. /// Vector is used to save the exact triggers order. matched_ids: CellTransaction<'block, 'set, Vec<(EventBox, TriggerId)>>, @@ -141,18 +139,18 @@ pub struct SetView<'set> { by_call_triggers: StorageView<'set, TriggerId, LoadedAction>, /// Trigger ids with type of events they process ids: StorageView<'set, TriggerId, TriggeringEventType>, - /// Original [`WasmSmartContract`]s by [`TriggerId`] for querying purposes. - contracts: WasmSmartContractMapView<'set>, + /// Original [`SmartContract`]s by [`TriggerId`] for querying purposes. + contracts: SmartContractMapView<'set>, /// List of actions that should be triggered by events provided by `handle_*` methods. /// Vector is used to save the exact triggers order. matched_ids: CellView<'set, Vec<(EventBox, TriggerId)>>, } -/// Entry in wasm smart-contracts map +/// Entry in smart-contracts map #[derive(Debug, Clone, Serialize)] -pub struct WasmSmartContractEntry { - /// Original wasm binary blob - original_contract: WasmSmartContract, +pub struct SmartContractEntry { + /// Original smart contract binary blob + original_contract: SmartContract, /// Compiled with [`wasmtime`] smart-contract #[serde(skip)] compiled_contract: wasmtime::Module, @@ -210,7 +208,7 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Set> { contracts = Some(map.next_value_seed(storage::serde::StorageSeeded { kseed: PhantomData, - vseed: self.loader.cast::(), + vseed: self.loader.cast::(), })?); } "matched_ids" => { @@ -242,22 +240,22 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Set> { } } -impl<'de> DeserializeSeed<'de> for WasmSeed<'_, WasmSmartContractEntry> { - type Value = WasmSmartContractEntry; +impl<'de> DeserializeSeed<'de> for WasmSeed<'_, SmartContractEntry> { + type Value = SmartContractEntry; fn deserialize(self, deserializer: D) -> Result where D: serde::Deserializer<'de>, { - struct WasmSmartContractEntryVisitor<'e> { - loader: WasmSeed<'e, WasmSmartContractEntry>, + struct SmartContractEntryVisitor<'e> { + loader: WasmSeed<'e, SmartContractEntry>, } - impl<'de> Visitor<'de> for WasmSmartContractEntryVisitor<'_> { - type Value = WasmSmartContractEntry; + impl<'de> Visitor<'de> for SmartContractEntryVisitor<'_> { + type Value = SmartContractEntry; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("struct WasmSmartContractEntry") + formatter.write_str("struct SmartContractEntry") } fn visit_map(self, mut map: M) -> Result @@ -285,7 +283,7 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, WasmSmartContractEntry> { let compiled_contract = wasm::load_module(self.loader.engine, &original_contract) .map_err(serde::de::Error::custom)?; - Ok(WasmSmartContractEntry { + Ok(SmartContractEntry { original_contract, compiled_contract, count, @@ -293,7 +291,7 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, WasmSmartContractEntry> { } } - deserializer.deserialize_map(WasmSmartContractEntryVisitor { loader: self }) + deserializer.deserialize_map(SmartContractEntryVisitor { loader: self }) } } /// Trait to perform read-only operations on [`WorldBlock`], [`WorldTransaction`] and [`WorldView`] @@ -308,18 +306,14 @@ pub trait SetReadOnly { &self, ) -> &impl StorageReadOnly>; fn ids(&self) -> &impl StorageReadOnly; - fn contracts(&self) - -> &impl StorageReadOnly, WasmSmartContractEntry>; + fn contracts(&self) -> &impl StorageReadOnly, SmartContractEntry>; fn matched_ids(&self) -> &[(EventBox, TriggerId)]; - /// Get original [`WasmSmartContract`] for [`TriggerId`]. + /// Get original [`SmartContract`] for [`TriggerId`]. /// Returns `None` if there's no [`Trigger`] - /// with specified `id` that has WASM executable + /// with specified `id` that has smart contract executable #[inline] - fn get_original_contract( - &self, - hash: &HashOf, - ) -> Option<&WasmSmartContract> { + fn get_original_contract(&self, hash: &HashOf) -> Option<&SmartContract> { self.contracts() .get(hash) .map(|entry| &entry.original_contract) @@ -327,16 +321,16 @@ pub trait SetReadOnly { /// Get compiled [`wasmtime::Module`] for [`TriggerId`]. /// Returns `None` if there's no [`Trigger`] - /// with specified `id` that has WASM executable + /// with specified `id` that has smart contract executable #[inline] - fn get_compiled_contract(&self, hash: &HashOf) -> Option<&wasmtime::Module> { + fn get_compiled_contract(&self, hash: &HashOf) -> Option<&wasmtime::Module> { self.contracts() .get(hash) .map(|entry| &entry.compiled_contract) } /// Convert [`LoadedAction`] to original [`Action`] by retrieving original - /// [`WasmSmartContract`] if applicable + /// [`SmartContract`] if applicable fn get_original_action(&self, action: LoadedAction) -> SpecializedAction { let LoadedAction { executable, @@ -347,12 +341,12 @@ pub trait SetReadOnly { } = action; let original_executable = match executable { - ExecutableRef::Wasm(ref blob_hash) => { - let original_wasm = self + ExecutableRef::SmartContract(ref blob_hash) => { + let original_smart_contract = self .get_original_contract(blob_hash) .cloned() .expect("No original smartcontract saved for trigger. This is a bug."); - Executable::Wasm(original_wasm) + Executable::SmartContract(original_smart_contract) } ExecutableRef::Instructions(isi) => Executable::Instructions(isi), }; @@ -502,7 +496,7 @@ macro_rules! impl_set_ro { fn ids(&self) -> &impl StorageReadOnly { &self.ids } - fn contracts(&self) -> &impl StorageReadOnly, WasmSmartContractEntry> { + fn contracts(&self) -> &impl StorageReadOnly, SmartContractEntry> { &self.contracts } fn matched_ids(&self) -> &[(EventBox, TriggerId)] { @@ -631,7 +625,7 @@ impl<'block, 'set> SetTransaction<'block, 'set> { /// /// # Errors /// - /// Return [`Err`] if failed to preload wasm trigger + /// Return [`Err`] if failed to preload trigger #[inline] pub fn add_data_trigger( &mut self, @@ -649,7 +643,7 @@ impl<'block, 'set> SetTransaction<'block, 'set> { /// /// # Errors /// - /// Return [`Err`] if failed to preload wasm trigger + /// Return [`Err`] if failed to preload trigger #[inline] pub fn add_pipeline_trigger( &mut self, @@ -667,7 +661,7 @@ impl<'block, 'set> SetTransaction<'block, 'set> { /// /// # Errors /// - /// Return [`Err`] if failed to preload wasm trigger + /// Return [`Err`] if failed to preload trigger #[inline] pub fn add_time_trigger( &mut self, @@ -685,7 +679,7 @@ impl<'block, 'set> SetTransaction<'block, 'set> { /// /// # Errors /// - /// Return [`Err`] if failed to preload wasm trigger + /// Return [`Err`] if failed to preload trigger #[inline] pub fn add_by_call_trigger( &mut self, @@ -703,7 +697,7 @@ impl<'block, 'set> SetTransaction<'block, 'set> { /// /// # Errors /// - /// Return [`Err`] if failed to preload wasm trigger + /// Return [`Err`] if failed to preload trigger fn add_to( &mut self, engine: &wasmtime::Engine, @@ -728,10 +722,10 @@ impl<'block, 'set> SetTransaction<'block, 'set> { } let loaded_executable = match executable { - Executable::Wasm(bytes) => { + Executable::SmartContract(bytes) => { let hash = HashOf::new(&bytes); // Store original executable representation to respond to queries with. - if let Some(WasmSmartContractEntry { count, .. }) = self.contracts.get_mut(&hash) { + if let Some(SmartContractEntry { count, .. }) = self.contracts.get_mut(&hash) { // Considering 1 trigger registration takes 1 second, // it would take 584 942 417 355 years to overflow. *count = count.checked_add(1).expect( @@ -742,14 +736,14 @@ impl<'block, 'set> SetTransaction<'block, 'set> { let module = wasm::load_module(engine, &bytes)?; self.contracts.insert( hash, - WasmSmartContractEntry { + SmartContractEntry { original_contract: bytes, compiled_contract: module, count: NonZeroU64::MIN, }, ); }; - ExecutableRef::Wasm(hash) + ExecutableRef::SmartContract(hash) } Executable::Instructions(instructions) => ExecutableRef::Instructions(instructions), }; @@ -861,13 +855,13 @@ impl<'block, 'set> SetTransaction<'block, 'set> { .and_then(std::convert::identity) } - /// Remove trigger from `triggers` and decrease the counter of the original [`WasmSmartContract`]. + /// Remove trigger from `triggers` and decrease the counter of the original [`SmartContract`]. /// /// Note that this function doesn't remove the trigger from [`Set::ids`]. /// /// Returns `true` if trigger was removed and `false` otherwise. fn remove_from( - contracts: &mut WasmSmartContractMapTransaction<'block, 'set>, + contracts: &mut SmartContractMapTransaction<'block, 'set>, triggers: &mut StorageTransaction<'block, 'set, TriggerId, LoadedAction>, trigger_id: TriggerId, ) -> bool { @@ -881,15 +875,15 @@ impl<'block, 'set> SetTransaction<'block, 'set> { .is_some() } - /// Decrease the counter of the original [`WasmSmartContract`] by `blob_hash` + /// Decrease the counter of the original [`SmartContract`] by `blob_hash` /// or remove it if the counter reaches zero. /// /// # Panics /// /// Panics if `blob_hash` is not in the [`Set::contracts`]. fn remove_original_trigger( - contracts: &mut WasmSmartContractMapTransaction, - blob_hash: HashOf, + contracts: &mut SmartContractMapTransaction, + blob_hash: HashOf, ) { #[allow(clippy::option_if_let_else)] // More readable this way match contracts.get_mut(&blob_hash) { @@ -932,7 +926,7 @@ impl<'block, 'set> SetTransaction<'block, 'set> { /// Remove actions with zero execution count from `triggers` fn remove_zeros( ids: &mut StorageTransaction<'block, 'set, TriggerId, TriggeringEventType>, - contracts: &mut WasmSmartContractMapTransaction<'block, 'set>, + contracts: &mut SmartContractMapTransaction<'block, 'set>, triggers: &mut StorageTransaction<'block, 'set, TriggerId, LoadedAction>, ) { let to_remove: Vec = triggers @@ -1000,12 +994,12 @@ impl<'block, 'set> SetTransaction<'block, 'set> { } /// Same as [`Executable`](iroha_data_model::transaction::Executable), but instead of -/// [`Wasm`](iroha_data_model::transaction::Executable::Wasm) contains hash of the WASM blob +/// [`SmartContract`](iroha_data_model::transaction::Executable::SmartContract) contains hash of the smart contract blob /// Which can be used to obtain compiled by `wasmtime` module #[derive(Clone, Serialize, Deserialize)] pub enum ExecutableRef { - /// Loaded WASM - Wasm(HashOf), + /// Loaded smart contract + SmartContract(HashOf), /// Vector of ISI Instructions(Vec), } @@ -1013,7 +1007,7 @@ pub enum ExecutableRef { impl core::fmt::Debug for ExecutableRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Wasm(hash) => f.debug_tuple("Wasm").field(hash).finish(), + Self::SmartContract(hash) => f.debug_tuple("smart contract").field(hash).finish(), Self::Instructions(instructions) => { f.debug_tuple("Instructions").field(instructions).finish() } diff --git a/core/src/smartcontracts/isi/triggers/specialized.rs b/core/src/smartcontracts/isi/triggers/specialized.rs index a3deafa5d83..9ff5d7a3ed6 100644 --- a/core/src/smartcontracts/isi/triggers/specialized.rs +++ b/core/src/smartcontracts/isi/triggers/specialized.rs @@ -127,9 +127,9 @@ pub struct LoadedAction { } impl LoadedAction { - pub(super) fn extract_blob_hash(&self) -> Option> { + pub(super) fn extract_blob_hash(&self) -> Option> { match self.executable { - ExecutableRef::Wasm(blob_hash) => Some(blob_hash), + ExecutableRef::SmartContract(blob_hash) => Some(blob_hash), ExecutableRef::Instructions(_) => None, } } diff --git a/core/src/smartcontracts/isi/world.rs b/core/src/smartcontracts/isi/world.rs index bb348f84475..7859184dc9b 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -402,7 +402,7 @@ pub mod isi { authority: &AccountId, state_transaction: &mut StateTransaction<'_, '_>, ) -> Result<(), Error> { - let raw_executor = self.executor; + let raw_executor = self.object; // Cloning executor to avoid multiple mutable borrows of `state_transaction`. // Also it's a cheap operation. @@ -410,7 +410,7 @@ pub mod isi { upgraded_executor .migrate(raw_executor, state_transaction, authority) .map_err(|migration_error| { - InvalidParameterError::Wasm(format!( + InvalidParameterError::SmartContract(format!( "{:?}", eyre::eyre!(migration_error).wrap_err("Migration failed"), )) diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 215d6d9a40b..04a23135665 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -713,7 +713,7 @@ impl Runtime> { (log_level, msg): (u8, String), state: &state::CommonState, ) -> Result<(), WasmtimeError> { - const TARGET: &str = "WASM"; + const TARGET: &str = "Smart contract"; let _span = state.log_span.enter(); match LogLevel::from_repr(log_level) @@ -745,7 +745,7 @@ impl Runtime> { store.limiter(|s| &mut s.store_limits); store .set_fuel(self.config.fuel.get()) - .expect("Wasm Runtime config is malformed, this is a bug"); + .expect("INTERNAL BUG: Smart contract config is malformed"); store } diff --git a/core/src/state.rs b/core/src/state.rs index 4b138674fd8..72ab80a9738 100644 --- a/core/src/state.rs +++ b/core/src/state.rs @@ -1464,7 +1464,7 @@ impl StateTransaction<'_, '_> { Executable::Instructions(instructions) => { self.process_instructions(instructions.iter().cloned(), &authority) } - Executable::Wasm(bytes) => { + Executable::SmartContract(bytes) => { let mut wasm_runtime = wasm::RuntimeBuilder::::new() .with_config(self.world().parameters().smart_contract) .with_engine(self.engine.clone()) // Cloning engine is cheap @@ -1500,7 +1500,7 @@ impl StateTransaction<'_, '_> { Instructions(instructions) => { self.process_instructions(instructions.iter().cloned(), authority) } - Wasm(blob_hash) => { + SmartContract(blob_hash) => { let module = self .world .triggers diff --git a/core/src/tx.rs b/core/src/tx.rs index 2b841f7bba2..6f7202c7f3a 100644 --- a/core/src/tx.rs +++ b/core/src/tx.rs @@ -134,7 +134,7 @@ impl AcceptedTransaction { // when executing wasm where we deny wasm if number of instructions exceeds the limit. // // Should we allow infinite instructions in wasm? And deny only based on fuel and size - Executable::Wasm(smart_contract) => { + Executable::SmartContract(smart_contract) => { let smart_contract_size_limit = limits .smart_contract_size .get() @@ -145,7 +145,7 @@ impl AcceptedTransaction { return Err(AcceptTransactionFail::TransactionLimit( TransactionLimitError { reason: format!( - "WASM binary size is too large: max {}, got {} \ + "Smart contract binary size is too large: max {}, got {} \ (configured by \"Parameter::SmartContractLimits\")", limits.smart_contract_size, smart_contract.size_bytes() @@ -232,21 +232,21 @@ impl TransactionExecutor { debug!("Validating transaction: {:?}", tx); Self::validate_with_runtime_executor(tx.clone(), state_transaction)?; - if let (authority, Executable::Wasm(bytes)) = tx.into() { - self.validate_wasm(authority, state_transaction, bytes)? + if let (authority, Executable::SmartContract(bytes)) = tx.into() { + self.validate_smart_contract(authority, state_transaction, bytes)? } debug!("Validation successful"); Ok(()) } - fn validate_wasm( + fn validate_smart_contract( &self, authority: AccountId, state_transaction: &mut StateTransaction<'_, '_>, - wasm: WasmSmartContract, + smart_contract: SmartContract, ) -> Result<(), TransactionRejectionReason> { - debug!("Validating wasm"); + debug!("Validating smart contract"); wasm::RuntimeBuilder::::new() .build() @@ -254,14 +254,14 @@ impl TransactionExecutor { wasm_runtime.validate( state_transaction, authority, - wasm, + smart_contract, self.limits.max_instructions, ) }) - .map_err(|error| WasmExecutionFail { + .map_err(|error| SmartContractExecutionFail { reason: format!("{:?}", eyre::Report::from(error)), }) - .map_err(TransactionRejectionReason::WasmExecution) + .map_err(TransactionRejectionReason::SmartContractExecution) } /// Validate transaction with runtime executors. diff --git a/data_model/src/executor.rs b/data_model/src/executor.rs index f03775cbe50..a4e1b36ac22 100644 --- a/data_model/src/executor.rs +++ b/data_model/src/executor.rs @@ -10,7 +10,7 @@ use iroha_primitives::json::JsonString; use iroha_schema::{Ident, IntoSchema}; pub use self::model::*; -use crate::transaction::WasmSmartContract; +use crate::transaction::SmartContract; #[model] mod model { @@ -48,8 +48,8 @@ mod model { // TODO: Derive with getset once FFI impl is fixed //#[getset(get = "pub")] pub struct Executor { - /// WASM code of the executor - pub wasm: WasmSmartContract, + /// Smart contract code of the executor + pub smart_contract: SmartContract, } /// Executor data model. diff --git a/data_model/src/isi.rs b/data_model/src/isi.rs index 60d6f2772ca..79a5e05ce75 100644 --- a/data_model/src/isi.rs +++ b/data_model/src/isi.rs @@ -252,7 +252,7 @@ mod transparent { iroha_data_model_derive::model_single! { /// Generic instruction for setting a chain-wide config parameter. - #[derive(Debug, Display, Clone, PartialEq, Eq, PartialOrd, Ord, Constructor)] + #[derive(Debug, Display, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(parity_scale_codec::Decode, parity_scale_codec::Encode)] #[derive(serde::Deserialize, serde::Serialize)] #[derive(iroha_schema::IntoSchema)] @@ -262,6 +262,13 @@ mod transparent { pub struct SetParameter(pub Parameter); } + impl SetParameter { + /// Construct a new [`SetParameter`] + pub fn new(parameter: impl Into) -> Self { + Self(parameter.into()) + } + } + isi! { /// Generic instruction to set key value at the object. #[schema(bounds = "O: Identifiable, O::Id: IntoSchema")] @@ -953,13 +960,20 @@ mod transparent { isi! { /// Generic instruction for upgrading runtime objects. - #[derive(Constructor, Display)] + #[derive(Display)] #[display(fmt = "UPGRADE")] #[serde(transparent)] #[repr(transparent)] pub struct Upgrade { /// Object to upgrade. - pub executor: Executor, + pub object: Executor, + } + } + + impl Upgrade { + /// Constructs a new [`Upgrade`] + pub fn executor(object: Executor) -> Self { + Self { object } } } @@ -1465,8 +1479,8 @@ pub mod error { #[ffi_type(opaque)] #[repr(u8)] pub enum InvalidParameterError { - /// Invalid WASM binary: {0} - Wasm(String), + /// Invalid smart contract binary: {0} + SmartContract(String), /// Name length violation /// /// i.e. too long [`AccountId`] diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index a86d786812b..c81153e8e53 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -18,7 +18,6 @@ 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 strum::FromRepr; @@ -371,9 +370,9 @@ mod model { ), /// Query execution failed QueryFailed(#[cfg_attr(feature = "std", source)] query::error::QueryExecutionFail), - /// Operation is too complex, perhaps `WASM_RUNTIME_CONFIG` blockchain parameters should be increased + /// Operation is too complex, perhaps `SmartContractParameter` limits should be increased /// - /// For example it's a very big WASM binary. + /// For example it's a very big smart contract binary. /// /// It's different from [`TransactionRejectionReason::LimitCheck`] because it depends on /// executor. diff --git a/data_model/src/parameter.rs b/data_model/src/parameter.rs index 546bb4a2455..576b942c385 100644 --- a/data_model/src/parameter.rs +++ b/data_model/src/parameter.rs @@ -20,6 +20,7 @@ mod model { use derive_more::{Constructor, Display, FromStr}; use getset::{CopyGetters, Getters}; use iroha_data_model_derive::IdEqOrdHash; + use iroha_macro::FromVariant; use iroha_schema::IntoSchema; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; @@ -155,7 +156,7 @@ mod model { pub struct TransactionParameters { /// Maximum number of instructions per transaction pub max_instructions: NonZeroU64, - /// Maximum size of wasm binary in bytes + /// Maximum size of smart contract binary in bytes pub smart_contract_size: NonZeroU64, } @@ -269,6 +270,7 @@ mod model { Eq, PartialOrd, Ord, + FromVariant, EnumDiscriminants, Decode, Encode, @@ -281,8 +283,16 @@ mod model { Sumeragi(SumeragiParameter), Block(BlockParameter), Transaction(TransactionParameter), - SmartContract(SmartContractParameter), - Executor(SmartContractParameter), + SmartContract( + #[skip_from] + #[skip_try_from] + SmartContractParameter, + ), + Executor( + #[skip_from] + #[skip_try_from] + SmartContractParameter, + ), Custom(CustomParameter), } } diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index 4520069e0b3..0cb00072b11 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -251,9 +251,9 @@ mod model { pub transaction: CommittedTransaction, } - /// Request type clients (like http clients or wasm) can send to a query endpoint. + /// Request type clients (like http clients or smart contract) can send to a query endpoint. /// - /// `Q` should be either [`http::SignedQuery`] for client or [`SmartContractQuery`] for wasm smart contract. + /// `Q` should be either [`http::SignedQuery`] for client or [`SmartContractQuery`] for smart contract. // NOTE: if updating, also update the `iroha_smart_contract::QueryRequest` and its encoding #[derive(Debug, Clone, Encode, Decode, Serialize, Deserialize)] pub enum QueryRequest { @@ -1034,7 +1034,7 @@ pub mod trigger { events::TriggeringEventFilterBox, prelude::InstructionBox, trigger::{Trigger, TriggerId}, - Executable, Identifiable, Name, + Identifiable, Name, }; queries! { diff --git a/data_model/src/transaction.rs b/data_model/src/transaction.rs index cc55718e155..658dbfa715f 100644 --- a/data_model/src/transaction.rs +++ b/data_model/src/transaction.rs @@ -34,7 +34,7 @@ mod model { use super::*; use crate::account::AccountId; - /// Either ISI or Wasm binary + /// Either ISI or smart contract binary #[derive( DebugCustom, Clone, @@ -55,10 +55,10 @@ mod model { #[debug(fmt = "{_0:?}")] Instructions(Vec), /// WebAssembly smartcontract - Wasm(WasmSmartContract), + SmartContract(SmartContract), } - /// Wrapper for byte representation of [`Executable::Wasm`]. + /// Wrapper for byte representation of [`Executable::SmartContract`]. /// /// Uses **base64** (de-)serialization format. #[derive( @@ -74,13 +74,13 @@ mod model { Serialize, IntoSchema, )] - #[debug(fmt = "WASM binary(len = {})", "self.0.len()")] + #[debug(fmt = "Smart contract binary(len = {})", "self.0.len()")] #[serde(transparent)] #[repr(transparent)] - // SAFETY: `WasmSmartContract` has no trap representation in `Vec` + // SAFETY: `SmartContract` has no trap representation in `Vec` #[ffi_type(unsafe {robust})] - pub struct WasmSmartContract( - /// Raw wasm blob. + pub struct SmartContract( + /// Raw smart contract blob. #[serde(with = "base64")] pub(super) Vec, ); @@ -191,20 +191,20 @@ impl> From for Executable { } } -impl From for Executable { - fn from(source: WasmSmartContract) -> Self { - Self::Wasm(source) +impl From for Executable { + fn from(source: SmartContract) -> Self { + Self::SmartContract(source) } } -impl AsRef<[u8]> for WasmSmartContract { +impl AsRef<[u8]> for SmartContract { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } -impl WasmSmartContract { - /// Create [`Self`] from raw wasm bytes +impl SmartContract { + /// Create [`Self`] from raw bytes #[inline] pub const fn from_compiled(blob: Vec) -> Self { Self(blob) @@ -381,7 +381,7 @@ mod candidate { mod base64 { //! Module with (de-)serialization functions for - //! [`WasmSmartContract`](super::WasmSmartContract)'s bytes using `base64`. + //! [`SmartContract`](super::SmartContract)'s bytes using `base64`. //! //! No extra heap allocation is performed nor for serialization nor for deserialization. @@ -490,12 +490,12 @@ pub mod error { Serialize, IntoSchema, )] - #[display(fmt = "Failed to execute wasm binary: {reason}")] + #[display(fmt = "Failed to execute smart contract: {reason}")] #[serde(transparent)] #[repr(transparent)] - // SAFETY: `WasmExecutionFail` has no trap representation in `String` + // SAFETY: `SmartContractExecutionFail` has no trap representation in `String` #[ffi_type(unsafe {robust})] - pub struct WasmExecutionFail { + pub struct SmartContractExecutionFail { /// Error which happened during execution pub reason: String, } @@ -540,7 +540,7 @@ pub mod error { /// and will be removed soon. InstructionExecution(#[cfg_attr(feature = "std", source)] InstructionExecutionFail), /// Failure in WebAssembly execution - WasmExecution(#[cfg_attr(feature = "std", source)] WasmExecutionFail), + SmartContractExecution(#[cfg_attr(feature = "std", source)] SmartContractExecutionFail), } } @@ -578,12 +578,14 @@ pub mod error { impl std::error::Error for InstructionExecutionFail {} #[cfg(feature = "std")] - impl std::error::Error for WasmExecutionFail {} + impl std::error::Error for SmartContractExecutionFail {} pub mod prelude { //! The prelude re-exports most commonly used traits, structs and macros from this module. - pub use super::{InstructionExecutionFail, TransactionRejectionReason, WasmExecutionFail}; + pub use super::{ + InstructionExecutionFail, SmartContractExecutionFail, TransactionRejectionReason, + }; } } @@ -671,9 +673,9 @@ mod http { self } - /// Add wasm to this transaction - pub fn with_wasm(mut self, wasm: WasmSmartContract) -> Self { - self.payload.instructions = wasm.into(); + /// Add smart contract to this transaction + pub fn with_smart_contract(mut self, smart_contract: SmartContract) -> Self { + self.payload.instructions = smart_contract.into(); self } @@ -738,7 +740,7 @@ pub mod prelude { #[cfg(feature = "http")] pub use super::http::TransactionBuilder; pub use super::{ - error::prelude::*, CommittedTransaction, Executable, SignedTransaction, WasmSmartContract, + error::prelude::*, CommittedTransaction, Executable, SignedTransaction, SmartContract, }; } @@ -751,7 +753,7 @@ mod tests { #[test] fn wasm_smart_contract_debug_repr_should_contain_just_len() { - let contract = WasmSmartContract::from_compiled(vec![0, 1, 2, 3, 4]); - assert_eq!(format!("{contract:?}"), "WASM binary(len = 5)"); + let contract = SmartContract::from_compiled(vec![0, 1, 2, 3, 4]); + assert_eq!(format!("{contract:?}"), "Smart contract binary(len = 5)"); } } diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index cc0e92764f5..66c7a4a0315 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -23,7 +23,7 @@ pub trait Visit { // Visit SignedTransaction visit_transaction(&SignedTransaction), visit_instruction(&InstructionBox), - visit_wasm(&WasmSmartContract), + visit_smart_contract(&SmartContract), visit_query(&QueryBox), // Visit InstructionBox @@ -150,7 +150,9 @@ pub fn visit_transaction( transaction: &SignedTransaction, ) { match transaction.instructions() { - Executable::Wasm(wasm) => visitor.visit_wasm(authority, wasm), + Executable::SmartContract(smart_contract) => { + visitor.visit_smart_contract(authority, smart_contract) + } Executable::Instructions(instructions) => { for isi in instructions { visitor.visit_instruction(authority, isi); @@ -213,10 +215,10 @@ pub fn visit_query(visitor: &mut V, authority: &AccountId, qu } } -pub fn visit_wasm( +pub fn visit_smart_contract( _visitor: &mut V, _authority: &AccountId, - _wasm: &WasmSmartContract, + _smart_contract: &SmartContract, ) { } diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index e6a73f5bedc..59aa9c0470f 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -1350,9 +1350,9 @@ "type": "Vec" }, { - "tag": "Wasm", + "tag": "SmartContract", "discriminant": 1, - "type": "WasmSmartContract" + "type": "SmartContract" } ] }, @@ -1412,8 +1412,8 @@ "Executor": { "Struct": [ { - "name": "wasm", - "type": "WasmSmartContract" + "name": "smart_contract", + "type": "SmartContract" } ] }, @@ -2223,7 +2223,7 @@ "InvalidParameterError": { "Enum": [ { - "tag": "Wasm", + "tag": "SmartContract", "discriminant": 0, "type": "String" }, @@ -3755,6 +3755,15 @@ } ] }, + "SmartContract": "Vec", + "SmartContractExecutionFail": { + "Struct": [ + { + "name": "reason", + "type": "String" + } + ] + }, "SmartContractParameter": { "Enum": [ { @@ -4071,9 +4080,9 @@ "type": "InstructionExecutionFail" }, { - "tag": "WasmExecution", + "tag": "SmartContractExecution", "discriminant": 4, - "type": "WasmExecutionFail" + "type": "SmartContractExecutionFail" } ] }, @@ -4476,7 +4485,7 @@ "Upgrade": { "Struct": [ { - "name": "executor", + "name": "object", "type": "Executor" } ] @@ -4538,15 +4547,6 @@ "Vec": { "Vec": "u8" }, - "WasmExecutionFail": { - "Struct": [ - { - "name": "reason", - "type": "String" - } - ] - }, - "WasmSmartContract": "Vec", "u128": { "Int": "FixedWidth" }, diff --git a/genesis/src/lib.rs b/genesis/src/lib.rs index 49c9526deff..695d6d893d5 100644 --- a/genesis/src/lib.rs +++ b/genesis/src/lib.rs @@ -140,7 +140,7 @@ fn build_transactions( chain_id: ChainId, genesis_key_pair: &KeyPair, ) -> Vec { - let upgrade_isi = Upgrade::new(executor).into(); + let upgrade_isi = Upgrade::executor(executor).into(); let transaction_executor = build_transaction(vec![upgrade_isi], chain_id.clone(), genesis_key_pair); let mut transactions = vec![transaction_executor]; @@ -180,7 +180,7 @@ fn build_transaction( fn get_executor(file: &Path) -> Result { let wasm = fs::read(file) .wrap_err_with(|| eyre!("failed to read the executor from {}", file.display()))?; - Ok(Executor::new(WasmSmartContract::from_compiled(wasm))) + Ok(Executor::new(SmartContract::from_compiled(wasm))) } /// Builder type for [`GenesisBlock`]/[`RawGenesisTransaction`] @@ -331,7 +331,7 @@ mod tests { use super::*; fn dummy_executor() -> Executor { - Executor::new(WasmSmartContract::from_compiled(vec![1, 2, 3])) + Executor::new(SmartContract::from_compiled(vec![1, 2, 3])) } #[test] @@ -395,7 +395,7 @@ mod tests { panic!("Expected instructions"); }; - assert_eq!(instructions[0], Upgrade::new(dummy_executor()).into()); + assert_eq!(instructions[0], Upgrade::executor(dummy_executor()).into()); assert_eq!(instructions.len(), 1); } diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index 83ca017e11e..3bf80d52264 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -360,6 +360,8 @@ types!( SignedQueryV1, SignedTransaction, SignedTransactionV1, + SmartContract, + SmartContractExecutionFail, SmartContractParameter, SmartContractParameters, SocketAddr, @@ -422,8 +424,6 @@ types!( Vec, Vec, Vec, - WasmExecutionFail, - WasmSmartContract, [u16; 8], [u8; 32], [u8; 4], diff --git a/smart_contract/README.md b/smart_contract/README.md index 5231e044444..e5e8e6a9ecb 100644 --- a/smart_contract/README.md +++ b/smart_contract/README.md @@ -1,10 +1,10 @@ -# Iroha WASM +# Iroha Smart Contract The library crate that is used for writing Iroha-compliant smart contracts in Rust using the WebAssembly format. ## Usage -Check the [WASM section of our tutorial](https://hyperledger.github.io/iroha-2-docs/guide/blockchain/wasm.html) for a detailed guide. +Check the [Smart Contract section of our tutorial](https://hyperledger.github.io/iroha-2-docs/guide/blockchain/smart_contract.html) for a detailed guide. ## Running tests @@ -20,7 +20,7 @@ Then run tests: cargo test ``` -## Reducing the size of WASM +## Reducing the size of smart contracts Since smart contracts are stored directly on the blockchain, you would want to reduce their size. By following this list of optimization steps you can reduce the size of your binary by an order of magnitude @@ -67,5 +67,5 @@ By following this list of optimization steps you can reduce the size of your bin $ wasm-opt -Os -o output.wasm input.wasm ``` -Following these steps is the bare minimum that can be done to all WASM smart contracts. +Following these steps is the bare minimum that can be done to all smart contracts. We encourage you to profile the binaries [using twiggy](https://rustwasm.github.io/twiggy/) to further reduce their size. diff --git a/smart_contract/derive/src/entrypoint.rs b/smart_contract/derive/src/entrypoint.rs index 081651fc878..e0e3d6dc8ae 100644 --- a/smart_contract/derive/src/entrypoint.rs +++ b/smart_contract/derive/src/entrypoint.rs @@ -50,7 +50,7 @@ pub fn impl_entrypoint(emitter: &mut Emitter, item: syn::ItemFn) -> TokenStream #fn_name(payload.owner) } - // NOTE: Host objects are always passed by value to wasm + // NOTE: Host objects are always passed by value to the smart contract #[allow(clippy::needless_pass_by_value)] #(#attrs)* #[inline] diff --git a/smart_contract/executor/data_model/derive/src/parameter.rs b/smart_contract/executor/data_model/derive/src/parameter.rs index e98e4abbf25..3baf2082ff5 100644 --- a/smart_contract/executor/data_model/derive/src/parameter.rs +++ b/smart_contract/executor/data_model/derive/src/parameter.rs @@ -12,10 +12,10 @@ pub fn impl_derive_parameter(input: &syn::DeriveInput) -> TokenStream { quote! { impl #impl_generics ::iroha_executor_data_model::parameter::Parameter for #ident #ty_generics #where_clause {} - impl #impl_generics TryFrom<&::iroha_executor_data_model::parameter::CustomParameter> for #ident #ty_generics #where_clause { + impl #impl_generics TryFrom<&::iroha_data_model::parameter::CustomParameter> for #ident #ty_generics #where_clause { type Error = ::iroha_executor_data_model::TryFromDataModelObjectError; - fn try_from(value: &::iroha_executor_data_model::parameter::CustomParameter) -> core::result::Result { + fn try_from(value: &::iroha_data_model::parameter::CustomParameter) -> core::result::Result { let value_id = iroha_data_model::Identifiable::id(value); if *value_id != ::id() { @@ -26,9 +26,9 @@ pub fn impl_derive_parameter(input: &syn::DeriveInput) -> TokenStream { } } - impl #impl_generics From<#ident #ty_generics> for ::iroha_executor_data_model::parameter::CustomParameter #where_clause { + impl #impl_generics From<#ident #ty_generics> for ::iroha_data_model::parameter::CustomParameter #where_clause { fn from(value: #ident #ty_generics) -> Self { - ::iroha_executor_data_model::parameter::CustomParameter::new( + ::iroha_data_model::parameter::CustomParameter::new( <#ident as ::iroha_executor_data_model::parameter::Parameter>::id(), ::serde_json::to_value::<#ident #ty_generics>(value) .expect("INTERNAL BUG: Failed to serialize Executor data model entity"), diff --git a/smart_contract/executor/data_model/src/parameter.rs b/smart_contract/executor/data_model/src/parameter.rs index 9756548efb7..c838e4533cc 100644 --- a/smart_contract/executor/data_model/src/parameter.rs +++ b/smart_contract/executor/data_model/src/parameter.rs @@ -1,6 +1,5 @@ //! Module with parameter related functionality. -pub use iroha_data_model::parameter::CustomParameter; use iroha_data_model::parameter::CustomParameterId; pub use iroha_executor_data_model_derive::Parameter; use iroha_schema::IntoSchema; diff --git a/smart_contract/executor/derive/src/entrypoint.rs b/smart_contract/executor/derive/src/entrypoint.rs index e546eb69809..5f5a4e75ebe 100644 --- a/smart_contract/executor/derive/src/entrypoint.rs +++ b/smart_contract/executor/derive/src/entrypoint.rs @@ -119,7 +119,7 @@ fn impl_validate_entrypoint( bytes_box.as_ptr() } - // NOTE: Host objects are always passed by value to wasm + // NOTE: Host objects are always passed by value to the smart contract #[allow(clippy::needless_pass_by_value)] #(#attrs)* #[inline] diff --git a/smart_contract/executor/src/default.rs b/smart_contract/executor/src/default.rs index 4e01bc24c00..08ec075545a 100644 --- a/smart_contract/executor/src/default.rs +++ b/smart_contract/executor/src/default.rs @@ -54,14 +54,16 @@ use crate::{ /// # Warning /// /// Each instruction is executed in sequence following successful validation. -/// [`Executable::Wasm`] is not executed because it is validated on the host side. +/// [`Executable::SmartContract`] is not executed because it is validated on the host side. pub fn visit_transaction( executor: &mut V, authority: &AccountId, transaction: &SignedTransaction, ) { match transaction.instructions() { - Executable::Wasm(wasm) => executor.visit_wasm(authority, wasm), + Executable::SmartContract(smart_contract) => { + executor.visit_smart_contract(authority, smart_contract) + } Executable::Instructions(instructions) => { for isi in instructions { if executor.verdict().is_ok() { diff --git a/smart_contract/executor/src/lib.rs b/smart_contract/executor/src/lib.rs index a280572cdf9..6a44359825a 100644 --- a/smart_contract/executor/src/lib.rs +++ b/smart_contract/executor/src/lib.rs @@ -26,7 +26,7 @@ pub mod utils { } pub mod log { - //! WASM logging utilities + //! Smart contract logging utilities pub use iroha_smart_contract_utils::{debug, error, event, info, log::*, trace, warn}; } diff --git a/smart_contract/src/lib.rs b/smart_contract/src/lib.rs index ee6e2ac2c0f..002ea906680 100644 --- a/smart_contract/src/lib.rs +++ b/smart_contract/src/lib.rs @@ -37,7 +37,7 @@ extern "C" fn _iroha_smart_contract_alloc(len: usize) -> *const u8 { } /// # Safety -/// - `offset` is a pointer to a `[u8; len]` which is allocated in the WASM memory. +/// - `offset` is a pointer to a `[u8; len]` which is allocated in the smart contract memory. /// - This function can't call destructor of the encoded object. #[no_mangle] unsafe extern "C" fn _iroha_smart_contract_dealloc(offset: *mut u8, len: usize) { diff --git a/smart_contract/trigger/derive/src/entrypoint.rs b/smart_contract/trigger/derive/src/entrypoint.rs index 29723cd3511..a4ac32f2d47 100644 --- a/smart_contract/trigger/derive/src/entrypoint.rs +++ b/smart_contract/trigger/derive/src/entrypoint.rs @@ -50,7 +50,7 @@ pub fn impl_entrypoint(emitter: &mut Emitter, item: syn::ItemFn) -> TokenStream #fn_name(payload.id, payload.owner, payload.event) } - // NOTE: Host objects are always passed by value to wasm + // NOTE: Host objects are always passed by value to the smart contract #[allow(clippy::needless_pass_by_value)] #(#attrs)* #[inline] diff --git a/smart_contract/trigger/src/lib.rs b/smart_contract/trigger/src/lib.rs index 413f6f2be77..e31d790207f 100644 --- a/smart_contract/trigger/src/lib.rs +++ b/smart_contract/trigger/src/lib.rs @@ -12,7 +12,7 @@ pub use iroha_trigger_derive::main; pub use smart_contract::{data_model, stub_getrandom}; pub mod log { - //! WASM logging utilities + //! Smart contract logging utilities pub use iroha_smart_contract_utils::{debug, error, event, info, log::*, trace, warn}; } diff --git a/smart_contract/utils/src/debug.rs b/smart_contract/utils/src/debug.rs index ef1780accd3..d06fc602c3a 100644 --- a/smart_contract/utils/src/debug.rs +++ b/smart_contract/utils/src/debug.rs @@ -1,4 +1,4 @@ -//! WASM debugging utilities +//! Smart contract debugging utilities #[cfg(feature = "debug")] use alloc::format; @@ -25,10 +25,10 @@ mod host { /// Print `obj` in debug representation. /// -/// When running as a wasm smart contract, prints to host's stdout. -/// Does nothing unless `debug` feature is enabled. +/// When running on a smart contract VM, prints to the host logging system. +/// Otherwise, prints the output along with its level to stderr /// -/// When running outside of wasm, always prints the output to stderr +/// Does nothing unless `debug` feature is enabled. #[allow(unused_variables)] pub fn dbg(obj: &T) { cfg_if! { @@ -85,7 +85,7 @@ impl DebugUnwrapExt for Result { Ok(out) => out, Err(err) => { dbg(&format!( - "WASM execution panicked at `called Result::dbg_unwrap()` on an `Err` value: {err:?}", + "Smart contract panicked at `called Result::dbg_unwrap()` on an `Err` value: {err:?}", )); panic!(""); } @@ -107,7 +107,7 @@ impl DebugUnwrapExt for Option { match self { Some(out) => out, None => { - dbg("WASM execution panicked at 'called `Option::dbg_unwrap()` on a `None` value'"); + dbg("Smart contract panicked at 'called `Option::dbg_unwrap()` on a `None` value'"); panic!(""); } } @@ -140,7 +140,7 @@ impl DebugExpectExt for Result { match self { Ok(out) => out, Err(err) => { - dbg(&format!("WASM execution panicked at `{msg}: {err:?}`",)); + dbg(&format!("Smart contract panicked at `{msg}: {err:?}`",)); panic!(""); } } @@ -161,7 +161,7 @@ impl DebugExpectExt for Option { match self { Some(out) => out, None => { - dbg(&format!("WASM execution panicked at `{msg}`",)); + dbg(&format!("Smart contract panicked at `{msg}`",)); panic!(""); } } diff --git a/smart_contract/utils/src/lib.rs b/smart_contract/utils/src/lib.rs index 971177c09fe..c76015130ae 100644 --- a/smart_contract/utils/src/lib.rs +++ b/smart_contract/utils/src/lib.rs @@ -1,6 +1,7 @@ //! Crate with utilities for implementing smart contract FFI -// do not use `no_std` when not running in wasm -// this is useful to implement `dbg` and `log` functions for host-side tests + +// not using `no_std` when not running outside of wasm so that +// `dbg` and `log` functions work for host-side tests #![cfg_attr(target_family = "wasm", no_std)] #![allow(unsafe_code)] diff --git a/smart_contract/utils/src/log.rs b/smart_contract/utils/src/log.rs index d42255aee72..b2ab6760f60 100644 --- a/smart_contract/utils/src/log.rs +++ b/smart_contract/utils/src/log.rs @@ -1,4 +1,4 @@ -//! WASM logging utilities +//! Smart contract logging utilities use cfg_if::cfg_if; pub use iroha_data_model::Level; @@ -21,10 +21,8 @@ mod host { /// Log `obj` with desired log level /// -/// When running as a wasm smart contract, -/// prints to the host logging system with the corresponding level. -/// -/// When running outside of wasm, prints the output along with its level to stderr +/// When running on a smart contract VM, prints to the host logging system. +/// Otherwise, prints the output along with its level to stderr pub fn log(log_level: Level, obj: &T) { cfg_if! { if #[cfg(not(target_family = "wasm"))] {