From fc4640903b4294584062bc7cd7cb136e73351f5b 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 501671 -> 501239 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 | 32 ++--- 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, 294 insertions(+), 272 deletions(-) diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 59cb2d91821..93566e5a3df 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -825,7 +825,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 624f454d82c..9af7031166e 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 8e6984ac0ca..6568900134c 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: InstructionBox = 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 f48fbf521f5..a5872f8f7f6 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: InstructionBox = Register::domain(Domain::new("domain".parse()?)).into(); 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 5fa97a5f231..99c9a9e7a61 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 ffd131e1b0b..b397877b47c 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 9d7c01bd745..2980400920d 100644 --- a/client/tests/integration/upgrade.rs +++ b/client/tests/integration/upgrade.rs @@ -405,8 +405,7 @@ fn define_custom_parameter() -> Result<()> { let parameter = DomainLimits { id_len: 2_u32.pow(6), - } - .into(); + }; let set_param_isi: InstructionBox = SetParameter::new(parameter).into(); client.submit_all_blocking([set_param_isi, create_domain.into()])?; @@ -422,9 +421,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 b45c53ad2b6..3f72f0a0913 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 }) } } @@ -1006,15 +1006,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, } @@ -1022,21 +1022,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 0fefcfab3a16f99bf13394c0edce678eef5e1c23..75e483f120aaa20f4bdb81ade0a2aef22947d6e7 100644 GIT binary patch delta 71847 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 wsWrEGlDFZbAmxg2xWmgfM}09uR4egFUf delta 72202 zcmdSC2Yi&p)<3>8^K417ArBBpPc{i9lu)Ee5!fgoD$R}!3$}m-uh)9735XDi5b_Wv z)PS_m0|63x=%EKisVYqcK?qG+fZzAbvl})L@Bj6^_kTaHQTBPJojG&n%$YN1&dhUp zTlCCb(Yc*@70xZpVzDs#p$Fr}vpl0J!g$v-i^go4#S&!EEXEDq!6^jSxYc6eR;C#} zMD^+x1pKUk!ML!7aK>$R#vR6|qJB+3z_w`kp$9+#hWfEsteVAPR>_U6BFZ=+W=8=g z=M34I#_&de!hs*4fvU2!hf{!`rlC6gZv!O8HO*$%6y}Ixnq3R8s@tg<8q;h*%dSy~ zTEHz z>umXc%QmmG1f*Epg~kATP4=x(Y>zO;vjA@S4zIP@_r?`_EIVw3JHpv7Ml;82DOIXY z_lrMizrW*bcG`ZC?-JjNonojqLffKk;(PdVK1Q6<&S+<~675&*f_70GXgk3#@Kpbw z`6c`B_MiA6zQul8o96cm|BavJzw$La)$yDClzlxP$4ytNFM5Fh9cg zi4BMyW4oknwp)Mm`$^km#Q0T9`C0qideMH?e#L&(e%U_6QDi@=UAJGe4|06r80t7< zAM65Cj-h^o{f7Hp zcU*N0^Xu<-+HuBF>bT(;;`f_lkl!sws^2xoML)yOf7{T=iT;z(e<|^nyga{iEM*>N zwiMCcoeMgupG1o#PPmy%M6|M4TtaK_Nkn|0CBVr70^An2!)0;dw@XBySStd|#VFvm zC%ZrD7iV$bx+Rk1m^(G~AN^u&NYg)vwYwLihFB)rbNVlZw|B8Pk&wbI$e7YeLok7B zE|wg}U6w9^Ru>+9T-JVZi0f5e}7He@aCl7Gh+nc2Wh1(LVQ4A8AbKs_m zHwQrBvZ#mzZV8Cxz*M8UxC>zWAiWzJM7fcSYyl=2EYxx>D1b13-(}MSJ-9n90hWO8 z851eg_&Zw7lVgQ@v2o2=6kU#%9JJ($mfWPJaX2v8p|YSJV|sWkrW@PCUuTt#rV-QG zO5;GpLsf%a7QGr_H4udpcpB5I8!aLw3o&*@&SRm*Kck+i9R~FJr>3TU)SNq1!`<60 z$-3^;0?dK|v6{9T+_^rPvUjf~Kz_$nsP<=evjOu8|BwNWW7p-O7bI?zvd zu_V@lM*=ZnJQ((naWS?bKdi}R2l-%QZrnp`tsHiUw=f#ShXa+)@$tsZ!0s&4=vL`o z7GP^lH$rd1;*53r-*k<5fxAU>jAA@j8XYS86xptd6jPB&l}EB@qd}F&P;fw%Q!Lkb zyJ|cr_e;&5Y)Rhfsl*70h*ULs9Gh~VjYofG6&ncG<`h$UAp+(;zKMS&j+ltKhNkO(K+dlJs zZIG=+keLVkZ}zv*CqBZTI-pUqOXx9q>G2I1bLFk6QJb-%ykBY_W^9B}RQnAOx^Y6= zfP<(KJZjO`bGhpwR>zo{@G<*A#(oGC3yijP>e;r>SZmSqjd$vFW4{|~>a?+~T!Dzs z4OVwJ`@tAdw>I*{ex1Y$WY;dNHlkwdwMU@xG8T`Nb64JPnPO?N_rzb|It5BetBC)L6-qnM8JQAet-JCS!yY$WJNs zgKVG5sKNbHsljqoA7-{VO15jtg3#=4P0{T6OVMnrr`ZC{rcr%SrZi=p*;!e6E&H5p zlU=#(oc&Yna#^u%%K!k<;!j1WDqFAtT?xl`KmHTF6=$7R-BHH&g z^q2gMHf<+)@?L7|&D*nGepy})Hj8Ng08y0ye&Y6I%KO1Ro3Y@$A@@HV-F zdSq(_SUG{!YsR!LDZ=Hl8t?W9HQIJ1FfTpwgmJ8ERpaFA!N&OH%ErmAuc_FM#+Yse zz8Dy*KKi?{vwJp>n35K5r1kJ(+WnIdLp)ly!~I~X^gP7p3< zC1d2HO^oMy`XSG2JsWFCT+^$A5%iQT@7VJPDeszIZvk%Ni+#&5N1HwLtgPr6_L8^e zZ(c&pdFNiL%0h^kss1zHp!gMyKRW ze^BZzC6`yfjE;y*2dslA6^2!;X1Nz6>o_i}AwHF2=imi%|o* z%gD(d8aUE#)1aDhA{|2^{R}G6+_|=77kJf}XuNH#%5fMsN4*6u;>N-mp~j#LD)qsv zj>fMUIlj5`CK`&oi$=FYhK1Q3je9fevk2qW%zIc+URGuTk#_Bv$(WRh$`0)SD6ta$v^pBifP&uR|d(cDGQK+VxphEd+mEY-=yV`BnHvDk+x!R4|UD@TVK zRmKrwRPP7l%IY<;GNbY?jDz|_bw6i3H{k(Qe@3~w2TiQuseApz-l~u7=;H>H6y^J6 zo9%he+ZF}${mBYu|0&+~y!}vO_)=?@IcKjM*Or(s3~kZb>{6>wV(bralwKa z;DWqgW;{>5SC(pY%Q>SG!;PnBp^14P%nD+m(O^S#q)8Kc)LB%FeMj1$sG!I4#iM#1i?<98QY#;FM#W%c~c?l-j~mTv`WnDdf=e?KD5D))g477AMqP zWOr8fMC93>y61JV-HX1y5HJk);xJ?KVn@h)yR(WX%YxelbB#5NL)a{1@8W3Z+}qLf z47MaX1QFgM^KPfjG+;fpr*nGkqpg*kQ1bw>ra(k;|$@O|Uw{ z%5n&w922e1P-E?~YT=Wt&XBSkR-YW%#;qlx&dFA1H4oNiy)BnEW8;i>mWFDj3?QhI zQNAF2E16<-R#%mLrJ#5a^{u4TIK4D95Rj^xm7v>6|`=e)k}A8 z_LTh4n#hhWs5rZapY$b)bYJH;XVZ;^1)*$)5m!*7=1j#{6_m`emND@{RkD9UL-Z9& zYO_&BHGYoD<0O^TjPZ!NmAg?T|6P2qXD*(CB>U0p|&P7(I-KSVPEUB`WhiXW-Q94^>>|S2= zzS(v+OV+2;`pHi*2e>QGN^4pZHgTL5$MhMu^Z9%8EjD6Tv|zW4o+}!&CB`s%m!+p! z4da&;ZP*c`#>zw{jYn60$ggZNwylijS4J48R@P((jmoPM*de3Us_EUaiWBY=w^wn( zorQVCZm!})9kCCqjs)0r%vBs-(*>>KP%42>v$|~b%(22|f#+N+mdp)T*QIqGf?2|6 zU1!&q8SkvlU_a#XHU12I5m;C!;*cHY1x$3X&A9bGalD2pb08zP8$Akhv0&&n2t%$w zzB`E3u}zpsiw>DRh&{|oj7e*gY(;a`@~Tl$9nmgD#`f_$)k@b1GY%xK19K145v4-v zN7HxZHQp4??r8E#wV?EE@}YTujV9NV9f!eq^UU@a*>+>a_TDC=r9qIAg#hLP;VwYH zuZ+>I2;!Mkt&Guf>D6Sk4K|mZQj2URqiwf=(cami3*+XS;+#!MQhkh9Lahf3+O6$SFu$!ZtiW2 zvCwE=%fQW^sSSn${g&~;z7JDY=3sOL)9Aqbj6v_dLJ?JcA}-SSsqPbTd^RG&d?F6b zK}5Ju#6FBzcbree()p1(zr`4Nn%=L4LhY#SJ)ZYt5AcyfPW5BG$+YX|&szC^g?Z1VwPqu@Tpe!>bJoNh=GNSW zTt|-g{Mj??sNCVtUS(g&CIPG$yOnPQz}CeJnH+VGEnK!+WAl@{o$NH^&)QL}7UqsX zh&sQO(`bsb!6;WbgGD%U5OfQDxoljCJ%MRv!6sHiVx18rmm>m}I_8F@4ogoN7R0tN zSN^deX61LxA%}eCkdtcKyaMKcRq}s3ZO$UzvJ+bb-kvs3`A(Z#&1ut<@qayS){}>; zvv2&SOh$d@EqbY38N!xpu7Gzfa`g;bh#VEl9$+r{T_}6MS%ubUb8`8g*rFq&(4%@Y zm>O+*5##M?nkKt+$3Sce=yT=HF!nCnlHV?zWi!7;*+A&52ch2b;YdvWcc>~5mE~2H z?U0232F?F#s!F~5!?7^MqCF*XECzh3$3yihHC3;6@$5l%TJ9dsTG>heuiQq<+Z-BN*vlDK$y|k||%q(z}?1zsX6M{gtKH zuAh+$zGgidc+ze&57~CHCO%|~1LI*|4trk|fi4qZjRxPaPHek8H4+_EAcv*1cSsTQ z7<`e74BcyMv(%Jg78C$=GnIMu&3%^SIDv_g_S&$2%^OpDl)T(D1LY#n2gT(PVH0Ya$0VVzDe* z<}_l5(Kz3Ih2ct8p>@9d3ezy#{e|`w^0BXgxu?89IHbDGROC$|oP(+J-w+7@9U&}N z_hLz^w_1GThfB#0C{(C}BLdb>4oCnnC@)dN$?-q0yp^*Ny1YLfQ zhoH@umm4d6mNsf@vJ^V=|8=>MkFCiX)DT}8QCg9Vm<*-)FC-%*WW-}*UW7o5eTEg^ zF|OvCJgDp(rmUC?z5Cx7SN|PZkq=qXm6T7P+3JuF*O?1ytf~I5bDi1{mv6nnrrp7L z+r4wI@9eY>OTNDt=e3cqe*y8A{O(<>cls{YE5I7?|2*r##Ae!?Wakg=RG3zJJI(8p zu?LIxzYGf|$XWkn|G0w>OVujz4lQXhEDe7}KK$hl>37;kt1zYC9vCM6GAwu=&GA(z zCYY;l-<8uqwfz38t(@+WZAP(yXq~UUV($OUUU6q1&oznSW69qGQ{unT$Nxpm@yje0 z5qJXnmAhec-Ug3688wbIWh>>cS?mG-+fHI~@;LT}oII92P$gC^8}&Fm$a^m?V6z;N z#lizm5}5iXn4|v!%+#u3CWLT2$mcOU;97v}wTO+9#pASUvUEKA1C5)R%~9;j_Njk4J(>&#_sG(j zY%j-Mno;04f}>mCd^@bFj#zap}BWX zL?v+V`%6qj`Ohz6Z)@dSbK0wgd#BYj*w6nGts%`WK|a3fu4#3yGTPlSt(K~0{k5DL zD^mGudrbwcCpk2vVVk~8#ul;ZKy`BwTh0#2 z0b5vn?R@NxCP2R8r@dall=F32xEa~YiXjJGa{CsR=(h}+-NDH)l=H3Z6}Cjaww29E zS;~|b10}RJEp5oh+>yy}8dlCEWPEcW1{n}Tg3awp*6aD?ZKP7j<%WtiR^A^S0s|3* zB@$)GqlKV!P!2eVjODz&=RcXgjaBgj5&#TGaXDuj8{Bvisz5MVSua)PHB9V6la+6( zH;Rx5O%6b@SGKbkAx}1JXaB@wcVAnS?6re+!~23A4C{P(Z3kP=^7SGo(Ieb6sz=p`L_e1V)mN)lf)UA>E2Uy+cx}qPwg3;g@F;61Lyp1OV~Kp=7;AU`in2D5uA}&fR3G(1nvi;F9pHUiT9&$Nfdz3}s1cQ9%rZt{jm%kpvR?150f1JfST>$}p*o$}PaJ`aDJdP#!m-6OuR$IoO z?awT-@;BHnaB(Vt z><~1=^85VEUS`O(^A{F&FI>mklive;{kcBhZu%OT5jcia#$5BP&bHocbu4fZlrbk* zSQz}q+W16cN`OZol4r>tNM=)HpA)Rs^Er2dwR?FMZfVUcEPrPShqnZLt(y9j03v5l z6S>0OBVDIiFxurh$-?eOyBhiAyN%hMkOO=mH}EL|$o~MK*8#b{H(K9#XX!w1=?!*g z-Lh*wvqo9A1$Snv?9B$ZwKy{y zHu7gOXRNo3*@OLmWnoRwJh-)*{a+5DJD~=9p-z!Ie#Kte3R&$Gs}Z@@dI!sdd-IL5 z$|p{-7;S|W3lC4%e0hq6aU|rN!hZXDxf?;kz~g%dy}_3xcVgi3LY^X{PP34DcU2wh z&4A8_Lta^<(3QPTgB?rd$ER7H==FD^T+>?)s0fAX-OZ}y%>(R9PP19nu46E{6Z*z- zfz4p8y^HpN*US08vF4$rEI>yP0}A>M`dA-r4T#2=mL>UGH7oLswaV&e*jwy~9C!w^ z!V#H!20NigWXT!Uf^C!uXIUIGq{)W>Kup(oOFWA6>}fPo~K=(Bj32h9%UJF#U(ZpkB5I}u_*?J(uMc*s|%Fl$FkiIaH-8 z9^P+=cheaqJC41L;n>YZu2i@k3efNrkZ_!sV82#3UNI|_P>hd@j;n;m9>RddiE+bOP74?8fJ=PGW8k@M~9BT z#>Vj@%ve|$EFZoO^Y;-ZA6aP)lltFa+b_6|lWybX&g<++HbK@b#T+zIjw@x4u}Shw zDf=2*>1%JW2`pQ_a1$eLa{i2)%e#uc3ghUcw_dH zoWuCTNV`mF$7C3X0&qmO;=C^VO}@%`17sP^`FM6fHWEA(Svm`ziY!}&Zeo=l` zKaLHcBl2(lym9O?FB&)~3R%LBYjOT9L@`z<;Etn=x0j)TJd$maNBudr_GIk<;B-{( z4&YV&k?~!XZ>YfY&!OM*+gw07d3lC+`tUkj?fJTX|~^ zEUS5wG@Sf3(CV5KwVUKph)YDR`&qL?uEAc0wKzKSLNX`r3@u=)@C3O8yk_CZ`N9AKd3X$bO3X#1*JQ|h% z9t1LMkTF$w2f$C(`3t~xi;gUN<&i4jstq!{GSZI87c2906gXG;PZaoA?x~8-J|@pp z1wyxEm0;eDe{Pqr1oMADK{y=DTLWZdH6(77?W^%le3Mlk3FdY37ggh{S=}3S>{z)a z-Yk2&RrZ!jO0G(UM%Q<|mgrFV85nQMcr8+%3gL}Ciz=oTRY*a8wWxx>n_5(rMb$%! zxv1(A%6ox7=Y;}Cm#iDcU$;WFbJ}H>FrFyahhgBIl-6+G@ljWRoAJB-llKafCmeA? z$r|+FYIBhaCc{{9>ZMpWaPwF(O%^1O+zi=P%8B9pL6H9EaNelFo$|_|c=QJ)#Yz}y zXq`-Xbr_@0B_D|3L#;T;qyH$siGYxRuyRC#BbSYobt8ErNULWfF}e=PVUc_kS{4j56PX;{6ltVX2%%L z!V0bA-%i79B+9z?K+AFe3a;lSbAiOfWQ;UgfR; zxX_HL%V)vdIlC@zRwWalTz<5`Q*RE;6X)vkNLvP+i1dv7s`dCYtcBq@_$yhE;!JLUC3M?+h+?IgZ5_bt;{@h4W^5w?-9yUm3Hs}NySK8 z6JDb=BDlMddcmPsLWNIIm}oG7QqwmB1^`fD)hN(e)B6kgY7<_s&gT>fcWY7;&@adX z_j)rka{(sB5U5hQtO@TDHC(vu@BgipWiXD?!_&${kh{}}cEvKjDSw__lKq?VkDAOt zDUcp!mof0S0)#AOW!m75^`oIzcyk^f0u@QkaG(&lB!gp6Fn953*`_&9V58-$&3UUz2k9OL-rjxX zJb*2i^P2OTb+hO_R|HzzMdq6t8;T^LoddFf^i>dSy`0pJhsxj<{A9ITL?2=!tit-k z?+|$Q*JPD@d2e*$hxhUZ&VgPsX!;j&;l2DGK0uQ{-OKCBQaAUPVJ&%IHc}31$)5_( zA1`(OLaoU+QFtW&vl9yZZmX4_^0ikI}v3O6Sayt6K98 z(OJ~Sfp+kaK8|uZ;GRFhe9`m?($$8)XJn(TZZf3X300bJUSh9dZ36ha9+68(>dD;C1^4mQ|(AAii2dj`EV zOg3uE>sEm-s~r9G#W>4-3Gqv0-?qF3Yys2S@){vXCWcVL2rV=jBKM5^v8`eVM?2oK zj3Elnq4*KmtsSo!d*v*FB8J#kqTYNMf(A@!er7xF$HEj35OnZBDm4Y;MX`g-Z_gL7 z&*kfG9v2QiVD9$Gv2=d1eIGSAkk1tau9)iP^{MZ6yLmlm@HgC$x*78CNqCHrza{aw zAoPx>+bV%Ua%J@WP{uN)`+gq67jXH^{rqP(O}Za|>^Lf4d4MN`s}eMD$r<)24N?fd zA`HXha{2>2sp@f)$tH8fWUA}swFmfHce7P}Ik^L`1u3+-1AnFRR02ee#RJkupDJ5- zPpsCm<-$0iqn!m$e)H%{_KPN5q+lSzQy{% zCl$jOQhuh)e~|x_2&n=tcDwX5gdiA?<|ucGx#D5^c@lAG9T<}7=j4{o{C-;wiKtn! z%0s+m+cLpUqMjxc6fWJq)`Ffn$MxBY1B99~Fqh7uAnL|%D5NO7kcT|PUtu}&w}<$= z=l5+}3k#;Dg|Gmh;@bf~chT(tQ1k|_)IeQVydm6k<1V=!(A+0(2cQ+p%MbH5DJBV^ z-_Q~`ftNJZOSnEy(Zy6uaSz9QAW0T|BoVemO2iTAI$*WH+=nog=?jS5hfxFGV5tfa z?M?0JN{u@p5~WRuIhyXTK;~eYpD$NF!vFRnP6R<3ktK^N(sMO+^NVMarJ^bWlFV$B zLCtt50!`{}Oz3hO63c0*Vy33glOwzEn5czRONpI;oIqbNT}1#qV2qaAx^TDuBFa)w z9}5&&y(^#e^2Hr!S{_BxNKqjw?-C7H|VUQF*QS&2`75Mz%gS&al3ar|(z$70GI z;J#RvM0H}T5hyH{)w}V{w&6s~CGuD|UNdEu7F!7w7PU=|3(^s&jKYEXQiVL?s=2UB z;i{zPlXwd<ih;~enD7pQf)T-cqrF)gHlvR{vUz=pK%U@RkQoBfyUTH!VIrJrz zBlW)IIAE=>ra%q?ey#w04OQ=F#z9EX;tat;%2KSd2z_l?7N5i`NOWQlBQb?&?s4Rv z3{p5TCY2MnNv$dfdLWh{70M5)1wx)`0n@CVsO1NUK<{>vS(2m$D#GYmYj!uGjn<*R zK&cl&HwDk>s$#ZO5g7ewmac?!)do_xkda#9Z&~gUIW>9Rr0P`BbwV-gxR0Q~6t>DW#4<%fW793KgQB zLBD_pRUs=SP&_eoxp;2In|%f0Yv%WJ2bl5HO_bly3#Ymn@9i4swyFX@cYQMmp2}^w&ql@5 zK(OA21P`rlH(N6Sl{L@PY&BncvSaU+q}0Pt@ZB!7Nv#dA!0@(Q->B#c7O?3XWt%5? zX!s@=?-1HdENnF=6jP=Z$+w?`z)sDP=}+=DSU2u?k|(jPQh$nP`5$7mnuB%cvRw2O zFN#ALTQfTS1nU%_0}n2jML$O7zI#awPI#J=apCCGyitT&Q&NFI3z^+QvFG90^Ex6E zd-5-wu=60$n5Qj70h0FrYE$RqcZ#%Xjd+I|1(&;9+Q8226j6bKB!1w zgsl85uPzrq!>hpRvH2M+b&gBFXR-7>DqB4Z&1SEB{#o99a|%fEbG#`)W8M@wbrW+2?s3guZwlIgiO1&#U4)o=5Sc z^2GDd6MvSj7qBwfD?fVy%ZQ)l5`=u)=Wn*JMK4wVL%kG$e!Ucc;k^K0uiVfJC6CGL zy@35O8U3Pag!@H4A0#Mwk(1YsyC-iV_rAp21i9$80Sl>5ZtXo71ma%i&mzNTFY`G_ zqg~G1Y4^SY8gSNG*Bj;;mwdf9f0Gr--Mx8S zRXVB+WtygSoqmG#EzC(uijI}pR1rNT#yHx*t&AKV)_FrH2 zc+$rHW0$QQvgG%bDOfYleuKA&swfR5i*Y7c-z{&v!EwKXWPSO2)r-d-y0D<==r?te zE@#czlm5%#Z$|>kn74V&W*!$YEPX6Vr&ce?o^koa7d2am!yMsddp}Q~eCopBzAfmy zyTwfwYv_0Sw{rJ8SZ&26^TcKqfi6SB4h3#6?J2wWp(xkaVxfaXg;l)l{sDio`o)t! z4Vm!c@U`PplE!T;nK1G9UikH({{Yo0y#=aO1o{tATYopzPM!OqXj5s%=^{(ghV3^NZTj}g{Eq)V z)xLNeRI3Q|AELJ5ZmRt>IQL|B>AE=|CtbXJ=J$!;9{uT@<=;i^sb&>H{X?ua-c7I* zh0F4P-?w|mxRj)`I~Gr0l{zo$brY)=o)dLy1RVcn#g99VU;b_*77%I(6lKjz8(w(r zs}e+1GzQ-7#}nf!0$vWe@8s%!Wuvj$-f>rl9GR55I6ldkd2&%&>WC%H{}ZSjdygkJ ztpIj;OngS;=DW#seb1=PKkk_GdH|ee}A6R+xmV6wl8S%*Zu-o;U$^!!srJ9cOUYOF zhv2P>V3)^Drhiz*TOnH~Z!?O&xo`v>*#EnnA4`W67cBcXX{2yj{1H!VULo-E$oLRy z+uejZfA!}zhj%Sp+CAya`3Z9}re_sg^vH&Pi%@kw0e4jd`wwy3eiwID8#m+3l4Zv( zuBno=U_{!EK}!c7`{+N=hZ8@=psWD&A7ZxSE~53bJe5b`*DL)i?6Ofy?MV^c$J>d`2N`Dc}181KzIfJlP9*W5PCWE_WN||&btY> z_uFwNelJ{=_h8bwl7fw2+|0i4_x}Ll(mo?;b~os9nE8&&U3U?#`j)HHzMQpx^3jiy z#@+g9%kf{X4qo-27z;O2z-|@6{zKe~@1k1B!oi1Dr(KwqR%%HqnwUOr(1f!W1^_wv zTPm;7^w0Hb`#z}nTO6E#^|xn#-nw~(u*)Im+oikjCfv_g3&*5gPF+`!l62z4rn#f{ ztR49(aC>?HuhHz!;RbKi+sJJkz+1;v1iL(LGWPQ_fmZG8kjX=~tuH!IDQVE0p}DEo zrtE(im=t~vD*Y*$f7ln1#DTnZ(+VJ$!^4-kzPXD=Av1>jcsgf7TEX0uq!GWTuNeL7 zjR7;L1M7bAr-_6;{o6#6U+~tgD+FE+JKrAMa~FHX%-p}_$kyePzWvpblv?_rQ>=mZWRbPE49xFnIR{LigceSmgal71x(? z1;coo<`n|JjTlyW-}%fD`|ob_;$MHiadQ5m9Xl;aS2qnj`rXK!DKv}=hVzx;JP0>K!K^^Js4HVMVn{*7ayr5zul-?eRhCz+EJZ*|h)r z1GBat$^Seh>CChpITx~TW$-f2EAnt&`w`&0KSw_}e0hO{FQW*Y|f(tlC#=&i*)O zz}#aUlZMY*J#EaDABV&OuQxLOBwi&Ryw+y$9xW??`G+X|a2Kg!#_!2GKJ)XzbH24C z4ZKt^>g>kCO95rnxeAeK8e`-Xeb05mNM}yfas^<^!{IMMAz8%fGRloSt;#((v z9LHk*$mW$THN>oQ>oJs}-qcu%+x zy*!3zu*&k%7=DZWDlbX?B+l17lEt5Ko?;fb%D7L!VdS)2l*NbQ;NE>>`Fn7X%N@)6 zRXYQNEnS(9PfFl}2OY_MNIxr^kAs18e89(dQQLtIb}zuJ1zrj*0v;22hV=^I-tBFPn3Q`&4Vlj3tz;NA7RjQEN_81*Z;KUv}Oo~+lgQmbJkgJs&CgVsmO)UWva@a?$t6|W74 zo2aQg#BqhWDq}C|YJQuk{4|5RWS!~!7|e-*Gx!K+wgVgdPFI{OR?n6*XTYSoPwt$- zr&5AemhjJ+aBAEq$IL|I_sMND`NLI^4idTi;226jI*NCh#Um5<@xV%S0))Hmop1}J z)8!AVHT}4B6tUbB}Ys3_DafRO1h>1p7>tNx6Imik{5nHIX-HA#cVCWru})A)78QFN7I=hMcj8 zzr$wA>UsE>M~>W+$6LW*9JH7x2G8_BebI$Y9}{AZ?7o<%Rh{7=B4XPbd%!~NmCnjP zwU|$0aHJc$lrO84?TEvcghu-k4qeI~`TPSmTc)qTcE*u>{v}S(yipDkA|=ZzA_)7cNyo4`kFU_JQqh-5trhJE3R zo2ldATkK451#=f5I#Y(N@K(AdWCHL(mjt+Hjez$U4TKu5c<{`-EBUK-l^7l%gEnF( zA!rpOfkLQSe%Dp-LkX7Z#0jGT>Hdw1+tH#vtC1~JX0GO6vF!YN*O04Tw#;6S{g(&V z!ozVQD#Ru~5$TG;rrRcdznr<2XQ5R4b^M=ql4#pHo}gtqoT2iijl7nOT94jU0PEnf zWj&8TIRztOgMzVk13D^OmTutBA*JU=Y%qB0kJ-elmMe1*8R~6DXJ^X;o8cBUTXrhq zS$Cs&wg|FvynJyBZ->5^yaf)Cnfa@?@Br2bh`}WoZNVbNnbiOIs)@&bKJ?Y&Nt?eM z3uR>Vk=HOFeS19r>Q>%~ZVz;C=Sw=EG@T(cDd8}CDQ;#!teyG_a?k8SJM|zkAp!-! zU+{tViIS~%D1>_M;7)-9L$4L{ByjPpVvLw;vi)wph+WUWup8L6D8+^t_%#^koers0 z)eQ!hdW&KnHLc(r)=lK0A50{t$;;S+GhWTU;c+~b=lA>uXNGuxE??in|6X|jBtM)$ z>5f$#1VrVs=C`~?7a)k}VAKZSMEfh`uC|^6|DmtO7*Qd;_!5WlS;$!V%3l7`|GzcKqVM>4*=axT zO?N}i+s~h)z0`mMaM4^X+aBO`Ll>wWOQ;9r4E#z!b?kP5Zg9X#J%AZ&p`3XDLUFsi zaR4qo3*}1(;b(hNetM9%fuB8nKWH~jI^o+vt#F&&rbE184ce9iD98jnXj;DO24Nr) z_B}QuFUk+U=TpT+)*pk%ms4#ao#3)mo1XO1A<7^|_`9qN%#uk4A%679-0o7BH4GM~chr18m4$ zpZVU;oHf2hgM^qEe<+M}4tN2zOhEcCgc=%mjGpi(I;P2~zwnN1W&W?fz-t~o()lEB z6IQT!9gb>R!c}o6KDh%KNd2)#PC5x6{-JW)NuC%xgnK^Zq_u~eQ7|e4hID~LX+|MY zcSQb~QxHZt{Lt$+lrEO3zhTzcEGwOXIy78t}ge2)R}zyc>>34lUtz8;-^9CVVgsoBnEW^b+*h zt7vs16DVbHEd`+PIV6T3JwqNV;q?NuIB)MxTc(iCkP+wj1(uN?bRItQ`JZ3rvxEKc zjVCIkXUXPHF&19q#ZD2@U2-~@h`N-2hPO^!m}s5~0=|#|c5gh1103)nPlrs@2Q;nl zw*yUNsN5m zfX}9)i-$Oz-1P-f3x3TOI=BSKPo<8kiohx=DiuD09l6 z7waMcjs0F1HG?EXwhtzsiC?S`K3~O)4k2EScRSn;-3fkI zFMH(8c+r|Im91)sWb@ovP7UiJN3I`~ zj@sg0=fI6{Q=-Yl;$A5qsV!>9u7d9thj$Tt5H$QCjlN+9Kh!$H(gL&4Iyt(wXbRM} z)E4*QJVW%ayfeNC^~SGIvyRGrzv9U8aXIJ|e?qT}*4-8ixP%}qLG(t}&k{rw9upG8 zl;G_+=+*^#GKM_ru=a7&SHybM5pCJd{Pa3vU1;@PL?!e)k?J4)Xl#gn`mX#plHdTv zcID5$Urb|=q}@7*y6kKDNe7VRYq_+8cr^HH4#0M5hy|_2IcEmgksU=NNZKwP(TO|c z2OUNIXyhYI$ytY{i^_r&Igp94*LTXoj$$Gol_Ps~61C_#xRbb-?Usd|L`w=@?}TxN zXVilt7FuV!2gSwc@6@~~*e_^8z~x{Js_-3z;jW<77LLf1hMwz9wz z5oFOma0m5s-;NDbv5q@pohsION34>d_-vwrAlr2n)!2>vC%OtN<6~CK=emi!pl^vv z4)>VV>n!k*{#HhJ7vaQXt-6chY=qq0T|D{N4_qDXr|W|83XRO-KBHdMl>mp-D-Nqb zTv5964oywfl&`AA9Y=A{d9di_h$5D(t^bh!ZV%CuvG3*9N5#IRW9U+IVK91XAsnIH z$LTQ{&dM|JoX7QJSjU0f=ui3>qXjE*d|Qz^z(!}VnXceOI@*p(_C_ah3?T<_2p-fP=R_AzB9<<8$S^p<(8fz&U4Rvd$@}=cn0GfA7gt)B*Awo{TZ>Ad>*S6wz?;F7D!ur5<3(v7s2i^rSOE z&}r$4UXB`TSn?gcA-97|%`j@lc@z@C7X7Mx>{T%sOnC5B(c6k=`#z#jup5%SBcf9V z(9~9JB_}^_9)?MvY0hT8V>2kubh%5Vd{|K+jU==RPF6FY)y!IifO!r^rNIt|k^=66 z>iA5SsVHM|Q>ldrVpO{QQ_N)3jzW&2Dj7>ff`yymRbea<(cg$LQxB_DyW8JPh0`X8hAcA14n(=i8Z@DXohc~3EQ@Y<3jT{37 zdXVckL#N7}1)@<;+OTvQ_OWOqtG_RTV+Ifn5@;r%UN<`uePh(RqfA{aAAqO8%{!sL-r7HE_V{O(+TX1uBi-d;4rx{cV+X?qqlaM(nsQ^=N21QZ?BTL5E$d{nEB`w^ zthnuV58tF7ejMui;g7`|&Oy{je320C9V{RJM6`_ff?^7ts)O{w6qp=9-D9OIIzACm zvf(kUp6s`ug=o0Mg~_#RZMEV_X$K3FE~pfEHwa4aq`;GuX8P#-cRm%nf}uRNOBc~~ z!#oLUJ%c4funRw-`bJJ)r-fXkB?KtV^%3%|bU~M(j7%33ur#SZN<0G7#>b;DL9dn0 z4AB9n%^%GWog9;>?>S6CQ!>PZFt+`gA-bbnYeT$*0uv3<9?H}YhDZ*YNL_5xv#Efl zPm)iK7B2!=!D!JxVw#{+9dVwIwQBlwP(YpW&}YcUGsWAmxvb9=HCkjS6`L3YK86-u zT{{339wU|(3AjH%#iWDL>4aV*WmgtB+!8%TM6$WE^%zkn5?OE>L7zZY3oAW1Zb=}g zZ5#ZbQ^$z7ItoatNCp5>v+0!GMAFkti27VXmKW$c^W?TMXy#m*C`EjwxgrkIMpcQA z#mE;Vrnz)xli3GE1}##7e2XY7aUv zL)yoRmVo0PD{4T2er>Gi77F}m&Y`+6t5^v+vh~c9JI0EqVz3UQk#Az+AX1Z!BwJ}8 z7Ja(Bf1K#-$RQ9M9yS)zG$+^d5T>(na+ zD8_OZV6_IkbTlH^({IAObBp=~jd*jmh!0daQiN*6*x8~!z;B|*T6tl%aLaCUpeJX_ zx8{h*fL!5O8^VM!dX9+4c}H4GacH+BF!8m6&2vN(TLDD2zHH1~D7On?+!gQON~*CS zJ3=exiki4qov9y!Jhb{s)>S%E%v_YNbVW*9 zCcnQ85+Fc!TCH=Aje^t)Zw%2u-Ryxyw|$9t87z>zL^Qx-tobNf zBA!R6)>82n9;26v*YLQ$6iVO{**0I?gGax7u_A609qq#{DKw1(D9HmaW^`ymKt1hR zfTdif{JcOk3#3IXh5^>V8csQFED-gOa;`wM4@Dbj#6X{=7e5_srPVU*G0Vigm6s4R zS-q6;13@yDi5_Gez=E9yFK_^$Wp`E4WI2{%nX>nCV4f*wE*DR+b@JA75#I&Wg6c@L zL*L`f3pm`1Ica$+zEJ5%R&P9}c_K2+-9QhrgdWh^@hOMy%b-6GULnHnK$Qd4g)781 zLKQ;YJ$X$bx*<~zT`3+4!w^B;&_Af|!=}ZC)Rav5+e-1UnVhPQ=Nv&M+Ps!)W4e{C}4 zZsbbf4|Kp0ODnxSsDC577K(9kdpsxi>5#+Wuh-HvX@10f9|B|p5b{=`2qS}Q_*!vK zC8{ogzeqp5_3z{}YsGm=>$(oTS}aGc6E*#Dfv0!UEL$@g)+h zKr{?GOJ@)bmQ!qSy0o`lILOOBpee;P%Db5yxqA@NJ z_1`F(1%Y`I_&^+3_oKC|Rd(Gd!c$P2zLGX!9p&hO&$)W&!7a4csH_K+5$DJLkaFE2 z)3BJ-^g_QlC}~7jUpRMF!rcrf2jhJmAN-L&QpaKrn?B- zSRYFb6S~MkuJ&p~JC?*q&o7-^u4Ui-_u0MB)TsM`G~=u6`Z>+l<&Oo(VpH zZlr~zcOL~yMyo8{ENY>-@kJuhA6HAkhy&tj@|hyh2?mm{io^$agl!Sc5)~iQCNuzR zbazA95t{FW+Y)O*&0wC6;4w5(e!4}}X#s$JVj(ApS^OvuUU}zOyUOZE+wyh{5M+lK zgI zK4n{E>~_%*j~?5_@+yVqoQ@?C2_I}q70Rd`qDQx_LbRmNm}dl_hK2&~#6LT&jp_bitOcfcHQOi37~9}_g*0EuP? zyAoPTVnfKND2EwEsiZ!7q#!LXQ7Km_mXnTjvlQZi7Y#@SN?Bs*HUxpG1*s&snyXwS zTd5*U5njkxYf&DO;mQh4+NZKYQ>ig>-cA@Cr98D0Q+B5G-(^~$%Pi_JxjwxM^j|Em z?GpFVwN-Z5WPuN63drS-#jrt)k!i)Efdgmk!Opn#XLYe?O6Tw|7DI*nMK;(CmHwCf z?z=@k!+wzC8?nMgmnQbZB{Z~PaKw?ZgG8bm8zwmGMf)hnzJcm=QabmDI@mO9z6aX< zZ*uS+Kq{28_CWV4$=|+5EMRaF`NwzA?#{|t--))t7e&B(=K8HYdX(00P#Ld(CqBmR z{NMMAT?rSIAQtZWH1?Q&fu?b#!P7-6E_(~h8^oCU1=)9>_zsRB_wN^PRg>c`Kvl?- zTP}!(_2!EtEjHN26D@@S`a*06VO`iEkQV8%umzID0z@~498NgLUxa!)NA|i1;^xZF zEb0^O~q#48xAWcQyZXI>Fcv$12YLeNi_ zHLs#8X2}PyLbaVKGp>qZa7Ku}ChFpPIOrjH^2izNY%G*PXQ8VumWgLY6FgozE4qX# zT_DY$@WYJab6Lfvv!Xd>^&4lw0ZV1A648d3sdtH(2s-g|A{TVZJ10J_zJO*~hn`CV zz^czCOT5s(&QCfI1ZBPJqJ`NEa}R??2V&N0auST0H9DPZ<~XtNg7@F2omL1-MXM>xa_%Dkjh6+v4QRQt@pdZdPDm8yH;# z43a}`0PR)s=nXK*4H7h2qv>2d}eEt@|=kKo;kJw5c}O?sOK-4@eQ zD0Mro3W3376&Z(YIM+)4SV)GJij=ubKOl2%V!4nmcit4OQvk|8@EIwexA#Xx5Vr0OlG21KMbuv=4lMNLNk>M=X3+%LUkzfJ*`EP za+Q?Tpv9^}-kbPP!lVxn);DJ!((1rg(2!}->JzwDE09_*AcW5>6Kx{lNkJDN-7zAmJ zE1cbvccTXabQOdGm-{V(x*4pG;6XDeWBs(yCRZ@0(Lq^s3FhcVaoE4W<~EwG5=f=> zjBoD7l}_kmVAa=8s~?I5C+z=f<+x9+1j$lG`fskEb{fb|^w-|R)q(Z^?R7lf3D82> z6`2;G)yHE=07Ulyr5w1x#pYWuE(0*%$P9p+T&g*7+36RuN}$$)E_Qi1P*U;nqzTX%RHZ=2X%8-R_94RW(;ty7sAzPhe)o?N9g$ zwN}-%SX{xiM*`PG$thLAv2*06s^DYfV8L2kE3fecr}5Eds|Sj}&a9~-BVOGwWhRgU zOyD$k)_M7Su-3E^R$#a)0rL#mc<0FMU~RfTNohg*Q#1_FtpSv0IkXm*Mi$pE6@(Rx^fEDpFnTHB8rI7 z8uUh+e#D0rJcKggf&@z?kI-t>G9fGFhL#lw+D%p@9I0&pio9JTw7QkNc|lnXn%kfV ztwA7aB1&eGeIQe=jnEpACUPM{yDwHXo!Ub?8%lfe-iieVvZ86SN2C_n&U0y&X?q}| zQeUBVMIS0fmn_9MFz5w<+WbbH=ZiD+W zS_`S6#0TxWK_LKtlr1C(Rix4A%#=mZkm0$qMT{2fgs~I&LXcw8$nPD4iLQx)Q38&_ zZ8Ki}qtp2?n{oPbd7M9FpQ2$dxQDLd87;TFFdt-&iPd`IlF?^kwT3__JzfiuQ)0E} z1Cf~&1w5dJ%CQ0iCADX)OYwByu-yC<%83>tp4~ zIIS^Ko{!feWs7*Nrukma0k96J$*RIIM9z+fe9M%(;uXQK$AkQt@`V~&XFPIhsI(n5 zw0cxK9BI9^Q}<=cfSPI&QFT0CQ;Vw#6hgcnG2t!~ks&oP^PiM!YieV?s=}078f|u* zsioy;`vFRJE3hSm#6pHB{{vF~$W(&|yvg$S*VbNS)lQhB1Y5)>{M?+@|4jc?cC7=6 zcS^od2VF5)PO77Q7;^%wmS{<>icEnP@B|cRa&|U7QuI@@XqKCcI* zr?$E7fQ=oRGU*3S-Ln$$Cn#vSdvcXze1rDM`r1?QS(#s7>x##X`uK=+wrrUQUF)QL zB@z14N;x=D>w(KS_9toyafdy!j~3&!qNQh4#|+;K~q8 zD?};~sBa@yO07X7km=jx&<5JQFT$csTZSR(y^+=?dL0RkK(jey0kA1Exce~H14O!7je%N`?A%z34F3`K0T8E%gfMgr4Fn+X zEh}!DOKGfCPx*?Z5lCp#)|a7%y8q$5ckj$5*(5Bal2CR-3xwXgxd;e? zh?Op&B1jVu6&neP(jn9n5Fzy5q-^M+BZ5@vEm9Q4hmO+U@0okE3F`Cv{r~U#!Y4a- zdOLIG%$ak}OoO!P_R1iWC(`B0fT-0}t%_Qx?WzC|ucptc7}XKCvWoFKd?8hh3I?x2 zs#pzqR#V5S1~a~ARyEqf_XyGOm8+%*?3b$Fnz1X~hACWknhsAU?Wu0e(EQZ1 zhH*A*t$ho^EDk@ls%iX!`;}*E83kk3Ff!pAQU*u6V-8$GzE{h54^V!t7SP2Ea@RJB zU<%6AHonG^T2b5Bfc4P3j!`TK_9S^bPp8RsFiT@;Lmfa)hW}U{S?4eq=k|+NfoTjTHTmZS^gI`JEf& zYh!dsVFP}+Emw?ob!(m*01;8%LX?d^D+z}{Y~ybsU`72c1Oga;3xTxB-$L*_4?_Hp z+8D0{$DHROfC)JVG-rSiO{iU*(676sBwy_A^`On*iTf%$4yO9yJ6(Eff-a<2b z7?-r0{-HgMXpOD7W%M#Cp_4csg2=%siBn}#b}yq8Z1o2BHqHs0`L4Wg?7(;}>u;DT zsThJpoez?Xczv4UF{j!ADIpx<^%XTU>=0as;&|ZmnzQWyNDf25-RCps+X1ko zmZ+EYC76rtfN&0|=qqL}w*&HVKviFHbCn%{S5y-9n!XZdrX2w5b$FA=SF)A4!44_F zA<4c{W|kcg!2u0@iRN}YK;7pz@s&1r+W}FWqPee(xz`Se2A;>7>0uu5H~P?krqxaV z_K$Ef4!y3sAsv9!k!CtQ{1|lmqU~E9Wix~@J1qH680qab&?p!UMh5fgPHTJvf};aqydn-JQwJLH zKmwTqfeX^<)Ibm!X;eQ2d-o)2odRY*h|Mokj6W-^WVC~OG5jtE?@xJ`DCYEc>L7z= z;|2m}cc#}oGigDp(WaKSrW)2~wd^i{Uh_(D&!R!@TwN$rQE(4KB!(n_TL5WN}Ku8KGQD^BO z7PcDc^o#&_d7X?We;8~uE5FC!3v(Q0aBKyvlyej{T?&^X9eNTBn1svh1#UDo{0e*2 zD*roQ8A1an_WauTBxdMNTUgln9Jt4ZnTeB-06;zZ+UOg1z+gJd^CRE9r~xpwevHB( zK|6Ga;j4kR9W?lbCzTIP)0LEx3g!DV9wZF@Aubq$kKf4vphN!iL%`#D1_t+FB^49L zB$MU=?&Q`o0BFdhV!1I0wS7FDSa;?TENfh>Ode(wEs(|3!FHH&gj6M)UBfXHcR9@$|BNmZsxY0Lwa>Deqf7^(tx3yCXpHkD-Pmu^%3xNh5KF_>r!U#6En8@{Ka4r=T;C!oxg3 zBhKsLzF9(f0DHSPOtdiO*v3%@a2Ug})$TVy&<6s*j5F9|5M-3#O zvZV+{f*qa`h)^~VVW<`nd~{TX4w*bvrXQUU)3FLtMi#jsW%?0R6te@kWUB&US#fl- zIakaGlUu6dAlvSvlW`f-w}5tzNCBfr*@|?UnTU8Qhuzfk2Yh@gNs0Q5jCH zi8w+M^_pnZ!sW!giN+)xCF@Tz%17@t+!X>Wd5tfIybj!uelf{d02&P}-^SFBaBj<{ z>0~s+b>r`_9gZbhDjlGFn);-J-+P8aC*uTohF+g+tj+(F?oTMQ(^joBYPz!x+-^bY%tn_Hgxx*g9T+ow1<^~%*g6s0qT5> z4YsC9e`g6A<{bwtL?5V?8$v_uJOAfM4e1 zn-WY5#sT*cJPyE0JPuAChor4WRg~9hs}ZRm*8{DdvQ@SE&{k0RKhU3BaTFa%FK#oc zra){QBnL=1{(+c{VtBBU74(jvx`f_0;h*Np{HNzn!(B`T{)?;~lM4X+c-@KU8ecZ3ked8j2K-D2dC~j9SOKiTiPt3E`FJ?KL;xr}&w9<$ z8MHvqvlgRdJyfYQ1~@O5j$ApKg=id7)kZkvq!G@7q?`kt#OQ+Cf!hHUp+Fl!rg$+Y z^a}I5>Bi4m1f@jGax1F^#bU%Bbl zQvK;h-O89)ekzNrcQOlxCq2R8!K)??GgV^&#sY}0pdp(1)(!}cFP?6+)kg>l$}n0* zj|>z&BJedz&<7cK8pewAJfMXcM%Rk}m+$yJB6Eh3%=LUZ!>IQ!ZyrCQ!!y8`znc>p}9GGNIn zNMN$uW9dV3Igqe3i_J7BK9r_bTU;Iix$7eaz=&jAbS2^E=Z6pct1 z?&Z4X%Bwy}E$144;YiVR9>|0z)NP(osL)Yt?M%iw)YEBL(FqEBu#V;v%9v+-mokN? zi0OoRT&=p>{Kg7W4-eWwQ>`HNu%#XJtrcXwifLt>W(DD*KTy_mD@dv!)S6-W?dn3i z)4}<;tDG`vfl)Bteod1rvEF`FWpn3e^1GRF)MA10O7l5+O5nJ;mfw0N(ON}NN#Xi9 zc3z&;xNGErpKk?mD<}1oUMhb~gj4)NBf8YWJVn`BtBb6lyd7Umtrr^2d`t2q=9-q~ zNy&bQ{Vp^*9HIum8m3iNkb3nHU=zx)qh9~yWy&JLxx=@bK3`&O6-h2cF@tri@z0r~F2KqZKR zhZh8#?OaHty@Hr1K^QMRD-l*zCC-7PFb_gbFrIPMyd|NDRaMoRQ;b@-$WjM;a!#o; zslpPYP!)fkzVm=0)dXAn30t?$S6v82o6sCg4=#`&(7+`)aj&6YmKcRYxwY0pA1??G zA`}astn}BgX&@h7C^VNEZwIXxZavxSY)O5W8&N@Q)P#`*?OAG!=L`B}YNdX@%qSj9 z0%LmHQnOS#DF9_8enM-JDEf)U;)6NMG*HeT%Z%w^Q@CEfXjP9IPF`-5OM1u~JLnM= z#P8ZbAJUo*HPRc^1X!_j0~x|*T4f|!WhAXI%2l3W1$nJ9l;H$x6OA%BE}*e5(~`vcgGRodp#e zxn0Vjf|@iNLezAql&GJ>tX49Fpwh9z3M<5Oq#3i62%=6Pj&t8j|M#3lb;c8`javf-7akSexCSx^YpDXB83kHwZl1>Q-^L|s#8Po`0_>>8`C zoSlZx`I9(^$xM8!-NXT!TPuaW^G~bVO zZYLO|2kG8U#oUSAWh50kguMW`l^&f&l|L3H!gUNP_^%kk1>tQ zzBdMGKT)MUMxlJ!MnZnjoDe`y)jZh-wcmqcZqXNea7%TR*6uMX!uf3vSlLIZ{11Tj zW0diO(WS<5>~tw$g@*HyAQS{Qn=3NGuVF)FC^V!IMwj2I3Cb~4hEK?)*4>L^@CoX> z*EoU_8}BoQ!8x$cSSe5<;`RDwIi33fZwcn@|Fn)3dLcB&&!Lw?(rmCTu zfIB?iNqJIE`|BStM(7deReU55B41;uVox73=7Jsa*6#<#u1|_HT((lbJG9TPlj7V3*S46W94yLdldJ3d#Lp>qYSQFzC32U&96=z z!^Gm%$KysjaYne^$&`IskNiL2GQc`a#&O8(9i_@AjFH+=|K=0MYZ}j2^eN2OPxSRE z0OT23b_(~j8))AtqXb9ZJ_Xj)&(t|q6rop78!ZyDH9c9Wc;aRltbGk~FwSQDjb)#J zlPwnT_S0BE`|0{=qbi;K*?1{_o~G+K%45OW z#4T3I9$iMMmniNRqcax8XTJc>{-Bw^7>%*=uKZ%0ivLdPt`xydy6(tPNQe9env_i! zFBrWre=lED?5uCtIY}2U8f#G0HQ zy){}Cxu!s*Nx+hyiCY=4p|J`oa<_`!1dfMf_D$n6ESGyXjnB&iq$6MrE@z!2NHz@@ zVutp>&6>x@3MY6+lMn9_lBTz4_ATQDHbZplmhmjRHE$bj*d2e{cppp1bqB}L>(uKG zZn;siQc(d*5nN8&s-IQLtUGG49KT~+=gfQV8WY&<^rx{njVT}PChbT)b9y@(qlu{U`Me06C+yxOVDnZ_M#7;7@sn1+N0k_UA54@kglAkTk{zw|+pLarHu*-g7MD!+tncV-F4spjsi4 z%p@v!H{)?fV|ww1vnWjubWs5XB{@Zha$m7Jywb2@ZV3<%1Wy#VWSDeY{GlXt2OO@E z(mjOESCAd)qi9hI(otqXQI}3di~jg-83VPGku)wwJjY4~>a1F&N-0i+mKo7N72#h*7 znRTg-%jiUw1DAW_L&WpEyPOLV(d_;iBH9%`*V1A>BRi$~l5mW<;};oPj7>)fbWJe*1Kb7)u7mzJgT(h57DU+)(IoZ_OWM(sGXzX0A=LzW5+Rp0-NyksM$tW4%5mgQH2^uqP8?V0WE6tbWV>H z(MdP?^>8QSee{NV4cRyxEcwdL>nyD&)&Td5FG>U+DLo%4W>*a7J>}e!EP#?{m#)}? zc>q2AZ-72X&}vQ8#%jH;iQ;No({rG-2z{iB+O#%S48c3>SOLr70Qjp=i8ul4UYx}z z(wz+3>DXVLm6EmSyCwMn5eILl9O7W^i3i0LhxOUBXOLd8-+w+9V6o@EK1h! zBB(S!5rr5mJmxD~_xkwa0L8Kf5#z9~0ID$|>h#RVtI?t~6ji9OFyp`AmF?~B`9fF( ztIEU2VN`aju&7lDW8f~wBV)%P?Qry(x$ED+weU(!8?SISe}^Jsng+y8kBW-%upuzk zE4~2wj`WEWkeUCFPxN7>pajwHS!*M)?ZD~E%m*9hxXXurMJzLWMCY@y>dZoE$*0}Vi>g&9kG?YQCxH@urvqEn46Dr zzhcn-QvlMdIs?n2;y|D_anzxNs72-CMSky!z%)M;?xHym1O5t&KrlnQOi5A1y)uw$ z6)i6*B3-L_oDOJo{el)n=SvEsE)S-%amNJbUC>rger-_XWrgU61Fb5A4Wh-foU>l# zO9cLa#171&dP|9M%`>IX;3;>SA+;S9;Z(Fx&RPz~PV6+@{|v{xGZxdjSBLQlhdF;X z4gpSR?maFgq6?{<%q7W_;y5o-PEj#Y#Jr(WfHjjh#VJl;{;r_ifVBF;9 zz|9uetm}ayxXVuNvV~DM(40h39@zXyqNrL*RfWBhcN3;Pff}tm9xD&dq=5DfRH3wp z0t2W~X^{zys>h|pGuTM$ml0KARrCEaqH)wc1uHPSqq>apu=n1hAIo6Nyia$_h!Wa8 zDwG81xJO-*L|ZM>pOqwHbezSHmlFdakkYEWXpgh_s`6rVlatQS2qu?cZ3>?S__G3k z<>#*;{_^lwD1R}>6&88$70zE_{DrlygN1d{KfHoCq@mOfmBem1B`X8x-;+MZMdPsM zb@Uqh4Rxy`p7&kU^khAmm+n-JQL=7kKzWrRd^wKbc-+>1xQYnY=x#Oi;vzj$T@=;! z`a4z^`82#GE|R0T0M4Fh<*v)?3Dsrs&6K%vxvzEEm+m>|dutwZs(odeugYZctin?D|Vc))Dpii0OfH zdk*PLFW153-J$_?knbqXs{>qiln&Mr4dF!BMGeR3t-9iKoaD3Xib6ULrBCXDMR1E^ z>WNCIw`o1WXU8J-#bh{{^~L^bKPbT@uv0O(Ky!au_8*ye{0t#*`tvvzf|4xESmTR% zq4#LRGXSn%aG-id3_wY}lEp$eIE2MgMN>@S9c!;C-qV*z+R{)&%B4J#h44zXj51_@ z0C84B5fzutp?CxOso~u%7#Uq_D0+g1Y2Qe^jA2{W2s_(oy4y&!eERlXa9MpCh_YPc zv<9N5K1@*Pvno@^XVIw96w*-4p~j6x1dfAk8)N*=QfgzsOD1JBMje?H_M9jTlO0LV zf#j6DX_Yli6V&G(@eGLw`Rhd z@0?7~pn1>R8c=K?u2yqVk*il6Zr#jpRnO{TkY`M7E~=xLuy!)Rl__~c)5vTtqUcU@ z5s7L-UJz%sbpMqX05c#GB3=|9@tD=CDGSqr7sX`#vSiKbIBI!E1kpP!K{)(E3tEbF z5CAa7Q;yzy39IWerMx62p`LtgL`jtTV<%CF+Ptj3^LG~2B*=azT0HVKQHIX80pa=^ zm3sx$WhUi+Q^Zl~D690JR|7&$x z4&!%RF{|JzI0)mhR*ihKm3TfZZ^QnewXH;AZUyLYC7G@&_Y-`k1)CaU9bRmRjTTj7M(rp}a=mqxb7Iba+;ZjW)^ zL~$KNC$s|7#K42usYRzc0FkRHswRtDz~g-bd2aGN6{4kY0IR9Vii>1S`?s0DNu@ig znSZsTf~ZeAVt|JR2Dk*K?^s7n-$c6CQS|!z5LZK6=5f#Yx)M1x?&T(eH>_IOMc^2YBi~G=QC*l<|%j&5VYMT}82i7t~`2 z5KF+n0X9DtDvQA3J-Y(TvuSKsY!TVCt*h`AIj&HB5Omv>On_*>7#dTm?j??s-c3}B z%to4Wj*6gw;8cR6!B*UJh(RGAcSDhbX<9c?2eiq_Zh)n)DC}K07by8%99)jm?su{F zv+2pZqIkZ+t^~cMy_~p|%H2gOQm*VS$^rPYyNl=aFC>-e0Sp;K&-W1H*n74I1|SwM zrHapapNz`GVxmz!)jqkhr>M#-jw?N(O$;}pm#D#R^IpKi$7oG2(M3;{RJgZ@XI_$< z&7EL%L+CHSO9}=@>gC>`txnL8-r^AFZug$}gxzEBi4~lEcpohBNB)(4#A!`?OlkeZ z%SHM90|zgL-D)KFs^6jNcckVyPTKq8P3^J&?f1pU8YB?T_7|%F9^*d{DRK9O7dFa0 zptgBnUsQ~3C1A6X%6=$5EOOx~(gqWxmxZ>I)5|m^#O$&@6tgjQsrR*5!MC+1>5Gp< zQ+jKHh(qu|$X|fQpFRPgx|7yU5Togbk5o*b_heBL0|2HcC}99FWES-pAPVvx@$~>e zTo#=gfW~g2*FF~QlZHwlL9p?p83iLVpqnI2elY2j5X&s=aF|615G|)a2I{#*L7!k7 z7)|CUfRNGj{wE+>MpNb|pofl8(x;+p;qN8i0Ec+oStEHFh#sp zaJ#})Y?>IIB5)MvjGyD(nv!B|(LsLEi` zFdoH(LEdp2lTYOwE3FF%a}^32PU8lPmKeqhgMquYP{pr6Tw@rUekDf1d+aOF*jwoJ zuf-@PRxW)liZc8b$a|F#F$BH5MdlCy-e~%8h^Po>-VmJYM$@lDfSZm{+o7ThxI0-x zEjsV)P(|n69jZVzX&C6d(UXRQ%o|NphKp?_PhoV9WAj31LDQXv>vdMwkF#HCeDX2I zbHe}S2(eQGT6unyXdHoY<9#iOcR6c}PSUJV;-`pj)er^Dq=%qr8ZlaIMxUFF0f2o= zJ;#V51&^s@w-wZ11y3z!q)+;1jS-vmc*OI&C`YX!TxAa-cC-Y2Fvnj|lnpR8^lf_S%%0u+xHvsg*{@&k!+y^J`>QvD*2hh{0 z-nZhFf(O;`Td4ei<~hK_kKTHY_!oRDe$^wUsQ6GHL{z}U^{G;4XMn?Zn0n6u{+>eP zXNZPzC1CHE^*&a@YgCEElJ^yq=TR9H978%(qqlbKC>7mMl)G6oY$ipvPqzWhtX zNIhE{pa1(vs{M_CWN&n!({tho*zQ2XO)ybl&-HIlOULi0Q-;OED9` z?&5p!7uR4}fvi{qQf?o8vj%8*A8lKMeRm&SWoI%)`9*isnCchRFnDYHqDwT&49Y1J zvt`L3O`%Ge*od;JdnO<-o4(Byy^znnR*@qO)&lU+?zJd$2c@kAQ8?Luc&*6KQ+sKh zsEZELj3uHZHC-<|4m;ba!zK_b7iiZeQJ>SeHiL72 zfktfxp50GNH)F*dfW)@=4D6dWS!nMunwo_fKR~;)1Sk%AX$$7~BBgEtLfuE1Tg1~B z`K-pt7x{m3vIA6dD-Nt{Y0*|J$gkGd7J6BFo@9q7b(+PFi+BJk)Apt*5$XNQ`evO6)_+0=C>nBo|VQ9DIS0jnjg)sli4 zXwMKqMRtkzkZklWRCa+@>=G67TdBGQQmv&MyMUZ$QNnIfG0KV^5QtsJOlSIak0?$f zc7uS=rUkoE)+O4zTMUe_Ql~P;gOLPOIaE-G@4@EDrZwLKelEhEnP_JxQ;5+@hTXpD z9#B@ZY1|%B#cp^;ZZT`=*dFkOvZ>e)DCGh*`9V~$Q_attYS<4L*^{*X2Mp;+I>Wwf z%C{Fx5F8Kc?L|YgsncFjhP@;A0)5P;J$sR87Cqbx{I-@}-Y32(Y2obyIL7kYz^p-f zo97SOV!-$K$iT;6en@>ZVoC}^CVf!up8aUr3A(mlG+~;i)&YRT3F>t~%)!nWaS*_B zkJ1kU+s&YT2f+z}D90frIYzw>VH3=z6^Agp7wGmOut3gI{lluUoeu+NPNboS#e2=~ zTIZAoMPb&!ZUuJk>dblz@o8SZs$fy?6t|QJnH$6TD z;M+z?r$wQZV>qD%61bDNKrVuXN=rjReSym=2PKq-&cGI^w%CQa<8f=mX}K;&_S+Dr z2&iW9u=x=vM>WM%jR`UZI5*r>b=+zUC3CuVUIb}%DDAu`2?c>zuBH&QRXdy)F@a9x zR8E7>i|UD7Pfi<3+V${_hTTAJFPaaVs;AD0LM^Ngl-7Aja`W+PD5~xARsXooywNq$ zHM0u{nH|;Bn$X~a4?npF-8)A=C1UQsiEbk zLBTAb^QW=+)>Dx)SON3tUb=g%kFZn9yXNi?6HH zh4VTW>-ee94K7Qv6&E)fT}+d!&`mDI>r=9OIG>}zp3N>MkYU)7uKXmbwzNvaPQ(DL zN>j3=pk{C#0YF!!@;cy4dQP=Km9Armx#*mX%m7ejP_LsRCKQoe2?O9-O8ZC1%A+E& z#A>Sm&l*k(K*KJvX$nZ0FIdNqLdRNhO$pU0sv5~Jf4%_pROnGNj2+89!u>` ziUywbV16*J!0i-tCScEa$w_QXTj}gc@kI(RA(l$!CC@*hm>h)Q5)3(1NDyWaA^eIb z<1OB)mC#+l1MuOiUC%tu$TwMm7=Tc&M|bmr0c0>5RY(k0xaiy|5mo4z;p3@hSZ6)5 z9QbF>>lS(?TU38}3zv;FcK$$eC0=X`y)tHo6s)qc&sABN%0glarv;&J0mMZIBV;_? z%?1&0h4TF@S_e&43U5H_o}VGTHR@;VL;I+kPZp=6KO@y6y7sduAN37yX5fr_;Xs27 zlnHB)RlcCeq)rz^T+o6n+yJ^@27kr{5ffy;i#~+TvCn=n*!GQBfRxfs89#I>d>+pb z@ZT|@%GfM=glAFQS1JERQ8?xt{kD43tqDK<>1eQR-=)#BeqZ!kI=}bZ@S-T8&ydvP zqDY9nerET~ufJRPONSaPY}?@MxKqQQOuf0VI35-QxepPLiy|@QUrXXMmzZ@h>7+M_|h#uabH=+I$-xeC9vP~ z%bON2`N7L+hcY6=>DRyXck#6hMg zTV#XW>T)0-#tl3Vun2HE=fiQ4KSinMRm)&Ci<^&Uo*)LRUK`=Y9A~s~;c-@=19mbz zcZ6ht6j$vOH0Dnc6{a%X;h-Rh-LF6p_}aVv1SkF!X@7~5&;Of=(7b&D3iqjH?C|N# z`{cIX%W1UwUog)8gsx&b16nanif*1iH=r~ooCrYH)AmKK% z@E!wX*U|B0$ZeVPb9=0266Or1U=m$CiFzKpri`rgT#Kh{ag0S%@>oh$L3xa*GD8~G zly)Z9aC+#(J@GnPU-7;uS>|7-4IM`to$57e&BP@?XnuPg1>mkh03!eYSVyHF1lCdA zf2krcoN66mchyXYAfQzcDW@C3iOEeFIUrhZlL_TO23Bd92p23q_TQ)Rm2-9i9r@0Dq~4Z zop-t26X(i?asR#3bmK=EF+S_Kq=8R_q+*&(XlJ(=bhq7NeAz9=m)&A~SuMtg-C}&% zEykDKVtm;x#uw!BGBjBTk`o&>S(HUX&T7)z#gaEn1Ez(*Ax}(CYgg^#vE<4CN4V+Y zhyhl_XC6zGtUn@FsT_kfD`qH^G*tlaMxHr=u}anHYByOFoUYJ!Ww|`c-fMOFCdk4< zPBd#B)pE-6V0~!&wRr728tjx6B5a*&jQm9lFivW8zn6?JQVwezBo=ds73u6(lz_t2 zK@hcg;*@=IRJTD`+r{7us@o%a%X0ciLF;Y3y)2g8=*0l2hpMSc?>C{?c_KS7@<-BmICiRTV>E7DI-%+Jk9 zC_Grk#v^}`K)h0Ew&PjfHCV=UnIS?81rjJlW;+3L#s?z8SlP~w*zO9A3q*wHi9lNb zOmj0+^!H=sX2;MLYiu5y?KihmXxN7@a2g>$(U)oMBR_4LP zoZ9gv^Teadv2IzT<~9v8w;ijL*BO>>5WG9oqOFOqouJ^D}Dtr~fSpqMCL%C;C zsI22zjD#SEAkFJ`Uodn*E$hodG$35&rvagIFhmX>g-Sm}4OWNAK|#2lhs-DFz53yD z5>B8$h0CgJ0U@7!AHIS4fQk0ew0trF&X#||Rvh-P zbkKXA^(;g>C_+AmllAuzvW|X5r&C_s{+EaZirh%AM#|dSP#O~{o8m&?M5Js7r&<&O zH&UM{IRQQqE$g%4m`2gEyoa2MO~m)HT+vYaGFn!^mDS2<*#b97dW>w10csb6UL2%> zF|v5ne>Zo7vTw%7*YxRW)HGJ|)$ixA@P0p5d0onyOmYv}AAu8RQb8Fjui%JhdgzCO z;1;}HPOSXcnS6^}FH4pQUgs|2`EXXE2)~nch9COA$t&oh?09UIE%Ym5uszu~G@O@K6 zjm3J)Ib}HyEGNFGimPKe?JVb0%lW3LEEM`z4s<%qEZSC7_CSFZyfUFIhRo`SHC{*f zFljgWxatMRDj8w-J1_!_C#WWRp?k59)*v^W6JGfu+F05r>%#}W(0*vr)J%|g6yyvo zDkc}>x}kM(2~(Q$))tqV_Pu{y2??W^59wA(*&6m(+!H+1vXm^D0_#hBFjE#3q1*-? z32BbhyZay+R6!f(#GPVjPoK+7@d-T{kuD|^f_zGcz|9xw!7!48{CuO&FYdsS7gXI~ zt`2kN!zmBEuW%L}fpP3$Z)mf4JbDhR_3-xahQ%iYn?a7}Ab{j(5>Mw#fpQ6U%X`sONq#uBlM-t3jyMkkpi=_00D%hP(Lj%jo!OxUupS#4OewNl|!L8zF4cFkHl*brqK^mWSD7~85lKV z$p*|2>*C@fsGlzk<+-Ru8CfEXry(JA;|Ax8mSlVpj4Xi{lsrn1e=6X1=q zryz*tB*`*bFdaw&^aj(7B>7T`E8eR!=f1iQ?iLg&%|vf*P^u2KMAa`493h^^Fiyu} zWjMqeY})}`m~gYW8erYNZNh~fl04Kf6>$I37$_3;+ZqpWqJCXti-KNYYYb@^@2a$= ztgH|YoL5~>XET6kuAs+dWg^C@R5>{^JcM7b3i0Aan>1){(w1^E8n`QjPL`9S@&%a_ zFxyf!9}gP%KP)eUwYc;kcfjJ)By}WH8?)hg%YU|lBrUcbZcQNZi1(8%4LS%8gVMpi zx*-P2uxl&GlF`bb*5tgIrv$kxP~XSGM~f@TB9c`~hUqk8lJOkHRF=;wPFG9+qRO(b zR(6aN>MDwkR|pjCQx$+^$%H-b79H*czPZWNpsBgJDkPuZtST!(V`f5COppp{3)u*z zn_IJ*Y=xM#YH}`O7FCx8sbzK9*7|N`r}F!1$XXipttn@)fORcwm>Z}?Et%}gZ?z-m zIMK+hjANli9D?JNn?}_Fq46CRs4efn392Ip>l-v`R$nec9e>uB_i;6J^BMVJv1Pn_ zCE}>TR{(saQqGYNrC@=2R>8U^m}Tc^M6w)3E9%IF$lJcIJb}E`>&cgjFXy}ySvE4AxQ^9*@V`uS8NM`3B zr^V+=%2x{4UIR{Dwo@xk3meFYpocSo$ZKF;cQlYGLE~q@mjqw)XXWOgP3)^~`M#y) z4P`>mZ4N4A1r4S*8p%4rXLHChH3?pC1aFT>W8-b*GkL(*HX(Jyj;0jIvwEDsg(bDnXIR+v19#~ zo0@64r`KBUhIN*E-VWcs-tsTsV7c=*TJGXab~@Xgy4muN%(C3nEtdP2<$`?jwLtY* z+pOSK+bwtb4$J*jxrx-`MH!{v*JyHS2-K&(D62_}eM6zIV53c=PA^L@rN1J>^xq5` z$(~)W$i}pxrHq6o(ZQDTT`N%;{XZ)H9oqMjOqABm2NzPFO1~_t=OntO5`BVaa9pp* zK2Mc@HMjhCaS>YSRrw~c@x%xB?AugggN?jrKE z0%do1D}oAgkUX~ypGD}v>#{iXCYH691!X$l#uVdNRGN!-+>(VN9Z5+sPFW9GTKyHg}Dhztv$5olk$X zmm~GD^J(uJ*el`w=MC9}-I^U`F?Kt21W=ZJLr(i268Vv+j;4>=L{mD+=k+n0=yE6d zx}LVlU%#_-=^XIfTe6ZqZWDd-mTZsvrx)MG>ENdN_T&2lJ%@7##?}8JA8d`qr32<= z-N}l!A}EYrup%hmW3ScV?gl4ODVZ0742@#?A;yac_*ZZOIwxIi_I3JE^gB`Pk`HoBQVT+WGHr7Pu>G_ z`EBs@%wf54OfJI>o&f=#8%O2kxWS8;JZ-KUbZdSA=&^>!1$Il6wLSvOSKAn-#hX-{ zpW!(}-*yAj%`!omgu&4~mDKMVI@e8>{a5~73F`W;tf#NhsIXJU|AUJc)?HS0uMY4} zXVIW{Fwx1CK)3YnF1wXqqp_Nz;^#g#SWi)XK2dxw^_ePIQ&D|lsEr=7LNM~ER(Yvz z4>_dDcbW;ZOYg3ZxN0hkTObgtjJL7&u>%|tHZy>$8n?$A8bmE(^=g#V6YIiDul1Cl z!a3MecE#gZ;Bo|%i6MpH4Hfi4LA_dWD1Mpg)G-I5q!37LGa&8n3jo;yk{X zEA6c5s|+X@OaniVMcfd|tB zZyIF}0Q+VvMSqN~1;&y-mM?QbV?G931OkS8KbD6;Jx%{aPQjBm1BTeVeWphrm>~r}E8e3){FfGI!2Lf+irjG~8 zI&tH1tV-0og+=jb^zoHOJ8{{Ic21xl2VzZ(r3VA$IHVq(B42|T{;Mw#xR?B2An+np{1U!2YBN+; zrU_r-Ad*I_zmzW{CTK8@M;EE?V9f3x)O9cb;3BPIA0)U3%a>4om9J3Z2ONF9 zfnvqVp|XD1C^aUTup`(gESfeCmBl=vzA~1Uai)?b8BLXjfhHSG{n!~sD=p{tFxddw zF+8G~o-mk6W|r^G)(C*bFseSv`p!oQBV`ow*Bprf`I>VSqpwF|qM)oa5*z3c&h|1Ka+FMt{?hK4DcMvk6e{q%0PO5m94+52oQ-DVSy3$vPxzH{Y*DUh_4W%F ztr#s?p4B%-R@GBo)M|`;mffji_;-#?KP=llo4^%DG6hC(F0t1Wy5oUGl#^MK;j* zg~%!2$hn-m!Bp^ZvT4>-1&?>8%9&cWKmA+g^`Nln@)SVum+7)1oY)Lm4}E++Lv{q26TQ4PJ>7o@!8r zznF7p&Q}=a1QnYN+?PqcX3Lu>vC|y6SI3+k>@TCK;apjl5u1^N*hb8iGuZZB`FXOK zTbVrMb1&YSX+IAO{0V(G53Sxs7v{-QrPl4<0*(N7PcVbRn0U}UM>Mb!lY8)UbLK2W z!&3Y2RB6790a?~`zBGYIz{msln{Pm){WM?pkSRBGce>ER`Lvzo>XBd+2O~%wh1onj zC=!^jS8@<+suaEuWj0=s=O{?I+*>Bsm3epTnE>VyDbwzFn*cH4;3MePGXnfpR~DCy z`*QG_oGCdGY>{3?u)>iiCxgL{+Vb5u00gltR~up{LpUC00JB{+^g42d;h-DNvHY~0 z+e!~hY5b8VWjZ)H;L+g0MNY|vf9<6DKayr4DL-uH;iPyG0bUKw+-#Y*+r$+y;!u(N zFdDxxu|-8Ol5|jWfxSU^YG#cDJu^i2=i>lqv8fji6bvwr}?*nmm`wj?NyP6 z2en$yO0eJw-ZuYd7Cx#YF$_v@ORZNXz@4<5AM<5(q&-A*oXg?S-w!7LKifs&COpU_h1DnZSxF2w%Nn9$}c;< z*d3>SSoYH@ss*Aa)19@lC)60h0c->&pw_rwm`1(VfgW*E z=z6&o&i?hXaIg+zE$TnrTra!&+i$>j4Rx$*8|6#-AZXxklJU_`x7J~|mbz^MhCJl| zaT9oF(B%3vOAgSHwa+%(TUMm zM%XTydCRQqVAJRU9(E8jukq+2E=GJVHF#JUO~devkT-};zc|@(Vnl;z*iM=Byj7m@ z|GGRV!Sw)xlFNI%Q^u$8LltaINiCbNJkhTms7!dVsEh1fi-wB7)|5xw#pGaO2`HDz$yULd0oxo6Yx+n7DdxA54gH8 zyaMh&=37tc-yK*3=_TlKpeMZQhEc=yq1V-egM+-mFQ_aP8P|ZpY6YUzP%KnU=NeHj zR*qFR1g^q3p;e4kG$U0oQUSqSHl{ULNQWBHBIU(V5J-lx*-?%K z>l+9dI)s+j!n^#k%`uK$jyqa`oXUeeOQ|k|dX95kCcONBXPD*9LP2eu0w{^%S-B;i93m&Rp~~pdWsF44H#GXSg=JjH^mfguTmimZu~PD4$DK zOm46>71J9$(Q=NdToc@f8iNEsx5L}ixnO023Lwn@0|W>qX7HpA<4LX*K#T%*ECxV4 zrd0ta&t3vn1aF}s-64&@SVch~GBySECYdZyvjITh!GVK^=6E1I`&82wqak?t1k|a5 zg#?9z0fZ=zuV%RRaL*6L&<1Wo7*+&Q@cxLB>;f2vqX^RX$OmpHKtlN3@1V~Q>t4EeF6xO!|4;qFRr~-MxHQp@9p}J2}uYO2Yf2dA`HW;)}&&gpp}d`8I%Ep>Wg6}CCKxms(r7{dnB%AbX*f9 zxJ+)P>&19n!r&RJ{?^n1v>6U@K*2>(cfKiH;wymNDL)#=toUFkLxX#x`J$%XA|Z!Me7@` zV=9rti)*?pbdNR5H?RvEL1>dTk0@QC8?`L)+NLVUbAcxhO~#s5m+GF2!NB#ZB!&Pk ziPsC4gqG!$gthLugr;zTDVPJ59XF#2cbL1G7|_*)CjxRjnYc=4S`vN3*ZVBdQPK!cJ6ZrMDJVT$xBNALko2@#*XrGZVAA+s13<`{(ZVw-(`zb)ea55nAUG;38 z#}9pGtb+e^??)M$Vu7^NfuT@f3u!XAIKwfufN=xf!-O*0#rcN8Rza;(jU2CSH7vXz zF#cg^`?uovAt!z_xHO&}y*xnSwM1PwvtLU3Df= z=c2*X&hcJX+tqD_4iUawc~|9lGn98Wdl^K4(LeM#EeK>-NJ005`364$+?!B^UUlBw z)CsOPhxOns2jne|>bz57QgahRln2X<$-%!R#BR+MGjSg3P-hO*d|qdn z^ue$e`}m+tC~yRAVhJ}7))oZRYdb=z+#wlPgR5XJcVO1Ar+^z^uVr|U2gC|<4UVFF zPSCt4b}W5*NbZXJ@7bu$Vek=G(TKxx`~Q^eog)$^dz^Ith`= z!F|F}Ctdpy?3wW6^3wlWKOebJzZuPoCNMS&Q5bVnDw6h-Ea#^avVitK4MEmP@X3#^ zIVG2C+A{x&)6%0!9P1pWgDRbsg-i0L1bohzH0OZmfZ+gmAn6r2>rOf=le8oLvS($y zQ#;^qk}Z3)iFNwc~VQ@u`2)&LeWf>i8cYo1^D{^rD<#V?>>>9C7x|`qm2mB^q zH}XAwBN{}>(~T&)`5&-$H&E;~FcKG2muvE*w%DJ1U5?UVlAN|3}%_%2a}%$a5PBE^-3(=xxC3e0W2$ELaxb*dJ)?OuwetSzfB6ph*4lml@w>QK zfw{nkf65459}Ovw`?3g_s}=790IyQ}`{1=+rTzDD$CVDl=<+xD2h2D7a7pz!tUf<{ zAS0{XPyvwmHE&s8(rw)H}z z&cB}JaNo^GQ|h~}lUCoA<{$oy>urfbuQhTt1Mt^r>?#OO&uficMWIgoL1R}jEb+;W zU2k#4kD9sW(e>u8B~-qJs}v1*!SyA7O{F_8xT^T~v~cy-^swnvyQQmz*3dt!rK_LQ zXw~`sUKI4IE74!!Ro4eXt4nj*xZWzb=v9xSG}=`be?j;&@HYg11IX9b)it=(YaSJK zo5r?vz32HBUMw@m+i(lQrAqBwb%0DnhLgejR>yO%HyaE?^RmT-t}eJ4tT4?#$! z3*lVwNUGM^)yh+$y~j}!-XORhPJXttE6z%u)!Ee~coxDrc{kX(bhQe0cd(LQq`q&W zSwrCEW;LXHZ@S(JdjKzYX)oMJTG8GWL7%MpMLf;YpEjqVQkx%^9db!#}rJQ@jg?k+4HT4ncFrTQ8f(~=^V?^o6MWGF- zzJ^9P%%$q9d#uCU$Y0LX!9^VAKJ|H^0OHT6&%wuH9OfVDv&+814)Y;@8s3f>1svwc zC;a{EhfR=V>XQ`q%$yL1M2k2=Bww0Z5vkTIPg;@f8=@WN56V-u8uD!OzJIvv!TamKf*iIK)BjsfFxspe&9#D8$l*3%0 zye)&T{e1Ld91^efPyEsq74cHN@g7GohD)JHHEjL6bnVj5+X>&T{}%UFx6b`KztvyG z_D7sMPrmmRe0Uvc{s)s>4K(etzka&wNO16Epx$t#n@908UGc%&;pNqKgr1q{YM<}+ zCNxrO?=aJ|@KKEV#<{#vYQAoB00Tk#R(#+E$d_ihD*E%ya=ohqAU>Ys8u 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 91feaa7a9da..9365112ccf0 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -59,11 +59,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 a6950a792ab..9b84e990c16 100644 --- a/core/src/smartcontracts/isi/triggers/mod.rs +++ b/core/src/smartcontracts/isi/triggers/mod.rs @@ -95,7 +95,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 ff65fdee954..bc5963baa8f 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -377,7 +377,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. @@ -385,7 +385,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 c113f9a8562..e089b3ea824 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 7335d11de48..d65d93ed38d 100644 --- a/core/src/state.rs +++ b/core/src/state.rs @@ -1360,7 +1360,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 @@ -1396,7 +1396,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 ca8e675c034..81c375a3db7 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 4841549d353..496a71bb732 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 6da46f26437..875c09eb158 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 b8ef73c6e7e..7af0fe8fb8b 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -1368,9 +1368,9 @@ "type": "Vec" }, { - "tag": "Wasm", + "tag": "SmartContract", "discriminant": 1, - "type": "WasmSmartContract" + "type": "SmartContract" } ] }, @@ -1430,8 +1430,8 @@ "Executor": { "Struct": [ { - "name": "wasm", - "type": "WasmSmartContract" + "name": "smart_contract", + "type": "SmartContract" } ] }, @@ -2241,7 +2241,7 @@ "InvalidParameterError": { "Enum": [ { - "tag": "Wasm", + "tag": "SmartContract", "discriminant": 0, "type": "String" }, @@ -3769,6 +3769,15 @@ } ] }, + "SmartContract": "Vec", + "SmartContractExecutionFail": { + "Struct": [ + { + "name": "reason", + "type": "String" + } + ] + }, "SmartContractParameter": { "Enum": [ { @@ -4103,9 +4112,9 @@ "type": "InstructionExecutionFail" }, { - "tag": "WasmExecution", + "tag": "SmartContractExecution", "discriminant": 4, - "type": "WasmExecutionFail" + "type": "SmartContractExecutionFail" } ] }, @@ -4567,15 +4576,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 fcecd5b0772..5fb000b4fe6 100644 --- a/genesis/src/lib.rs +++ b/genesis/src/lib.rs @@ -128,7 +128,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); if instructions.is_empty() { @@ -156,7 +156,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`] @@ -295,7 +295,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] @@ -359,7 +359,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 0b8fb381f22..df3aa05be95 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -364,6 +364,8 @@ types!( SignedQueryV1, SignedTransaction, SignedTransactionV1, + SmartContract, + SmartContractExecutionFail, SmartContractParameter, SmartContractParameters, SocketAddr, @@ -425,8 +427,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"))] {