diff --git a/Cargo.lock b/Cargo.lock index eafbb47adb3..33332f6484a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2001,11 +2001,14 @@ dependencies = [ name = "gear-common" version = "0.1.0" dependencies = [ + "frame-benchmarking", "frame-support", + "frame-system", "gear-core", "gear-runtime-interface", "log", "parity-scale-codec", + "parity-wasm 0.42.2", "primitive-types", "scale-info", "sp-arithmetic", @@ -2125,6 +2128,7 @@ dependencies = [ "pallet-gas", "pallet-gear", "pallet-gear-debug", + "pallet-gear-program", "pallet-gear-rpc-runtime-api", "pallet-grandpa", "pallet-randomness-collective-flip", @@ -4358,6 +4362,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-gas", + "pallet-gear-program", "pallet-timestamp", "parity-scale-codec", "parity-wasm 0.42.2", @@ -4374,6 +4379,7 @@ dependencies = [ "tests-exit-init", "tests-init-wait", "tests-program-factory", + "tests-proxy", "wabt", ] @@ -4394,6 +4400,7 @@ dependencies = [ "pallet-balances", "pallet-gas", "pallet-gear", + "pallet-gear-program", "pallet-timestamp", "parity-scale-codec", "parity-wasm 0.42.2", @@ -4407,6 +4414,27 @@ dependencies = [ "wabt", ] +[[package]] +name = "pallet-gear-program" +version = "2.0.0" +dependencies = [ + "env_logger", + "frame-benchmarking", + "frame-support", + "frame-system", + "gear-common", + "gear-core", + "log", + "pallet-balances", + "parity-scale-codec", + "primitive-types", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-gear-rpc" version = "2.0.0" @@ -4586,6 +4614,7 @@ dependencies = [ "pallet-balances", "pallet-gas", "pallet-gear", + "pallet-gear-program", "pallet-timestamp", "parity-scale-codec", "parity-wasm 0.42.2", @@ -7716,6 +7745,16 @@ dependencies = [ "tests-common", ] +[[package]] +name = "tests-proxy" +version = "0.1.0" +dependencies = [ + "gear-wasm-builder", + "gstd", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "tests-wait-wake" version = "0.1.0" diff --git a/common/Cargo.toml b/common/Cargo.toml index d53b25393f1..50d96f12edb 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -22,7 +22,10 @@ sp-runtime = { version = "5.0.0", git = "https://github.com/gear-tech/substrate. sp-std = { version = "4.0.0", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false } sp-arithmetic = { version = "4.0.0-dev", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false } frame-support = { version = "4.0.0-dev", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false } +frame-system = { version = "4.0.0-dev", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false, optional = true } +frame-benchmarking = { version = "4.0.0-dev", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false, optional = true } gear-runtime-interface = { path = "../runtime-interface", default-features = false } +parity-wasm = { version = "0.42.2", default-features = false, optional = true } [features] default = ["std"] @@ -38,3 +41,9 @@ std = [ "primitive-types/std", "gear-runtime-interface/std", ] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-system/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "parity-wasm", +] diff --git a/common/src/benchmarking.rs b/common/src/benchmarking.rs new file mode 100644 index 00000000000..306ae9328d5 --- /dev/null +++ b/common/src/benchmarking.rs @@ -0,0 +1,147 @@ +// This file is part of Gear. + +// Copyright (C) 2022 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; + +use parity_wasm::elements::*; +use sp_io::hashing::blake2_256; +use sp_std::borrow::ToOwned; + +pub fn account(name: &'static str, index: u32, seed: u32) -> AccountId { + let entropy = (name, index, seed).using_encoded(blake2_256); + AccountId::from_origin(H256::from_slice(&entropy[..])) +} + +// A wasm module that allocates `$num_pages` of memory in `init` function. +// In text format would look something like +// (module +// (type (func)) +// (import "env" "memory" (memory $num_pages)) +// (func (type 0)) +// (export "init" (func 0))) +pub fn create_module(num_pages: u32) -> parity_wasm::elements::Module { + parity_wasm::elements::Module::new(vec![ + Section::Type(TypeSection::with_types(vec![Type::Function( + FunctionType::new(vec![], vec![]), + )])), + Section::Import(ImportSection::with_entries(vec![ImportEntry::new( + "env".into(), + "memory".into(), + External::Memory(MemoryType::new(num_pages, None)), + )])), + Section::Function(FunctionSection::with_entries(vec![Func::new(0)])), + Section::Export(ExportSection::with_entries(vec![ExportEntry::new( + "init".into(), + Internal::Function(0), + )])), + Section::Code(CodeSection::with_bodies(vec![FuncBody::new( + vec![], + Instructions::new(vec![Instruction::End]), + )])), + ]) +} + +pub fn generate_wasm(num_pages: u32) -> Result, &'static str> { + let module = create_module(num_pages); + let code = parity_wasm::serialize(module).map_err(|_| "Failed to serialize module")?; + + Ok(code) +} + +// A wasm module that allocates `$num_pages` in `handle` function: +// (module +// (import "env" "memory" (memory 1)) +// (import "env" "alloc" (func $alloc (param i32) (result i32))) +// (export "init" (func $init)) +// (export "handle" (func $handle)) +// (func $init) +// (func $handle +// (local $result i32) +// (local.set $result (call $alloc (i32.const $num_pages))) +// ) +// ) +pub fn generate_wasm2(num_pages: i32) -> Result, &'static str> { + let module = parity_wasm::elements::Module::new(vec![ + Section::Type(TypeSection::with_types(vec![ + Type::Function(FunctionType::new( + vec![ValueType::I32], + vec![ValueType::I32], + )), + Type::Function(FunctionType::new(vec![], vec![])), + ])), + Section::Import(ImportSection::with_entries(vec![ + ImportEntry::new( + "env".into(), + "memory".into(), + External::Memory(MemoryType::new(1_u32, None)), + ), + ImportEntry::new("env".into(), "alloc".into(), External::Function(0_u32)), + ])), + Section::Function(FunctionSection::with_entries(vec![ + Func::new(1_u32), + Func::new(1_u32), + ])), + Section::Export(ExportSection::with_entries(vec![ + ExportEntry::new("init".into(), Internal::Function(1)), + ExportEntry::new("handle".into(), Internal::Function(2)), + ])), + Section::Code(CodeSection::with_bodies(vec![ + FuncBody::new(vec![], Instructions::new(vec![Instruction::End])), + FuncBody::new( + vec![Local::new(1, ValueType::I32)], + Instructions::new(vec![ + Instruction::I32Const(num_pages), + Instruction::Call(0), + Instruction::SetLocal(0), + Instruction::End, + ]), + ), + ])), + ]); + let code = parity_wasm::serialize(module).map_err(|_| "Failed to serialize module")?; + + Ok(code) +} + +pub fn generate_wasm3(payload: Vec) -> Result, &'static str> { + let mut module = create_module(1); + module + .insert_section(Section::Custom(CustomSection::new( + "zeroed_section".to_owned(), + payload, + ))) + .unwrap(); + let code = parity_wasm::serialize(module).map_err(|_| "Failed to serialize module")?; + + Ok(code) +} + +pub fn set_program(program_id: H256, code: Vec, static_pages: u32, nonce: u64) { + let code_hash = CodeHash::generate(&code).into_origin(); + super::set_program( + program_id, + ActiveProgram { + static_pages, + persistent_pages: (0..static_pages).collect(), + code_hash, + nonce, + state: ProgramState::Initialized, + }, + (0..static_pages).map(|i| (i, vec![0u8; 65536])).collect(), + ); +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 3aeb1bfe6f4..d6a1594d8e1 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -22,6 +22,9 @@ pub mod lazy_pages; pub mod native; pub mod storage_queue; +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchError, DispatchResult}, @@ -492,22 +495,32 @@ fn code_key(code_hash: H256, kind: CodeKeyPrefixKind) -> Vec { key } -fn page_key(id: H256, page: u32) -> Vec { +pub fn pages_prefix(program_id: H256) -> Vec { let mut key = Vec::new(); key.extend(STORAGE_PROGRAM_PAGES_PREFIX); - id.encode_to(&mut key); + program_id.encode_to(&mut key); + + key +} + +fn page_key(id: H256, page: u32) -> Vec { + let mut key = pages_prefix(id); key.extend(b"::"); page.encode_to(&mut key); key } -pub fn wait_key(prog_id: H256, msg_id: H256) -> Vec { +pub fn wait_prefix(prog_id: H256) -> Vec { let mut key = Vec::new(); key.extend(STORAGE_WAITLIST_PREFIX); prog_id.encode_to(&mut key); key.extend(b"::"); - msg_id.encode_to(&mut key); + key +} +pub fn wait_key(prog_id: H256, msg_id: H256) -> Vec { + let mut key = wait_prefix(prog_id); + msg_id.encode_to(&mut key); key } @@ -545,9 +558,8 @@ pub fn set_program_terminated_status(id: H256) -> Result<(), ProgramError> { if program.is_terminated() { return Err(ProgramError::IsTerminated); } - let mut pages_prefix = STORAGE_PROGRAM_PAGES_PREFIX.to_vec(); - pages_prefix.extend(&program_key(id)); - sp_io::storage::clear_prefix(&pages_prefix, None); + + sp_io::storage::clear_prefix(&pages_prefix(id), None); sp_io::storage::set(&program_key(id), &Program::Terminated.encode()); Ok(()) @@ -699,7 +711,7 @@ pub fn remove_waiting_message(dest_prog_id: H256, msg_id: H256) -> Option<(Queue msg } -fn waiting_init_prefix(prog_id: H256) -> Vec { +pub fn waiting_init_prefix(prog_id: H256) -> Vec { let mut key = Vec::new(); key.extend(STORAGE_PROGRAM_STATE_WAIT_PREFIX); prog_id.encode_to(&mut key); diff --git a/pallets/gear-debug/Cargo.toml b/pallets/gear-debug/Cargo.toml index 95196f303a0..cea1fdcfdce 100644 --- a/pallets/gear-debug/Cargo.toml +++ b/pallets/gear-debug/Cargo.toml @@ -43,6 +43,7 @@ gear-backend-sandbox = { path = "../../core-backend/sandbox", default-features = hex-literal = "0.3.3" pallet-timestamp = { version = "4.0.0-dev", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable" } pallet-gas = { path = "../gas" } +pallet-gear-program = { path = "../gear-program", default-features = false } [features] default = ['std'] diff --git a/pallets/gear-debug/src/mock.rs b/pallets/gear-debug/src/mock.rs index 85fe2b993cf..82aa3785ded 100644 --- a/pallets/gear-debug/src/mock.rs +++ b/pallets/gear-debug/src/mock.rs @@ -118,6 +118,12 @@ impl common::GasPrice for GasConverter { type Balance = u128; } +impl pallet_gear_program::Config for Test { + type Event = Event; + type WeightInfo = (); + type Currency = Balances; +} + impl pallet_gear::Config for Test { type Event = Event; type Currency = Balances; @@ -143,6 +149,7 @@ construct_runtime!( Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Authorship: pallet_authorship::{Pallet, Storage}, Timestamp: pallet_timestamp::{Pallet, Storage}, + GearProgram: pallet_gear_program::{Pallet, Storage, Event}, Gear: pallet_gear::{Pallet, Call, Storage, Event}, Gas: pallet_gas, } diff --git a/pallets/gear-program/Cargo.toml b/pallets/gear-program/Cargo.toml new file mode 100644 index 00000000000..52d9476153d --- /dev/null +++ b/pallets/gear-program/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "pallet-gear-program" +version = "2.0.0" +authors = ['Gear Technologies'] +edition = '2018' +license = "GPL-3.0" +homepage = "https://gear-tech.io" +repository = "https://github.com/gear-tech/gear" +description = "Gear pallet to work with programs" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +log = { version = "0.4.14", default-features = false } +primitive-types = { version = "0.10.1", default-features = false, features = ["scale-info"] } + +# Internal deps +common = { package = "gear-common", path = "../../common", default-features = false } + +# Substrate deps +frame-support = { version = "4.0.0-dev", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false } +frame-system = { version = "4.0.0-dev", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false } +frame-benchmarking = { version = "4.0.0-dev", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false, optional = true } +sp-core = { version = "5.0.0", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false } +sp-std = { version = "4.0.0-dev", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false } +sp-io = { version = "5.0.0", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false } +sp-runtime = { version = "5.0.0", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable", default-features = false } +pallet-balances = { version = "4.0.0-dev", default-features = false, git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable" } + +[dev-dependencies] +env_logger = "0.9" +gear-core = { path = "../../core" } + +[features] +default = ['std'] +std = [ + "codec/std", + "log/std", + "common/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-io/std", + "sp-std/std", + "sp-core/std", + "sp-runtime/std", + "primitive-types/std", + "pallet-balances/std" +] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-system/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "common/runtime-benchmarks" +] diff --git a/pallets/gear-program/README.md b/pallets/gear-program/README.md new file mode 100644 index 00000000000..a35e52035ff --- /dev/null +++ b/pallets/gear-program/README.md @@ -0,0 +1,14 @@ +# API to work with programs + +A module provides functions for things like pause/resume/check existence of programs. + +## Interface + +### Dispatchable Functions + +### Functions + +* `pause_program` - pause running program +* `resume_program` - resumes previously paused program +* `program_paused` - checks if the paused program with specified id exists +* `program_exists` - checks if the program with specified id exists diff --git a/pallets/gear-program/src/benchmarking.rs b/pallets/gear-program/src/benchmarking.rs new file mode 100644 index 00000000000..575f3692a80 --- /dev/null +++ b/pallets/gear-program/src/benchmarking.rs @@ -0,0 +1,53 @@ +// This file is part of Gear. + +// Copyright (C) 2022 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; +use common::{benchmarking, Origin}; +use sp_runtime::traits::UniqueSaturatedInto; + +#[allow(unused)] +use crate::Pallet as GearProgram; +use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; +use frame_support::traits::Currency; +use frame_system::RawOrigin; + +benchmarks! { + where_clause { where + T::AccountId: Origin, + } + + resume_program { + let q in 1 .. 256; + let caller: T::AccountId = benchmarking::account("caller", 0, 0); + ::Currency::deposit_creating(&caller, (1u128 << 60).unique_saturated_into()); + let code = benchmarking::generate_wasm(q).unwrap(); + + let program_id = benchmarking::account::("program", 0, 100).into_origin(); + benchmarking::set_program(program_id, code, q, 0u64); + + let memory_pages = common::get_program_pages(program_id, (0..q).collect()).unwrap(); + + crate::Pallet::::pause_program(program_id).unwrap(); + }: _(RawOrigin::Signed(caller), program_id, memory_pages, Default::default(), 10_000u32.into()) + verify { + assert!(crate::Pallet::::program_exists(program_id)); + assert!(!crate::Pallet::::program_paused(program_id)); + } +} + +impl_benchmark_test_suite!(GearProgram, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/pallets/gear-program/src/lib.rs b/pallets/gear-program/src/lib.rs new file mode 100644 index 00000000000..1a5f5b47f49 --- /dev/null +++ b/pallets/gear-program/src/lib.rs @@ -0,0 +1,151 @@ +// This file is part of Gear. + +// Copyright (C) 2022 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; +use primitive_types::H256; +use sp_std::collections::btree_map::BTreeMap; +use sp_std::prelude::*; + +mod pause; +pub use pause::PauseError; + +mod program; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{ + pallet_prelude::*, + traits::{ + Currency, ExistenceRequirement, LockIdentifier, LockableCurrency, WithdrawReasons, + }, + }; + use frame_system::pallet_prelude::*; + use sp_runtime::traits::{UniqueSaturatedInto, Zero}; + use weights::WeightInfo; + + const LOCK_ID: LockIdentifier = *b"resume_p"; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type Event: From> + IsType<::Event>; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + + type Currency: LockableCurrency; + } + + type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Program has been successfully resumed + ProgramResumed(H256), + /// Program has been paused + ProgramPaused(H256), + } + + #[pallet::error] + pub enum Error { + PausedProgramNotFound, + WrongMemoryPages, + ResumeProgramNotEnoughValue, + WrongWaitList, + } + + #[pallet::storage] + #[pallet::unbounded] + pub(crate) type PausedPrograms = StorageMap<_, Identity, H256, pause::PausedProgram>; + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet + where + T::AccountId: common::Origin, + { + /// Resumes a previously paused program + /// + /// The origin must be Signed and the sender must have sufficient funds to + /// transfer value to the program. + /// + /// Parameters: + /// - `program_id`: id of the program to resume. + /// - `memory_pages`: program memory before it was paused. + /// - `value`: balance to be transferred to the program once it's been resumed. + /// + /// - `ProgramResumed(H256)` in the case of success. + #[frame_support::transactional] + #[pallet::weight(::WeightInfo::resume_program(memory_pages.values().map(|p| p.len() as u32).sum()))] + pub fn resume_program( + origin: OriginFor, + program_id: H256, + memory_pages: BTreeMap>, + wait_list: BTreeMap, + value: BalanceOf, + ) -> DispatchResultWithPostInfo { + let account = ensure_signed(origin)?; + + ensure!(!value.is_zero(), Error::::ResumeProgramNotEnoughValue); + + Self::resume_program_impl( + program_id, + memory_pages, + wait_list, + >::block_number().unique_saturated_into(), + )?; + + let program_account = &::from_origin(program_id); + T::Currency::transfer( + &account, + program_account, + value, + ExistenceRequirement::AllowDeath, + )?; + + // TODO: maybe it is sufficient just to reserve value? (#762) + T::Currency::extend_lock(LOCK_ID, program_account, value, WithdrawReasons::FEE); + + Self::deposit_event(Event::ProgramResumed(program_id)); + + Ok(().into()) + } + } +} diff --git a/pallets/gear-program/src/mock.rs b/pallets/gear-program/src/mock.rs new file mode 100644 index 00000000000..2dbf60d4583 --- /dev/null +++ b/pallets/gear-program/src/mock.rs @@ -0,0 +1,114 @@ +// This file is part of Gear. + +// Copyright (C) 2022 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate as pallet_gear_program; +use frame_support::traits::{OnFinalize, OnInitialize}; +use frame_support::{construct_runtime, parameter_types}; +use frame_system as system; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; +type AccountId = u64; + +// Configure a mock runtime to test the pallet. +construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + GearProgram: pallet_gear_program::{Pallet, Storage, Event}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; + pub const ExistentialDeposit: u64 = 1; +} + +impl system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = u128; + type DustRemoval = (); + type Event = Event; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); +} + +impl pallet_gear_program::Config for Test { + type Event = Event; + type WeightInfo = (); + type Currency = Balances; +} + +// Build genesis storage according to the mock runtime. +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +pub fn run_to_block(n: u64, _remaining_weight: Option) { + while System::block_number() < n { + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + } +} diff --git a/pallets/gear-program/src/pause.rs b/pallets/gear-program/src/pause.rs new file mode 100644 index 00000000000..c05c9a9f836 --- /dev/null +++ b/pallets/gear-program/src/pause.rs @@ -0,0 +1,125 @@ +// This file is part of Gear. + +// Copyright (C) 2022 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; +use codec::{Decode, Encode}; +use common::{self, QueuedDispatch}; +use frame_support::{dispatch::DispatchResult, storage::PrefixIterator}; +use scale_info::TypeInfo; + +#[derive(Clone, Debug, PartialEq, Decode, Encode, TypeInfo)] +pub(super) struct PausedProgram { + program_id: H256, + program: common::ActiveProgram, + pages_hash: H256, + wait_list_hash: H256, + waiting_init: Vec, +} + +fn decode_dispatch_tuple(_key: &[u8], value: &[u8]) -> Result<(QueuedDispatch, u32), codec::Error> { + <(QueuedDispatch, u32)>::decode(&mut &*value) +} + +fn memory_pages_hash(pages: &BTreeMap>) -> H256 { + pages.using_encoded(sp_io::hashing::blake2_256).into() +} + +fn wait_list_hash(wait_list: &BTreeMap) -> H256 { + wait_list.using_encoded(sp_io::hashing::blake2_256).into() +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum PauseError { + ProgramNotFound, + ProgramTerminated, +} + +impl pallet::Pallet { + pub fn pause_program(program_id: H256) -> Result<(), PauseError> { + let program = common::get_program(program_id).ok_or(PauseError::ProgramNotFound)?; + let program: common::ActiveProgram = program + .try_into() + .map_err(|_| PauseError::ProgramTerminated)?; + + let prefix = common::wait_prefix(program_id); + let previous_key = prefix.clone(); + + let paused_program = PausedProgram { + program_id, + pages_hash: memory_pages_hash( + &common::get_program_pages(program_id, program.persistent_pages.clone()) + .expect("pause_program: active program exists, therefore pages do"), + ), + program, + wait_list_hash: wait_list_hash( + &PrefixIterator::<_, ()>::new(prefix, previous_key, decode_dispatch_tuple) + .drain() + .map(|(d, _)| (d.message.id, d)) + .collect(), + ), + waiting_init: common::waiting_init_take_messages(program_id), + }; + + // code shouldn't be removed + // remove_program(program_id); + sp_io::storage::clear_prefix(&common::pages_prefix(program_id), None); + sp_io::storage::clear_prefix(&common::program_key(program_id), None); + + PausedPrograms::::insert(program_id, paused_program); + + Self::deposit_event(Event::ProgramPaused(program_id)); + + Ok(()) + } + + pub fn program_paused(id: H256) -> bool { + PausedPrograms::::contains_key(id) + } + + pub(super) fn resume_program_impl( + program_id: H256, + memory_pages: BTreeMap>, + wait_list: BTreeMap, + block_number: u32, + ) -> DispatchResult { + let paused_program = + PausedPrograms::::get(program_id).ok_or(Error::::PausedProgramNotFound)?; + + if paused_program.pages_hash != memory_pages_hash(&memory_pages) { + return Err(Error::::WrongMemoryPages.into()); + } + + if paused_program.wait_list_hash != wait_list_hash(&wait_list) { + return Err(Error::::WrongWaitList.into()); + } + + PausedPrograms::::remove(program_id); + + common::set_program(program_id, paused_program.program, memory_pages); + + wait_list.into_iter().for_each(|(msg_id, d)| { + common::insert_waiting_message(program_id, msg_id, d, block_number) + }); + sp_io::storage::set( + &common::waiting_init_prefix(program_id), + &paused_program.waiting_init.encode()[..], + ); + + Ok(()) + } +} diff --git a/pallets/gear-program/src/program.rs b/pallets/gear-program/src/program.rs new file mode 100644 index 00000000000..608a87538db --- /dev/null +++ b/pallets/gear-program/src/program.rs @@ -0,0 +1,29 @@ +// This file is part of Gear. + +// Copyright (C) 2022 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; + +impl pallet::Pallet { + pub fn program_exists(program_id: H256) -> bool { + common::program_exists(program_id) | Self::program_paused(program_id) + } + + pub fn reset_storage() { + PausedPrograms::::remove_all(None); + } +} diff --git a/pallets/gear-program/src/tests.rs b/pallets/gear-program/src/tests.rs new file mode 100644 index 00000000000..3c6fc829be3 --- /dev/null +++ b/pallets/gear-program/src/tests.rs @@ -0,0 +1,460 @@ +// This file is part of Gear. + +// Copyright (C) 2022 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use common::{ActiveProgram, Origin, ProgramState, QueuedDispatch, QueuedMessage}; +use frame_support::{assert_noop, assert_ok}; +use gear_core::program::CodeHash; +use sp_std::collections::btree_map::BTreeMap; + +use super::*; +use crate::mock::*; + +use utils::CreateProgramResult; + +#[test] +fn pause_program_works() { + new_test_ext().execute_with(|| { + let code = b"pretended wasm code".to_vec(); + let code_hash: H256 = CodeHash::generate(&code).into_origin(); + common::set_code(code_hash, &code); + + let static_pages: u32 = 16; + let memory_pages = { + let mut pages = BTreeMap::new(); + pages.insert(static_pages, vec![static_pages as u8]); + pages.insert(static_pages + 2, vec![static_pages as u8 + 2]); + for i in 0..static_pages { + pages.insert(i, vec![i as u8]); + } + + pages + }; + + let program_id = H256::from_low_u64_be(1); + + common::set_program( + program_id, + ActiveProgram { + static_pages, + persistent_pages: memory_pages.clone().into_keys().collect(), + code_hash, + nonce: 0, + state: ProgramState::Initialized, + }, + memory_pages.clone(), + ); + + let msg_id_1 = H256::from_low_u64_be(1); + common::insert_waiting_message( + program_id, + msg_id_1, + QueuedDispatch::new_handle(QueuedMessage { + id: msg_id_1, + source: H256::from_low_u64_be(3), + dest: program_id, + payload: Default::default(), + value: 0, + reply: None, + }), + 0, + ); + + let msg_id_2 = H256::from_low_u64_be(2); + common::insert_waiting_message( + program_id, + msg_id_2, + QueuedDispatch::new_handle(QueuedMessage { + id: msg_id_2, + source: H256::from_low_u64_be(4), + dest: program_id, + payload: Default::default(), + value: 0, + reply: None, + }), + 0, + ); + + run_to_block(2, None); + + assert_ok!(GearProgram::pause_program(program_id)); + + assert!(GearProgram::program_paused(program_id)); + + assert!(common::get_code(code_hash).is_some()); + + // although the memory pages should be removed + assert_eq!( + common::get_program_pages(program_id, memory_pages.into_keys().collect()), + None + ); + + assert!(common::remove_waiting_message(program_id, msg_id_1).is_none()); + assert!(common::remove_waiting_message(program_id, msg_id_2).is_none()); + }); +} + +#[test] +fn pause_program_twice_fails() { + new_test_ext().execute_with(|| { + let code = b"pretended wasm code".to_vec(); + let code_hash: H256 = CodeHash::generate(&code).into_origin(); + common::set_code(code_hash, &code); + + let program_id = H256::from_low_u64_be(1); + let static_pages = 256; + common::set_program( + program_id, + ActiveProgram { + static_pages, + persistent_pages: Default::default(), + code_hash, + nonce: 0, + state: ProgramState::Initialized, + }, + Default::default(), + ); + + run_to_block(2, None); + + assert_ok!(GearProgram::pause_program(program_id)); + assert_noop!( + GearProgram::pause_program(program_id), + PauseError::ProgramNotFound + ); + }); +} + +#[test] +fn pause_terminated_program_fails() { + new_test_ext().execute_with(|| { + let code = b"pretended wasm code".to_vec(); + let code_hash: H256 = CodeHash::generate(&code).into_origin(); + common::set_code(code_hash, &code); + + let program_id = H256::from_low_u64_be(1); + let static_pages = 256; + common::set_program( + program_id, + ActiveProgram { + static_pages, + persistent_pages: Default::default(), + code_hash, + nonce: 0, + state: ProgramState::Initialized, + }, + Default::default(), + ); + + run_to_block(2, None); + + assert_ok!(common::set_program_terminated_status(program_id)); + + assert_noop!( + GearProgram::pause_program(program_id), + PauseError::ProgramTerminated + ); + }); +} + +#[test] +fn pause_uninitialized_program_works() { + new_test_ext().execute_with(|| { + let static_pages = 16; + let CreateProgramResult { + program_id, + code_hash, + init_msg, + msg_1, + msg_2, + memory_pages, + } = utils::create_uninitialized_program_messages(static_pages); + + run_to_block(2, None); + + assert_ok!(GearProgram::pause_program(program_id)); + + assert!(GearProgram::program_paused(program_id)); + assert!(common::get_program(program_id).is_none()); + + assert!(common::get_code(code_hash).is_some()); + + // although the memory pages should be removed + assert_eq!( + common::get_program_pages(program_id, memory_pages.into_keys().collect()), + None + ); + + assert!(common::remove_waiting_message(program_id, msg_1.message.id).is_none()); + assert!(common::remove_waiting_message(program_id, msg_2.message.id).is_none()); + assert!(common::remove_waiting_message(program_id, init_msg.message.id).is_none()); + + assert!(common::waiting_init_take_messages(program_id).is_empty()); + }); +} + +#[test] +fn resume_uninitialized_program_works() { + new_test_ext().execute_with(|| { + let static_pages = 16; + let CreateProgramResult { + program_id, + init_msg, + msg_1, + msg_2, + memory_pages, + .. + } = utils::create_uninitialized_program_messages(static_pages); + + run_to_block(2, None); + + assert_ok!(GearProgram::pause_program(program_id)); + + let wait_list = IntoIterator::into_iter([&init_msg, &msg_1, &msg_2]) + .map(|d| (d.message.id, d.clone())) + .collect::>(); + + let block_number = 100; + assert_ok!(GearProgram::resume_program_impl( + program_id, + memory_pages.clone(), + wait_list, + block_number + )); + assert!(!GearProgram::program_paused(program_id)); + + let new_memory_pages = + common::get_program_pages(program_id, memory_pages.clone().into_keys().collect()) + .unwrap(); + assert_eq!(memory_pages, new_memory_pages); + + let waiting_init = common::waiting_init_take_messages(program_id); + assert_eq!(waiting_init.len(), 2); + assert!(waiting_init.contains(&msg_1.message.id)); + assert!(waiting_init.contains(&msg_2.message.id)); + + assert_eq!( + block_number, + common::remove_waiting_message(program_id, init_msg.message.id) + .map(|(_, bn)| bn) + .unwrap() + ); + assert_eq!( + block_number, + common::remove_waiting_message(program_id, msg_1.message.id) + .map(|(_, bn)| bn) + .unwrap() + ); + assert_eq!( + block_number, + common::remove_waiting_message(program_id, msg_2.message.id) + .map(|(_, bn)| bn) + .unwrap() + ); + }); +} + +#[test] +fn resume_program_twice_fails() { + new_test_ext().execute_with(|| { + let static_pages = 16; + let CreateProgramResult { + program_id, + memory_pages, + init_msg, + msg_1, + msg_2, + .. + } = utils::create_uninitialized_program_messages(static_pages); + + run_to_block(2, None); + + assert_ok!(GearProgram::pause_program(program_id)); + + let wait_list = IntoIterator::into_iter([init_msg, msg_1, msg_2]) + .map(|d| (d.message.id, d)) + .collect::>(); + + let block_number = 100; + assert_ok!(GearProgram::resume_program_impl( + program_id, + memory_pages.clone(), + wait_list.clone(), + block_number + )); + assert_noop!( + GearProgram::resume_program_impl(program_id, memory_pages, wait_list, block_number), + Error::::PausedProgramNotFound + ); + }); +} + +#[test] +fn resume_program_wrong_memory_fails() { + new_test_ext().execute_with(|| { + let static_pages = 16; + let CreateProgramResult { + program_id, + mut memory_pages, + init_msg, + msg_1, + msg_2, + .. + } = utils::create_uninitialized_program_messages(static_pages); + + run_to_block(2, None); + + assert_ok!(GearProgram::pause_program(program_id)); + + let block_number = 100; + memory_pages.remove(&0); + assert_noop!( + GearProgram::resume_program_impl( + program_id, + memory_pages, + IntoIterator::into_iter([init_msg, msg_1, msg_2]) + .map(|d| (d.message.id, d)) + .collect(), + block_number + ), + Error::::WrongMemoryPages + ); + }); +} + +#[test] +fn resume_program_wrong_list_fails() { + new_test_ext().execute_with(|| { + let static_pages = 16; + let CreateProgramResult { + program_id, + memory_pages, + init_msg, + msg_1, + mut msg_2, + .. + } = utils::create_uninitialized_program_messages(static_pages); + + run_to_block(2, None); + + assert_ok!(GearProgram::pause_program(program_id)); + + let block_number = 100; + msg_2.message.payload = [0, 1, 2, 3, 4, 5].into(); + assert_noop!( + GearProgram::resume_program_impl( + program_id, + memory_pages, + IntoIterator::into_iter([init_msg, msg_1, msg_2]) + .map(|d| (d.message.id, d)) + .collect(), + block_number + ), + Error::::WrongWaitList + ); + }); +} + +mod utils { + use super::*; + + pub struct CreateProgramResult { + pub program_id: H256, + pub code_hash: H256, + pub init_msg: QueuedDispatch, + pub msg_1: QueuedDispatch, + pub msg_2: QueuedDispatch, + pub memory_pages: BTreeMap>, + } + + pub fn create_uninitialized_program_messages(static_pages: u32) -> CreateProgramResult { + let code = b"pretended wasm code".to_vec(); + let code_hash: H256 = CodeHash::generate(&code).into_origin(); + common::set_code(code_hash, &code); + + let memory_pages = { + let mut pages = BTreeMap::>::new(); + pages.insert(static_pages, vec![static_pages as u8]); + pages.insert(static_pages + 2, vec![static_pages as u8 + 2]); + for i in 0..static_pages { + pages.insert(i, vec![i as u8]); + } + + pages + }; + + let init_msg_id = H256::from_low_u64_be(3); + let program_id = H256::from_low_u64_be(1); + common::set_program( + program_id, + ActiveProgram { + static_pages, + persistent_pages: memory_pages.clone().into_keys().collect(), + code_hash, + nonce: 0, + state: ProgramState::Uninitialized { + message_id: init_msg_id, + }, + }, + memory_pages.clone(), + ); + + // init message + let init_msg = QueuedDispatch::new_handle(QueuedMessage { + id: init_msg_id, + source: H256::from_low_u64_be(3), + dest: program_id, + payload: Default::default(), + value: 0, + reply: None, + }); + common::insert_waiting_message(program_id, init_msg_id, init_msg.clone(), 0); + + let msg_id_1 = H256::from_low_u64_be(1); + let msg_1 = QueuedDispatch::new_handle(QueuedMessage { + id: msg_id_1, + source: H256::from_low_u64_be(3), + dest: program_id, + payload: Default::default(), + value: 0, + reply: None, + }); + common::insert_waiting_message(program_id, msg_id_1, msg_1.clone(), 0); + common::waiting_init_append_message_id(program_id, msg_id_1); + + let msg_id_2 = H256::from_low_u64_be(2); + let msg_2 = QueuedDispatch::new_handle(QueuedMessage { + id: msg_id_2, + source: H256::from_low_u64_be(4), + dest: program_id, + payload: Default::default(), + value: 0, + reply: None, + }); + common::insert_waiting_message(program_id, msg_id_2, msg_2.clone(), 0); + common::waiting_init_append_message_id(program_id, msg_id_2); + + CreateProgramResult { + program_id, + code_hash, + init_msg, + msg_1, + msg_2, + memory_pages, + } + } +} diff --git a/pallets/gear-program/src/weights/mod.rs b/pallets/gear-program/src/weights/mod.rs new file mode 100644 index 00000000000..7d95887b4c5 --- /dev/null +++ b/pallets/gear-program/src/weights/mod.rs @@ -0,0 +1,38 @@ +// This file is part of Gear. + +// Copyright (C) 2022 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use frame_support::weights::{constants::RocksDbWeight, Weight}; + +mod pallet_gear_program; +pub use self::pallet_gear_program::WeightInfo as GearProgramWeight; + +/// Weight functions for pallet_gear_program. +pub trait WeightInfo { + fn resume_program(q: u32) -> Weight; +} + +// For backwards compatibility and tests +const SUBMIT_WEIGHT_PER_BYTE: u64 = 1_000_000; + +impl WeightInfo for () { + fn resume_program(q: u32) -> Weight { + (0u64) + .saturating_add(RocksDbWeight::get().writes(4u64)) + .saturating_add(SUBMIT_WEIGHT_PER_BYTE.saturating_mul(q as Weight)) + } +} diff --git a/pallets/gear-program/src/weights/pallet_gear_program.rs b/pallets/gear-program/src/weights/pallet_gear_program.rs new file mode 100644 index 00000000000..5cea7ff2b22 --- /dev/null +++ b/pallets/gear-program/src/weights/pallet_gear_program.rs @@ -0,0 +1,35 @@ + +//! Autogenerated weights for `pallet_gear_program` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-03-14, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("local"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/gear-node benchmark --chain=local --execution=wasm --wasm-execution=compiled --pallet=pallet_gear_program --steps 50 --repeat 20 --output ./pallets/gear-program/src/weights/ --extrinsic=* + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(clippy::unnecessary_cast)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `pallet_gear_program`. +pub struct WeightInfo(PhantomData); +impl super::WeightInfo for WeightInfo { + // Storage: GearProgram PausedPrograms (r:1 w:1) + // Storage: System Account (r:2 w:2) + // Storage: unknown [0x673a3a70616765733a3a13614ad1183876953cdd99749d6dcf5d41b7ffc0740c] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a13614ad1183876953cdd99749d6dcf5d41b7ffc0740cd2] (r:0 w:1) + // Storage: unknown [0x673a3a70726f675f776169743a3a13614ad1183876953cdd99749d6dcf5d41b7] (r:0 w:1) + fn resume_program(q: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 249_000 + .saturating_add((133_779_000 as Weight).saturating_mul(q as Weight)) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(5 as Weight)) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(q as Weight))) + } +} diff --git a/pallets/gear/Cargo.toml b/pallets/gear/Cargo.toml index 09f10689804..2f6bf240af8 100644 --- a/pallets/gear/Cargo.toml +++ b/pallets/gear/Cargo.toml @@ -40,6 +40,7 @@ sp-arithmetic = { version = "4.0.0-dev", git = "https://github.com/gear-tech/sub pallet-balances = { version = "4.0.0-dev", default-features = false, git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable" } pallet-authorship = { version = "4.0.0-dev", default-features = false, git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable" } +pallet-gear-program = { path = "../gear-program", default-features = false } [dev-dependencies] serde = "1.0.136" @@ -52,6 +53,7 @@ tests-init-wait = { path = "../../tests/init-wait" } tests-exit-init = { path = "../../tests/exit-init" } tests-exit-handle = { path = "../../tests/exit-handle" } tests-program-factory = { path = "../../tests/program-factory" } +tests-proxy = { path = "../../tests/proxy" } [features] default = ['std'] @@ -70,6 +72,7 @@ std = [ "sp-runtime/std", "pallet-balances/std", "pallet-authorship/std", + "pallet-gear-program/std", "primitive-types/std", "serde/std", "gear-runtime-interface/std", @@ -79,4 +82,5 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "frame-support/runtime-benchmarks", "parity-wasm", + "common/runtime-benchmarks" ] diff --git a/pallets/gear/src/benchmarking.rs b/pallets/gear/src/benchmarking.rs index 559670b9af4..d795db1cdff 100644 --- a/pallets/gear/src/benchmarking.rs +++ b/pallets/gear/src/benchmarking.rs @@ -19,14 +19,10 @@ //! Gear pallet benchmarking use super::*; -use codec::Encode; -use common::Origin; +use common::{benchmarking, Origin}; use gear_core::program::CodeHash; -use parity_wasm::elements::*; use sp_core::H256; -use sp_io::hashing::blake2_256; use sp_runtime::traits::UniqueSaturatedInto; -use sp_std::borrow::ToOwned; use sp_std::prelude::*; #[allow(unused)] @@ -40,139 +36,15 @@ const MAX_CODE_LEN: u32 = 128 * 1024; const MAX_PAYLOAD_LEN: u32 = 64 * 1024; const MAX_PAGES: u32 = 512; -pub fn account(name: &'static str, index: u32, seed: u32) -> AccountId { - let entropy = (name, index, seed).using_encoded(blake2_256); - AccountId::from_origin(H256::from_slice(&entropy[..])) -} - -// A wasm module that allocates `$num_pages` of memory in `init` function. -// In text format would look something like -// (module -// (type (func)) -// (import "env" "memory" (memory $num_pages)) -// (func (type 0)) -// (export "init" (func 0))) -fn create_module(num_pages: u32) -> parity_wasm::elements::Module { - parity_wasm::elements::Module::new(vec![ - Section::Type(TypeSection::with_types(vec![Type::Function( - FunctionType::new(vec![], vec![]), - )])), - Section::Import(ImportSection::with_entries(vec![ImportEntry::new( - "env".into(), - "memory".into(), - External::Memory(MemoryType::new(num_pages, None)), - )])), - Section::Function(FunctionSection::with_entries(vec![Func::new(0)])), - Section::Export(ExportSection::with_entries(vec![ExportEntry::new( - "init".into(), - Internal::Function(0), - )])), - Section::Code(CodeSection::with_bodies(vec![FuncBody::new( - vec![], - Instructions::new(vec![Instruction::End]), - )])), - ]) -} - -fn generate_wasm(num_pages: u32) -> Result, &'static str> { - let module = create_module(num_pages); - let code = parity_wasm::serialize(module).map_err(|_| "Failed to serialize module")?; - - Ok(code) -} - -// A wasm module that allocates `$num_pages` in `handle` function: -// (module -// (import "env" "memory" (memory 1)) -// (import "env" "alloc" (func $alloc (param i32) (result i32))) -// (export "init" (func $init)) -// (export "handle" (func $handle)) -// (func $init) -// (func $handle -// (local $result i32) -// (local.set $result (call $alloc (i32.const $num_pages))) -// ) -// ) -fn generate_wasm2(num_pages: i32) -> Result, &'static str> { - let module = parity_wasm::elements::Module::new(vec![ - Section::Type(TypeSection::with_types(vec![ - Type::Function(FunctionType::new( - vec![ValueType::I32], - vec![ValueType::I32], - )), - Type::Function(FunctionType::new(vec![], vec![])), - ])), - Section::Import(ImportSection::with_entries(vec![ - ImportEntry::new( - "env".into(), - "memory".into(), - External::Memory(MemoryType::new(1_u32, None)), - ), - ImportEntry::new("env".into(), "alloc".into(), External::Function(0_u32)), - ])), - Section::Function(FunctionSection::with_entries(vec![ - Func::new(1_u32), - Func::new(1_u32), - ])), - Section::Export(ExportSection::with_entries(vec![ - ExportEntry::new("init".into(), Internal::Function(1)), - ExportEntry::new("handle".into(), Internal::Function(2)), - ])), - Section::Code(CodeSection::with_bodies(vec![ - FuncBody::new(vec![], Instructions::new(vec![Instruction::End])), - FuncBody::new( - vec![Local::new(1, ValueType::I32)], - Instructions::new(vec![ - Instruction::I32Const(num_pages), - Instruction::Call(0), - Instruction::SetLocal(0), - Instruction::End, - ]), - ), - ])), - ]); - let code = parity_wasm::serialize(module).map_err(|_| "Failed to serialize module")?; - - Ok(code) -} - -fn generate_wasm3(payload: Vec) -> Result, &'static str> { - let mut module = create_module(1); - module - .insert_section(Section::Custom(CustomSection::new( - "zeroed_section".to_owned(), - payload, - ))) - .unwrap(); - let code = parity_wasm::serialize(module).map_err(|_| "Failed to serialize module")?; - - Ok(code) -} - -fn set_program(program_id: H256, code: Vec, static_pages: u32, nonce: u64) { - let code_hash = CodeHash::generate(&code).into_origin(); - common::set_program( - program_id, - common::ActiveProgram { - static_pages, - persistent_pages: (0..static_pages).collect(), - code_hash, - nonce, - state: common::ProgramState::Initialized, - }, - (0..static_pages).map(|i| (i, vec![0u8; 65536])).collect(), - ); -} - benchmarks! { where_clause { where T::AccountId: Origin, } submit_code { - let c in 0 .. MAX_CODE_LEN; - let caller: T::AccountId = account("caller", 0, 0); - let code = vec![0u8; c as usize]; + let c in MIN_CODE_LEN .. MAX_CODE_LEN; + let caller: T::AccountId = benchmarking::account("caller", 0, 0); + let code = benchmarking::generate_wasm3(vec![0u8; (c - MIN_CODE_LEN) as usize]).unwrap(); let code_hash: H256 = CodeHash::generate(&code).into_origin(); }: _(RawOrigin::Signed(caller), code) verify { @@ -182,9 +54,9 @@ benchmarks! { submit_program { let c in MIN_CODE_LEN .. MAX_CODE_LEN; let p in 0 .. MAX_PAYLOAD_LEN; - let caller: T::AccountId = account("caller", 0, 0); - T::Currency::deposit_creating(&caller, 100_000_000_000_000_u128.unique_saturated_into()); - let code = generate_wasm3(vec![0u8; (c - MIN_CODE_LEN) as usize]).unwrap(); + let caller: T::AccountId = benchmarking::account("caller", 0, 0); + ::Currency::deposit_creating(&caller, 100_000_000_000_000_u128.unique_saturated_into()); + let code = benchmarking::generate_wasm3(vec![0u8; (c - MIN_CODE_LEN) as usize]).unwrap(); let salt = vec![255u8; 32]; let payload = vec![1_u8; p as usize]; // Using a non-zero `value` to count in the transfer, as well @@ -196,11 +68,11 @@ benchmarks! { send_message { let p in 0 .. MAX_PAYLOAD_LEN; - let caller = account("caller", 0, 0); - T::Currency::deposit_creating(&caller, 100_000_000_000_000_u128.unique_saturated_into()); - let program_id = account::("program", 0, 100).into_origin(); - let code = generate_wasm2(16_i32).unwrap(); - set_program(program_id, code, 1_u32, 0_u64); + let caller = benchmarking::account("caller", 0, 0); + ::Currency::deposit_creating(&caller, 100_000_000_000_000_u128.unique_saturated_into()); + let program_id = benchmarking::account::("program", 0, 100).into_origin(); + let code = benchmarking::generate_wasm2(16_i32).unwrap(); + benchmarking::set_program(program_id, code, 1_u32, 0_u64); let payload = vec![0_u8; p as usize]; }: _(RawOrigin::Signed(caller), program_id, payload, 100_000_000_u64, 10_000_u32.into()) verify { @@ -209,12 +81,12 @@ benchmarks! { send_reply { let p in 0 .. MAX_PAYLOAD_LEN; - let caller = account("caller", 0, 0); - T::Currency::deposit_creating(&caller, 100_000_000_000_000_u128.unique_saturated_into()); - let program_id = account::("program", 0, 100).into_origin(); - let code = generate_wasm2(16_i32).unwrap(); - set_program(program_id, code, 1_u32, 0_u64); - let original_message_id = account::("message", 0, 100).into_origin(); + let caller = benchmarking::account("caller", 0, 0); + ::Currency::deposit_creating(&caller, 100_000_000_000_000_u128.unique_saturated_into()); + let program_id = benchmarking::account::("program", 0, 100).into_origin(); + let code = benchmarking::generate_wasm2(16_i32).unwrap(); + benchmarking::set_program(program_id, code, 1_u32, 0_u64); + let original_message_id = benchmarking::account::("message", 0, 100).into_origin(); Gear::::insert_to_mailbox( caller.clone().into_origin(), common::QueuedMessage { @@ -234,9 +106,9 @@ benchmarks! { initial_allocation { let q in 1 .. MAX_PAGES; - let caller: T::AccountId = account("caller", 0, 0); - T::Currency::deposit_creating(&caller, (1u128 << 60).unique_saturated_into()); - let code = generate_wasm(q).unwrap(); + let caller: T::AccountId = benchmarking::account("caller", 0, 0); + ::Currency::deposit_creating(&caller, (1u128 << 60).unique_saturated_into()); + let code = benchmarking::generate_wasm(q).unwrap(); let salt = vec![255u8; 32]; }: { let _ = crate::Pallet::::submit_program(RawOrigin::Signed(caller).into(), code, salt, vec![], 100_000_000u64, 0u32.into()); @@ -248,9 +120,9 @@ benchmarks! { alloc_in_handle { let q in 0 .. MAX_PAGES; - let caller: T::AccountId = account("caller", 0, 0); - T::Currency::deposit_creating(&caller, (1_u128 << 60).unique_saturated_into()); - let code = generate_wasm2(q as i32).unwrap(); + let caller: T::AccountId = benchmarking::account("caller", 0, 0); + ::Currency::deposit_creating(&caller, (1_u128 << 60).unique_saturated_into()); + let code = benchmarking::generate_wasm2(q as i32).unwrap(); let salt = vec![255u8; 32]; }: { let _ = crate::Pallet::::submit_program(RawOrigin::Signed(caller).into(), code, salt, vec![], 100_000_000u64, 0u32.into()); diff --git a/pallets/gear/src/lib.rs b/pallets/gear/src/lib.rs index 15e8844ba03..36de01db6f5 100644 --- a/pallets/gear/src/lib.rs +++ b/pallets/gear/src/lib.rs @@ -37,6 +37,8 @@ mod tests; pub type Authorship = pallet_authorship::Pallet; +use pallet_gear_program::Pallet as GearProgramPallet; + pub trait DebugInfo { fn is_remap_id_enabled() -> bool; fn remap_id(); @@ -70,7 +72,7 @@ pub mod pallet { use frame_support::{ dispatch::{DispatchError, DispatchResultWithPostInfo}, pallet_prelude::*, - traits::{BalanceStatus, Currency, Get, ReservableCurrency}, + traits::{BalanceStatus, Currency, Get, LockableCurrency, ReservableCurrency}, }; use frame_system::pallet_prelude::*; use gear_backend_sandbox::SandboxEnvironment; @@ -86,13 +88,16 @@ pub mod pallet { #[pallet::config] pub trait Config: - frame_system::Config + pallet_authorship::Config + pallet_timestamp::Config + frame_system::Config + + pallet_authorship::Config + + pallet_timestamp::Config + + pallet_gear_program::Config::Currency> { /// Because this pallet emits events, it depends on the runtime's definition of an event. type Event: From> + IsType<::Event>; /// Gas and value transfer currency - type Currency: Currency + ReservableCurrency; + type Currency: LockableCurrency + ReservableCurrency; /// Gas to Currency converter type GasPrice: GasPrice>; @@ -315,7 +320,7 @@ pub mod pallet { if message.value > 0 { // Assuming the programs has enough balance - T::Currency::repatriate_reserved( + ::Currency::repatriate_reserved( &::from_origin(message.source), user_id, message.value.unique_saturated_into(), @@ -334,7 +339,8 @@ pub mod pallet { timestamp: >::get().unique_saturated_into(), }; - let existential_deposit = T::Currency::minimum_balance().unique_saturated_into(); + let existential_deposit = + ::Currency::minimum_balance().unique_saturated_into(); let (dest, reply) = match kind { HandleKind::Init(ref code) => (CodeHash::generate(code).into_origin(), None), @@ -449,7 +455,8 @@ pub mod pallet { timestamp: >::get().unique_saturated_into(), }; - let existential_deposit = T::Currency::minimum_balance().unique_saturated_into(); + let existential_deposit = + ::Currency::minimum_balance().unique_saturated_into(); if T::DebugInfo::is_remap_id_enabled() { T::DebugInfo::remap_id(); @@ -473,15 +480,15 @@ pub mod pallet { break; } - let maybe_active_actor = { - let program_id = dispatch.message.dest; + let program_id = dispatch.message.dest; + let maybe_active_actor = if let Some(maybe_active_program) = + common::get_program(program_id) + { let current_message_id = dispatch.message.id; let maybe_message_reply = dispatch.message.reply; - let maybe_program = common::get_program(program_id); - // Check whether message should be added to the wait list - if let Some(Program::Active(ref prog)) = maybe_program { + if let Program::Active(ref prog) = maybe_active_program { let is_for_wait_list = maybe_message_reply.is_none() && matches!(prog.state, ProgramState::Uninitialized {message_id} if message_id != current_message_id); if is_for_wait_list { @@ -498,16 +505,19 @@ pub mod pallet { } } - maybe_program - .and_then(|prog| prog.try_into_native(program_id).ok()) + maybe_active_program + .try_into_native(program_id) + .ok() .map(|program| { - let balance = T::Currency::free_balance( + let balance = ::Currency::free_balance( &::from_origin(program_id), ) .unique_saturated_into(); ExecutableActor { program, balance } }) + } else { + None }; let journal = core_processor::process::< @@ -669,7 +679,7 @@ pub mod pallet { // Make sure there is no program with such id in program storage ensure!( - !common::program_exists(id.into_origin()), + !GearProgramPallet::::program_exists(id.into_origin()), Error::::ProgramAlreadyExists ); @@ -682,7 +692,7 @@ pub mod pallet { // First we reserve enough funds on the account to pay for `gas_limit` // and to transfer declared value. - T::Currency::reserve(&who, reserve_fee + value) + ::Currency::reserve(&who, reserve_fee + value) .map_err(|_| Error::::NotEnoughBalanceForReserve)?; let origin = who.into_origin(); @@ -747,7 +757,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let numeric_value: u128 = value.unique_saturated_into(); - let minimum: u128 = T::Currency::minimum_balance().unique_saturated_into(); + let minimum: u128 = ::Currency::minimum_balance().unique_saturated_into(); // Check that provided `gas_limit` value does not exceed the block gas limit ensure!( @@ -771,14 +781,14 @@ pub mod pallet { // Message is not guaranteed to be executed, that's why value is not immediately transferred. // That's because destination can fail to be initialized, while this dispatch message is next // in the queue. - T::Currency::reserve(&who, value.unique_saturated_into()) + ::Currency::reserve(&who, value.unique_saturated_into()) .map_err(|_| Error::::NotEnoughBalanceForReserve)?; - if common::program_exists(destination) { + if GearProgramPallet::::program_exists(destination) { let gas_limit_reserve = T::GasPrice::gas_price(gas_limit); // First we reserve enough funds on the account to pay for `gas_limit` - T::Currency::reserve(&who, gas_limit_reserve) + ::Currency::reserve(&who, gas_limit_reserve) .map_err(|_| Error::::NotEnoughBalanceForReserve)?; let origin = who.into_origin(); @@ -843,7 +853,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let numeric_value: u128 = value.unique_saturated_into(); - let minimum: u128 = T::Currency::minimum_balance().unique_saturated_into(); + let minimum: u128 = ::Currency::minimum_balance().unique_saturated_into(); // Ensure the `gas_limit` allows the extrinsic to fit into a block ensure!( @@ -864,16 +874,16 @@ pub mod pallet { // Message is not guaranteed to be executed, that's why value is not immediately transferred. // That's because destination can fail to be initialized, while this dispatch message is next // in the queue. - T::Currency::reserve(&who, value.unique_saturated_into()) + ::Currency::reserve(&who, value.unique_saturated_into()) .map_err(|_| Error::::NotEnoughBalanceForReserve)?; let message_id = common::next_message_id(&payload); - if common::program_exists(destination) { + if GearProgramPallet::::program_exists(destination) { let gas_limit_reserve = T::GasPrice::gas_price(gas_limit); // First we reserve enough funds on the account to pay for `gas_limit` - T::Currency::reserve(&who, gas_limit_reserve) + ::Currency::reserve(&who, gas_limit_reserve) .map_err(|_| Error::::NotEnoughBalanceForReserve)?; let origin = who.into_origin(); @@ -934,6 +944,7 @@ pub mod pallet { pub fn reset(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; >::remove_all(None); + GearProgramPallet::::reset_storage(); common::reset_storage(); Self::deposit_event(Event::DatabaseWiped); @@ -953,7 +964,7 @@ pub mod pallet { dest: &T::AccountId, amount: Self::Balance, ) -> Result<(), DispatchError> { - let _ = T::Currency::repatriate_reserved( + let _ = ::Currency::repatriate_reserved( &::from_origin(source), dest, amount, diff --git a/pallets/gear/src/manager.rs b/pallets/gear/src/manager.rs index 381ed68729f..1aafb2767a6 100644 --- a/pallets/gear/src/manager.rs +++ b/pallets/gear/src/manager.rs @@ -17,8 +17,8 @@ // along with this program. If not, see . use crate::{ - pallet::Reason, Authorship, Config, DispatchOutcome, Event, ExecutionResult, MessageInfo, - Pallet, + pallet::Reason, Authorship, Config, DispatchOutcome, Event, ExecutionResult, GearProgramPallet, + MessageInfo, Pallet, }; use codec::{Decode, Encode}; use common::{DAGBasedLedger, GasPrice, Origin, Program, QueuedDispatch, STORAGE_PROGRAM_PREFIX}; @@ -132,8 +132,9 @@ where let program = common::get_program(id) .and_then(|prog_with_status| prog_with_status.try_into_native(id).ok())?; - let balance = T::Currency::free_balance(&::from_origin(id)) - .unique_saturated_into(); + let balance = + ::Currency::free_balance(&::from_origin(id)) + .unique_saturated_into(); Some(ExecutableActor { program, balance }) } @@ -298,7 +299,7 @@ where if let Some((_, origin)) = T::GasHandler::get_limit(message_id) { let charge = T::GasPrice::gas_price(amount); if let Some(author) = Authorship::::author() { - let _ = T::Currency::repatriate_reserved( + let _ = ::Currency::repatriate_reserved( &::from_origin(origin), &author, charge, @@ -335,9 +336,9 @@ where assert!(res.is_ok(), "`exit` can be called only from active program"); let program_account = &::from_origin(program_id); - let balance = T::Currency::total_balance(program_account); + let balance = ::Currency::total_balance(program_account); if !balance.is_zero() { - T::Currency::transfer( + ::Currency::transfer( program_account, &::from_origin(value_destination.into_origin()), balance, @@ -356,8 +357,10 @@ where let refund = T::GasPrice::gas_price(gas_left); - let _ = - T::Currency::unreserve(&::from_origin(external), refund); + let _ = ::Currency::unreserve( + &::from_origin(external), + refund, + ); } } @@ -366,7 +369,7 @@ where let (gas_limit, dispatch) = QueuedDispatch::without_gas_limit(dispatch); if dispatch.message.value != 0 - && T::Currency::reserve( + && ::Currency::reserve( &::from_origin(dispatch.message.source), dispatch.message.value.unique_saturated_into(), ) @@ -386,10 +389,11 @@ where message_id ); - if common::program_exists(dispatch.message.dest) + let destination = dispatch.message.dest; + if GearProgramPallet::::program_exists(destination) || self .marked_destinations - .contains(&ProgramId::from_origin(dispatch.message.dest)) + .contains(&ProgramId::from_origin(destination)) { if let Some(gas_limit) = gas_limit { let _ = @@ -402,7 +406,7 @@ where // Being placed into a user's mailbox means the end of a message life cycle. // There can be no further processing whatsoever, hence any gas attempted to be // passed along must be returned (i.e. remain in the parent message's value tree). - Pallet::::insert_to_mailbox(dispatch.message.dest, dispatch.message.clone()); + Pallet::::insert_to_mailbox(destination, dispatch.message.clone()); Pallet::::deposit_event(Event::Log(dispatch.message)); } } @@ -444,7 +448,7 @@ where if let Some((_, origin)) = T::GasHandler::get_limit(message_id.into_origin()) { let charge = T::GasPrice::gas_price(chargeable_amount); if let Some(author) = Authorship::::author() { - let _ = T::Currency::repatriate_reserved( + let _ = ::Currency::repatriate_reserved( &::from_origin(origin), &author, charge, @@ -525,17 +529,18 @@ where ); let from = ::from_origin(from); let to = ::from_origin(to); - if T::Currency::can_reserve(&to, T::Currency::minimum_balance()) { + if ::Currency::can_reserve(&to, ::Currency::minimum_balance()) + { // `to` account exists, so we can repatriate reserved value for it. - let _ = T::Currency::repatriate_reserved( + let _ = ::Currency::repatriate_reserved( &from, &to, value.unique_saturated_into(), BalanceStatus::Free, ); } else { - T::Currency::unreserve(&from, value.unique_saturated_into()); - let _ = T::Currency::transfer( + ::Currency::unreserve(&from, value.unique_saturated_into()); + let _ = ::Currency::transfer( &from, &to, value.unique_saturated_into(), @@ -545,7 +550,7 @@ where } else { log::debug!("Value unreserve of amount {:?} from {:?}", value, from,); let from = ::from_origin(from); - T::Currency::unreserve(&from, value.unique_saturated_into()); + ::Currency::unreserve(&from, value.unique_saturated_into()); } } @@ -554,7 +559,7 @@ where if let Some(code) = common::get_code(code_hash) { for (candidate_id, init_message) in candidates { - if !common::program_exists(candidate_id.into_origin()) { + if !GearProgramPallet::::program_exists(candidate_id.into_origin()) { // Code hash for invalid code can't be added to the storage from extrinsics. let new_program = NativeProgram::new(candidate_id, code.clone()) .expect("guaranteed to be valid"); diff --git a/pallets/gear/src/mock.rs b/pallets/gear/src/mock.rs index 0d51df1f92e..5c97d0e33a4 100644 --- a/pallets/gear/src/mock.rs +++ b/pallets/gear/src/mock.rs @@ -44,6 +44,7 @@ construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: system::{Pallet, Call, Config, Storage, Event}, + GearProgram: pallet_gear_program::{Pallet, Storage, Event}, Gear: pallet_gear::{Pallet, Call, Storage, Event}, Gas: pallet_gas::{Pallet, Storage}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, @@ -102,6 +103,12 @@ impl common::GasPrice for GasConverter { type Balance = u128; } +impl pallet_gear_program::Config for Test { + type Event = Event; + type WeightInfo = (); + type Currency = Balances; +} + parameter_types! { pub const BlockGasLimit: u64 = 100_000_000; pub const WaitListFeePerBlock: u64 = 1_000; diff --git a/pallets/gear/src/tests.rs b/pallets/gear/src/tests.rs index 13ea0c4c841..c738949f961 100644 --- a/pallets/gear/src/tests.rs +++ b/pallets/gear/src/tests.rs @@ -28,11 +28,11 @@ use tests_program_factory::{CreateProgram, WASM_BINARY as PROGRAM_FACTORY_WASM_B use super::{ manager::HandleKind, mock::{ - new_test_ext, run_to_block, Event as MockEvent, Gear, Origin, System, Test, BLOCK_AUTHOR, - LOW_BALANCE_USER, USER_1, USER_2, USER_3, + new_test_ext, run_to_block, Event as MockEvent, Gear, GearProgram, Origin, System, Test, + BLOCK_AUTHOR, LOW_BALANCE_USER, USER_1, USER_2, USER_3, }, - pallet, Config, DispatchOutcome, Error, Event, ExecutionResult, GasAllowance, Mailbox, - MessageInfo, Pallet as GearPallet, Reason, + pallet, Config, DispatchOutcome, Error, Event, ExecutionResult, GasAllowance, + GearProgramPallet, Mailbox, MessageInfo, Pallet as GearPallet, Reason, }; use utils::*; @@ -1267,18 +1267,7 @@ fn messages_to_uninitialized_program_wait() { 0u128 )); - let event = match SystemPallet::::events() - .last() - .map(|r| r.event.clone()) - { - Some(MockEvent::Gear(e)) => e, - _ => unreachable!("Should be one Gear event"), - }; - - let MessageInfo { program_id, .. } = match event { - Event::InitMessageEnqueued(info) => info, - _ => unreachable!("expect Event::InitMessageEnqueued"), - }; + let program_id = utils::get_last_program_id(); assert!(!Gear::is_initialized(program_id)); assert!(!Gear::is_terminated(program_id)); @@ -1319,18 +1308,7 @@ fn uninitialized_program_should_accept_replies() { 0u128 )); - let event = match SystemPallet::::events() - .last() - .map(|r| r.event.clone()) - { - Some(MockEvent::Gear(e)) => e, - _ => unreachable!("Should be one Gear event"), - }; - - let MessageInfo { program_id, .. } = match event { - Event::InitMessageEnqueued(info) => info, - _ => unreachable!("expect Event::InitMessageEnqueued"), - }; + let program_id = utils::get_last_program_id(); assert!(!Gear::is_initialized(program_id)); assert!(!Gear::is_terminated(program_id)); @@ -1381,18 +1359,7 @@ fn defer_program_initialization() { 0u128 )); - let event = match SystemPallet::::events() - .last() - .map(|r| r.event.clone()) - { - Some(MockEvent::Gear(e)) => e, - _ => unreachable!("Should be one Gear event"), - }; - - let MessageInfo { program_id, .. } = match event { - Event::InitMessageEnqueued(info) => info, - _ => unreachable!("expect Event::InitMessageEnqueued"), - }; + let program_id = utils::get_last_program_id(); run_to_block(2, None); @@ -1456,18 +1423,7 @@ fn wake_messages_after_program_inited() { 0u128 )); - let event = match SystemPallet::::events() - .last() - .map(|r| r.event.clone()) - { - Some(MockEvent::Gear(e)) => e, - _ => unreachable!("Should be one Gear event"), - }; - - let MessageInfo { program_id, .. } = match event { - Event::InitMessageEnqueued(info) => info, - _ => unreachable!("expect Event::InitMessageEnqueued"), - }; + let program_id = utils::get_last_program_id(); run_to_block(2, None); @@ -2109,6 +2065,276 @@ fn exit_handle() { }) } +#[test] +fn paused_program_keeps_id() { + use tests_init_wait::WASM_BINARY; + + init_logger(); + new_test_ext().execute_with(|| { + System::reset_events(); + + let code = WASM_BINARY.to_vec(); + assert_ok!(GearPallet::::submit_program( + Origin::signed(USER_1).into(), + code.clone(), + vec![], + Vec::new(), + 100_000_000u64, + 0u128 + )); + + let program_id = utils::get_last_program_id(); + + run_to_block(2, None); + + assert_ok!(GearProgram::pause_program(program_id)); + + assert_noop!( + GearPallet::::submit_program( + Origin::signed(USER_3).into(), + code.clone(), + vec![], + Vec::new(), + 100_000_000u64, + 0u128 + ), + Error::::ProgramAlreadyExists + ); + + assert!(!Gear::is_initialized(program_id)); + assert!(!Gear::is_terminated(program_id)); + }) +} + +#[test] +fn messages_to_paused_program_skipped() { + use tests_init_wait::WASM_BINARY; + + init_logger(); + new_test_ext().execute_with(|| { + System::reset_events(); + + let code = WASM_BINARY.to_vec(); + assert_ok!(GearPallet::::submit_program( + Origin::signed(USER_1).into(), + code.clone(), + vec![], + Vec::new(), + 100_000_000u64, + 0u128 + )); + + let program_id = utils::get_last_program_id(); + + run_to_block(2, None); + + assert_ok!(GearProgram::pause_program(program_id)); + + let before_balance = BalancesPallet::::free_balance(USER_3); + + assert_ok!(GearPallet::::send_message( + Origin::signed(USER_3).into(), + program_id, + vec![], + 100_000_000u64, + 1000u128 + )); + + run_to_block(3, None); + + assert_eq!(before_balance, BalancesPallet::::free_balance(USER_3)); + }) +} + +#[test] +fn replies_to_paused_program_skipped() { + use tests_init_wait::WASM_BINARY; + + init_logger(); + new_test_ext().execute_with(|| { + System::reset_events(); + + let code = WASM_BINARY.to_vec(); + assert_ok!(GearPallet::::submit_program( + Origin::signed(USER_1).into(), + code.clone(), + vec![], + Vec::new(), + 100_000_000u64, + 0u128 + )); + + let program_id = utils::get_last_program_id(); + + run_to_block(2, None); + + assert_ok!(GearProgram::pause_program(program_id)); + + run_to_block(3, None); + + let message_id = Gear::mailbox(USER_1).and_then(|t| { + let mut keys = t.keys(); + keys.next().cloned() + }); + assert!(message_id.is_some()); + + let before_balance = BalancesPallet::::free_balance(USER_1); + + assert_ok!(GearPallet::::send_reply( + Origin::signed(USER_1).into(), + message_id.unwrap(), + b"PONG".to_vec(), + 50_000_000u64, + 1000u128, + )); + + run_to_block(4, None); + + assert_eq!(before_balance, BalancesPallet::::free_balance(USER_1)); + }) +} + +#[test] +fn program_messages_to_paused_program_skipped() { + use tests_init_wait::WASM_BINARY; + use tests_proxy::{InputArgs, WASM_BINARY as PROXY_WASM_BINARY}; + + init_logger(); + new_test_ext().execute_with(|| { + System::reset_events(); + + let code = WASM_BINARY.to_vec(); + assert_ok!(GearPallet::::submit_program( + Origin::signed(USER_1).into(), + code.clone(), + vec![], + Vec::new(), + 100_000_000u64, + 0u128 + )); + + let paused_program_id = utils::get_last_program_id(); + + let code = PROXY_WASM_BINARY.to_vec(); + assert_ok!(GearPallet::::submit_program( + Origin::signed(USER_3).into(), + code.clone(), + vec![], + InputArgs { + destination: paused_program_id.into() + } + .encode(), + 100_000_000u64, + 1_000u128 + )); + + let program_id = utils::get_last_program_id(); + + run_to_block(2, None); + + assert_ok!(GearProgram::pause_program(paused_program_id)); + + run_to_block(3, None); + + assert_ok!(GearPallet::::send_message( + Origin::signed(USER_3).into(), + program_id, + vec![], + 100_000_000u64, + 1_000u128 + )); + + run_to_block(4, None); + + assert_eq!( + 2_000u128, + BalancesPallet::::free_balance( + &::from_origin(program_id) + ) + ); + }) +} + +#[test] +fn resume_program_works() { + use tests_init_wait::WASM_BINARY; + + init_logger(); + new_test_ext().execute_with(|| { + System::reset_events(); + + let code = WASM_BINARY.to_vec(); + assert_ok!(GearPallet::::submit_program( + Origin::signed(USER_1).into(), + code.clone(), + vec![], + Vec::new(), + 100_000_000u64, + 0u128 + )); + + let program_id = utils::get_last_program_id(); + + run_to_block(2, None); + + let message_id = Gear::mailbox(USER_1).and_then(|t| { + let mut keys = t.keys(); + keys.next().cloned() + }); + assert!(message_id.is_some()); + + assert_ok!(GearPallet::::send_reply( + Origin::signed(USER_1).into(), + message_id.unwrap(), + b"PONG".to_vec(), + 50_000_000u64, + 1_000u128, + )); + + run_to_block(3, None); + + let program = match common::get_program(program_id).expect("program exists") { + common::Program::Active(p) => p, + _ => unreachable!(), + }; + let memory_pages = common::get_program_pages(program_id, program.persistent_pages) + .expect("program exists, so do pages"); + + assert_ok!(GearProgram::pause_program(program_id)); + + run_to_block(4, None); + + assert_ok!(GearProgramPallet::::resume_program( + Origin::signed(USER_3).into(), + program_id, + memory_pages, + Default::default(), + 10_000u128 + )); + + assert_ok!(GearPallet::::send_message( + Origin::signed(USER_3).into(), + program_id, + vec![], + 25_000_000u64, + 0u128 + )); + + run_to_block(5, None); + + let actual_n = Gear::mailbox(USER_3) + .map(|t| { + t.into_values().fold(0usize, |i, m| { + assert_eq!(m.payload, b"Hello, world!".encode()); + i + 1 + }) + }) + .unwrap_or(0); + + assert_eq!(actual_n, 1); + }) +} + mod utils { use codec::Encode; use frame_support::dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo}; diff --git a/pallets/gear/src/weights.rs b/pallets/gear/src/weights.rs index 4b1a160f66f..7acada8ab23 100644 --- a/pallets/gear/src/weights.rs +++ b/pallets/gear/src/weights.rs @@ -16,11 +16,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Autogenerated weights for pallet_gear +//! Autogenerated weights for `pallet_gear` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-08-25, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("local"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-02-25, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("local"), DB CACHE: 1024 // Executed Command: // ./target/release/gear-node @@ -29,86 +29,580 @@ // --execution=wasm // --wasm-execution=compiled // --pallet=pallet_gear -// --extrinsic='*' // --steps // 50 // --repeat // 20 // --output // . +// --extrinsic=* + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, + traits::Get, + weights::{constants::RocksDbWeight, Weight}, }; use sp_std::marker::PhantomData; /// Weight functions for pallet_gear. pub trait WeightInfo { - fn submit_code(c: u32) -> Weight; - fn submit_program(c: u32, p: u32) -> Weight; - fn send_message(p: u32) -> Weight; - fn send_reply(p: u32) -> Weight; + fn submit_code(c: u32) -> Weight; + fn submit_program(c: u32, p: u32) -> Weight; + fn send_message(p: u32) -> Weight; + fn send_reply(p: u32) -> Weight; } +/// Weight functions for `pallet_gear`. pub struct GearWeight(PhantomData); impl WeightInfo for GearWeight { - fn submit_code(c: u32) -> Weight { - (17_289_000_u64) - .saturating_add((1_000_u64).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - - fn submit_program(c: u32, p: u32) -> Weight { - (200_000_000_u64) - .saturating_add((5_000_u64).saturating_mul(c as Weight)) - .saturating_add((5_000_u64).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) - } - - fn send_message(p: u32) -> Weight { - (160_000_000_u64) - .saturating_add((6_000_u64).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) - } - - fn send_reply(p: u32) -> Weight { - (170_000_000_u64) - .saturating_add((6_000_u64).saturating_mul(p as Weight)) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) - } + // Storage: unknown [0x673a3a636f64653a3ac9cc4c0689648a67c955143538b059c3522b99d4b3f4d4] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ac9cc4c0689648a67c955143538] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a7587bd872c774944a17e23b62e833d1958a4f947699c24] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a7587bd872c774944a17e23b62e] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a8923f0218f97fe793b9b7156b6dc3340e504036d40832a] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a8923f0218f97fe793b9b7156b6] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a91e93c9050948319c98a0afb4370067915951b1d77a5d0] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a91e93c9050948319c98a0afb43] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3ab989b1a047aad6c6696163cae14c434667e0709d554573] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ab989b1a047aad6c6696163cae1] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3add349d2edb2feb38ae9a53b857bc960e79bb8dfc836097] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3add349d2edb2feb38ae9a53b857] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a767db7f1520a3b28964bf5a9801c57ad91703c1376014f] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a767db7f1520a3b28964bf5a980] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3ae95634a640361cabe2a5c7e62976f0c41d9f2bc98eb4ee] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ae95634a640361cabe2a5c7e629] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3ab7eab7925022c836e27c1551089891f85cb71d18d56a32] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ab7eab7925022c836e27c155108] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3adf9b2dd3cd87b923039a2c25a2ae720cbcc4bd0efb8c3f] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3adf9b2dd3cd87b923039a2c25a2] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a485bf54cf8489305f0edc2e78793c43ba768d9305c7bb1] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a485bf54cf8489305f0edc2e787] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a534428c3d767f8ea2ca19380781ceaad4855e7f7a5e4f7] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a534428c3d767f8ea2ca1938078] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3ae1963c24744a86dac3013d8629255a29eb21db345b52cb] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ae1963c24744a86dac3013d8629] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a38479aa6ab8b9fcd96be87a161d5cdfd33efa2cfa41332] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a38479aa6ab8b9fcd96be87a161] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a9d358e3ec3d820aae2dde1f1417ce41b91a069813ea8c8] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a9d358e3ec3d820aae2dde1f141] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a0fabd078b4860c0cbb5f32860f8f61f4546e475a8da5a7] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a0fabd078b4860c0cbb5f32860f] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3ab8b600fc2f9378bd1732f19e6ffd0a8e8d81efa7c0df72] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ab8b600fc2f9378bd1732f19e6f] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a5891990588de1d32dcba9c1303771c17bb372b9fd440a5] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a5891990588de1d32dcba9c1303] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a3e0e4f9dd93be6d99fc9df63e2689689486fe325d7370b] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a3e0e4f9dd93be6d99fc9df63e2] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3acf933bd36643b6584d5b820c7ce4e0233f5c5de39dc1dc] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3acf933bd36643b6584d5b820c7c] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3af32325bf3bb7402a9ec60eb0e60dc662a425d1a7d33f07] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3af32325bf3bb7402a9ec60eb0e6] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3aff6a42141c69663e8b3b4384f8629bc21b12dacb84a617] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3aff6a42141c69663e8b3b4384f8] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a44f39939d8d4435693e0596f2b1bd67f5d18e7d4870984] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a44f39939d8d4435693e0596f2b] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a2fe31b4c3d02326cd7d1ed09f242f0b8d058875223c452] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a2fe31b4c3d02326cd7d1ed09f2] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a861139ea34d3021d46e86da7a365d739f8a100032745b9] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a861139ea34d3021d46e86da7a3] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3afc74ae020a611048571dd6ba1659adff666e6c0847e9be] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3afc74ae020a611048571dd6ba16] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a310ee166c31f4f70ba738892e0981f9a2c9c067cb8dd6a] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a310ee166c31f4f70ba738892e0] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3ae67a81768a0934a97c511829d125a550271d6418b1867a] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ae67a81768a0934a97c511829d1] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a3c0cb0b280a082d9786b0ad21bb60e412f38d1bb0409d4] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a3c0cb0b280a082d9786b0ad21b] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a36cccd720e5c737815c9da7a6959e8bdc059a35882de83] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a36cccd720e5c737815c9da7a69] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a5174704d3a61ef516278e5ad373eb332b62a8218c80fb8] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a5174704d3a61ef516278e5ad37] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3aa15b86be5bec9f5231c60ed0fc8f6fefd65231aa0cfffd] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3aa15b86be5bec9f5231c60ed0fc] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a2e6ec4391107dcafc3c046462a2ad3f9a78a36a111424f] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a2e6ec4391107dcafc3c046462a] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a1c1005bab4ab1fa306652ec3a33f0a2b269af07310c2a7] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a1c1005bab4ab1fa306652ec3a3] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3aaafa9cc7b0008e26947ca47e3737887d67a9ae5b5646d3] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3aaafa9cc7b0008e26947ca47e37] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a4a9d7be33b48393a2f3c1e5f2fd9af4be5e71de646c64d] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a4a9d7be33b48393a2f3c1e5f2f] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3aafcee95a8836c4477426fe0319a6a72f019fe07bc91a7a] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3aafcee95a8836c4477426fe0319] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a4958004a5bc5311052bd125f67ac0ebf2ee367ea79ee9b] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a4958004a5bc5311052bd125f67] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3af81de216441b17aefe48e94b5cfd111b83046330b4302e] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3af81de216441b17aefe48e94b5c] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3ac1f1fe2d0437406ac3fa2777b76104958e38894e96211d] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ac1f1fe2d0437406ac3fa2777b7] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3ab55852db1ba113fc8a9f391ecdaf84b690f1265b4e813c] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ab55852db1ba113fc8a9f391ecd] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a64935351a68fbfd2d392d8dfaedaa8bc01d1f0e9a50a99] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a64935351a68fbfd2d392d8dfae] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a38fab0241e1a5ef738d73ba5acee5c3815f50a0a0d96a7] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a38fab0241e1a5ef738d73ba5ac] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a6ca822d162722dd0e4606a35ba098a44a289aa8bd959bd] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a6ca822d162722dd0e4606a35ba] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a5f365cf401bc9ce25862d7b2e884a64d43161cc26f7ce0] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a5f365cf401bc9ce25862d7b2e8] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3abff7e68243e56af80e189657c6602dd8c43f19b0fcfb7c] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3abff7e68243e56af80e189657c6] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a9787170a91d30f935b8cf180cc6b43ec5cb9e97309d449] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a9787170a91d30f935b8cf180cc] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a5fe949460a655945d5ab38ab18e0b507322c52db80d4df] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a5fe949460a655945d5ab38ab18] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3a71927a87aa91cbf4e336418c036f450de11e831da5dcf7] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a71927a87aa91cbf4e336418c03] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3abb443f78b6b1016408a2e194aa3ea4ec4978a7d7416caa] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3abb443f78b6b1016408a2e194aa] (r:0 w:1) + // Storage: unknown [0x673a3a636f64653a3afda0ad7c1b0733865c5d2de8d7e965359c140b43a55934] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3afda0ad7c1b0733865c5d2de8d7] (r:0 w:1) + fn submit_code(c: u32, ) -> Weight { + (27_434_000u32 as Weight) + // Standard Error: 0 + .saturating_add((2_000u32 as Weight).saturating_mul(c as Weight)) + .saturating_add(T::DbWeight::get().reads(1u32 as Weight)) + .saturating_add(T::DbWeight::get().writes(2u32 as Weight)) + } + // Storage: unknown [0x673a3a70726f673a3a67e342cacbd4e7809eb9498740b407c0bd24f18b77b3cf] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a67e342cacbd4e7809eb9498740b407c0] (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3ac9cc4c0689648a67c955143538b059c3522b99d4b3f4d4] (r:1 w:1) + // Storage: unknown [0x673a3a6d73673a3a6e6f6e6365] (r:1 w:1) + // Storage: Gas ValueView (r:1 w:1) + // Storage: Gas TotalIssuance (r:1 w:1) + // Storage: unknown [0x673a3a6d73673a3a68656164] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ac9cc4c0689648a67c955143538] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a7461696c] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aa65799c2efdac02e971c1e79a342b334afa3089b3fee3867] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a474dab32081a2c2deb31b7930866f2903f3af1c95fdc98] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a474dab32081a2c2deb31b7930866f290] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a7587bd872c774944a17e23b62e833d1958a4f947699c24] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a7587bd872c774944a17e23b62e] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a9ff48c8eed03a69ab9c3dfcd37fb11e471a90825058b39] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a9ff48c8eed03a69ab9c3dfcd37fb11e4] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a8923f0218f97fe793b9b7156b6dc3340e504036d40832a] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a8923f0218f97fe793b9b7156b6] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a02ba1a898ad5d93fff57505441f504fe86b84802a14d90] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a02ba1a898ad5d93fff57505441f504fe] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a91e93c9050948319c98a0afb4370067915951b1d77a5d0] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a91e93c9050948319c98a0afb43] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3af69cc42a055e8b200f3069144d1f6b06fec08015251c58] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3af69cc42a055e8b200f3069144d1f6b06] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3ab989b1a047aad6c6696163cae14c434667e0709d554573] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ab989b1a047aad6c6696163cae1] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a0121e5a746c7c9612987084e95852bd93f3ce9be69c7cd] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a0121e5a746c7c9612987084e95852bd9] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3add349d2edb2feb38ae9a53b857bc960e79bb8dfc836097] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3add349d2edb2feb38ae9a53b857] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a4a2ff82be3be2f920fc90b1d2ab0e4b527df2c88546506] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a4a2ff82be3be2f920fc90b1d2ab0e4b5] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a767db7f1520a3b28964bf5a9801c57ad91703c1376014f] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a767db7f1520a3b28964bf5a980] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a972e42704e6bbeaa7b89d26efa29f38804ee3ed20df57a] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a972e42704e6bbeaa7b89d26efa29f388] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3ae95634a640361cabe2a5c7e62976f0c41d9f2bc98eb4ee] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ae95634a640361cabe2a5c7e629] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a4e326680f6bd5a66860f806281412bdd0d93707a8808f2] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a4e326680f6bd5a66860f806281412bdd] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3ab7eab7925022c836e27c1551089891f85cb71d18d56a32] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ab7eab7925022c836e27c155108] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a838a5966185d4ec12f8fb9a6d3b375e7600779da58751d] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a838a5966185d4ec12f8fb9a6d3b375e7] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3adf9b2dd3cd87b923039a2c25a2ae720cbcc4bd0efb8c3f] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3adf9b2dd3cd87b923039a2c25a2] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3ad629e77ddaa9d4ed54f596a03b234408a3090cb7aa67bd] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3ad629e77ddaa9d4ed54f596a03b234408] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a485bf54cf8489305f0edc2e78793c43ba768d9305c7bb1] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a485bf54cf8489305f0edc2e787] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a93eb010622a4b1035851394b13873c0bedf2273e301165] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a93eb010622a4b1035851394b13873c0b] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a534428c3d767f8ea2ca19380781ceaad4855e7f7a5e4f7] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a534428c3d767f8ea2ca1938078] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3ae589755546f966d4f2e8c1864b3fcea6d65992eac53ed6] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3ae589755546f966d4f2e8c1864b3fcea6] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3ae1963c24744a86dac3013d8629255a29eb21db345b52cb] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ae1963c24744a86dac3013d8629] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3aba8d8d317997cce7f489dc6a4e5f8538c15622dd761475] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3aba8d8d317997cce7f489dc6a4e5f8538] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a38479aa6ab8b9fcd96be87a161d5cdfd33efa2cfa41332] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a38479aa6ab8b9fcd96be87a161] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a5d8d1fa3ca68d239b83b87d41bca3ffdcbdb6ca9639f61] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a5d8d1fa3ca68d239b83b87d41bca3ffd] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a9d358e3ec3d820aae2dde1f1417ce41b91a069813ea8c8] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a9d358e3ec3d820aae2dde1f141] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a1486da6045cc9a7d14355b2c8bb50211dd844a3b8fbde3] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a1486da6045cc9a7d14355b2c8bb50211] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a0fabd078b4860c0cbb5f32860f8f61f4546e475a8da5a7] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a0fabd078b4860c0cbb5f32860f] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a3580459e8f7aabc1fb79d171055d50c2ab15014b140d50] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a3580459e8f7aabc1fb79d171055d50c2] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3ab8b600fc2f9378bd1732f19e6ffd0a8e8d81efa7c0df72] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ab8b600fc2f9378bd1732f19e6f] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3ae374408744fd339474eadfff456c8b7e988e87d9b201d8] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3ae374408744fd339474eadfff456c8b7e] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a5891990588de1d32dcba9c1303771c17bb372b9fd440a5] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a5891990588de1d32dcba9c1303] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a15589c230b9d8382409935b6c552e7b80010b485681ac1] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a15589c230b9d8382409935b6c552e7b8] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a3e0e4f9dd93be6d99fc9df63e2689689486fe325d7370b] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a3e0e4f9dd93be6d99fc9df63e2] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3afd1628cb071e5fff5c4b65a82394be58d2c2fffdd17770] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3afd1628cb071e5fff5c4b65a82394be58] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3acf933bd36643b6584d5b820c7ce4e0233f5c5de39dc1dc] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3acf933bd36643b6584d5b820c7c] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a0bd3ba5708b04f2ab3a83c31e0f89b84215f61b3321534] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a0bd3ba5708b04f2ab3a83c31e0f89b84] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3af32325bf3bb7402a9ec60eb0e60dc662a425d1a7d33f07] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3af32325bf3bb7402a9ec60eb0e6] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a58165dd25529c3adaef7e727bbf3c1acfbf001a9e71360] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a58165dd25529c3adaef7e727bbf3c1ac] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3aff6a42141c69663e8b3b4384f8629bc21b12dacb84a617] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3aff6a42141c69663e8b3b4384f8] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a136d1d40ce4039c202917469735d8de87f2927282920b9] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a136d1d40ce4039c202917469735d8de8] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a44f39939d8d4435693e0596f2b1bd67f5d18e7d4870984] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a44f39939d8d4435693e0596f2b] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a027687f0cd49a71377ede6d85aebeefd70ee91f99b3d45] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a027687f0cd49a71377ede6d85aebeefd] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a2fe31b4c3d02326cd7d1ed09f242f0b8d058875223c452] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a2fe31b4c3d02326cd7d1ed09f2] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a91507fd62b606c287f741ef5a246c34d34103dcc664f49] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a91507fd62b606c287f741ef5a246c34d] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a861139ea34d3021d46e86da7a365d739f8a100032745b9] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a861139ea34d3021d46e86da7a3] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a9831a829e78aea842eb7a39f251b5a0e018bf82017fc88] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a9831a829e78aea842eb7a39f251b5a0e] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3afc74ae020a611048571dd6ba1659adff666e6c0847e9be] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3afc74ae020a611048571dd6ba16] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3ae6383233415e9dd73e3a5386785c498e69f758ea040dd2] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3ae6383233415e9dd73e3a5386785c498e] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a310ee166c31f4f70ba738892e0981f9a2c9c067cb8dd6a] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a310ee166c31f4f70ba738892e0] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a702b1dc288d12157078c46b21cebbcf85eb25b505f6de6] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a702b1dc288d12157078c46b21cebbcf8] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3ae67a81768a0934a97c511829d125a550271d6418b1867a] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ae67a81768a0934a97c511829d1] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3af7606fa5f9eb2b3b2d44bc8831b8875efaabc67e619ef7] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3af7606fa5f9eb2b3b2d44bc8831b8875e] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a3c0cb0b280a082d9786b0ad21bb60e412f38d1bb0409d4] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a3c0cb0b280a082d9786b0ad21b] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a8f3592870ef506c78caf3273733b89b2a89d3dc1bf717c] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a8f3592870ef506c78caf3273733b89b2] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a36cccd720e5c737815c9da7a6959e8bdc059a35882de83] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a36cccd720e5c737815c9da7a69] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a65deee47fa7d1854b84bab837fd643a0147888b37dd6ac] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a65deee47fa7d1854b84bab837fd643a0] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a5174704d3a61ef516278e5ad373eb332b62a8218c80fb8] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a5174704d3a61ef516278e5ad37] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a26192ebc14aee01b696d312fa2ec8d78292319bae755c5] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a26192ebc14aee01b696d312fa2ec8d78] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3aa15b86be5bec9f5231c60ed0fc8f6fefd65231aa0cfffd] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3aa15b86be5bec9f5231c60ed0fc] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3acf7d229e1073ed021b5394b156ae52c171113006189890] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3acf7d229e1073ed021b5394b156ae52c1] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a2e6ec4391107dcafc3c046462a2ad3f9a78a36a111424f] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a2e6ec4391107dcafc3c046462a] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a9251d449e35f168e39e508dcba3f7b19ed225e4ab1571c] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a9251d449e35f168e39e508dcba3f7b19] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a1c1005bab4ab1fa306652ec3a33f0a2b269af07310c2a7] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a1c1005bab4ab1fa306652ec3a3] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3af91bfe31a82e875ec018ffa2d41e126928c251f7d26f1b] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3af91bfe31a82e875ec018ffa2d41e1269] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3aaafa9cc7b0008e26947ca47e3737887d67a9ae5b5646d3] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3aaafa9cc7b0008e26947ca47e37] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a8827ff6a530efbb3a7a2c16b99700b6e8a061e4060baf6] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a8827ff6a530efbb3a7a2c16b99700b6e] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a4a9d7be33b48393a2f3c1e5f2fd9af4be5e71de646c64d] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a4a9d7be33b48393a2f3c1e5f2f] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a06420b6c0d04b077c4c1c0ef122f2f3c8baedec0c31c68] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a06420b6c0d04b077c4c1c0ef122f2f3c] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3aafcee95a8836c4477426fe0319a6a72f019fe07bc91a7a] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3aafcee95a8836c4477426fe0319] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a51f96abf2299b290f0230d7261ec34f9608cd25706eef7] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a51f96abf2299b290f0230d7261ec34f9] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a4958004a5bc5311052bd125f67ac0ebf2ee367ea79ee9b] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a4958004a5bc5311052bd125f67] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3afd7ea8d55f24e554e8a5a15817659fa2ef184b7300ddce] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3afd7ea8d55f24e554e8a5a15817659fa2] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3af81de216441b17aefe48e94b5cfd111b83046330b4302e] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3af81de216441b17aefe48e94b5c] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a788cd30303963b03dd1d40697c31fb97645a97e7905d37] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a788cd30303963b03dd1d40697c31fb97] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3ac1f1fe2d0437406ac3fa2777b76104958e38894e96211d] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ac1f1fe2d0437406ac3fa2777b7] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3acd41d7e468bd6e0e366099cda99c92cff0e0aa24d4116e] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3acd41d7e468bd6e0e366099cda99c92cf] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3ab55852db1ba113fc8a9f391ecdaf84b690f1265b4e813c] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3ab55852db1ba113fc8a9f391ecd] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3adb9d6eefd1c2bc17aed478d71f2e1088a7dbc733946f34] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3adb9d6eefd1c2bc17aed478d71f2e1088] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a64935351a68fbfd2d392d8dfaedaa8bc01d1f0e9a50a99] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a64935351a68fbfd2d392d8dfae] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a90675db93e49154ef8fc11fe09257e427ec49be23f6993] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a90675db93e49154ef8fc11fe09257e42] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a38fab0241e1a5ef738d73ba5acee5c3815f50a0a0d96a7] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a38fab0241e1a5ef738d73ba5ac] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a0077bd3fa60bbc1ae773e7de394947f05c96d335392061] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a0077bd3fa60bbc1ae773e7de394947f0] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a6ca822d162722dd0e4606a35ba098a44a289aa8bd959bd] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a6ca822d162722dd0e4606a35ba] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a2634e60948085d16e2e5dbab22c57515759b3fef47bdfe] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a2634e60948085d16e2e5dbab22c57515] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a5f365cf401bc9ce25862d7b2e884a64d43161cc26f7ce0] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a5f365cf401bc9ce25862d7b2e8] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a745d4768657b7dfdc5a828185043541d1c8cd435b73622] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a745d4768657b7dfdc5a828185043541d] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3abff7e68243e56af80e189657c6602dd8c43f19b0fcfb7c] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3abff7e68243e56af80e189657c6] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a7febff85204c1d69785da33a722f9cbf17310f7f761934] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a7febff85204c1d69785da33a722f9cbf] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a9787170a91d30f935b8cf180cc6b43ec5cb9e97309d449] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a9787170a91d30f935b8cf180cc] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3aa1e11b13847c0a1d2c98bb079c4108a688b8f40ce0a2fd] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3aa1e11b13847c0a1d2c98bb079c4108a6] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a5fe949460a655945d5ab38ab18e0b507322c52db80d4df] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a5fe949460a655945d5ab38ab18] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a8de5062cf07f378e6260fcb2594fd292723972edd88d9c] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a8de5062cf07f378e6260fcb2594fd292] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3a71927a87aa91cbf4e336418c036f450de11e831da5dcf7] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3a71927a87aa91cbf4e336418c03] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3acb9909d9a494d6f603d7fa13a380fd1663bc30d23cb914] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3acb9909d9a494d6f603d7fa13a380fd16] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3abb443f78b6b1016408a2e194aa3ea4ec4978a7d7416caa] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3abb443f78b6b1016408a2e194aa] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3ae41418438b8187d19d40827243c0d112ddf2791b20795a] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3ae41418438b8187d19d40827243c0d112] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3afda0ad7c1b0733865c5d2de8d7e965359c140b43a55934] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3afda0ad7c1b0733865c5d2de8d7] (r:0 w:1) + // Storage: unknown [0x673a3a70726f673a3a7e72f07e9e79d04faaadf9e9d90363ad3326e51b9c3bea] (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a7e72f07e9e79d04faaadf9e9d90363ad] (r:1 w:0) + // Storage: unknown [0x673a3a636f64653a3aaf3fa9250be40e01e2597adb04c8128f2d7dcfef9a0393] (r:1 w:1) + // Storage: unknown [0x673a3a636f64653a3a6d657461646174613a3aaf3fa9250be40e01e2597adb04] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a29fd22b3bbfb883c65b0d117aef2acf005a322623e74e176] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a72c655e2fc927dfa34bb265a0fafba78952cd7e2277207de] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a1ed310eb2ab21836e2a2bd621ec74da64cd4e574be0a80d3] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a788293f49af1e8639b89ea671f2588bfe7e326d5f9744774] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aa39ad07faa5848c619216610ad3ef9afdfee65e3142f91f4] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aef9a3fee4b9f5b2d73aacf39a1f37fb1918c5ecda299abc1] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a30f27253451e0f9e3e1e36990d2a17095fdcd2cc04930f80] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a70999d5d9679be27e114baf64bd649e3bb62dd093737d4b4] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a8a5abbbd6b96e041af5856d09b4ac254d0c346b2e8fc51d8] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a668fe0cfdbb92b4bc779c7f2205162a90f75fac375c1dcb8] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a6fd4c342411c5e0d75cea409fedb9bd1c703e4968ec66325] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3abebdb1c9c79a1b145459689bac92ac55f39a375ff1a312ee] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3af12e7cfc2dac7b6fce07eb00c6cc39c2f890b8a1d7022195] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a1834390ef741f1d1b874aa57a3e490b0657a33cd7fa7d1e5] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aae5ba1e6cbc3ccc5e54392d6989982172348488ad9d751e7] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a9e8b6e599195553aacdf6836b79b358d6e4489880fe3535b] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ae4d9f74c92cd5e6eeb7d9d6dccca89b3258c5b95c3aa32d2] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a92db6c15172756b9a0a647eb388fea594aae48ef43469644] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3abad81620314439080f98e4516fcded95d1a569c22526f89b] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ad1e32f4c34de078086660976c4eb9e2df9dc162026ecfd35] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a9a974b2bce8da3cda0fc4c3cd5b3ed3d36e1b853faa3e11e] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3afdcdb7cd9f528855f6808eba35a98f5181f72267b1952b12] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ad157ef36046f784171ee394eb6a78111f1b198b739afdab8] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3abddea7b802ab0c607c9e1acbaeb775c2f7047686468f7b63] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ac2abe41015137dd68f06d3b0c16538713ef68663127b900b] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a5a9b70b97900c2fb3568a9ac6a7fe60c1d694e4fdf01c74d] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a07d837b4b1207d45cf5ff714bad99bd72bd89502fb8c6558] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a1d14fbf47e1e7cc9809c14d43b7bc8191a8772cb3c67f6d3] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3af1f9c5d0697b9d0d84e38394f698fea3c777dc38158f01d4] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aa46ceb98695b52d9c50f7effd3a7dd5aa83ccac7fcfa1b12] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a492d3d6836cfac43e9406ea2d803232b9059352e9f35e752] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3adb2837ff4433ba56639d593af09a1bd1787cddbe8ffe9984] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3af6de683dd55aefcfa08830ebd32d1a0ecf8194a423952d03] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ae158652fa6e8cd6df246427e752b5e35d1f17dd92287fd6a] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3acbc6b3c53e5971ca4a3f0459e8b767049adbe582f0cee4d9] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ac93d67bacfb8475a051f964ff92b53ce8fad8ecec2ad175d] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3afeed710e1631b03a098c96edffc263b1b3629285015731be] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a6d209bad9598b629d1ec93fb1539891a61d280e2466cf75b] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a15503ada741f6a1e455e5798a667b71c2c5acbf6832e374b] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a14cb71dd8cb6e5f78cbb85e6d3f339e267ac7a5a1e64739f] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a500d3531ed91138b63e2d1e8ab70646da3d12fb8c1c38ed6] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3acca39672d23556d2ad67ac33ebb981f8386597c747583b1d] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a79620fef2fd6882919d0fbc8938a779fc6ebe069fc34d0a2] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ab58c1f69844236a500160be3b323044ef61065e0622457c0] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a9e29404010869da9758b4f9d52a6ca8fe5b68ecbb37269f8] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a34770943427885bd5d9feab330a40e47479716c08ea2a5b2] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a1c0728ea29c8481eeeb85bc4dcecce7b54ddb658114d4495] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a8ac8066f558210b720374a38049f9c440376b8bf0922a399] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aa17ca0046fa9c9985e394bbedd9e9c00e9ae84b0c0837c22] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3adee80d31c0f5560d6dd7324bc01693c341807653fda3b609] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a71aed0e1fa1a567fb7aaf0756a4515aa007d4f87f6ceb046] (r:0 w:1) + fn submit_program(c: u32, p: u32, ) -> Weight { + (81_628_000u32 as Weight) + // Standard Error: 0 + .saturating_add((4_000u32 as Weight).saturating_mul(c as Weight)) + // Standard Error: 0 + .saturating_add((1_000u32 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(8u32 as Weight)) + .saturating_add(T::DbWeight::get().writes(10u32 as Weight)) + } + // Storage: unknown [0x673a3a70726f673a3a13614ad1183876953cdd99749d6dcf5d41b7ffc0740cd2] (r:1 w:0) + // Storage: unknown [0x673a3a6d73673a3a6e6f6e6365] (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a13614ad1183876953cdd99749d6dcf5d] (r:1 w:0) + // Storage: Gas ValueView (r:1 w:1) + // Storage: Gas TotalIssuance (r:1 w:1) + // Storage: unknown [0x673a3a6d73673a3a68656164] (r:1 w:1) + // Storage: unknown [0x673a3a6d73673a3a29fd22b3bbfb883c65b0d117aef2acf005a322623e74e176] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a7461696c] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a45072b00f246da7ee052d5ad6cbebd4c1524c1edfc330847] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a87dc935305f2e209459cf39b6f2972fc894617e8cd4539ac] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a197218d9d59fd62f6ebcf6dbde66cdf8556a48fbad332470] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a1b7eaf61e777c0bf465cc88eae6ed54dfacf298deac7c701] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ac579d303643059fb7368f6610e94f592f0057a74f812d2fa] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a3896343992d41b7fd8767d9e6ea1f3695c59b641703ac8e6] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ae9d26a2a3bf2090f327d4d91fac82b086d87e4a55eab5f77] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3afd7bb6f79afd54a537b1ed76e8fac1b5b878a60a1fa48c9f] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a77855e60112c4d0b2d804d7a1495562f5aec71899b9525e3] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a5d7f398f50782c0ba9b4c07abbfc3f8b1756530c6ed011df] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a48be3fa5bd8701b408df8b85404638eac5a4415fb8a221c2] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a02c45e34dcb34c0fb5e44055230eda06f61d43190bc60e28] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3abdfa8756bf33be66f2b2627eab3f4d0564872e7110cf9d9f] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aa2d7ed0ff0aa76fba598942a21ebb99e3212358400b0c713] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ac823abce2e1f65e5dcf558a8fdbfb74cb7a59340667ed030] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3af04bdf70bf76040d894758abff16f96f3e71ef243a212762] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a6ed9442cbf9ad509824ab6e8d8bc755d403b092f3053788b] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ae685b493126a0a8dd32bebe67f87aeba55d6742641ae93e9] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a0c567787eab13cbfd34f8032356e1043460cdba3bd64269c] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a61b41f6a5be081ee5b77933c14fe3110cbe28b3a5092208d] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a62c54be0afe01930f756b38698e2a4d2073451e20e9fa114] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ae14e807f66728b1c25f0a83def45e6e8d81e7bdc2d9f89b7] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a259f47c27cf9627c056f4cc6e0cdca0b89a3ab5317b04b9c] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a5711315315f1dfda45654675c464078d079197b2d4dd7601] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3abb3b0641b9bc61c9b02cd92e7ab945bf5b92a8143a93e4f3] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a70054e7571d378d0e1b69f4e4d682a8082608c08f3d00950] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a5a5101ea998de25aa93aa5d9cb395c3bb0c820375c124fa6] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ab7d2ad61118df5ab6196fecfe086d0dec54c5e79ec89899e] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a65ac638d8826a6b8ba051e8ffba5800d159de7da47c770e1] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a3eb97cf8504d86dbdd68bb8782598adbc39f4473757eed32] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a54bb7b2310535adbe1e1708b70a4eb5f2ef0cc0941df681b] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a35248af2758765acd7b109f3468d6bf1b94fea502433c03e] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a7df1700e53703f2a7201292446cd4ef22ac12a3baa100e93] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aaec17edbd48453db6eb0ed02b5d20792206b77d4e6152a1e] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3abd2dbf3c9a55144ead83ccac62f5beb836c90d9b43d48ad2] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a806e0a96788ffad2ff576e7766d29558055748946a986eb5] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a5e3fcc25ec497d27126c30a27a51e44f15baf8ff45209600] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a2fa9fe6fa80c07cb72a0cbb837a0362344bd9a25a28dee21] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a3543c66e15b6629b3323171ce8eb20bde011baef92dd06f5] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a7c64f5301d56b646a4249aafd23c5e2160e86a7b218720eb] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a2190f803ac4dbbb06a3cb8941a7e7efb8994b600fbee2214] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a515df56a1192fb9d06409745d25da087516cf97f77bac377] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a60f05b5c27c6a31a37d34d758231ad4b5ce75c6f6d4625a6] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aadd2a58071db328143dec6c4e5a9ed067ad260e6a07689fd] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a707f7d0d2cf9f4f4070abbe10ef8845fbec05023bfe5ac02] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a9f056a24e082286b8e04eb3c3076542707c0333cb259063d] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a7f3b1c4a5c931e5a62dd7d04c342d9d77c85a4c269367538] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a5317b522ff4c944a681a57e0c17a8aaca91c47104761cfa9] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a53b03fae6bd8b459b234c767c0c3d0a16b08aef56b3f15db] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a9844704e94d0c75b6ec6fb1678261c4a197acb2683a44d7b] (r:0 w:1) + fn send_message(p: u32, ) -> Weight { + (58_540_000u32 as Weight) + // Standard Error: 0 + .saturating_add((2_000u32 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(7u32 as Weight)) + .saturating_add(T::DbWeight::get().writes(7u32 as Weight)) + } + // Storage: Gear Mailbox (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: unknown [0x673a3a6d73673a3a6e6f6e6365] (r:1 w:1) + // Storage: unknown [0x673a3a70726f673a3a13614ad1183876953cdd99749d6dcf5d41b7ffc0740cd2] (r:1 w:0) + // Storage: unknown [0x673a3a7061757365645f70726f673a3a13614ad1183876953cdd99749d6dcf5d] (r:1 w:0) + // Storage: Gas ValueView (r:1 w:1) + // Storage: Gas TotalIssuance (r:1 w:1) + // Storage: unknown [0x673a3a6d73673a3a68656164] (r:1 w:1) + // Storage: unknown [0x673a3a6d73673a3a29fd22b3bbfb883c65b0d117aef2acf005a322623e74e176] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a7461696c] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a45072b00f246da7ee052d5ad6cbebd4c1524c1edfc330847] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a87dc935305f2e209459cf39b6f2972fc894617e8cd4539ac] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a197218d9d59fd62f6ebcf6dbde66cdf8556a48fbad332470] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a1b7eaf61e777c0bf465cc88eae6ed54dfacf298deac7c701] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ac579d303643059fb7368f6610e94f592f0057a74f812d2fa] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a3896343992d41b7fd8767d9e6ea1f3695c59b641703ac8e6] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ae9d26a2a3bf2090f327d4d91fac82b086d87e4a55eab5f77] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3afd7bb6f79afd54a537b1ed76e8fac1b5b878a60a1fa48c9f] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a77855e60112c4d0b2d804d7a1495562f5aec71899b9525e3] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a5d7f398f50782c0ba9b4c07abbfc3f8b1756530c6ed011df] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a48be3fa5bd8701b408df8b85404638eac5a4415fb8a221c2] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a02c45e34dcb34c0fb5e44055230eda06f61d43190bc60e28] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3abdfa8756bf33be66f2b2627eab3f4d0564872e7110cf9d9f] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aa2d7ed0ff0aa76fba598942a21ebb99e3212358400b0c713] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ac823abce2e1f65e5dcf558a8fdbfb74cb7a59340667ed030] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3af04bdf70bf76040d894758abff16f96f3e71ef243a212762] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a6ed9442cbf9ad509824ab6e8d8bc755d403b092f3053788b] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ae685b493126a0a8dd32bebe67f87aeba55d6742641ae93e9] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a0c567787eab13cbfd34f8032356e1043460cdba3bd64269c] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a61b41f6a5be081ee5b77933c14fe3110cbe28b3a5092208d] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a62c54be0afe01930f756b38698e2a4d2073451e20e9fa114] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ae14e807f66728b1c25f0a83def45e6e8d81e7bdc2d9f89b7] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a259f47c27cf9627c056f4cc6e0cdca0b89a3ab5317b04b9c] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a5711315315f1dfda45654675c464078d079197b2d4dd7601] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3abb3b0641b9bc61c9b02cd92e7ab945bf5b92a8143a93e4f3] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a70054e7571d378d0e1b69f4e4d682a8082608c08f3d00950] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a5a5101ea998de25aa93aa5d9cb395c3bb0c820375c124fa6] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3ab7d2ad61118df5ab6196fecfe086d0dec54c5e79ec89899e] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a65ac638d8826a6b8ba051e8ffba5800d159de7da47c770e1] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a3eb97cf8504d86dbdd68bb8782598adbc39f4473757eed32] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a54bb7b2310535adbe1e1708b70a4eb5f2ef0cc0941df681b] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a35248af2758765acd7b109f3468d6bf1b94fea502433c03e] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a7df1700e53703f2a7201292446cd4ef22ac12a3baa100e93] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aaec17edbd48453db6eb0ed02b5d20792206b77d4e6152a1e] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3abd2dbf3c9a55144ead83ccac62f5beb836c90d9b43d48ad2] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a806e0a96788ffad2ff576e7766d29558055748946a986eb5] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a5e3fcc25ec497d27126c30a27a51e44f15baf8ff45209600] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a2fa9fe6fa80c07cb72a0cbb837a0362344bd9a25a28dee21] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a3543c66e15b6629b3323171ce8eb20bde011baef92dd06f5] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a7c64f5301d56b646a4249aafd23c5e2160e86a7b218720eb] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a2190f803ac4dbbb06a3cb8941a7e7efb8994b600fbee2214] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a515df56a1192fb9d06409745d25da087516cf97f77bac377] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a60f05b5c27c6a31a37d34d758231ad4b5ce75c6f6d4625a6] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3aadd2a58071db328143dec6c4e5a9ed067ad260e6a07689fd] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a707f7d0d2cf9f4f4070abbe10ef8845fbec05023bfe5ac02] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a9f056a24e082286b8e04eb3c3076542707c0333cb259063d] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a7f3b1c4a5c931e5a62dd7d04c342d9d77c85a4c269367538] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a5317b522ff4c944a681a57e0c17a8aaca91c47104761cfa9] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a53b03fae6bd8b459b234c767c0c3d0a16b08aef56b3f15db] (r:0 w:1) + // Storage: unknown [0x673a3a6d73673a3a9844704e94d0c75b6ec6fb1678261c4a197acb2683a44d7b] (r:0 w:1) + fn send_reply(p: u32, ) -> Weight { + (70_895_000u32 as Weight) + // Standard Error: 0 + .saturating_add((2_000u32 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(8u32 as Weight)) + .saturating_add(T::DbWeight::get().writes(8u32 as Weight)) + } } // For backwards compatibility and tests const SUBMIT_WEIGHT_PER_BYTE: u64 = 1_000_000; const MESSAGE_PER_BYTE: u64 = 100_000; impl WeightInfo for () { - fn submit_code(c: u32) -> Weight { - (0_u64) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(SUBMIT_WEIGHT_PER_BYTE.saturating_mul(c as Weight)) - } + fn submit_code(c: u32) -> Weight { + (0_u64) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(SUBMIT_WEIGHT_PER_BYTE.saturating_mul(c as Weight)) + } - fn submit_program(c: u32, p: u32) -> Weight { - (0_u64) - .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(SUBMIT_WEIGHT_PER_BYTE.saturating_mul(c as Weight)) - .saturating_add(MESSAGE_PER_BYTE.saturating_mul(p as Weight)) - } + fn submit_program(c: u32, p: u32) -> Weight { + (0_u64) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(SUBMIT_WEIGHT_PER_BYTE.saturating_mul(c as Weight)) + .saturating_add(MESSAGE_PER_BYTE.saturating_mul(p as Weight)) + } - fn send_message(p: u32) -> Weight { - (0_u64) - .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(MESSAGE_PER_BYTE.saturating_mul(p as Weight)) - } + fn send_message(p: u32) -> Weight { + (0_u64) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(MESSAGE_PER_BYTE.saturating_mul(p as Weight)) + } - fn send_reply(p: u32) -> Weight { - (0_u64) - .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(MESSAGE_PER_BYTE.saturating_mul(p as Weight)) - } + fn send_reply(p: u32) -> Weight { + (0_u64) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(MESSAGE_PER_BYTE.saturating_mul(p as Weight)) + } } diff --git a/pallets/usage/Cargo.toml b/pallets/usage/Cargo.toml index 9f19b39a06a..510c0fefb03 100644 --- a/pallets/usage/Cargo.toml +++ b/pallets/usage/Cargo.toml @@ -45,6 +45,7 @@ gear-core = { path = "../../core" } pallet-gas = { path = "../gas" } pallet-timestamp = { version = "4.0.0-dev", git = "https://github.com/gear-tech/substrate.git", branch = "gear-stable" } hex-literal = "0.3.3" +pallet-gear-program = { path = "../gear-program", default-features = false } [features] default = ['std'] diff --git a/pallets/usage/src/mock.rs b/pallets/usage/src/mock.rs index 6ec77550094..5e35eafbbb4 100644 --- a/pallets/usage/src/mock.rs +++ b/pallets/usage/src/mock.rs @@ -49,6 +49,7 @@ construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: system::{Pallet, Call, Config, Storage, Event}, + GearProgram: pallet_gear_program::{Pallet, Storage, Event}, Gear: pallet_gear::{Pallet, Call, Storage, Event}, Gas: pallet_gas::{Pallet, Storage}, Usage: pallet_usage::{Pallet, Call, Storage, Event, ValidateUnsigned}, @@ -108,6 +109,12 @@ impl common::GasPrice for GasConverter { type Balance = u128; } +impl pallet_gear_program::Config for Test { + type Event = Event; + type WeightInfo = (); + type Currency = Balances; +} + parameter_types! { pub const WaitListFeePerBlock: u64 = 100; } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index c13e312ed18..20d0a9c9317 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -57,6 +57,7 @@ frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, g hex-literal = { version = "0.3.4", optional = true } # Internal deps +pallet-gear-program = { version = "2.0.0", default-features = false, path = "../pallets/gear-program" } pallet-gear = { version = "2.0.0", default-features = false, path = "../pallets/gear" } pallet-gear-debug = { version = "2.0.0", default-features = false, path = "../pallets/gear-debug", optional = true } pallet-usage = { version = "2.0.0", default-features = false, path = "../pallets/usage" } @@ -78,6 +79,7 @@ std = [ "pallet-aura/std", "pallet-authorship/std", "pallet-balances/std", + "pallet-gear-program/std", "pallet-gear/std", "pallet-gear-debug/std", "pallet-usage/std", @@ -115,6 +117,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-gear/runtime-benchmarks", + "pallet-gear-program/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] debug-mode = [ diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 94eedf6c99e..6ea9f90cc07 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -124,7 +124,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // The version of the runtime specification. A full node will not attempt to use its native // runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`, // `spec_version`, and `authoring_version` are the same between Wasm and native. - spec_version: 350, + spec_version: 360, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -328,6 +328,12 @@ impl gear_common::GasPrice for GasConverter { type Balance = Balance; } +impl pallet_gear_program::Config for Runtime { + type Event = Event; + type WeightInfo = pallet_gear_program::weights::GearProgramWeight; + type Currency = Balances; +} + parameter_types! { pub const GasLimitMaxPercentage: Percent = Percent::from_percent(75); pub BlockGasLimit: u64 = GasLimitMaxPercentage::get() * BlockWeights::get().max_block; @@ -393,6 +399,7 @@ construct_runtime!( Sudo: pallet_sudo, Utility: pallet_utility, Authorship: pallet_authorship, + GearProgram: pallet_gear_program, Gear: pallet_gear, Usage: pallet_usage, Gas: pallet_gas, @@ -419,6 +426,7 @@ construct_runtime!( Sudo: pallet_sudo, Utility: pallet_utility, Authorship: pallet_authorship, + GearProgram: pallet_gear_program, Gear: pallet_gear, Usage: pallet_usage, Gas: pallet_gas, @@ -615,6 +623,7 @@ impl_runtime_apis! { list_benchmark!(list, extra, frame_system, SystemBench::); list_benchmark!(list, extra, pallet_balances, Balances); list_benchmark!(list, extra, pallet_timestamp, Timestamp); + list_benchmark!(list, extra, pallet_gear_program, GearProgram); list_benchmark!(list, extra, pallet_gear, Gear); let storage_info = AllPalletsWithSystem::storage_info(); @@ -649,6 +658,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, frame_system, SystemBench::); add_benchmark!(params, batches, pallet_balances, Balances); add_benchmark!(params, batches, pallet_timestamp, Timestamp); + add_benchmark!(params, batches, pallet_gear_program, GearProgram); add_benchmark!(params, batches, pallet_gear, Gear); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } diff --git a/tests/proxy/Cargo.toml b/tests/proxy/Cargo.toml new file mode 100644 index 00000000000..d863ecc354d --- /dev/null +++ b/tests/proxy/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "tests-proxy" +version = "0.1.0" +authors = ["Gear Technologies"] +edition = "2018" +license = "GPL-3.0" + +[dependencies] +gstd = { path = "../../gstd", features = ["debug"] } +codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } + +[build-dependencies] +gear-wasm-builder = { path = "../../utils/wasm-builder" } + +[lib] + +[features] +std = ["codec/std", "scale-info/std"] +default = ["std"] diff --git a/tests/proxy/build.rs b/tests/proxy/build.rs new file mode 100644 index 00000000000..199b5faeeff --- /dev/null +++ b/tests/proxy/build.rs @@ -0,0 +1,21 @@ +// This file is part of Gear. + +// Copyright (C) 2021 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +fn main() { + gear_wasm_builder::build(); +} diff --git a/tests/proxy/src/lib.rs b/tests/proxy/src/lib.rs new file mode 100644 index 00000000000..73f12e1b7d8 --- /dev/null +++ b/tests/proxy/src/lib.rs @@ -0,0 +1,60 @@ +// This file is part of Gear. + +// Copyright (C) 2021 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +mod code { + include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +} + +#[cfg(feature = "std")] +pub use code::WASM_BINARY_OPT as WASM_BINARY; + +#[derive(Debug, Decode, Encode, TypeInfo)] +pub struct InputArgs { + pub destination: gstd::ActorId, +} + +#[cfg(not(feature = "std"))] +mod wasm { + use crate::InputArgs; + use gstd::{msg, ActorId, ToString}; + + static mut DESTINATION: ActorId = ActorId::new([0u8; 32]); + + gstd::metadata! { + title: "tests-proxy", + handle: + input: InputArgs, + } + + #[no_mangle] + pub unsafe extern "C" fn handle() { + msg::send(DESTINATION, b"proxied message", msg::value()); + } + + #[no_mangle] + pub unsafe extern "C" fn init() { + let args: InputArgs = msg::load().expect("Failed to decode `InputArgs'"); + DESTINATION = args.destination; + } +} diff --git a/utils/wasm-builder/test-program/Cargo.lock b/utils/wasm-builder/test-program/Cargo.lock index dd36f02648b..cd79d237530 100644 --- a/utils/wasm-builder/test-program/Cargo.lock +++ b/utils/wasm-builder/test-program/Cargo.lock @@ -564,7 +564,7 @@ dependencies = [ [[package]] name = "gear-wasm-builder" -version = "0.2.0" +version = "0.1.2" dependencies = [ "anyhow", "cargo_metadata",