diff --git a/Cargo.lock b/Cargo.lock index a3e25173e7..43db7aad2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -976,6 +976,7 @@ dependencies = [ "parachain-info", "parity-scale-codec", "polkadot-parachain", + "rococo-parachain-primitives", "serde", "sp-api", "sp-block-builder", @@ -1213,6 +1214,7 @@ dependencies = [ "parachain-info", "parity-scale-codec", "polkadot-parachain", + "rococo-parachain-primitives", "serde", "sp-api", "sp-block-builder", @@ -5831,6 +5833,7 @@ dependencies = [ "polkadot-test-runtime-client", "polkadot-test-service", "rand 0.7.3", + "rococo-parachain-primitives", "sc-basic-authorship", "sc-chain-spec", "sc-cli", @@ -5840,15 +5843,20 @@ dependencies = [ "sc-finality-grandpa", "sc-informant", "sc-network", + "sc-rpc", "sc-service", "sc-transaction-pool", "serde", "sp-api", + "sp-block-builder", + "sp-blockchain", "sp-consensus", "sp-core", "sp-inherents", "sp-io", + "sp-offchain", "sp-runtime", + "sp-session", "sp-timestamp", "sp-transaction-pool", "sp-trie", @@ -5860,6 +5868,14 @@ dependencies = [ "trie-root 0.15.2", ] +[[package]] +name = "rococo-parachain-primitives" +version = "0.1.0" +dependencies = [ + "sp-core", + "sp-runtime", +] + [[package]] name = "rococo-runtime" version = "0.8.22" diff --git a/Cargo.toml b/Cargo.toml index bf46da28f7..9c26bef75f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "rococo-parachains/contracts-runtime", "rococo-parachains/pallets/parachain-info", "rococo-parachains/pallets/token-dealer", + "rococo-parachains/primitives", "rococo-parachains/runtime", "runtime", "service", diff --git a/collator/src/lib.rs b/collator/src/lib.rs index f409cf0d45..18e994e6fb 100644 --- a/collator/src/lib.rs +++ b/collator/src/lib.rs @@ -518,18 +518,17 @@ where Box::new(self.polkadot_network.clone()), ))); - let follow = - match cumulus_consensus::follow_polkadot( - self.para_id, - self.client, - polkadot_client, - self.announce_block.clone(), - ) { - Ok(follow) => follow, - Err(e) => { - return Err(error!("Could not start following polkadot: {:?}", e)); - } - }; + let follow = match cumulus_consensus::follow_polkadot( + self.para_id, + self.client, + polkadot_client, + self.announce_block.clone(), + ) { + Ok(follow) => follow, + Err(e) => { + return Err(error!("Could not start following polkadot: {:?}", e)); + } + }; self.spawner .spawn("cumulus-follow-polkadot", follow.map(|_| ()).boxed()); diff --git a/network/src/lib.rs b/network/src/lib.rs index 04c634d0a7..ec057c87bd 100644 --- a/network/src/lib.rs +++ b/network/src/lib.rs @@ -23,7 +23,10 @@ mod tests; use sp_api::ProvideRuntimeApi; use sp_blockchain::{Error as ClientError, HeaderBackend}; -use sp_consensus::{block_validation::{BlockAnnounceValidator, Validation}, SyncOracle}; +use sp_consensus::{ + block_validation::{BlockAnnounceValidator, Validation}, + SyncOracle, +}; use sp_core::traits::SpawnNamed; use sp_runtime::{ generic::BlockId, diff --git a/network/src/tests.rs b/network/src/tests.rs index 6d4da4c204..ed84ea1397 100644 --- a/network/src/tests.rs +++ b/network/src/tests.rs @@ -17,9 +17,9 @@ use super::*; use cumulus_test_runtime::{Block, Header}; use polkadot_primitives::v0::{ - AbridgedCandidateReceipt, Chain, CollatorId, DutyRoster, GlobalValidationData, - Id as ParaId, LocalValidationData, ParachainHost, Retriable, SigningContext, - ValidationCode, ValidatorId, Block as PBlock, Hash as PHash, Header as PHeader, + AbridgedCandidateReceipt, Block as PBlock, Chain, CollatorId, DutyRoster, GlobalValidationData, + Hash as PHash, Header as PHeader, Id as ParaId, LocalValidationData, ParachainHost, Retriable, + SigningContext, ValidationCode, ValidatorId, }; use polkadot_test_runtime_client::{ DefaultTestClientBuilderExt, TestClient, TestClientBuilder, TestClientBuilderExt, diff --git a/rococo-parachains/Cargo.toml b/rococo-parachains/Cargo.toml index 62bc618c58..344ef2adda 100644 --- a/rococo-parachains/Cargo.toml +++ b/rococo-parachains/Cargo.toml @@ -25,6 +25,7 @@ hex-literal = "0.2.1" # Parachain dependencies parachain-runtime = { package = "cumulus-test-parachain-runtime", path = "runtime" } parachain-contracts-runtime = { package = "cumulus-contracts-parachain-runtime", path = "contracts-runtime" } +rococo-parachain-primitives = { path = "primitives" } # Substrate dependencies sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" } @@ -32,6 +33,7 @@ sp-io = { git = "https://github.com/paritytech/substrate", branch = "rococo-bran sp-core = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } +sp-session = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } sc-cli = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } @@ -42,11 +44,15 @@ sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch sc-network = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch", version = "0.8.0-rc5" } sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } +sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } sp-api = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } sc-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } sc-informant = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } +sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } +sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "rococo-branch" } # RPC related dependencies cumulus-pallet-contracts-rpc = { path = "./pallets/contracts/rpc" } diff --git a/rococo-parachains/contracts-runtime/Cargo.toml b/rococo-parachains/contracts-runtime/Cargo.toml index a5b1eb51ef..b2812c1f9e 100644 --- a/rococo-parachains/contracts-runtime/Cargo.toml +++ b/rococo-parachains/contracts-runtime/Cargo.toml @@ -10,6 +10,7 @@ codec = { package = "parity-scale-codec", version = "1.3.0", default-features = cumulus-token-dealer = { path = "../pallets/token-dealer", default-features = false} parachain-info = { path = "../pallets/parachain-info", default-features = false} +rococo-parachain-primitives = { path = "../primitives", default-features = false} # Substrate dependencies sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" } @@ -79,6 +80,7 @@ std = [ "pallet-sudo/std", "pallet-transaction-payment/std", "parachain-info/std", + "rococo-parachain-primitives/std", "cumulus-runtime/std", "cumulus-parachain-upgrade/std", "cumulus-message-broker/std", diff --git a/rococo-parachains/contracts-runtime/src/lib.rs b/rococo-parachains/contracts-runtime/src/lib.rs index bc5095eab4..fd6c774bc7 100644 --- a/rococo-parachains/contracts-runtime/src/lib.rs +++ b/rococo-parachains/contracts-runtime/src/lib.rs @@ -23,13 +23,14 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use cumulus_pallet_contracts_rpc_runtime_api::ContractExecResult; +use rococo_parachain_primitives::*; use sp_api::impl_runtime_apis; use sp_core::OpaqueMetadata; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, Saturating, Verify}, + traits::{BlakeTwo256, Block as BlockT, IdentityLookup, Saturating}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, MultiSignature, + ApplyExtrinsicResult, }; use sp_std::prelude::*; #[cfg(feature = "std")] @@ -49,53 +50,10 @@ pub use pallet_timestamp::Call as TimestampCall; pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; -/// An index to a block. -pub type BlockNumber = u32; +pub type SessionHandlers = (); -/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. -pub type Signature = MultiSignature; - -/// Some way of identifying an account on the chain. We intentionally make it equivalent -/// to the public key of our transaction signing scheme. -pub type AccountId = <::Signer as IdentifyAccount>::AccountId; - -/// The type for looking up accounts. We don't expect more than 4 billion of them, but you -/// never know... -pub type AccountIndex = u32; - -/// Balance of an account. -pub type Balance = u128; - -/// Index of a transaction in the chain. -pub type Index = u32; - -/// A hash of some data used by the chain. -pub type Hash = sp_core::H256; - -/// Digest item type. -pub type DigestItem = generic::DigestItem; - -/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know -/// the specifics of the runtime. They can then be made to be agnostic over specific formats -/// of data like extrinsics, allowing for them to continue syncing the network through upgrades -/// to even the core datastructures. -pub mod opaque { - use super::*; - - pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; - - /// Opaque block header type. - pub type Header = generic::Header; - /// Opaque block type. - pub type Block = generic::Block; - /// Opaque block identifier type. - pub type BlockId = generic::BlockId; - - pub type SessionHandlers = (); - - impl_opaque_keys! { - pub struct SessionKeys {} - } +impl_opaque_keys! { + pub struct SessionKeys {} } /// This runtime version. @@ -103,7 +61,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("cumulus-contracts-parachain"), impl_name: create_runtime_str!("cumulus-contracts-parachain"), authoring_version: 1, - spec_version: 1, + spec_version: 2, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -292,7 +250,7 @@ impl cumulus_pallet_contracts::Trait for Runtime { construct_runtime! { pub enum Runtime where Block = Block, - NodeBlock = opaque::Block, + NodeBlock = rococo_parachain_primitives::Block, UncheckedExtrinsic = UncheckedExtrinsic { System: frame_system::{Module, Call, Storage, Config, Event}, @@ -405,11 +363,11 @@ impl_runtime_apis! { fn decode_session_keys( encoded: Vec, ) -> Option, sp_core::crypto::KeyTypeId)>> { - opaque::SessionKeys::decode_into_raw_public_keys(&encoded) + SessionKeys::decode_into_raw_public_keys(&encoded) } fn generate_session_keys(seed: Option>) -> Vec { - opaque::SessionKeys::generate(seed) + SessionKeys::generate(seed) } } diff --git a/rococo-parachains/pallets/contracts/rpc/src/lib.rs b/rococo-parachains/pallets/contracts/rpc/src/lib.rs index e98e5e7652..7922ada4a5 100644 --- a/rococo-parachains/pallets/contracts/rpc/src/lib.rs +++ b/rococo-parachains/pallets/contracts/rpc/src/lib.rs @@ -20,9 +20,9 @@ use std::sync::Arc; use codec::Codec; +use cumulus_pallet_contracts_primitives::RentProjection; use jsonrpc_core::{Error, ErrorCode, Result}; use jsonrpc_derive::rpc; -use cumulus_pallet_contracts_primitives::RentProjection; use serde::{Deserialize, Serialize}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; @@ -106,7 +106,11 @@ pub enum RpcContractExecResult { impl From for RpcContractExecResult { fn from(r: ContractExecResult) -> Self { match r { - ContractExecResult::Success { flags, data, gas_consumed } => RpcContractExecResult::Success { + ContractExecResult::Success { + flags, + data, + gas_consumed, + } => RpcContractExecResult::Success { flags, data: data.into(), gas_consumed, @@ -293,7 +297,8 @@ mod tests { #[test] fn call_request_should_serialize_deserialize_properly() { type Req = CallRequest; - let req: Req = serde_json::from_str(r#" + let req: Req = serde_json::from_str( + r#" { "origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", "dest": "5DRakbLVnjVrW6niwLfHGW24EeCEvDAFGEXrtaYS5M4ynoom", @@ -301,7 +306,9 @@ mod tests { "gasLimit": 1000000000000, "inputData": "0x8c97db39" } - "#).unwrap(); + "#, + ) + .unwrap(); assert_eq!(req.gas_limit.into_u256(), U256::from(0xe8d4a51000u64)); } diff --git a/rococo-parachains/pallets/contracts/src/account_db.rs b/rococo-parachains/pallets/contracts/src/account_db.rs index 02e3beb796..5e9ab01a9e 100644 --- a/rococo-parachains/pallets/contracts/src/account_db.rs +++ b/rococo-parachains/pallets/contracts/src/account_db.rs @@ -21,14 +21,19 @@ use super::{ TrieIdGenerator, }; use crate::exec::StorageKey; -use sp_std::cell::RefCell; -use sp_std::collections::btree_map::{BTreeMap, Entry}; -use sp_std::prelude::*; +use frame_support::{ + storage::unhashed as storage, + traits::{Currency, Imbalance, SignedImbalance}, + StorageMap, +}; +use frame_system; use sp_io::hashing::blake2_256; use sp_runtime::traits::{Bounded, Zero}; -use frame_support::traits::{Currency, Imbalance, SignedImbalance}; -use frame_support::{storage::unhashed as storage, StorageMap}; -use frame_system; +use sp_std::{ + cell::RefCell, + collections::btree_map::{BTreeMap, Entry}, + prelude::*, +}; // Note: we don't provide Option because we can't create // the trie_id in the overlay, thus we provide an overlay on the fields @@ -133,8 +138,7 @@ impl AccountDb for DirectAccountDb { trie_id: Option<&TrieId>, location: &StorageKey, ) -> Option> { - trie_id - .and_then(|id| storage::get_raw(&crate::prefixed_key(id, &blake2_256(location)))) + trie_id.and_then(|id| storage::get_raw(&crate::prefixed_key(id, &blake2_256(location)))) } fn get_code_hash(&self, account: &T::AccountId) -> Option> { >::get(account).and_then(|i| i.as_alive().map(|i| i.code_hash)) @@ -241,13 +245,13 @@ impl AccountDb for DirectAccountDb { if prev_value.is_empty() { new_info.empty_pair_count -= 1; } - }, + } (None, Some(new_value)) => { new_info.total_pair_count += 1; if new_value.is_empty() { new_info.empty_pair_count += 1; } - }, + } (Some(prev_value), Some(new_value)) => { if prev_value.is_empty() { new_info.empty_pair_count -= 1; diff --git a/rococo-parachains/pallets/contracts/src/exec.rs b/rococo-parachains/pallets/contracts/src/exec.rs index 88e66ad462..76caa5be8e 100644 --- a/rococo-parachains/pallets/contracts/src/exec.rs +++ b/rococo-parachains/pallets/contracts/src/exec.rs @@ -14,19 +14,23 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use super::{CodeHash, Config, ContractAddressFor, Event, RawEvent, Trait, - TrieId, BalanceOf, ContractInfo}; -use crate::account_db::{AccountDb, DirectAccountDb, OverlayAccountDb}; -use crate::gas::{Gas, GasMeter, Token}; -use crate::rent; +use super::{ + BalanceOf, CodeHash, Config, ContractAddressFor, ContractInfo, Event, RawEvent, Trait, TrieId, +}; +use crate::{ + account_db::{AccountDb, DirectAccountDb, OverlayAccountDb}, + gas::{Gas, GasMeter, Token}, + rent, +}; -use sp_std::prelude::*; -use sp_runtime::traits::{Bounded, Zero, Convert, CheckedSub, CheckedAdd}; use frame_support::{ - storage::unhashed, dispatch::DispatchError, - traits::{Currency, Time, Randomness, WithdrawReason}, + dispatch::DispatchError, + storage::unhashed, + traits::{Currency, Randomness, Time, WithdrawReason}, weights::Weight, }; +use sp_runtime::traits::{Bounded, CheckedAdd, CheckedSub, Convert, Zero}; +use sp_std::prelude::*; pub type AccountIdOf = ::AccountId; pub type CallOf = ::Call; @@ -84,11 +88,14 @@ macro_rules! try_or_exec_error { ($e:expr, $buffer:expr) => { match $e { Ok(val) => val, - Err(reason) => return Err( - $crate::exec::ExecError { reason: reason.into(), buffer: $buffer } - ), - } - } + Err(reason) => { + return Err($crate::exec::ExecError { + reason: reason.into(), + buffer: $buffer, + }) + } + } + }; } /// An interface that provides access to the external environment in which the @@ -332,9 +339,11 @@ where } } - fn nested<'b, 'c: 'b>(&'c self, dest: T::AccountId, trie_id: Option) - -> ExecutionContext<'b, T, V, L> - { + fn nested<'b, 'c: 'b>( + &'c self, + dest: T::AccountId, + trie_id: Option, + ) -> ExecutionContext<'b, T, V, L> { ExecutionContext { caller: Some(self), self_trie_id: trie_id, @@ -355,7 +364,7 @@ where &mut self, dest: T::AccountId, value: BalanceOf, - gas_meter: &mut GasMeter + gas_meter: &mut GasMeter, ) -> Result<(), DispatchError> { transfer( gas_meter, @@ -427,21 +436,21 @@ where // it is a regular account since tombstone accounts have already been rejected. match nested.overlay.get_code_hash(&dest) { Some(dest_code_hash) => { - let executable = try_or_exec_error!( - nested.loader.load_main(&dest_code_hash), - input_data - ); - let output = nested.vm - .execute( - &executable, - nested.new_call_context(caller, value), - input_data, - gas_meter, - )?; + let executable = + try_or_exec_error!(nested.loader.load_main(&dest_code_hash), input_data); + let output = nested.vm.execute( + &executable, + nested.new_call_context(caller, value), + input_data, + gas_meter, + )?; Ok(output) } - None => Ok(ExecReturnValue { status: STATUS_SUCCESS, data: Vec::new() }), + None => Ok(ExecReturnValue { + status: STATUS_SUCCESS, + data: Vec::new(), + }), } }) } @@ -471,18 +480,17 @@ where } let caller = self.self_account.clone(); - let dest = T::DetermineContractAddress::contract_address_for( - code_hash, - &input_data, - &caller, - ); + let dest = + T::DetermineContractAddress::contract_address_for(code_hash, &input_data, &caller); // TrieId has not been generated yet and storage is empty since contract is new. let dest_trie_id = None; let output = self.with_nested_context(dest.clone(), dest_trie_id, |nested| { try_or_exec_error!( - nested.overlay.instantiate_contract(&dest, code_hash.clone()), + nested + .overlay + .instantiate_contract(&dest, code_hash.clone()), input_data ); @@ -500,17 +508,13 @@ where input_data ); - let executable = try_or_exec_error!( - nested.loader.load_init(&code_hash), - input_data - ); - let output = nested.vm - .execute( - &executable, - nested.new_call_context(caller.clone(), endowment), - input_data, - gas_meter, - )?; + let executable = try_or_exec_error!(nested.loader.load_init(&code_hash), input_data); + let output = nested.vm.execute( + &executable, + nested.new_call_context(caller.clone(), endowment), + input_data, + gas_meter, + )?; // Error out if insufficient remaining balance. if nested.overlay.get_balance(&dest) < nested.config.existential_deposit { @@ -574,9 +578,14 @@ where } } - fn with_nested_context(&mut self, dest: T::AccountId, trie_id: Option, func: F) - -> ExecResult - where F: FnOnce(&mut ExecutionContext) -> ExecResult + fn with_nested_context( + &mut self, + dest: T::AccountId, + trie_id: Option, + func: F, + ) -> ExecResult + where + F: FnOnce(&mut ExecutionContext) -> ExecResult, { let (output, change_set, deferred) = { let mut nested = self.nested(dest, trie_id); @@ -595,8 +604,7 @@ where /// Returns whether a contract, identified by address, is currently live in the execution /// stack, meaning it is in the middle of an execution. fn is_live(&self, account: &T::AccountId) -> bool { - &self.self_account == account || - self.caller.map_or(false, |caller| caller.is_live(account)) + &self.self_account == account || self.caller.map_or(false, |caller| caller.is_live(account)) } } @@ -656,8 +664,7 @@ fn transfer<'a, T: Trait, V: Vm, L: Loader>( value: BalanceOf, ctx: &mut ExecutionContext<'a, T, V, L>, ) -> Result<(), DispatchError> { - use self::TransferCause::*; - use self::TransferFeeKind::*; + use self::{TransferCause::*, TransferFeeKind::*}; let token = { let kind: TransferFeeKind = match cause { @@ -668,9 +675,7 @@ fn transfer<'a, T: Trait, V: Vm, L: Loader>( // Otherwise the fee is to transfer to an account. Call | Terminate => TransferFeeKind::Transfer, }; - TransferFeeToken { - kind, - } + TransferFeeToken { kind } }; if gas_meter.charge(ctx.config, token).is_out_of_gas() { @@ -691,14 +696,15 @@ fn transfer<'a, T: Trait, V: Vm, L: Loader>( // Only ext_terminate is allowed to bring the sender below the existential deposit let required_balance = match cause { Terminate => 0.into(), - _ => ctx.config.existential_deposit + _ => ctx.config.existential_deposit, }; T::Currency::ensure_can_withdraw( transactor, value, WithdrawReason::Transfer.into(), - new_from_balance.checked_sub(&required_balance) + new_from_balance + .checked_sub(&required_balance) .ok_or("brings sender below existential deposit")?, )?; @@ -736,7 +742,9 @@ where type T = T; fn get_storage(&self, key: &StorageKey) -> Option> { - self.ctx.overlay.get_storage(&self.ctx.self_account, self.ctx.self_trie_id.as_ref(), key) + self.ctx + .overlay + .get_storage(&self.ctx.self_account, self.ctx.self_trie_id.as_ref(), key) } fn set_storage(&mut self, key: StorageKey, value: Option>) -> Result<(), &'static str> { @@ -759,7 +767,8 @@ where gas_meter: &mut GasMeter, input_data: Vec, ) -> Result<(AccountIdOf, ExecReturnValue), ExecError> { - self.ctx.instantiate(endowment, gas_meter, code_hash, input_data) + self.ctx + .instantiate(endowment, gas_meter, code_hash, input_data) } fn transfer( @@ -852,15 +861,21 @@ where } fn set_rent_allowance(&mut self, rent_allowance: BalanceOf) { - self.ctx.overlay.set_rent_allowance(&self.ctx.self_account, rent_allowance) + self.ctx + .overlay + .set_rent_allowance(&self.ctx.self_account, rent_allowance) } fn rent_allowance(&self) -> BalanceOf { - self.ctx.overlay.get_rent_allowance(&self.ctx.self_account) + self.ctx + .overlay + .get_rent_allowance(&self.ctx.self_account) .unwrap_or(>::max_value()) // Must never be triggered actually } - fn block_number(&self) -> T::BlockNumber { self.block_number } + fn block_number(&self) -> T::BlockNumber { + self.block_number + } fn max_value_size(&self) -> u32 { self.ctx.config.max_value_size @@ -888,17 +903,19 @@ where #[cfg(test)] mod tests { use super::{ - BalanceOf, ExecFeeToken, ExecutionContext, Ext, Loader, TransferFeeKind, TransferFeeToken, - Vm, ExecResult, RawEvent, DeferredAction, + BalanceOf, DeferredAction, ExecFeeToken, ExecResult, ExecutionContext, Ext, Loader, + RawEvent, TransferFeeKind, TransferFeeToken, Vm, }; use crate::{ - account_db::AccountDb, gas::GasMeter, tests::{ExtBuilder, Test}, - exec::{ExecReturnValue, ExecError, STATUS_SUCCESS}, CodeHash, Config, - gas::Gas, + account_db::AccountDb, + exec::{ExecError, ExecReturnValue, STATUS_SUCCESS}, + gas::{Gas, GasMeter}, + tests::{ExtBuilder, Test}, + CodeHash, Config, }; - use std::{cell::RefCell, rc::Rc, collections::HashMap, marker::PhantomData}; use assert_matches::assert_matches; use sp_runtime::DispatchError; + use std::{cell::RefCell, collections::HashMap, marker::PhantomData, rc::Rc}; const ALICE: u64 = 1; const BOB: u64 = 2; @@ -907,7 +924,8 @@ mod tests { const GAS_LIMIT: Gas = 10_000_000_000; impl<'a, T, V, L> ExecutionContext<'a, T, V, L> - where T: crate::Trait + where + T: crate::Trait, { fn events(&self) -> Vec> { self.deferred @@ -965,7 +983,9 @@ mod tests { impl<'a> MockVm<'a> { fn new() -> Self { - MockVm { _marker: PhantomData } + MockVm { + _marker: PhantomData, + } } } @@ -1005,7 +1025,10 @@ mod tests { } fn exec_success() -> ExecResult { - Ok(ExecReturnValue { status: STATUS_SUCCESS, data: Vec::new() }) + Ok(ExecReturnValue { + status: STATUS_SUCCESS, + data: Vec::new(), + }) } #[test] @@ -1029,10 +1052,7 @@ mod tests { let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, exec_ch).unwrap(); - assert_matches!( - ctx.call(BOB, value, &mut gas_meter, data), - Ok(_) - ); + assert_matches!(ctx.call(BOB, value, &mut gas_meter, data), Ok(_)); }); assert_eq!(&*test_data.borrow(), &vec![0, 1]); @@ -1098,12 +1118,9 @@ mod tests { ctx.overlay.set_balance(&origin, 100); ctx.overlay.set_balance(&dest, 0); - let output = ctx.call( - dest, - 55, - &mut GasMeter::::new(GAS_LIMIT), - vec![], - ).unwrap(); + let output = ctx + .call(dest, 55, &mut GasMeter::::new(GAS_LIMIT), vec![]) + .unwrap(); assert!(output.is_success()); assert_eq!(ctx.overlay.get_balance(&origin), 45); @@ -1120,9 +1137,12 @@ mod tests { let vm = MockVm::new(); let mut loader = MockLoader::empty(); - let return_ch = loader.insert( - |_| Ok(ExecReturnValue { status: 1, data: Vec::new() }) - ); + let return_ch = loader.insert(|_| { + Ok(ExecReturnValue { + status: 1, + data: Vec::new(), + }) + }); ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); @@ -1131,12 +1151,9 @@ mod tests { ctx.overlay.set_balance(&origin, 100); ctx.overlay.set_balance(&dest, 0); - let output = ctx.call( - dest, - 55, - &mut GasMeter::::new(GAS_LIMIT), - vec![], - ).unwrap(); + let output = ctx + .call(dest, 55, &mut GasMeter::::new(GAS_LIMIT), vec![]) + .unwrap(); assert!(!output.is_success()); assert_eq!(ctx.overlay.get_balance(&origin), 100); @@ -1152,81 +1169,90 @@ mod tests { // This test sends 50 units of currency to a non-existent account. // This should lead to creation of a new account thus // a fee should be charged. - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let vm = MockVm::new(); - let loader = MockLoader::empty(); - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); - ctx.overlay.set_balance(&origin, 100); - ctx.overlay.set_balance(&dest, 0); + ExtBuilder::default() + .existential_deposit(15) + .build() + .execute_with(|| { + let vm = MockVm::new(); + let loader = MockLoader::empty(); + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); + ctx.overlay.set_balance(&origin, 100); + ctx.overlay.set_balance(&dest, 0); - let mut gas_meter = GasMeter::::new(GAS_LIMIT); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); - let result = ctx.call(dest, 50, &mut gas_meter, vec![]); - assert_matches!(result, Ok(_)); + let result = ctx.call(dest, 50, &mut gas_meter, vec![]); + assert_matches!(result, Ok(_)); - let mut toks = gas_meter.tokens().iter(); - match_tokens!( - toks, - ExecFeeToken::Call, - TransferFeeToken { - kind: TransferFeeKind::Transfer, - }, - ); - }); + let mut toks = gas_meter.tokens().iter(); + match_tokens!( + toks, + ExecFeeToken::Call, + TransferFeeToken { + kind: TransferFeeKind::Transfer, + }, + ); + }); // This one is similar to the previous one but transfer to an existing account. // In this test we expect that a regular transfer fee is charged. - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let vm = MockVm::new(); - let loader = MockLoader::empty(); - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); - ctx.overlay.set_balance(&origin, 100); - ctx.overlay.set_balance(&dest, 15); + ExtBuilder::default() + .existential_deposit(15) + .build() + .execute_with(|| { + let vm = MockVm::new(); + let loader = MockLoader::empty(); + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); + ctx.overlay.set_balance(&origin, 100); + ctx.overlay.set_balance(&dest, 15); - let mut gas_meter = GasMeter::::new(GAS_LIMIT); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); - let result = ctx.call(dest, 50, &mut gas_meter, vec![]); - assert_matches!(result, Ok(_)); + let result = ctx.call(dest, 50, &mut gas_meter, vec![]); + assert_matches!(result, Ok(_)); - let mut toks = gas_meter.tokens().iter(); - match_tokens!( - toks, - ExecFeeToken::Call, - TransferFeeToken { - kind: TransferFeeKind::Transfer, - }, - ); - }); + let mut toks = gas_meter.tokens().iter(); + match_tokens!( + toks, + ExecFeeToken::Call, + TransferFeeToken { + kind: TransferFeeKind::Transfer, + }, + ); + }); // This test sends 50 units of currency as an endowment to a newly // instantiated contract. - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let mut loader = MockLoader::empty(); - let code = loader.insert(|_| exec_success()); + ExtBuilder::default() + .existential_deposit(15) + .build() + .execute_with(|| { + let mut loader = MockLoader::empty(); + let code = loader.insert(|_| exec_success()); - let vm = MockVm::new(); - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); + let vm = MockVm::new(); + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); - ctx.overlay.set_balance(&origin, 100); - ctx.overlay.set_balance(&dest, 15); + ctx.overlay.set_balance(&origin, 100); + ctx.overlay.set_balance(&dest, 15); - let mut gas_meter = GasMeter::::new(GAS_LIMIT); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); - let result = ctx.instantiate(50, &mut gas_meter, &code, vec![]); - assert_matches!(result, Ok(_)); + let result = ctx.instantiate(50, &mut gas_meter, &code, vec![]); + assert_matches!(result, Ok(_)); - let mut toks = gas_meter.tokens().iter(); - match_tokens!( - toks, - ExecFeeToken::Instantiate, - TransferFeeToken { - kind: TransferFeeKind::ContractInstantiate, - }, - ); - }); + let mut toks = gas_meter.tokens().iter(); + match_tokens!( + toks, + ExecFeeToken::Instantiate, + TransferFeeToken { + kind: TransferFeeKind::ContractInstantiate, + }, + ); + }); } #[test] @@ -1244,12 +1270,7 @@ mod tests { let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.set_balance(&origin, 0); - let result = ctx.call( - dest, - 100, - &mut GasMeter::::new(GAS_LIMIT), - vec![], - ); + let result = ctx.call(dest, 100, &mut GasMeter::::new(GAS_LIMIT), vec![]); assert_matches!( result, @@ -1272,21 +1293,19 @@ mod tests { let vm = MockVm::new(); let mut loader = MockLoader::empty(); - let return_ch = loader.insert( - |_| Ok(ExecReturnValue { status: STATUS_SUCCESS, data: vec![1, 2, 3, 4] }) - ); + let return_ch = loader.insert(|_| { + Ok(ExecReturnValue { + status: STATUS_SUCCESS, + data: vec![1, 2, 3, 4], + }) + }); ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap(); - let result = ctx.call( - dest, - 0, - &mut GasMeter::::new(GAS_LIMIT), - vec![], - ); + let result = ctx.call(dest, 0, &mut GasMeter::::new(GAS_LIMIT), vec![]); let output = result.unwrap(); assert!(output.is_success()); @@ -1303,21 +1322,19 @@ mod tests { let vm = MockVm::new(); let mut loader = MockLoader::empty(); - let return_ch = loader.insert( - |_| Ok(ExecReturnValue { status: 1, data: vec![1, 2, 3, 4] }) - ); + let return_ch = loader.insert(|_| { + Ok(ExecReturnValue { + status: 1, + data: vec![1, 2, 3, 4], + }) + }); ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap(); - let result = ctx.call( - dest, - 0, - &mut GasMeter::::new(GAS_LIMIT), - vec![], - ); + let result = ctx.call(dest, 0, &mut GasMeter::::new(GAS_LIMIT), vec![]); let output = result.unwrap(); assert!(!output.is_success()); @@ -1338,7 +1355,9 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); - ctx.overlay.instantiate_contract(&BOB, input_data_ch).unwrap(); + ctx.overlay + .instantiate_contract(&BOB, input_data_ch) + .unwrap(); let result = ctx.call( BOB, @@ -1415,12 +1434,7 @@ mod tests { ctx.overlay.set_balance(&BOB, 1); ctx.overlay.instantiate_contract(&BOB, recurse_ch).unwrap(); - let result = ctx.call( - BOB, - value, - &mut GasMeter::::new(GAS_LIMIT), - vec![], - ); + let result = ctx.call(BOB, value, &mut GasMeter::::new(GAS_LIMIT), vec![]); assert_matches!(result, Ok(_)); }); @@ -1442,10 +1456,7 @@ mod tests { *witnessed_caller_bob.borrow_mut() = Some(*ctx.ext.caller()); // Call into CHARLIE contract. - assert_matches!( - ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), - Ok(_) - ); + assert_matches!(ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), Ok(_)); exec_success() }); let charlie_ch = loader.insert(|ctx| { @@ -1459,14 +1470,11 @@ mod tests { let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&dest, bob_ch).unwrap(); - ctx.overlay.instantiate_contract(&CHARLIE, charlie_ch).unwrap(); + ctx.overlay + .instantiate_contract(&CHARLIE, charlie_ch) + .unwrap(); - let result = ctx.call( - dest, - 0, - &mut GasMeter::::new(GAS_LIMIT), - vec![], - ); + let result = ctx.call(dest, 0, &mut GasMeter::::new(GAS_LIMIT), vec![]); assert_matches!(result, Ok(_)); }); @@ -1485,10 +1493,7 @@ mod tests { assert_eq!(*ctx.ext.address(), BOB); // Call into charlie contract. - assert_matches!( - ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), - Ok(_) - ); + assert_matches!(ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), Ok(_)); exec_success() }); let charlie_ch = loader.insert(|ctx| { @@ -1500,14 +1505,11 @@ mod tests { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, bob_ch).unwrap(); - ctx.overlay.instantiate_contract(&CHARLIE, charlie_ch).unwrap(); + ctx.overlay + .instantiate_contract(&CHARLIE, charlie_ch) + .unwrap(); - let result = ctx.call( - BOB, - 0, - &mut GasMeter::::new(GAS_LIMIT), - vec![], - ); + let result = ctx.call(BOB, 0, &mut GasMeter::::new(GAS_LIMIT), vec![]); assert_matches!(result, Ok(_)); }); @@ -1520,20 +1522,23 @@ mod tests { let mut loader = MockLoader::empty(); let dummy_ch = loader.insert(|_| exec_success()); - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); + ExtBuilder::default() + .existential_deposit(15) + .build() + .execute_with(|| { + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); - assert_matches!( - ctx.instantiate( - 0, // <- zero endowment - &mut GasMeter::::new(GAS_LIMIT), - &dummy_ch, - vec![], - ), - Err(_) - ); - }); + assert_matches!( + ctx.instantiate( + 0, // <- zero endowment + &mut GasMeter::::new(GAS_LIMIT), + &dummy_ch, + vec![], + ), + Err(_) + ); + }); } #[test] @@ -1541,39 +1546,53 @@ mod tests { let vm = MockVm::new(); let mut loader = MockLoader::empty(); - let dummy_ch = loader.insert( - |_| Ok(ExecReturnValue { status: STATUS_SUCCESS, data: vec![80, 65, 83, 83] }) - ); - - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); - ctx.overlay.set_balance(&ALICE, 1000); - - let instantiated_contract_address = assert_matches!( - ctx.instantiate( - 100, - &mut GasMeter::::new(GAS_LIMIT), - &dummy_ch, - vec![], - ), - Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address - ); - - // Check that the newly created account has the expected code hash and - // there are instantiation event. - assert_eq!(ctx.overlay.get_code_hash(&instantiated_contract_address).unwrap(), dummy_ch); - assert_eq!(&ctx.events(), &[ - DeferredAction::DepositEvent { - event: RawEvent::Transfer(ALICE, instantiated_contract_address, 100), - topics: Vec::new(), - }, - DeferredAction::DepositEvent { - event: RawEvent::Instantiated(ALICE, instantiated_contract_address), - topics: Vec::new(), - } - ]); + let dummy_ch = loader.insert(|_| { + Ok(ExecReturnValue { + status: STATUS_SUCCESS, + data: vec![80, 65, 83, 83], + }) }); + + ExtBuilder::default() + .existential_deposit(15) + .build() + .execute_with(|| { + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); + ctx.overlay.set_balance(&ALICE, 1000); + + let instantiated_contract_address = assert_matches!( + ctx.instantiate( + 100, + &mut GasMeter::::new(GAS_LIMIT), + &dummy_ch, + vec![], + ), + Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address + ); + + // Check that the newly created account has the expected code hash and + // there are instantiation event. + assert_eq!( + ctx.overlay + .get_code_hash(&instantiated_contract_address) + .unwrap(), + dummy_ch + ); + assert_eq!( + &ctx.events(), + &[ + DeferredAction::DepositEvent { + event: RawEvent::Transfer(ALICE, instantiated_contract_address, 100), + topics: Vec::new(), + }, + DeferredAction::DepositEvent { + event: RawEvent::Instantiated(ALICE, instantiated_contract_address), + topics: Vec::new(), + } + ] + ); + }); } #[test] @@ -1581,29 +1600,38 @@ mod tests { let vm = MockVm::new(); let mut loader = MockLoader::empty(); - let dummy_ch = loader.insert( - |_| Ok(ExecReturnValue { status: 1, data: vec![70, 65, 73, 76] }) - ); - - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); - ctx.overlay.set_balance(&ALICE, 1000); - - let instantiated_contract_address = assert_matches!( - ctx.instantiate( - 100, - &mut GasMeter::::new(GAS_LIMIT), - &dummy_ch, - vec![], - ), - Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address - ); - - // Check that the account has not been created. - assert!(ctx.overlay.get_code_hash(&instantiated_contract_address).is_none()); - assert!(ctx.events().is_empty()); + let dummy_ch = loader.insert(|_| { + Ok(ExecReturnValue { + status: 1, + data: vec![70, 65, 73, 76], + }) }); + + ExtBuilder::default() + .existential_deposit(15) + .build() + .execute_with(|| { + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); + ctx.overlay.set_balance(&ALICE, 1000); + + let instantiated_contract_address = assert_matches!( + ctx.instantiate( + 100, + &mut GasMeter::::new(GAS_LIMIT), + &dummy_ch, + vec![], + ), + Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address + ); + + // Check that the account has not been created. + assert!(ctx + .overlay + .get_code_hash(&instantiated_contract_address) + .is_none()); + assert!(ctx.events().is_empty()); + }); } #[test] @@ -1618,50 +1646,65 @@ mod tests { let instantiated_contract_address = Rc::clone(&instantiated_contract_address); move |ctx| { // Instantiate a contract and save it's address in `instantiated_contract_address`. - let (address, output) = ctx.ext.instantiate( - &dummy_ch, - 15u64, - ctx.gas_meter, - vec![] - ).unwrap(); + let (address, output) = ctx + .ext + .instantiate(&dummy_ch, 15u64, ctx.gas_meter, vec![]) + .unwrap(); *instantiated_contract_address.borrow_mut() = address.into(); Ok(output) } }); - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); - ctx.overlay.set_balance(&ALICE, 1000); - ctx.overlay.set_balance(&BOB, 100); - ctx.overlay.instantiate_contract(&BOB, instantiator_ch).unwrap(); + ExtBuilder::default() + .existential_deposit(15) + .build() + .execute_with(|| { + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); + ctx.overlay.set_balance(&ALICE, 1000); + ctx.overlay.set_balance(&BOB, 100); + ctx.overlay + .instantiate_contract(&BOB, instantiator_ch) + .unwrap(); - assert_matches!( - ctx.call(BOB, 20, &mut GasMeter::::new(GAS_LIMIT), vec![]), - Ok(_) - ); + assert_matches!( + ctx.call(BOB, 20, &mut GasMeter::::new(GAS_LIMIT), vec![]), + Ok(_) + ); - let instantiated_contract_address = instantiated_contract_address.borrow().as_ref().unwrap().clone(); + let instantiated_contract_address = instantiated_contract_address + .borrow() + .as_ref() + .unwrap() + .clone(); - // Check that the newly created account has the expected code hash and - // there are instantiation event. - assert_eq!(ctx.overlay.get_code_hash(&instantiated_contract_address).unwrap(), dummy_ch); - assert_eq!(&ctx.events(), &[ - DeferredAction::DepositEvent { - event: RawEvent::Transfer(ALICE, BOB, 20), - topics: Vec::new(), - }, - DeferredAction::DepositEvent { - event: RawEvent::Transfer(BOB, instantiated_contract_address, 15), - topics: Vec::new(), - }, - DeferredAction::DepositEvent { - event: RawEvent::Instantiated(BOB, instantiated_contract_address), - topics: Vec::new(), - }, - ]); - }); + // Check that the newly created account has the expected code hash and + // there are instantiation event. + assert_eq!( + ctx.overlay + .get_code_hash(&instantiated_contract_address) + .unwrap(), + dummy_ch + ); + assert_eq!( + &ctx.events(), + &[ + DeferredAction::DepositEvent { + event: RawEvent::Transfer(ALICE, BOB, 20), + topics: Vec::new(), + }, + DeferredAction::DepositEvent { + event: RawEvent::Transfer(BOB, instantiated_contract_address, 15), + topics: Vec::new(), + }, + DeferredAction::DepositEvent { + event: RawEvent::Instantiated(BOB, instantiated_contract_address), + topics: Vec::new(), + }, + ] + ); + }); } #[test] @@ -1669,48 +1712,55 @@ mod tests { let vm = MockVm::new(); let mut loader = MockLoader::empty(); - let dummy_ch = loader.insert( - |_| Err(ExecError { reason: "It's a trap!".into(), buffer: Vec::new() }) - ); + let dummy_ch = loader.insert(|_| { + Err(ExecError { + reason: "It's a trap!".into(), + buffer: Vec::new(), + }) + }); let instantiator_ch = loader.insert({ let dummy_ch = dummy_ch.clone(); move |ctx| { // Instantiate a contract and save it's address in `instantiated_contract_address`. assert_matches!( - ctx.ext.instantiate( - &dummy_ch, - 15u64, - ctx.gas_meter, - vec![] - ), - Err(ExecError { reason: DispatchError::Other("It's a trap!"), buffer: _ }) + ctx.ext.instantiate(&dummy_ch, 15u64, ctx.gas_meter, vec![]), + Err(ExecError { + reason: DispatchError::Other("It's a trap!"), + buffer: _, + }) ); exec_success() } }); - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); - ctx.overlay.set_balance(&ALICE, 1000); - ctx.overlay.set_balance(&BOB, 100); - ctx.overlay.instantiate_contract(&BOB, instantiator_ch).unwrap(); + ExtBuilder::default() + .existential_deposit(15) + .build() + .execute_with(|| { + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); + ctx.overlay.set_balance(&ALICE, 1000); + ctx.overlay.set_balance(&BOB, 100); + ctx.overlay + .instantiate_contract(&BOB, instantiator_ch) + .unwrap(); - assert_matches!( - ctx.call(BOB, 20, &mut GasMeter::::new(GAS_LIMIT), vec![]), - Ok(_) - ); + assert_matches!( + ctx.call(BOB, 20, &mut GasMeter::::new(GAS_LIMIT), vec![]), + Ok(_) + ); - // The contract wasn't instantiated so we don't expect to see an instantiation - // event here. - assert_eq!(&ctx.events(), &[ - DeferredAction::DepositEvent { - event: RawEvent::Transfer(ALICE, BOB, 20), - topics: Vec::new(), - }, - ]); - }); + // The contract wasn't instantiated so we don't expect to see an instantiation + // event here. + assert_eq!( + &ctx.events(), + &[DeferredAction::DepositEvent { + event: RawEvent::Transfer(ALICE, BOB, 20), + topics: Vec::new(), + },] + ); + }); } #[test] @@ -1745,10 +1795,7 @@ mod tests { }) if buffer == Vec::::new() ); - assert_eq!( - &ctx.events(), - &[] - ); + assert_eq!(&ctx.events(), &[]); }); } diff --git a/rococo-parachains/pallets/contracts/src/gas.rs b/rococo-parachains/pallets/contracts/src/gas.rs index 5ca6e88f7d..a9b5155507 100644 --- a/rococo-parachains/pallets/contracts/src/gas.rs +++ b/rococo-parachains/pallets/contracts/src/gas.rs @@ -15,11 +15,11 @@ // along with Substrate. If not, see . use crate::Trait; -use sp_std::marker::PhantomData; -use sp_runtime::traits::Zero; use frame_support::dispatch::{ - DispatchError, DispatchResultWithPostInfo, PostDispatchInfo, DispatchErrorWithPostInfo, + DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo, PostDispatchInfo, }; +use sp_runtime::traits::Zero; +use sp_std::marker::PhantomData; #[cfg(test)] use std::{any::Any, fmt::Debug}; @@ -189,7 +189,8 @@ impl GasMeter { } /// Turn this GasMeter into a DispatchResult that contains the actually used gas. - pub fn into_dispatch_result(self, result: Result) -> DispatchResultWithPostInfo where + pub fn into_dispatch_result(self, result: Result) -> DispatchResultWithPostInfo + where E: Into, { let post_info = PostDispatchInfo { @@ -199,7 +200,10 @@ impl GasMeter { result .map(|_| post_info) - .map_err(|e| DispatchErrorWithPostInfo { post_info, error: e.into() }) + .map_err(|e| DispatchErrorWithPostInfo { + post_info, + error: e.into(), + }) } #[cfg(test)] @@ -256,7 +260,9 @@ mod tests { struct SimpleToken(u64); impl Token for SimpleToken { type Metadata = (); - fn calculate_amount(&self, _metadata: &()) -> u64 { self.0 } + fn calculate_amount(&self, _metadata: &()) -> u64 { + self.0 + } } struct MultiplierTokenMetadata { @@ -285,8 +291,10 @@ mod tests { fn simple() { let mut gas_meter = GasMeter::::new(50000); - let result = gas_meter - .charge(&MultiplierTokenMetadata { multiplier: 3 }, MultiplierToken(10)); + let result = gas_meter.charge( + &MultiplierTokenMetadata { multiplier: 3 }, + MultiplierToken(10), + ); assert!(!result.is_out_of_gas()); assert_eq!(gas_meter.gas_left(), 49_970); @@ -297,7 +305,10 @@ mod tests { let mut gas_meter = GasMeter::::new(50000); assert!(!gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas()); assert!(!gas_meter - .charge(&MultiplierTokenMetadata { multiplier: 3 }, MultiplierToken(10)) + .charge( + &MultiplierTokenMetadata { multiplier: 3 }, + MultiplierToken(10) + ) .is_out_of_gas()); let mut tokens = gas_meter.tokens()[0..2].iter(); @@ -327,7 +338,6 @@ mod tests { assert!(gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas()); } - // Charging the exact amount that the user paid for should be // possible. #[test] diff --git a/rococo-parachains/pallets/contracts/src/lib.rs b/rococo-parachains/pallets/contracts/src/lib.rs index fcf59e1de2..6751e8bcd8 100644 --- a/rococo-parachains/pallets/contracts/src/lib.rs +++ b/rococo-parachains/pallets/contracts/src/lib.rs @@ -84,42 +84,42 @@ mod gas; mod account_db; mod exec; -mod wasm; mod rent; +mod wasm; #[cfg(test)] mod tests; -use crate::exec::ExecutionContext; -use crate::account_db::{AccountDb, DirectAccountDb}; -use crate::wasm::{WasmLoader, WasmVm}; +use crate::{ + account_db::{AccountDb, DirectAccountDb}, + exec::ExecutionContext, + wasm::{WasmLoader, WasmVm}, +}; -pub use crate::gas::{Gas, GasMeter}; -pub use crate::exec::{ExecResult, ExecReturnValue, ExecError, StatusCode}; +pub use crate::{ + exec::{ExecError, ExecResult, ExecReturnValue, StatusCode}, + gas::{Gas, GasMeter}, +}; +use codec::{Codec, Decode, Encode}; +use cumulus_pallet_contracts_primitives::{ContractAccessError, RentProjection}; +use frame_support::{ + decl_error, decl_event, decl_module, decl_storage, + dispatch::{DispatchResult, DispatchResultWithPostInfo, Dispatchable, PostDispatchInfo}, + parameter_types, + traits::{Currency, Get, OnUnbalanced, Randomness, Time}, + weights::{GetDispatchInfo, Weight}, + Parameter, +}; +use frame_system::{ensure_root, ensure_signed, RawOrigin}; #[cfg(feature = "std")] -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use sp_core::crypto::UncheckedFrom; -use sp_std::{prelude::*, marker::PhantomData, fmt::Debug}; -use codec::{Codec, Encode, Decode}; use sp_runtime::{ - traits::{ - Hash, StaticLookup, Zero, MaybeSerializeDeserialize, Member, Convert, - }, + traits::{Convert, Hash, MaybeSerializeDeserialize, Member, StaticLookup, Zero}, RuntimeDebug, }; -use frame_support::dispatch::{ - PostDispatchInfo, DispatchResult, Dispatchable, DispatchResultWithPostInfo -}; -use frame_support::{ - Parameter, decl_module, decl_event, decl_storage, decl_error, - parameter_types, -}; -use frame_support::traits::{OnUnbalanced, Currency, Get, Time, Randomness}; -use frame_support::weights::GetDispatchInfo; -use frame_system::{ensure_signed, RawOrigin, ensure_root}; -use cumulus_pallet_contracts_primitives::{RentProjection, ContractAccessError}; -use frame_support::weights::Weight; +use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; pub type CodeHash = ::Hash; pub type TrieId = Vec; @@ -240,10 +240,16 @@ pub struct RawTombstoneContractInfo(H, PhantomData); impl RawTombstoneContractInfo where - H: Member + MaybeSerializeDeserialize+ Debug - + AsRef<[u8]> + AsMut<[u8]> + Copy + Default - + sp_std::hash::Hash + Codec, - Hasher: Hash, + H: Member + + MaybeSerializeDeserialize + + Debug + + AsRef<[u8]> + + AsMut<[u8]> + + Copy + + Default + + sp_std::hash::Hash + + Codec, + Hasher: Hash, { fn new(storage_root: &[u8], code_hash: H) -> Self { let mut buf = Vec::new(); @@ -272,7 +278,7 @@ pub struct TrieIdFromParentCounter(PhantomData); /// accountid_counter`. impl TrieIdGenerator for TrieIdFromParentCounter where - T::AccountId: AsRef<[u8]> + T::AccountId: AsRef<[u8]>, { fn trie_id(account_id: &T::AccountId) -> TrieId { // Note that skipping a value due to error is not an issue here. @@ -321,10 +327,9 @@ pub trait Trait: frame_system::Trait { type Currency: Currency; /// The outer call dispatch type. - type Call: - Parameter + - Dispatchable::Origin> + - GetDispatchInfo; + type Call: Parameter + + Dispatchable::Origin> + + GetDispatchInfo; /// The overarching event type. type Event: From> + Into<::Event>; @@ -390,9 +395,13 @@ pub trait Trait: frame_system::Trait { pub struct SimpleAddressDeterminer(PhantomData); impl ContractAddressFor, T::AccountId> for SimpleAddressDeterminer where - T::AccountId: UncheckedFrom + AsRef<[u8]> + T::AccountId: UncheckedFrom + AsRef<[u8]>, { - fn contract_address_for(code_hash: &CodeHash, data: &[u8], origin: &T::AccountId) -> T::AccountId { + fn contract_address_for( + code_hash: &CodeHash, + data: &[u8], + origin: &T::AccountId, + ) -> T::AccountId { let data_hash = T::Hashing::hash(data); let mut buf = Vec::new(); @@ -641,13 +650,15 @@ impl Module { impl Module { fn calc_code_put_costs(code: &Vec) -> Gas { - >::current_schedule().put_code_per_byte_cost.saturating_mul(code.len() as Gas) + >::current_schedule() + .put_code_per_byte_cost + .saturating_mul(code.len() as Gas) } fn execute_wasm( origin: T::AccountId, gas_meter: &mut GasMeter, - func: impl FnOnce(&mut ExecutionContext, &mut GasMeter) -> ExecResult + func: impl FnOnce(&mut ExecutionContext, &mut GasMeter) -> ExecResult, ) -> ExecResult { let cfg = Config::preload(); let vm = WasmVm::new(&cfg.schedule); @@ -656,7 +667,11 @@ impl Module { let result = func(&mut ctx, gas_meter); - if result.as_ref().map(|output| output.is_success()).unwrap_or(false) { + if result + .as_ref() + .map(|output| output.is_success()) + .unwrap_or(false) + { // Commit all changes that made it thus far into the persistent storage. DirectAccountDb.commit(ctx.overlay.into_change_set()); } @@ -665,17 +680,11 @@ impl Module { ctx.deferred.into_iter().for_each(|deferred| { use self::exec::DeferredAction::*; match deferred { - DepositEvent { - topics, - event, - } => >::deposit_event_indexed( + DepositEvent { topics, event } => >::deposit_event_indexed( &*topics, ::Event::from(event).into(), ), - DispatchRuntimeCall { - origin: who, - call, - } => { + DispatchRuntimeCall { origin: who, call } => { let info = call.get_dispatch_info(); let result = call.dispatch(RawOrigin::Signed(who.clone()).into()); let post_info = match result { @@ -693,11 +702,19 @@ impl Module { delta, } => { let result = Self::restore_to( - donor.clone(), dest.clone(), code_hash.clone(), rent_allowance.clone(), delta - ); - Self::deposit_event( - RawEvent::Restored(donor, dest, code_hash, rent_allowance, result.is_ok()) + donor.clone(), + dest.clone(), + code_hash.clone(), + rent_allowance.clone(), + delta, ); + Self::deposit_event(RawEvent::Restored( + donor, + dest, + code_hash, + rent_allowance, + result.is_ok(), + )); } } }); diff --git a/rococo-parachains/pallets/contracts/src/rent.rs b/rococo-parachains/pallets/contracts/src/rent.rs index 43fab490e5..253ccd568f 100644 --- a/rococo-parachains/pallets/contracts/src/rent.rs +++ b/rococo-parachains/pallets/contracts/src/rent.rs @@ -20,10 +20,14 @@ use crate::{ AliveContractInfo, BalanceOf, ContractInfo, ContractInfoOf, Module, RawEvent, TombstoneContractInfo, Trait, }; -use frame_support::storage::unhashed as storage; -use frame_support::traits::{Currency, ExistenceRequirement, Get, OnUnbalanced, WithdrawReason}; -use frame_support::StorageMap; -use cumulus_pallet_contracts_primitives::{ContractAccessError, RentProjection, RentProjectionResult}; +use cumulus_pallet_contracts_primitives::{ + ContractAccessError, RentProjection, RentProjectionResult, +}; +use frame_support::{ + storage::unhashed as storage, + traits::{Currency, ExistenceRequirement, Get, OnUnbalanced, WithdrawReason}, + StorageMap, +}; use sp_runtime::traits::{Bounded, CheckedDiv, CheckedMul, SaturatedConversion, Saturating, Zero}; /// The amount to charge. @@ -238,10 +242,8 @@ fn enact_verdict( // Use a dummy storage root because restoration is currentlyy unsupported // for parachains anyways. - let tombstone = >::new( - &[0u8; 32], - alive_contract_info.code_hash, - ); + let tombstone = + >::new(&[0u8; 32], alive_contract_info.code_hash); let tombstone_info = ContractInfo::Tombstone(tombstone); >::insert(account, &tombstone_info); diff --git a/rococo-parachains/pallets/contracts/src/tests.rs b/rococo-parachains/pallets/contracts/src/tests.rs index 1b94a9f9c8..954e05a003 100644 --- a/rococo-parachains/pallets/contracts/src/tests.rs +++ b/rococo-parachains/pallets/contracts/src/tests.rs @@ -15,27 +15,28 @@ // along with Substrate. If not, see . use crate::{ - BalanceOf, ContractAddressFor, ContractInfo, ContractInfoOf, GenesisConfig, Module, - RawAliveContractInfo, RawEvent, Trait, TrieId, Schedule, TrieIdGenerator, account_db::{AccountDb, DirectAccountDb, OverlayAccountDb}, gas::Gas, + BalanceOf, ContractAddressFor, ContractInfo, ContractInfoOf, GenesisConfig, Module, + RawAliveContractInfo, RawEvent, Schedule, Trait, TrieId, TrieIdGenerator, }; use assert_matches::assert_matches; -use hex_literal::*; use codec::Encode; -use sp_runtime::{ - Perbill, - traits::{BlakeTwo256, Hash, IdentityLookup, Convert}, - testing::{Header, H256}, -}; use frame_support::{ - assert_ok, assert_err_ignore_postinfo, impl_outer_dispatch, impl_outer_event, - impl_outer_origin, parameter_types, StorageMap, StorageValue, + assert_err_ignore_postinfo, assert_ok, impl_outer_dispatch, impl_outer_event, + impl_outer_origin, parameter_types, traits::{Currency, Get}, - weights::{Weight, PostDispatchInfo}, + weights::{PostDispatchInfo, Weight}, + StorageMap, StorageValue, +}; +use frame_system::{self as system, EventRecord, Phase}; +use hex_literal::*; +use sp_runtime::{ + testing::{Header, H256}, + traits::{BlakeTwo256, Convert, Hash, IdentityLookup}, + Perbill, }; use std::cell::RefCell; -use frame_system::{self as system, EventRecord, Phase}; mod contracts { // Re-export contents of the root. This basically @@ -70,7 +71,9 @@ thread_local! { pub struct ExistentialDeposit; impl Get for ExistentialDeposit { - fn get() -> u64 { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow()) } + fn get() -> u64 { + EXISTENTIAL_DEPOSIT.with(|v| *v.borrow()) + } } #[derive(Clone, Eq, PartialEq, Debug)] @@ -221,16 +224,20 @@ impl ExtBuilder { } pub fn build(self) -> sp_io::TestExternalities { self.set_associated_consts(); - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![], - }.assimilate_storage(&mut t).unwrap(); + let mut t = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + pallet_balances::GenesisConfig:: { balances: vec![] } + .assimilate_storage(&mut t) + .unwrap(); GenesisConfig { current_schedule: Schedule { enable_println: true, ..Default::default() }, - }.assimilate_storage(&mut t).unwrap(); + } + .assimilate_storage(&mut t) + .unwrap(); let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); ext @@ -250,8 +257,8 @@ where use std::fs; let fixture_path = ["fixtures/", fixture_name, ".wat"].concat(); - let module_wat_source = - fs::read_to_string(&fixture_path).expect(&format!("Unable to find {} fixture", fixture_name)); + let module_wat_source = fs::read_to_string(&fixture_path) + .expect(&format!("Unable to find {} fixture", fixture_name)); let wasm_binary = wabt::wat2wasm(module_wat_source)?; let code_hash = T::Hashing::hash(&wasm_binary); Ok((wasm_binary, code_hash)) @@ -266,91 +273,98 @@ fn returns_base_call_cost() { assert_eq!( Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, Vec::new()), - Ok( - PostDispatchInfo { - actual_weight: Some(67500000), - pays_fee: Default::default(), - } - ) + Ok(PostDispatchInfo { + actual_weight: Some(67500000), + pays_fee: Default::default(), + }) ); }); } #[test] fn account_removal_does_not_remove_storage() { - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let trie_id1 = ::TrieIdGenerator::trie_id(&1); - let trie_id2 = ::TrieIdGenerator::trie_id(&2); - let key1 = &[1; 32]; - let key2 = &[2; 32]; + ExtBuilder::default() + .existential_deposit(100) + .build() + .execute_with(|| { + let trie_id1 = ::TrieIdGenerator::trie_id(&1); + let trie_id2 = ::TrieIdGenerator::trie_id(&2); + let key1 = &[1; 32]; + let key2 = &[2; 32]; - // Set up two accounts with free balance above the existential threshold. - { - let _ = Balances::deposit_creating(&1, 110); - ContractInfoOf::::insert(1, &ContractInfo::Alive(RawAliveContractInfo { - trie_id: trie_id1.clone(), - storage_size: 0, - empty_pair_count: 0, - total_pair_count: 0, - deduct_block: System::block_number(), - code_hash: H256::repeat_byte(1), - rent_allowance: 40, - last_write: None, - })); + // Set up two accounts with free balance above the existential threshold. + { + let _ = Balances::deposit_creating(&1, 110); + ContractInfoOf::::insert( + 1, + &ContractInfo::Alive(RawAliveContractInfo { + trie_id: trie_id1.clone(), + storage_size: 0, + empty_pair_count: 0, + total_pair_count: 0, + deduct_block: System::block_number(), + code_hash: H256::repeat_byte(1), + rent_allowance: 40, + last_write: None, + }), + ); - let mut overlay = OverlayAccountDb::::new(&DirectAccountDb); - overlay.set_storage(&1, key1.clone(), Some(b"1".to_vec())); - overlay.set_storage(&1, key2.clone(), Some(b"2".to_vec())); - DirectAccountDb.commit(overlay.into_change_set()); + let mut overlay = OverlayAccountDb::::new(&DirectAccountDb); + overlay.set_storage(&1, key1.clone(), Some(b"1".to_vec())); + overlay.set_storage(&1, key2.clone(), Some(b"2".to_vec())); + DirectAccountDb.commit(overlay.into_change_set()); - let _ = Balances::deposit_creating(&2, 110); - ContractInfoOf::::insert(2, &ContractInfo::Alive(RawAliveContractInfo { - trie_id: trie_id2.clone(), - storage_size: 0, - empty_pair_count: 0, - total_pair_count: 0, - deduct_block: System::block_number(), - code_hash: H256::repeat_byte(2), - rent_allowance: 40, - last_write: None, - })); + let _ = Balances::deposit_creating(&2, 110); + ContractInfoOf::::insert( + 2, + &ContractInfo::Alive(RawAliveContractInfo { + trie_id: trie_id2.clone(), + storage_size: 0, + empty_pair_count: 0, + total_pair_count: 0, + deduct_block: System::block_number(), + code_hash: H256::repeat_byte(2), + rent_allowance: 40, + last_write: None, + }), + ); - let mut overlay = OverlayAccountDb::::new(&DirectAccountDb); - overlay.set_storage(&2, key1.clone(), Some(b"3".to_vec())); - overlay.set_storage(&2, key2.clone(), Some(b"4".to_vec())); - DirectAccountDb.commit(overlay.into_change_set()); - } + let mut overlay = OverlayAccountDb::::new(&DirectAccountDb); + overlay.set_storage(&2, key1.clone(), Some(b"3".to_vec())); + overlay.set_storage(&2, key2.clone(), Some(b"4".to_vec())); + DirectAccountDb.commit(overlay.into_change_set()); + } - // Transfer funds from account 1 of such amount that after this transfer - // the balance of account 1 will be below the existential threshold. - // - // This does not remove the contract storage as we are not notified about a - // account removal. This cannot happen in reality because a contract can only - // remove itself by `ext_terminate`. There is no external event that can remove - // the account appart from that. - assert_ok!(Balances::transfer(Origin::signed(1), 2, 20)); + // Transfer funds from account 1 of such amount that after this transfer + // the balance of account 1 will be below the existential threshold. + // + // This does not remove the contract storage as we are not notified about a + // account removal. This cannot happen in reality because a contract can only + // remove itself by `ext_terminate`. There is no external event that can remove + // the account appart from that. + assert_ok!(Balances::transfer(Origin::signed(1), 2, 20)); - // Verify that no entries are removed. - { - assert_eq!( - >::get_storage(&DirectAccountDb, &1, Some(&trie_id1), key1), - Some(b"1".to_vec()) - ); - assert_eq!( - >::get_storage(&DirectAccountDb, &1, Some(&trie_id1), key2), - Some(b"2".to_vec()) - ); + // Verify that no entries are removed. + { + assert_eq!( + >::get_storage(&DirectAccountDb, &1, Some(&trie_id1), key1), + Some(b"1".to_vec()) + ); + assert_eq!( + >::get_storage(&DirectAccountDb, &1, Some(&trie_id1), key2), + Some(b"2".to_vec()) + ); - assert_eq!( - >::get_storage(&DirectAccountDb, &2, Some(&trie_id2), key1), - Some(b"3".to_vec()) - ); - assert_eq!( - >::get_storage(&DirectAccountDb, &2, Some(&trie_id2), key2), - Some(b"4".to_vec()) - ); - } - }); + assert_eq!( + >::get_storage(&DirectAccountDb, &2, Some(&trie_id2), key1), + Some(b"3".to_vec()) + ); + assert_eq!( + >::get_storage(&DirectAccountDb, &2, Some(&trie_id2), key2), + Some(b"4".to_vec()) + ); + } + }); } #[test] @@ -374,50 +388,56 @@ fn instantiate_and_call_and_deposit_event() { vec![], ); - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(BOB)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances( - pallet_balances::RawEvent::Endowed(BOB, 100) - ), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::Transfer(ALICE, BOB, 100)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::ContractExecution(BOB, vec![1, 2, 3, 4])), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::Instantiated(ALICE, BOB)), - topics: vec![], - } - ]); + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed( + 1, 1_000_000 + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount(BOB)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(BOB, 100)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Transfer(ALICE, BOB, 100)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::ContractExecution( + BOB, + vec![1, 2, 3, 4] + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Instantiated(ALICE, BOB)), + topics: vec![], + } + ] + ); assert_ok!(creation); assert!(ContractInfoOf::::contains_key(BOB)); @@ -428,7 +448,9 @@ fn instantiate_and_call_and_deposit_event() { fn dispatch_call() { // This test can fail due to the encoding changes. In case it becomes too annoying // let's rewrite so as we use this module controlled call or we serialize it in runtime. - let encoded = Encode::encode(&Call::Balances(pallet_balances::Call::transfer(CHARLIE, 50))); + let encoded = Encode::encode(&Call::Balances(pallet_balances::Call::transfer( + CHARLIE, 50, + ))); assert_eq!(&encoded[..], &hex!("00000300000000000000C8")[..]); let (wasm, code_hash) = compile_module::("dispatch_call").unwrap(); @@ -443,23 +465,28 @@ fn dispatch_call() { // Let's keep this assert even though it's redundant. If you ever need to update the // wasm source this test will fail and will show you the actual hash. - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - ]); + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed( + 1, 1_000_000 + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + ] + ); assert_ok!(Contracts::instantiate( Origin::signed(ALICE), @@ -477,73 +504,72 @@ fn dispatch_call() { vec![], )); - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(BOB)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances( - pallet_balances::RawEvent::Endowed(BOB, 100) - ), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::Transfer(ALICE, BOB, 100)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::Instantiated(ALICE, BOB)), - topics: vec![], - }, - - // Dispatching the call. - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(CHARLIE)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances( - pallet_balances::RawEvent::Endowed(CHARLIE, 50) - ), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances( - pallet_balances::RawEvent::Transfer(BOB, CHARLIE, 50) - ), - topics: vec![], - }, - - // Event emitted as a result of dispatch. - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::Dispatched(BOB, true)), - topics: vec![], - } - ]); + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed( + 1, 1_000_000 + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount(BOB)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(BOB, 100)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Transfer(ALICE, BOB, 100)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Instantiated(ALICE, BOB)), + topics: vec![], + }, + // Dispatching the call. + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount(CHARLIE)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(CHARLIE, 50)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Transfer( + BOB, CHARLIE, 50 + )), + topics: vec![], + }, + // Event emitted as a result of dispatch. + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Dispatched(BOB, true)), + topics: vec![], + } + ] + ); }); } @@ -551,7 +577,9 @@ fn dispatch_call() { fn dispatch_call_not_dispatched_after_top_level_transaction_failure() { // This test can fail due to the encoding changes. In case it becomes too annoying // let's rewrite so as we use this module controlled call or we serialize it in runtime. - let encoded = Encode::encode(&Call::Balances(pallet_balances::Call::transfer(CHARLIE, 50))); + let encoded = Encode::encode(&Call::Balances(pallet_balances::Call::transfer( + CHARLIE, 50, + ))); assert_eq!(&encoded[..], &hex!("00000300000000000000C8")[..]); let (wasm, code_hash) = compile_module::("dispatch_call_then_trap").unwrap(); @@ -566,23 +594,28 @@ fn dispatch_call_not_dispatched_after_top_level_transaction_failure() { // Let's keep this assert even though it's redundant. If you ever need to update the // wasm source this test will fail and will show you the actual hash. - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - ]); + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed( + 1, 1_000_000 + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + ] + ); assert_ok!(Contracts::instantiate( Origin::signed(ALICE), @@ -604,46 +637,49 @@ fn dispatch_call_not_dispatched_after_top_level_transaction_failure() { ), "contract trapped during execution" ); - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(BOB)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances( - pallet_balances::RawEvent::Endowed(BOB, 100) - ), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::Transfer(ALICE, BOB, 100)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::Instantiated(ALICE, BOB)), - topics: vec![], - }, - // ABSENCE of events which would be caused by dispatched Balances::transfer call - ]); + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed( + 1, 1_000_000 + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount(BOB)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(BOB, 100)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Transfer(ALICE, BOB, 100)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Instantiated(ALICE, BOB)), + topics: vec![], + }, + // ABSENCE of events which would be caused by dispatched Balances::transfer call + ] + ); }); } @@ -684,10 +720,18 @@ fn run_out_of_gas() { /// Input data for each call in set_rent code mod call { - pub fn set_storage_4_byte() -> Vec { vec![] } - pub fn remove_storage_4_byte() -> Vec { vec![0] } - pub fn transfer() -> Vec { vec![0, 0] } - pub fn null() -> Vec { vec![0, 0, 0] } + pub fn set_storage_4_byte() -> Vec { + vec![] + } + pub fn remove_storage_4_byte() -> Vec { + vec![0] + } + pub fn transfer() -> Vec { + vec![0, 0] + } + pub fn null() -> Vec { + vec![0, 0, 0] + } } /// Test correspondence of set_rent code and its hash. @@ -696,7 +740,9 @@ mod call { fn test_set_rent_code_and_hash() { // This test can fail due to the encoding changes. In case it becomes too annoying // let's rewrite so as we use this module controlled call or we serialize it in runtime. - let encoded = Encode::encode(&Call::Balances(pallet_balances::Call::transfer(CHARLIE, 50))); + let encoded = Encode::encode(&Call::Balances(pallet_balances::Call::transfer( + CHARLIE, 50, + ))); assert_eq!(&encoded[..], &hex!("00000300000000000000C8")[..]); let (wasm, code_hash) = compile_module::("set_rent").unwrap(); @@ -710,23 +756,28 @@ fn test_set_rent_code_and_hash() { // If you ever need to update the wasm source this test will fail // and will show you the actual hash. - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - ]); + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed( + 1, 1_000_000 + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + ] + ); }); } @@ -753,18 +804,9 @@ fn storage_size() { .unwrap() .get_alive() .unwrap(); - assert_eq!( - bob_contract.storage_size, - 4 - ); - assert_eq!( - bob_contract.total_pair_count, - 1, - ); - assert_eq!( - bob_contract.empty_pair_count, - 0, - ); + assert_eq!(bob_contract.storage_size, 4); + assert_eq!(bob_contract.total_pair_count, 1,); + assert_eq!(bob_contract.empty_pair_count, 0,); assert_ok!(Contracts::call( Origin::signed(ALICE), @@ -777,18 +819,9 @@ fn storage_size() { .unwrap() .get_alive() .unwrap(); - assert_eq!( - bob_contract.storage_size, - 4 + 4 - ); - assert_eq!( - bob_contract.total_pair_count, - 2, - ); - assert_eq!( - bob_contract.empty_pair_count, - 0, - ); + assert_eq!(bob_contract.storage_size, 4 + 4); + assert_eq!(bob_contract.total_pair_count, 2,); + assert_eq!(bob_contract.empty_pair_count, 0,); assert_ok!(Contracts::call( Origin::signed(ALICE), @@ -801,18 +834,9 @@ fn storage_size() { .unwrap() .get_alive() .unwrap(); - assert_eq!( - bob_contract.storage_size, - 4 - ); - assert_eq!( - bob_contract.total_pair_count, - 1, - ); - assert_eq!( - bob_contract.empty_pair_count, - 0, - ); + assert_eq!(bob_contract.storage_size, 4); + assert_eq!(bob_contract.total_pair_count, 1,); + assert_eq!(bob_contract.empty_pair_count, 0,); }); } @@ -820,36 +844,25 @@ fn storage_size() { fn empty_kv_pairs() { let (wasm, code_hash) = compile_module::("set_empty_storage").unwrap(); - ExtBuilder::default() - .build() - .execute_with(|| { - let _ = Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contracts::put_code(Origin::signed(ALICE), wasm)); - assert_ok!(Contracts::instantiate( - Origin::signed(ALICE), - 30_000, - GAS_LIMIT, - code_hash.into(), - vec![], - )); - let bob_contract = ContractInfoOf::::get(BOB) - .unwrap() - .get_alive() - .unwrap(); + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contracts::put_code(Origin::signed(ALICE), wasm)); + assert_ok!(Contracts::instantiate( + Origin::signed(ALICE), + 30_000, + GAS_LIMIT, + code_hash.into(), + vec![], + )); + let bob_contract = ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .unwrap(); - assert_eq!( - bob_contract.storage_size, - 0, - ); - assert_eq!( - bob_contract.total_pair_count, - 1, - ); - assert_eq!( - bob_contract.empty_pair_count, - 1, - ); - }); + assert_eq!(bob_contract.storage_size, 0,); + assert_eq!(bob_contract.total_pair_count, 1,); + assert_eq!(bob_contract.empty_pair_count, 1,); + }); } fn initialize_block(number: u64) { @@ -876,25 +889,38 @@ fn deduct_blocks() { assert_ok!(Contracts::instantiate( Origin::signed(ALICE), 30_000, - GAS_LIMIT, code_hash.into(), + GAS_LIMIT, + code_hash.into(), ::Balance::from(1_000u32).encode() // rent allowance )); // Check creation - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + let bob_contract = ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .unwrap(); assert_eq!(bob_contract.rent_allowance, 1_000); // Advance 4 blocks initialize_block(5); // Trigger rent through call - assert_ok!(Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, call::null())); + assert_ok!(Contracts::call( + Origin::signed(ALICE), + BOB, + 0, + GAS_LIMIT, + call::null() + )); // Check result let rent = (8 + 4 - 3) // storage size = size_offset + deploy_set_storage - deposit_offset * 4 // rent byte price * 4; // blocks to rent - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + let bob_contract = ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .unwrap(); assert_eq!(bob_contract.rent_allowance, 1_000 - rent); assert_eq!(bob_contract.deduct_block, 5); assert_eq!(Balances::free_balance(BOB), 30_000 - rent); @@ -903,21 +929,39 @@ fn deduct_blocks() { initialize_block(12); // Trigger rent through call - assert_ok!(Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, call::null())); + assert_ok!(Contracts::call( + Origin::signed(ALICE), + BOB, + 0, + GAS_LIMIT, + call::null() + )); // Check result let rent_2 = (8 + 4 - 2) // storage size = size_offset + deploy_set_storage - deposit_offset * 4 // rent byte price * 7; // blocks to rent - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + let bob_contract = ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .unwrap(); assert_eq!(bob_contract.rent_allowance, 1_000 - rent - rent_2); assert_eq!(bob_contract.deduct_block, 12); assert_eq!(Balances::free_balance(BOB), 30_000 - rent - rent_2); // Second call on same block should have no effect on rent - assert_ok!(Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, call::null())); + assert_ok!(Contracts::call( + Origin::signed(ALICE), + BOB, + 0, + GAS_LIMIT, + call::null() + )); - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + let bob_contract = ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .unwrap(); assert_eq!(bob_contract.rent_allowance, 1_000 - rent - rent_2); assert_eq!(bob_contract.deduct_block, 12); assert_eq!(Balances::free_balance(BOB), 30_000 - rent - rent_2); @@ -946,16 +990,48 @@ fn signed_claim_surcharge_contract_removals() { #[test] fn claim_surcharge_malus() { // Test surcharge malus for inherent - claim_surcharge(4, || Contracts::claim_surcharge(Origin::none(), BOB, Some(ALICE)).is_ok(), true); - claim_surcharge(3, || Contracts::claim_surcharge(Origin::none(), BOB, Some(ALICE)).is_ok(), true); - claim_surcharge(2, || Contracts::claim_surcharge(Origin::none(), BOB, Some(ALICE)).is_ok(), true); - claim_surcharge(1, || Contracts::claim_surcharge(Origin::none(), BOB, Some(ALICE)).is_ok(), false); + claim_surcharge( + 4, + || Contracts::claim_surcharge(Origin::none(), BOB, Some(ALICE)).is_ok(), + true, + ); + claim_surcharge( + 3, + || Contracts::claim_surcharge(Origin::none(), BOB, Some(ALICE)).is_ok(), + true, + ); + claim_surcharge( + 2, + || Contracts::claim_surcharge(Origin::none(), BOB, Some(ALICE)).is_ok(), + true, + ); + claim_surcharge( + 1, + || Contracts::claim_surcharge(Origin::none(), BOB, Some(ALICE)).is_ok(), + false, + ); // Test surcharge malus for signed - claim_surcharge(4, || Contracts::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), true); - claim_surcharge(3, || Contracts::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), false); - claim_surcharge(2, || Contracts::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), false); - claim_surcharge(1, || Contracts::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), false); + claim_surcharge( + 4, + || Contracts::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), + true, + ); + claim_surcharge( + 3, + || Contracts::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), + false, + ); + claim_surcharge( + 2, + || Contracts::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), + false, + ); + claim_surcharge( + 1, + || Contracts::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), + false, + ); } /// Claim surcharge with the given trigger_call at the given blocks. @@ -973,7 +1049,8 @@ fn claim_surcharge(blocks: u64, trigger_call: impl Fn() -> bool, removes: bool) assert_ok!(Contracts::instantiate( Origin::signed(ALICE), 100, - GAS_LIMIT, code_hash.into(), + GAS_LIMIT, + code_hash.into(), ::Balance::from(1_000u32).encode() // rent allowance )); @@ -984,9 +1061,15 @@ fn claim_surcharge(blocks: u64, trigger_call: impl Fn() -> bool, removes: bool) assert!(trigger_call()); if removes { - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + assert!(ContractInfoOf::::get(BOB) + .unwrap() + .get_tombstone() + .is_some()); } else { - assert!(ContractInfoOf::::get(BOB).unwrap().get_alive().is_some()); + assert!(ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .is_some()); } }); } @@ -1009,7 +1092,8 @@ fn removals(trigger_call: impl Fn() -> bool) { assert_ok!(Contracts::instantiate( Origin::signed(ALICE), 100, - GAS_LIMIT, code_hash.into(), + GAS_LIMIT, + code_hash.into(), ::Balance::from(1_000u32).encode() // rent allowance )); @@ -1017,7 +1101,14 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); - assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); + assert_eq!( + ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .unwrap() + .rent_allowance, + 1_000 + ); assert_eq!(Balances::free_balance(BOB), 100); // Advance blocks @@ -1025,7 +1116,10 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent through call assert!(trigger_call()); - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + assert!(ContractInfoOf::::get(BOB) + .unwrap() + .get_tombstone() + .is_some()); assert_eq!(Balances::free_balance(BOB), subsistence_threshold); // Advance blocks @@ -1033,7 +1127,10 @@ fn removals(trigger_call: impl Fn() -> bool) { // Trigger rent must have no effect assert!(trigger_call()); - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + assert!(ContractInfoOf::::get(BOB) + .unwrap() + .get_tombstone() + .is_some()); assert_eq!(Balances::free_balance(BOB), subsistence_threshold); }); @@ -1171,12 +1268,19 @@ fn call_removed_contract() { assert_ok!(Contracts::instantiate( Origin::signed(ALICE), 100, - GAS_LIMIT, code_hash.into(), + GAS_LIMIT, + code_hash.into(), ::Balance::from(1_000u32).encode() // rent allowance )); // Calling contract should succeed. - assert_ok!(Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, call::null())); + assert_ok!(Contracts::call( + Origin::signed(ALICE), + BOB, + 0, + GAS_LIMIT, + call::null() + )); // Advance blocks initialize_block(10); @@ -1187,13 +1291,14 @@ fn call_removed_contract() { "contract has been evicted" ); // Calling a contract that is about to evict shall emit an event. - assert_eq!(System::events(), vec![ - EventRecord { + assert_eq!( + System::events(), + vec![EventRecord { phase: Phase::Initialization, event: MetaEvent::contracts(RawEvent::Evicted(BOB, true)), topics: vec![], - }, - ]); + },] + ); // Subsequent contract calls should also fail. assert_err_ignore_postinfo!( @@ -1223,14 +1328,23 @@ fn default_rent_allowance_on_instantiate() { )); // Check creation - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + let bob_contract = ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .unwrap(); assert_eq!(bob_contract.rent_allowance, >::max_value()); // Advance blocks initialize_block(5); // Trigger rent through call - assert_ok!(Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, call::null())); + assert_ok!(Contracts::call( + Origin::signed(ALICE), + BOB, + 0, + GAS_LIMIT, + call::null() + )); // Check contract is still alive let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive(); @@ -1274,28 +1388,37 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: // If you ever need to update the wasm source this test will fail // and will show you the actual hash. - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::CodeStored(restoration_code_hash.into())), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::CodeStored(set_rent_code_hash.into())), - topics: vec![], - }, - ]); + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount(1)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed( + 1, 1_000_000 + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::CodeStored( + restoration_code_hash.into() + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::CodeStored( + set_rent_code_hash.into() + )), + topics: vec![], + }, + ] + ); // Create an account with address `BOB` with code `CODE_SET_RENT`. // The input parameter sets the rent allowance to 0. @@ -1309,39 +1432,49 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: // Check if `BOB` was created successfully and that the rent allowance is // set to 0. - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + let bob_contract = ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .unwrap(); assert_eq!(bob_contract.rent_allowance, 0); if test_different_storage { assert_ok!(Contracts::call( Origin::signed(ALICE), - BOB, 0, GAS_LIMIT, - call::set_storage_4_byte()) - ); + BOB, + 0, + GAS_LIMIT, + call::set_storage_4_byte() + )); } // Advance 4 blocks, to the 5th. initialize_block(5); // Preserve `BOB`'s code hash for later introspection. - let bob_code_hash = ContractInfoOf::::get(BOB).unwrap() - .get_alive().unwrap().code_hash; + let bob_code_hash = ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .unwrap() + .code_hash; // Call `BOB`, which makes it pay rent. Since the rent allowance is set to 0 // we expect that it will get removed leaving tombstone. assert_err_ignore_postinfo!( Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, call::null()), "contract has been evicted" ); - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - assert_eq!(System::events(), vec![ - EventRecord { + assert!(ContractInfoOf::::get(BOB) + .unwrap() + .get_tombstone() + .is_some()); + assert_eq!( + System::events(), + vec![EventRecord { phase: Phase::Initialization, - event: MetaEvent::contracts( - RawEvent::Evicted(BOB.clone(), true) - ), + event: MetaEvent::contracts(RawEvent::Evicted(BOB.clone(), true)), topics: vec![], - }, - ]); + },] + ); // Create another account with the address `DJANGO` with `CODE_RESTORATION`. // @@ -1357,8 +1490,11 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: )); // Before performing a call to `DJANGO` save its original trie id. - let django_trie_id = ContractInfoOf::::get(DJANGO).unwrap() - .get_alive().unwrap().trie_id; + let django_trie_id = ContractInfoOf::::get(DJANGO) + .unwrap() + .get_alive() + .unwrap() + .trie_id; if !test_restore_to_with_dirty_storage { // Advance 1 block, to the 6th. @@ -1378,73 +1514,98 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: if test_different_storage || test_restore_to_with_dirty_storage { // Parametrization of the test imply restoration failure. Check that `DJANGO` aka // restoration contract is still in place and also that `BOB` doesn't exist. - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - let django_contract = ContractInfoOf::::get(DJANGO).unwrap() - .get_alive().unwrap(); + assert!(ContractInfoOf::::get(BOB) + .unwrap() + .get_tombstone() + .is_some()); + let django_contract = ContractInfoOf::::get(DJANGO) + .unwrap() + .get_alive() + .unwrap(); assert_eq!(django_contract.storage_size, 8); assert_eq!(django_contract.trie_id, django_trie_id); assert_eq!(django_contract.deduct_block, System::block_number()); match (test_different_storage, test_restore_to_with_dirty_storage) { (true, false) => { - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts( - RawEvent::Restored(DJANGO, BOB, bob_code_hash, 50, false) - ), - topics: vec![], - }, - ]); - } - (_, true) => { - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::Evicted(BOB, true)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(CHARLIE)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(CHARLIE, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(frame_system::RawEvent::NewAccount(DJANGO)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::balances(pallet_balances::RawEvent::Endowed(DJANGO, 30_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::Transfer(CHARLIE, DJANGO, 30_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts(RawEvent::Instantiated(CHARLIE, DJANGO)), - topics: vec![], - }, - EventRecord { + assert_eq!( + System::events(), + vec![EventRecord { phase: Phase::Initialization, event: MetaEvent::contracts(RawEvent::Restored( DJANGO, BOB, bob_code_hash, 50, - false, + false )), topics: vec![], - }, - ]); + },] + ); + } + (_, true) => { + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Evicted(BOB, true)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount( + CHARLIE + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed( + CHARLIE, 1_000_000 + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(frame_system::RawEvent::NewAccount( + DJANGO + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::balances(pallet_balances::RawEvent::Endowed( + DJANGO, 30_000 + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Transfer( + CHARLIE, DJANGO, 30_000 + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Instantiated( + CHARLIE, DJANGO + )), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Restored( + DJANGO, + BOB, + bob_code_hash, + 50, + false, + )), + topics: vec![], + }, + ] + ); } _ => unreachable!(), } @@ -1452,27 +1613,36 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: // Here we expect that the restoration is succeeded. Check that the restoration // contract `DJANGO` ceased to exist and that `BOB` returned back. println!("{:?}", ContractInfoOf::::get(BOB)); - let bob_contract = ContractInfoOf::::get(BOB).unwrap() - .get_alive().unwrap(); + let bob_contract = ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .unwrap(); assert_eq!(bob_contract.rent_allowance, 50); assert_eq!(bob_contract.storage_size, 4); assert_eq!(bob_contract.trie_id, django_trie_id); assert_eq!(bob_contract.deduct_block, System::block_number()); assert!(ContractInfoOf::::get(DJANGO).is_none()); - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::system(system::RawEvent::KilledAccount(DJANGO)), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: MetaEvent::contracts( - RawEvent::Restored(DJANGO, BOB, bob_contract.code_hash, 50, true) - ), - topics: vec![], - }, - ]); + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::system(system::RawEvent::KilledAccount(DJANGO)), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: MetaEvent::contracts(RawEvent::Restored( + DJANGO, + BOB, + bob_contract.code_hash, + 50, + true + )), + topics: vec![], + }, + ] + ); } }); } @@ -1497,7 +1667,10 @@ fn storage_max_value_limit() { )); // Check creation - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + let bob_contract = ContractInfoOf::::get(BOB) + .unwrap() + .get_alive() + .unwrap(); assert_eq!(bob_contract.rent_allowance, >::max_value()); // Call contract with allowed storage value. @@ -1585,13 +1758,7 @@ fn cannot_self_destruct_through_draning() { // Call BOB with no input data, forcing it to run until out-of-balance // and eventually trapping because below existential deposit. assert_err_ignore_postinfo!( - Contracts::call( - Origin::signed(ALICE), - BOB, - 0, - GAS_LIMIT, - vec![], - ), + Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, vec![],), "contract trapped during execution" ); }); @@ -1625,13 +1792,7 @@ fn cannot_self_destruct_while_live() { // Call BOB with input data, forcing it make a recursive call to itself to // self-destruct, resulting in a trap. assert_err_ignore_postinfo!( - Contracts::call( - Origin::signed(ALICE), - BOB, - 0, - GAS_LIMIT, - vec![0], - ), + Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, vec![0],), "contract trapped during execution" ); @@ -1670,13 +1831,7 @@ fn self_destruct_works() { // Call BOB without input data which triggers termination. assert_matches!( - Contracts::call( - Origin::signed(ALICE), - BOB, - 0, - GAS_LIMIT, - vec![], - ), + Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, vec![],), Ok(_) ); @@ -1770,7 +1925,7 @@ fn get_runtime_storage() { frame_support::storage::unhashed::put_raw( &[1, 2, 3, 4], - 0x14144020u32.to_le_bytes().to_vec().as_ref() + 0x14144020u32.to_le_bytes().to_vec().as_ref(), ); assert_ok!(Contracts::put_code(Origin::signed(ALICE), wasm)); @@ -1831,13 +1986,9 @@ fn crypto_hashes() { // We offset data in the contract tables by 1. let mut params = vec![(n + 1) as u8]; params.extend_from_slice(input); - let result = >::bare_call( - ALICE, - BOB, - 0, - GAS_LIMIT, - params, - ).0.unwrap(); + let result = >::bare_call(ALICE, BOB, 0, GAS_LIMIT, params) + .0 + .unwrap(); assert_eq!(result.status, 0); let expected = hash_fn(input.as_ref()); assert_eq!(&result.data[..*expected_size], &*expected); diff --git a/rococo-parachains/pallets/contracts/src/wasm/code_cache.rs b/rococo-parachains/pallets/contracts/src/wasm/code_cache.rs index ba7a02356d..6514ff1656 100644 --- a/rococo-parachains/pallets/contracts/src/wasm/code_cache.rs +++ b/rococo-parachains/pallets/contracts/src/wasm/code_cache.rs @@ -26,11 +26,13 @@ //! this guarantees that every instrumented contract code in cache cannot have the version equal to the current one. //! Thus, before executing a contract it should be reinstrument with new schedule. -use crate::wasm::{prepare, runtime::Env, PrefabWasmModule}; -use crate::{CodeHash, CodeStorage, PristineCode, Schedule, Trait}; -use sp_std::prelude::*; -use sp_runtime::traits::Hash; +use crate::{ + wasm::{prepare, runtime::Env, PrefabWasmModule}, + CodeHash, CodeStorage, PristineCode, Schedule, Trait, +}; use frame_support::StorageMap; +use sp_runtime::traits::Hash; +use sp_std::prelude::*; /// Put code in the storage. The hash of code is used as a key and is returned /// as a result of this function. @@ -58,8 +60,7 @@ pub fn load( code_hash: &CodeHash, schedule: &Schedule, ) -> Result { - let mut prefab_module = - >::get(code_hash).ok_or_else(|| "code is not found")?; + let mut prefab_module = >::get(code_hash).ok_or_else(|| "code is not found")?; if prefab_module.schedule_version < schedule.version { // The current schedule version is greater than the version of the one cached diff --git a/rococo-parachains/pallets/contracts/src/wasm/env_def/macros.rs b/rococo-parachains/pallets/contracts/src/wasm/env_def/macros.rs index 335d35f1e7..88ef68ec75 100644 --- a/rococo-parachains/pallets/contracts/src/wasm/env_def/macros.rs +++ b/rococo-parachains/pallets/contracts/src/wasm/env_def/macros.rs @@ -193,14 +193,14 @@ macro_rules! define_env { #[cfg(test)] mod tests { - use parity_wasm::elements::FunctionType; - use parity_wasm::elements::ValueType; + use crate::{ + exec::Ext, + gas::Gas, + wasm::{tests::MockExt, Runtime}, + }; + use parity_wasm::elements::{FunctionType, ValueType}; use sp_runtime::traits::Zero; use sp_sandbox::{ReturnValue, Value}; - use crate::wasm::tests::MockExt; - use crate::wasm::Runtime; - use crate::exec::Ext; - use crate::gas::Gas; #[test] fn macro_unmarshall_then_body_then_marshall_value_or_trap() { @@ -263,8 +263,10 @@ mod tests { Err(sp_sandbox::HostError) } }); - let _f: fn(&mut Runtime, &[sp_sandbox::Value]) - -> Result = ext_gas::; + let _f: fn( + &mut Runtime, + &[sp_sandbox::Value], + ) -> Result = ext_gas::; } #[test] @@ -317,7 +319,13 @@ mod tests { }, ); - assert!(Env::can_satisfy(b"ext_gas", &FunctionType::new(vec![ValueType::I32], None))); - assert!(!Env::can_satisfy(b"not_exists", &FunctionType::new(vec![], None))); + assert!(Env::can_satisfy( + b"ext_gas", + &FunctionType::new(vec![ValueType::I32], None) + )); + assert!(!Env::can_satisfy( + b"not_exists", + &FunctionType::new(vec![], None) + )); } } diff --git a/rococo-parachains/pallets/contracts/src/wasm/env_def/mod.rs b/rococo-parachains/pallets/contracts/src/wasm/env_def/mod.rs index 7b67f74ec9..4bb7660aeb 100644 --- a/rococo-parachains/pallets/contracts/src/wasm/env_def/mod.rs +++ b/rococo-parachains/pallets/contracts/src/wasm/env_def/mod.rs @@ -17,8 +17,8 @@ use super::Runtime; use crate::exec::Ext; -use sp_sandbox::Value; use parity_wasm::elements::{FunctionType, ValueType}; +use sp_sandbox::Value; #[macro_use] pub(crate) mod macros; @@ -66,11 +66,10 @@ impl ConvertibleToWasm for u64 { } } -pub(crate) type HostFunc = - fn( - &mut Runtime, - &[sp_sandbox::Value] - ) -> Result; +pub(crate) type HostFunc = fn( + &mut Runtime, + &[sp_sandbox::Value], +) -> Result; pub(crate) trait FunctionImplProvider { fn impls)>(f: &mut F); diff --git a/rococo-parachains/pallets/contracts/src/wasm/mod.rs b/rococo-parachains/pallets/contracts/src/wasm/mod.rs index 1e19296480..2c81467fbe 100644 --- a/rococo-parachains/pallets/contracts/src/wasm/mod.rs +++ b/rococo-parachains/pallets/contracts/src/wasm/mod.rs @@ -17,14 +17,16 @@ //! This module provides a means for executing contracts //! represented in wasm. -use crate::{CodeHash, Schedule, Trait}; -use crate::wasm::env_def::FunctionImplProvider; -use crate::exec::{Ext, ExecResult}; -use crate::gas::GasMeter; +use crate::{ + exec::{ExecResult, Ext}, + gas::GasMeter, + wasm::env_def::FunctionImplProvider, + CodeHash, Schedule, Trait, +}; -use sp_std::prelude::*; -use codec::{Encode, Decode}; +use codec::{Decode, Encode}; use sp_sandbox; +use sp_std::prelude::*; #[macro_use] mod env_def; @@ -32,8 +34,10 @@ mod code_cache; mod prepare; mod runtime; -use self::runtime::{to_execution_result, Runtime}; -use self::code_cache::load as load_code; +use self::{ + code_cache::load as load_code, + runtime::{to_execution_result, Runtime}, +}; pub use self::code_cache::save as save_code; @@ -116,8 +120,8 @@ impl<'a, T: Trait> crate::exec::Vm for WasmVm<'a> { let memory = sp_sandbox::Memory::new(exec.prefab_module.initial, Some(exec.prefab_module.maximum)) .unwrap_or_else(|_| { - // unlike `.expect`, explicit panic preserves the source location. - // Needed as we can't use `RUST_BACKTRACE` in here. + // unlike `.expect`, explicit panic preserves the source location. + // Needed as we can't use `RUST_BACKTRACE` in here. panic!( "exec.prefab_module.initial can't be greater than exec.prefab_module.maximum; thus Memory::new must not fail; @@ -131,13 +135,7 @@ impl<'a, T: Trait> crate::exec::Vm for WasmVm<'a> { imports.add_host_func("env", name, func_ptr); }); - let mut runtime = Runtime::new( - &mut ext, - input_data, - &self.schedule, - memory, - gas_meter, - ); + let mut runtime = Runtime::new(&mut ext, input_data, &self.schedule, memory, gas_meter); // Instantiate the instance from the instrumented module code and invoke the contract // entrypoint. @@ -150,19 +148,20 @@ impl<'a, T: Trait> crate::exec::Vm for WasmVm<'a> { #[cfg(test)] mod tests { use super::*; - use std::collections::HashMap; - use std::cell::RefCell; - use sp_core::H256; - use crate::exec::{Ext, StorageKey, ExecError, ExecReturnValue, STATUS_SUCCESS}; - use crate::gas::{Gas, GasMeter}; - use crate::tests::{Test, Call}; - use crate::wasm::prepare::prepare_contract; - use crate::{CodeHash, BalanceOf}; - use wabt; - use hex_literal::hex; + use crate::{ + exec::{ExecError, ExecReturnValue, Ext, StorageKey, STATUS_SUCCESS}, + gas::{Gas, GasMeter}, + tests::{Call, Test}, + wasm::prepare::prepare_contract, + BalanceOf, CodeHash, + }; use assert_matches::assert_matches; - use sp_runtime::DispatchError; use frame_support::weights::Weight; + use hex_literal::hex; + use sp_core::H256; + use sp_runtime::DispatchError; + use std::{cell::RefCell, collections::HashMap}; + use wabt; const GAS_LIMIT: Gas = 10_000_000_000; @@ -230,9 +229,11 @@ mod tests { fn get_storage(&self, key: &StorageKey) -> Option> { self.storage.get(key).cloned() } - fn set_storage(&mut self, key: StorageKey, value: Option>) - -> Result<(), &'static str> - { + fn set_storage( + &mut self, + key: StorageKey, + value: Option>, + ) -> Result<(), &'static str> { *self.storage.entry(key).or_insert(Vec::new()) = value.unwrap_or(Vec::new()); Ok(()) } @@ -289,7 +290,10 @@ mod tests { }); // Assume for now that it was just a plain transfer. // TODO: Add tests for different call outcomes. - Ok(ExecReturnValue { status: STATUS_SUCCESS, data: Vec::new() }) + Ok(ExecReturnValue { + status: STATUS_SUCCESS, + data: Vec::new(), + }) } fn terminate( &mut self, @@ -360,21 +364,22 @@ mod tests { self.rent_allowance } - fn block_number(&self) -> u64 { 121 } + fn block_number(&self) -> u64 { + 121 + } - fn max_value_size(&self) -> u32 { 16_384 } + fn max_value_size(&self) -> u32 { + 16_384 + } fn get_runtime_storage(&self, key: &[u8]) -> Option> { - let opt_value = self.runtime_storage_keys - .borrow_mut() - .remove(key); - opt_value.unwrap_or_else(|| + let opt_value = self.runtime_storage_keys.borrow_mut().remove(key); + opt_value.unwrap_or_else(|| { panic!( "{:?} doesn't exist. values that do exist {:?}", - key, - self.runtime_storage_keys + key, self.runtime_storage_keys ) - ) + }) } fn get_weight_price(&self, weight: Weight) -> BalanceOf { BalanceOf::::from(1312_u32).saturating_mul(weight.into()) @@ -387,9 +392,11 @@ mod tests { fn get_storage(&self, key: &[u8; 32]) -> Option> { (**self).get_storage(key) } - fn set_storage(&mut self, key: [u8; 32], value: Option>) - -> Result<(), &'static str> - { + fn set_storage( + &mut self, + key: [u8; 32], + value: Option>, + ) -> Result<(), &'static str> { (**self).set_storage(key, value) } fn instantiate( @@ -435,12 +442,7 @@ mod tests { rent_allowance: u64, delta: Vec, ) { - (**self).note_restore_to( - dest, - code_hash, - rent_allowance, - delta, - ) + (**self).note_restore_to(dest, code_hash, rent_allowance, delta) } fn caller(&self) -> &u64 { (**self).caller() @@ -499,8 +501,7 @@ mod tests { let wasm = wabt::wat2wasm(wat).unwrap(); let schedule = crate::Schedule::default(); - let prefab_module = - prepare_contract::(&wasm, &schedule).unwrap(); + let prefab_module = prepare_contract::(&wasm, &schedule).unwrap(); let exec = WasmExecutable { // Use a "call" convention. @@ -554,7 +555,8 @@ mod tests { vec![], &mut mock_ext, &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); assert_eq!( &mock_ext.transfers, @@ -614,7 +616,8 @@ mod tests { vec![], &mut mock_ext, &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); assert_eq!( &mock_ext.transfers, @@ -676,7 +679,8 @@ mod tests { vec![], &mut mock_ext, &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); assert_eq!( &mock_ext.instantiates, @@ -719,7 +723,8 @@ mod tests { vec![], &mut mock_ext, &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); assert_eq!( &mock_ext.terminations, @@ -777,7 +782,8 @@ mod tests { vec![], &mut mock_ext, &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); assert_eq!( &mock_ext.transfers, @@ -861,18 +867,23 @@ mod tests { #[test] fn get_storage_puts_data_into_scratch_buf() { let mut mock_ext = MockExt::default(); - mock_ext - .storage - .insert([0x11; 32], [0x22; 32].to_vec()); + mock_ext.storage.insert([0x11; 32], [0x22; 32].to_vec()); let output = execute( CODE_GET_STORAGE, vec![], mock_ext, &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); - assert_eq!(output, ExecReturnValue { status: STATUS_SUCCESS, data: [0x22; 32].to_vec() }); + assert_eq!( + output, + ExecReturnValue { + status: STATUS_SUCCESS, + data: [0x22; 32].to_vec() + } + ); } /// calls `ext_caller`, loads the address from the scratch buffer and @@ -934,7 +945,8 @@ mod tests { vec![], MockExt::default(), &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); } /// calls `ext_address`, loads the address from the scratch buffer and @@ -996,7 +1008,8 @@ mod tests { vec![], MockExt::default(), &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); } const CODE_BALANCE: &str = r#" @@ -1051,12 +1064,7 @@ mod tests { #[test] fn balance() { let mut gas_meter = GasMeter::new(GAS_LIMIT); - let _ = execute( - CODE_BALANCE, - vec![], - MockExt::default(), - &mut gas_meter, - ).unwrap(); + let _ = execute(CODE_BALANCE, vec![], MockExt::default(), &mut gas_meter).unwrap(); } const CODE_GAS_PRICE: &str = r#" @@ -1111,12 +1119,7 @@ mod tests { #[test] fn gas_price() { let mut gas_meter = GasMeter::new(GAS_LIMIT); - let _ = execute( - CODE_GAS_PRICE, - vec![], - MockExt::default(), - &mut gas_meter, - ).unwrap(); + let _ = execute(CODE_GAS_PRICE, vec![], MockExt::default(), &mut gas_meter).unwrap(); } const CODE_GAS_LEFT: &str = r#" @@ -1170,16 +1173,14 @@ mod tests { fn gas_left() { let mut gas_meter = GasMeter::new(GAS_LIMIT); - let output = execute( - CODE_GAS_LEFT, - vec![], - MockExt::default(), - &mut gas_meter, - ).unwrap(); + let output = execute(CODE_GAS_LEFT, vec![], MockExt::default(), &mut gas_meter).unwrap(); let gas_left = Gas::decode(&mut output.data.as_slice()).unwrap(); assert!(gas_left < GAS_LIMIT, "gas_left must be less than initial"); - assert!(gas_left > gas_meter.gas_left(), "gas_left must be greater than final"); + assert!( + gas_left > gas_meter.gas_left(), + "gas_left must be greater than final" + ); } const CODE_VALUE_TRANSFERRED: &str = r#" @@ -1239,7 +1240,8 @@ mod tests { vec![], MockExt::default(), &mut gas_meter, - ).unwrap(); + ) + .unwrap(); } const CODE_DISPATCH_CALL: &str = r#" @@ -1270,13 +1272,14 @@ mod tests { vec![], &mut mock_ext, &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); assert_eq!( &mock_ext.dispatches, - &[DispatchEntry( - Call::Balances(pallet_balances::Call::set_balance(42, 1337, 0)), - )] + &[DispatchEntry(Call::Balances( + pallet_balances::Call::set_balance(42, 1337, 0) + ),)] ); } @@ -1310,9 +1313,16 @@ mod tests { vec![], MockExt::default(), &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); - assert_eq!(output, ExecReturnValue { status: STATUS_SUCCESS, data: vec![1, 2, 3, 4] }); + assert_eq!( + output, + ExecReturnValue { + status: STATUS_SUCCESS, + data: vec![1, 2, 3, 4] + } + ); } const CODE_TIMESTAMP_NOW: &str = r#" @@ -1372,7 +1382,8 @@ mod tests { vec![], MockExt::default(), &mut gas_meter, - ).unwrap(); + ) + .unwrap(); } const CODE_MINIMUM_BALANCE: &str = r#" @@ -1431,7 +1442,8 @@ mod tests { vec![], MockExt::default(), &mut gas_meter, - ).unwrap(); + ) + .unwrap(); } const CODE_TOMBSTONE_DEPOSIT: &str = r#" @@ -1490,7 +1502,8 @@ mod tests { vec![], MockExt::default(), &mut gas_meter, - ).unwrap(); + ) + .unwrap(); } const CODE_RANDOM: &str = r#" @@ -1554,19 +1567,15 @@ mod tests { fn random() { let mut gas_meter = GasMeter::new(GAS_LIMIT); - let output = execute( - CODE_RANDOM, - vec![], - MockExt::default(), - &mut gas_meter, - ).unwrap(); + let output = execute(CODE_RANDOM, vec![], MockExt::default(), &mut gas_meter).unwrap(); // The mock ext just returns the same data that was passed as the subject. assert_eq!( output, ExecReturnValue { status: STATUS_SUCCESS, - data: hex!("000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F").to_vec(), + data: hex!("000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F") + .to_vec(), }, ); } @@ -1598,17 +1607,15 @@ mod tests { fn deposit_event() { let mut mock_ext = MockExt::default(); let mut gas_meter = GasMeter::new(GAS_LIMIT); - let _ = execute( - CODE_DEPOSIT_EVENT, - vec![], - &mut mock_ext, - &mut gas_meter - ).unwrap(); + let _ = execute(CODE_DEPOSIT_EVENT, vec![], &mut mock_ext, &mut gas_meter).unwrap(); - assert_eq!(mock_ext.events, vec![ - (vec![H256::repeat_byte(0x33)], - vec![0x00, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00]) - ]); + assert_eq!( + mock_ext.events, + vec![( + vec![H256::repeat_byte(0x33)], + vec![0x00, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00] + )] + ); assert_eq!(gas_meter.gas_left(), 9967000000); } @@ -1653,7 +1660,8 @@ mod tests { &mut gas_meter ), Err(ExecError { - reason: DispatchError::Other("contract trapped during execution"), buffer: _ + reason: DispatchError::Other("contract trapped during execution"), + buffer: _, }) ); } @@ -1696,7 +1704,10 @@ mod tests { MockExt::default(), &mut gas_meter ), - Err(ExecError { reason: DispatchError::Other("contract trapped during execution"), buffer: _ }) + Err(ExecError { + reason: DispatchError::Other("contract trapped during execution"), + buffer: _, + }) ); } @@ -1759,7 +1770,8 @@ mod tests { vec![], MockExt::default(), &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); } // asserts that the size of the input data is 4. @@ -1799,7 +1811,8 @@ mod tests { input_data, MockExt::default(), &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); assert_eq!(output.data.len(), 0); assert_eq!(output.data.capacity(), 1_234); @@ -1815,7 +1828,9 @@ mod tests { input_data, MockExt::default(), &mut GasMeter::new(GAS_LIMIT), - ).err().unwrap(); + ) + .err() + .unwrap(); assert_eq!(error.buffer.capacity(), 1_234); } @@ -1869,9 +1884,16 @@ mod tests { hex!("00112233445566778899").to_vec(), MockExt::default(), &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); - assert_eq!(output, ExecReturnValue { status: 0, data: hex!("445566778899").to_vec() }); + assert_eq!( + output, + ExecReturnValue { + status: 0, + data: hex!("445566778899").to_vec() + } + ); assert!(output.is_success()); } @@ -1882,9 +1904,16 @@ mod tests { hex!("112233445566778899").to_vec(), MockExt::default(), &mut GasMeter::new(GAS_LIMIT), - ).unwrap(); + ) + .unwrap(); - assert_eq!(output, ExecReturnValue { status: 17, data: hex!("5566778899").to_vec() }); + assert_eq!( + output, + ExecReturnValue { + status: 17, + data: hex!("5566778899").to_vec() + } + ); assert!(!output.is_success()); } @@ -1973,17 +2002,15 @@ mod tests { // "\01\02\03\04" - Some(0x14144020) // "\02\03\04\05" - None *mock_ext.runtime_storage_keys.borrow_mut() = [ - ([1, 2, 3, 4].to_vec(), Some(0x14144020u32.to_le_bytes().to_vec())), + ( + [1, 2, 3, 4].to_vec(), + Some(0x14144020u32.to_le_bytes().to_vec()), + ), ([2, 3, 4, 5].to_vec().to_vec(), None), ] .iter() .cloned() .collect(); - let _ = execute( - CODE_GET_RUNTIME_STORAGE, - vec![], - mock_ext, - &mut gas_meter, - ).unwrap(); + let _ = execute(CODE_GET_RUNTIME_STORAGE, vec![], mock_ext, &mut gas_meter).unwrap(); } } diff --git a/rococo-parachains/pallets/contracts/src/wasm/prepare.rs b/rococo-parachains/pallets/contracts/src/wasm/prepare.rs index ba934f353e..a20088b3b9 100644 --- a/rococo-parachains/pallets/contracts/src/wasm/prepare.rs +++ b/rococo-parachains/pallets/contracts/src/wasm/prepare.rs @@ -18,15 +18,15 @@ //! wasm module before execution. It also extracts some essential information //! from a module. -use crate::wasm::env_def::ImportSatisfyCheck; -use crate::wasm::PrefabWasmModule; -use crate::Schedule; +use crate::{ + wasm::{env_def::ImportSatisfyCheck, PrefabWasmModule}, + Schedule, +}; -use parity_wasm::elements::{self, Internal, External, MemoryType, Type, ValueType}; -use pwasm_utils; -use pwasm_utils::rules; +use parity_wasm::elements::{self, External, Internal, MemoryType, Type, ValueType}; +use pwasm_utils::{self, rules}; +use sp_runtime::traits::SaturatedConversion; use sp_std::prelude::*; -use sp_runtime::traits::{SaturatedConversion}; struct ContractModule<'a> { /// A deserialized module. The module is valid (this is Guaranteed by `new` method). @@ -39,10 +39,7 @@ impl<'a> ContractModule<'a> { /// /// Returns `Err` if the `original_code` couldn't be decoded or /// if it contains an invalid module. - fn new( - original_code: &[u8], - schedule: &'a Schedule, - ) -> Result { + fn new(original_code: &[u8], schedule: &'a Schedule) -> Result { use wasmi_validation::{validate_module, PlainValidator}; let module = @@ -53,10 +50,7 @@ impl<'a> ContractModule<'a> { // Return a `ContractModule` instance with // __valid__ module. - Ok(ContractModule { - module, - schedule, - }) + Ok(ContractModule { module, schedule }) } /// Ensures that module doesn't declare internal memories. @@ -65,7 +59,8 @@ impl<'a> ContractModule<'a> { /// Memory section contains declarations of internal linear memories, so if we find one /// we reject such a module. fn ensure_no_internal_memory(&self) -> Result<(), &'static str> { - if self.module + if self + .module .memory_section() .map_or(false, |ms| ms.entries().len() > 0) { @@ -86,7 +81,7 @@ impl<'a> ContractModule<'a> { // Check the table's initial size as there is no instruction or environment function // capable of growing the table. if table_type.limits().initial() > limit { - return Err("table exceeds maximum size allowed") + return Err("table exceeds maximum size allowed"); } } } @@ -98,8 +93,9 @@ impl<'a> ContractModule<'a> { if let Some(global_section) = self.module.global_section() { for global in global_section.entries() { match global.global_type().content_type() { - ValueType::F32 | ValueType::F64 => - return Err("use of floating point type in globals is forbidden"), + ValueType::F32 | ValueType::F64 => { + return Err("use of floating point type in globals is forbidden") + } _ => {} } } @@ -109,8 +105,9 @@ impl<'a> ContractModule<'a> { for func_body in code_section.bodies() { for local in func_body.locals() { match local.value_type() { - ValueType::F32 | ValueType::F64 => - return Err("use of floating point type in locals is forbidden"), + ValueType::F32 | ValueType::F64 => { + return Err("use of floating point type in locals is forbidden") + } _ => {} } } @@ -124,8 +121,11 @@ impl<'a> ContractModule<'a> { let return_type = func_type.return_type(); for value_type in func_type.params().iter().chain(return_type.iter()) { match value_type { - ValueType::F32 | ValueType::F64 => - return Err("use of floating point type in function types is forbidden"), + ValueType::F32 | ValueType::F64 => { + return Err( + "use of floating point type in function types is forbidden", + ) + } _ => {} } } @@ -138,13 +138,12 @@ impl<'a> ContractModule<'a> { } fn inject_gas_metering(self) -> Result { - let gas_rules = - rules::Set::new( - self.schedule.regular_op_cost.clone().saturated_into(), - Default::default(), - ) - .with_grow_cost(self.schedule.grow_mem_cost.clone().saturated_into()) - .with_forbidden_floats(); + let gas_rules = rules::Set::new( + self.schedule.regular_op_cost.clone().saturated_into(), + Default::default(), + ) + .with_grow_cost(self.schedule.grow_mem_cost.clone().saturated_into()) + .with_forbidden_floats(); let contract_module = pwasm_utils::inject_gas_counter(self.module, &gas_rules) .map_err(|_| "gas instrumentation failed")?; @@ -195,11 +194,9 @@ impl<'a> ContractModule<'a> { .map(|is| is.entries()) .unwrap_or(&[]) .iter() - .filter(|entry| { - match *entry.external() { - External::Function(_) => true, - _ => false, - } + .filter(|entry| match *entry.external() { + External::Function(_) => true, + _ => false, }) .count(); @@ -232,15 +229,17 @@ impl<'a> ContractModule<'a> { // The [] -> [] signature predates the [] -> [i32] signature and is supported for // backwards compatibility. This will likely be removed once ink! is updated to // generate modules with the new function signatures. - let func_ty_idx = func_entries.get(fn_idx as usize) + let func_ty_idx = func_entries + .get(fn_idx as usize) .ok_or_else(|| "export refers to non-existent function")? .type_ref(); let Type::Function(ref func_ty) = types .get(func_ty_idx as usize) .ok_or_else(|| "function has a non-existent type")?; - if !func_ty.params().is_empty() || - !(func_ty.return_type().is_none() || - func_ty.return_type() == Some(ValueType::I32)) { + if !func_ty.params().is_empty() + || !(func_ty.return_type().is_none() + || func_ty.return_type() == Some(ValueType::I32)) + { return Err("entry point has wrong signature"); } } @@ -286,10 +285,10 @@ impl<'a> ContractModule<'a> { &External::Function(ref type_idx) => type_idx, &External::Memory(ref memory_type) => { if import.field() != "memory" { - return Err("Memory import must have the field name 'memory'") + return Err("Memory import must have the field name 'memory'"); } if imported_mem_type.is_some() { - return Err("Multiple memory imports defined") + return Err("Multiple memory imports defined"); } imported_mem_type = Some(memory_type); continue; @@ -317,8 +316,7 @@ impl<'a> ContractModule<'a> { } fn into_wasm_code(self) -> Result, &'static str> { - elements::serialize(self.module) - .map_err(|_| "error serializing instrumented module") + elements::serialize(self.module).map_err(|_| "error serializing instrumented module") } } @@ -394,9 +392,9 @@ pub fn prepare_contract( mod tests { use super::*; use crate::exec::Ext; + use assert_matches::assert_matches; use std::fmt; use wabt; - use assert_matches::assert_matches; impl fmt::Debug for PrefabWasmModule { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -429,7 +427,8 @@ mod tests { }; } - prepare_test!(no_floats, + prepare_test!( + no_floats, r#" (module (func (export "call") @@ -454,7 +453,8 @@ mod tests { assert_eq!(Schedule::default().max_memory_pages, 16); } - prepare_test!(memory_with_one_page, + prepare_test!( + memory_with_one_page, r#" (module (import "env" "memory" (memory 1 1)) @@ -466,7 +466,8 @@ mod tests { Ok(_) ); - prepare_test!(internal_memory_declaration, + prepare_test!( + internal_memory_declaration, r#" (module (memory 1 1) @@ -478,7 +479,8 @@ mod tests { Err("module declares internal memory") ); - prepare_test!(no_memory_import, + prepare_test!( + no_memory_import, r#" (module ;; no memory imported @@ -489,7 +491,8 @@ mod tests { Ok(_) ); - prepare_test!(initial_exceeds_maximum, + prepare_test!( + initial_exceeds_maximum, r#" (module (import "env" "memory" (memory 16 1)) @@ -501,7 +504,8 @@ mod tests { Err("Module is not valid") ); - prepare_test!(no_maximum, + prepare_test!( + no_maximum, r#" (module (import "env" "memory" (memory 1)) @@ -513,7 +517,8 @@ mod tests { Err("Maximum number of pages should be always declared.") ); - prepare_test!(requested_maximum_exceeds_configured_maximum, + prepare_test!( + requested_maximum_exceeds_configured_maximum, r#" (module (import "env" "memory" (memory 1 17)) @@ -525,7 +530,8 @@ mod tests { Err("Maximum number of pages should not exceed the configured maximum.") ); - prepare_test!(field_name_not_memory, + prepare_test!( + field_name_not_memory, r#" (module (import "env" "forgetit" (memory 1 1)) @@ -537,7 +543,8 @@ mod tests { Err("Memory import must have the field name 'memory'") ); - prepare_test!(multiple_memory_imports, + prepare_test!( + multiple_memory_imports, r#" (module (import "env" "memory" (memory 1 1)) @@ -550,7 +557,8 @@ mod tests { Err("Module is not valid") ); - prepare_test!(table_import, + prepare_test!( + table_import, r#" (module (import "env" "table" (table 1 anyfunc)) @@ -562,7 +570,8 @@ mod tests { Err("Cannot import tables") ); - prepare_test!(global_import, + prepare_test!( + global_import, r#" (module (global $g (import "env" "global") i32) @@ -583,7 +592,8 @@ mod tests { assert_eq!(Schedule::default().max_table_size, 16384); } - prepare_test!(no_tables, + prepare_test!( + no_tables, r#" (module (func (export "call")) @@ -593,7 +603,8 @@ mod tests { Ok(_) ); - prepare_test!(table_valid_size, + prepare_test!( + table_valid_size, r#" (module (table 10000 funcref) @@ -605,7 +616,8 @@ mod tests { Ok(_) ); - prepare_test!(table_too_big, + prepare_test!( + table_too_big, r#" (module (table 20000 funcref) @@ -620,7 +632,8 @@ mod tests { mod imports { use super::*; - prepare_test!(can_import_legit_function, + prepare_test!( + can_import_legit_function, r#" (module (import "env" "nop" (func (param i64))) @@ -634,7 +647,8 @@ mod tests { // even though gas is defined the contract can't import it since // it is an implementation defined. - prepare_test!(can_not_import_gas_function, + prepare_test!( + can_not_import_gas_function, r#" (module (import "env" "gas" (func (param i32))) @@ -647,7 +661,8 @@ mod tests { ); // nothing can be imported from non-"env" module for now. - prepare_test!(non_env_import, + prepare_test!( + non_env_import, r#" (module (import "another_module" "memory" (memory 1 1)) @@ -660,7 +675,8 @@ mod tests { ); // wrong signature - prepare_test!(wrong_signature, + prepare_test!( + wrong_signature, r#" (module (import "env" "gas" (func (param i64))) @@ -672,7 +688,8 @@ mod tests { Err("module imports a non-existent function") ); - prepare_test!(unknown_func_name, + prepare_test!( + unknown_func_name, r#" (module (import "env" "unknown_func" (func)) @@ -684,7 +701,8 @@ mod tests { Err("module imports a non-existent function") ); - prepare_test!(ext_println_debug_disabled, + prepare_test!( + ext_println_debug_disabled, r#" (module (import "env" "ext_println" (func $ext_println (param i32 i32))) @@ -698,16 +716,19 @@ mod tests { #[test] fn ext_println_debug_enabled() { - let wasm = wabt::Wat2Wasm::new().validate(false).convert( - r#" + let wasm = wabt::Wat2Wasm::new() + .validate(false) + .convert( + r#" (module (import "env" "ext_println" (func $ext_println (param i32 i32))) (func (export "call")) (func (export "deploy")) ) - "# - ).unwrap(); + "#, + ) + .unwrap(); let mut schedule = Schedule::default(); schedule.enable_println = true; let r = prepare_contract::(wasm.as_ref(), &schedule); @@ -718,7 +739,8 @@ mod tests { mod entrypoints { use super::*; - prepare_test!(it_works, + prepare_test!( + it_works, r#" (module (func (export "call")) @@ -728,7 +750,8 @@ mod tests { Ok(_) ); - prepare_test!(omit_deploy, + prepare_test!( + omit_deploy, r#" (module (func (export "call")) @@ -737,7 +760,8 @@ mod tests { Err("deploy function isn't exported") ); - prepare_test!(omit_call, + prepare_test!( + omit_call, r#" (module (func (export "deploy")) @@ -747,7 +771,8 @@ mod tests { ); // Try to use imported function as an entry point. - prepare_test!(try_sneak_export_as_entrypoint, + prepare_test!( + try_sneak_export_as_entrypoint, r#" (module (import "env" "panic" (func)) @@ -761,7 +786,8 @@ mod tests { ); // Try to use imported function as an entry point. - prepare_test!(try_sneak_export_as_global, + prepare_test!( + try_sneak_export_as_global, r#" (module (func (export "deploy")) @@ -771,7 +797,8 @@ mod tests { Err("expected a function") ); - prepare_test!(wrong_signature, + prepare_test!( + wrong_signature, r#" (module (func (export "deploy")) @@ -781,7 +808,8 @@ mod tests { Err("entry point has wrong signature") ); - prepare_test!(unknown_exports, + prepare_test!( + unknown_exports, r#" (module (func (export "call")) @@ -792,7 +820,8 @@ mod tests { Err("unknown export: expecting only deploy and call functions") ); - prepare_test!(global_float, + prepare_test!( + global_float, r#" (module (global $x f32 (f32.const 0)) @@ -803,7 +832,8 @@ mod tests { Err("use of floating point type in globals is forbidden") ); - prepare_test!(local_float, + prepare_test!( + local_float, r#" (module (func $foo (local f32)) @@ -814,7 +844,8 @@ mod tests { Err("use of floating point type in locals is forbidden") ); - prepare_test!(param_float, + prepare_test!( + param_float, r#" (module (func $foo (param f32)) @@ -825,7 +856,8 @@ mod tests { Err("use of floating point type in function types is forbidden") ); - prepare_test!(result_float, + prepare_test!( + result_float, r#" (module (func $foo (result f32) (f32.const 0)) diff --git a/rococo-parachains/pallets/contracts/src/wasm/runtime.rs b/rococo-parachains/pallets/contracts/src/wasm/runtime.rs index 117a4b3534..490621ba94 100644 --- a/rococo-parachains/pallets/contracts/src/wasm/runtime.rs +++ b/rococo-parachains/pallets/contracts/src/wasm/runtime.rs @@ -16,23 +16,18 @@ //! Environment definition of the wasm smart-contract runtime. -use crate::{Schedule, Trait, CodeHash, BalanceOf}; -use crate::exec::{ - Ext, ExecResult, ExecError, ExecReturnValue, StorageKey, TopicOf, STATUS_SUCCESS, +use crate::{ + exec::{ExecError, ExecResult, ExecReturnValue, Ext, StorageKey, TopicOf, STATUS_SUCCESS}, + gas::{Gas, GasMeter, GasMeterResult, Token}, + BalanceOf, CodeHash, Schedule, Trait, }; -use crate::gas::{Gas, GasMeter, Token, GasMeterResult}; -use sp_sandbox; -use frame_system; -use sp_std::{prelude::*, mem, convert::TryInto}; use codec::{Decode, Encode}; -use sp_runtime::traits::{Bounded, SaturatedConversion}; -use sp_io::hashing::{ - keccak_256, - blake2_256, - blake2_128, - sha2_256, -}; use frame_support::weights::GetDispatchInfo; +use frame_system; +use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; +use sp_runtime::traits::{Bounded, SaturatedConversion}; +use sp_sandbox; +use sp_std::{convert::TryInto, mem, prelude::*}; /// The value returned from ext_call and ext_instantiate contract external functions if the call or /// instantiation traps. This value is chosen as if the execution does not trap, the return value @@ -93,19 +88,19 @@ pub(crate) fn to_execution_result( status: STATUS_SUCCESS, data, }) - }, + } Some(SpecialTrap::Termination) => { return Ok(ExecReturnValue { status: STATUS_SUCCESS, data: Vec::new(), }) - }, + } Some(SpecialTrap::OutOfGas) => { return Err(ExecError { reason: "ran out of gas during contract execution".into(), buffer: runtime.scratch_buf, }) - }, + } None => (), } @@ -115,29 +110,43 @@ pub(crate) fn to_execution_result( Ok(sp_sandbox::ReturnValue::Unit) => { let mut buffer = runtime.scratch_buf; buffer.clear(); - Ok(ExecReturnValue { status: STATUS_SUCCESS, data: buffer }) + Ok(ExecReturnValue { + status: STATUS_SUCCESS, + data: buffer, + }) } Ok(sp_sandbox::ReturnValue::Value(sp_sandbox::Value::I32(exit_code))) => { - let status = (exit_code & 0xFF).try_into() + let status = (exit_code & 0xFF) + .try_into() .expect("exit_code is masked into the range of a u8; qed"); - Ok(ExecReturnValue { status, data: runtime.scratch_buf }) + Ok(ExecReturnValue { + status, + data: runtime.scratch_buf, + }) } // This should never happen as the return type of exported functions should have been // validated by the code preparation process. However, because panics are really // undesirable in the runtime code, we treat this as a trap for now. Eventually, we might // want to revisit this. - Ok(_) => Err(ExecError { reason: "return type error".into(), buffer: runtime.scratch_buf }), + Ok(_) => Err(ExecError { + reason: "return type error".into(), + buffer: runtime.scratch_buf, + }), // `Error::Module` is returned only if instantiation or linking failed (i.e. // wasm binary tried to import a function that is not provided by the host). // This shouldn't happen because validation process ought to reject such binaries. // // Because panics are really undesirable in the runtime code, we treat this as // a trap for now. Eventually, we might want to revisit this. - Err(sp_sandbox::Error::Module) => - Err(ExecError { reason: "validation error".into(), buffer: runtime.scratch_buf }), + Err(sp_sandbox::Error::Module) => Err(ExecError { + reason: "validation error".into(), + buffer: runtime.scratch_buf, + }), // Any other kind of a trap should result in a failure. - Err(sp_sandbox::Error::Execution) | Err(sp_sandbox::Error::OutOfBounds) => - Err(ExecError { reason: "contract trapped during execution".into(), buffer: runtime.scratch_buf }), + Err(sp_sandbox::Error::Execution) | Err(sp_sandbox::Error::OutOfBounds) => Err(ExecError { + reason: "contract trapped during execution".into(), + buffer: runtime.scratch_buf, + }), } } @@ -188,14 +197,12 @@ impl Token for RuntimeToken { data_cost .and_then(|data_cost| { - topics_cost.and_then(|topics_cost| { - data_cost.checked_add(topics_cost) - }) + topics_cost.and_then(|topics_cost| data_cost.checked_add(topics_cost)) }) - .and_then(|data_and_topics_cost| + .and_then(|data_and_topics_cost| { data_and_topics_cost.checked_add(metadata.event_base_cost) - ) - }, + }) + } DispatchWithWeight(gas) => gas.checked_add(metadata.dispatch_base_cost), }; @@ -214,10 +221,10 @@ fn charge_gas>( ) -> Result<(), sp_sandbox::HostError> { match gas_meter.charge(metadata, token) { GasMeterResult::Proceed => Ok(()), - GasMeterResult::OutOfGas => { + GasMeterResult::OutOfGas => { *special_trap = Some(SpecialTrap::OutOfGas); Err(sp_sandbox::HostError) - }, + } } } @@ -242,7 +249,9 @@ fn read_sandbox_memory( )?; let mut buf = vec![0u8; len as usize]; - ctx.memory.get(ptr, buf.as_mut_slice()).map_err(|_| sp_sandbox::HostError)?; + ctx.memory + .get(ptr, buf.as_mut_slice()) + .map_err(|_| sp_sandbox::HostError)?; Ok(buf) } @@ -267,7 +276,9 @@ fn read_sandbox_memory_into_scratch( )?; ctx.scratch_buf.resize(len as usize, 0); - ctx.memory.get(ptr, ctx.scratch_buf.as_mut_slice()).map_err(|_| sp_sandbox::HostError)?; + ctx.memory + .get(ptr, ctx.scratch_buf.as_mut_slice()) + .map_err(|_| sp_sandbox::HostError)?; Ok(()) } @@ -1165,14 +1176,10 @@ where /// the order of items is not preserved. fn has_duplicates>(items: &mut Vec) -> bool { // Sort the vector - items.sort_unstable_by(|a, b| { - Ord::cmp(a.as_ref(), b.as_ref()) - }); + items.sort_unstable_by(|a, b| Ord::cmp(a.as_ref(), b.as_ref())); // And then find any two consecutive equal elements. - items.windows(2).any(|w| { - match w { - &[ref a, ref b] => a == b, - _ => false, - } + items.windows(2).any(|w| match w { + &[ref a, ref b] => a == b, + _ => false, }) } diff --git a/rococo-parachains/pallets/parachain-info/src/lib.rs b/rococo-parachains/pallets/parachain-info/src/lib.rs index 56acde48df..472f5b2d03 100644 --- a/rococo-parachains/pallets/parachain-info/src/lib.rs +++ b/rococo-parachains/pallets/parachain-info/src/lib.rs @@ -25,7 +25,7 @@ use cumulus_primitives::ParaId; /// Configuration trait of this pallet. pub trait Trait: frame_system::Trait {} -impl Get for Module { +impl Get for Module { fn get() -> ParaId { Self::parachain_id() } diff --git a/rococo-parachains/pallets/token-dealer/src/lib.rs b/rococo-parachains/pallets/token-dealer/src/lib.rs index ee05fd1538..6ffc6952f1 100644 --- a/rococo-parachains/pallets/token-dealer/src/lib.rs +++ b/rococo-parachains/pallets/token-dealer/src/lib.rs @@ -17,7 +17,8 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::{ - decl_event, decl_module, dispatch::DispatchResult, + decl_event, decl_module, + dispatch::DispatchResult, traits::{Currency, ExistenceRequirement, WithdrawReason}, }; use frame_system::ensure_signed; diff --git a/rococo-parachains/primitives/Cargo.toml b/rococo-parachains/primitives/Cargo.toml new file mode 100644 index 0000000000..c173f29ddb --- /dev/null +++ b/rococo-parachains/primitives/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "rococo-parachain-primitives" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +# Substrate dependencies +sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" } +sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" } + +[features] +default = [ "std" ] +std = [ + "sp-runtime/std", + "sp-core/std" +] diff --git a/rococo-parachains/primitives/src/lib.rs b/rococo-parachains/primitives/src/lib.rs new file mode 100644 index 0000000000..4c93d3f3bb --- /dev/null +++ b/rococo-parachains/primitives/src/lib.rs @@ -0,0 +1,59 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Substrate 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. + +// Substrate 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 Cumulus. If not, see . + +//! Primitives used by the Parachains Tick, Trick and Track. + +#![cfg_attr(not(feature = "std"), no_std)] + +use sp_runtime::{ + generic, + traits::{BlakeTwo256, IdentifyAccount, Verify}, + MultiSignature, +}; + +pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + +/// Opaque block header type. +pub type Header = generic::Header; +/// Opaque block type. +pub type Block = generic::Block; +/// Opaque block identifier type. +pub type BlockId = generic::BlockId; +/// An index to a block. +pub type BlockNumber = u32; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// The type for looking up accounts. We don't expect more than 4 billion of them, but you +/// never know... +pub type AccountIndex = u32; + +/// Balance of an account. +pub type Balance = u128; + +/// Index of a transaction in the chain. +pub type Index = u32; + +/// A hash of some data used by the chain. +pub type Hash = sp_core::H256; + +/// Digest item type. +pub type DigestItem = generic::DigestItem; diff --git a/rococo-parachains/runtime/Cargo.toml b/rococo-parachains/runtime/Cargo.toml index f588969235..860dd36bed 100644 --- a/rococo-parachains/runtime/Cargo.toml +++ b/rococo-parachains/runtime/Cargo.toml @@ -8,8 +8,9 @@ edition = '2018' serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false, features = ["derive"] } -cumulus-token-dealer = { path = "../pallets/token-dealer", default-features = false} -parachain-info = { path = "../pallets/parachain-info", default-features = false} +cumulus-token-dealer = { path = "../pallets/token-dealer", default-features = false } +parachain-info = { path = "../pallets/parachain-info", default-features = false } +rococo-parachain-primitives = { path = "../primitives", default-features = false } # Substrate dependencies sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "rococo-branch" } @@ -71,6 +72,7 @@ std = [ "pallet-sudo/std", "pallet-transaction-payment/std", "parachain-info/std", + "rococo-parachain-primitives/std", "cumulus-runtime/std", "cumulus-parachain-upgrade/std", "cumulus-message-broker/std", diff --git a/rococo-parachains/runtime/src/lib.rs b/rococo-parachains/runtime/src/lib.rs index e707771dd1..072a2d048c 100644 --- a/rococo-parachains/runtime/src/lib.rs +++ b/rococo-parachains/runtime/src/lib.rs @@ -22,13 +22,14 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +use rococo_parachain_primitives::*; use sp_api::impl_runtime_apis; use sp_core::OpaqueMetadata; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, Saturating, Verify}, + traits::{BlakeTwo256, Block as BlockT, IdentityLookup, Saturating}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, MultiSignature, + ApplyExtrinsicResult, }; use sp_std::prelude::*; #[cfg(feature = "std")] @@ -51,53 +52,10 @@ pub use pallet_timestamp::Call as TimestampCall; pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; -/// An index to a block. -pub type BlockNumber = u32; +pub type SessionHandlers = (); -/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. -pub type Signature = MultiSignature; - -/// Some way of identifying an account on the chain. We intentionally make it equivalent -/// to the public key of our transaction signing scheme. -pub type AccountId = <::Signer as IdentifyAccount>::AccountId; - -/// The type for looking up accounts. We don't expect more than 4 billion of them, but you -/// never know... -pub type AccountIndex = u32; - -/// Balance of an account. -pub type Balance = u128; - -/// Index of a transaction in the chain. -pub type Index = u32; - -/// A hash of some data used by the chain. -pub type Hash = sp_core::H256; - -/// Digest item type. -pub type DigestItem = generic::DigestItem; - -/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know -/// the specifics of the runtime. They can then be made to be agnostic over specific formats -/// of data like extrinsics, allowing for them to continue syncing the network through upgrades -/// to even the core datastructures. -pub mod opaque { - use super::*; - - pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; - - /// Opaque block header type. - pub type Header = generic::Header; - /// Opaque block type. - pub type Block = generic::Block; - /// Opaque block identifier type. - pub type BlockId = generic::BlockId; - - pub type SessionHandlers = (); - - impl_opaque_keys! { - pub struct SessionKeys {} - } +impl_opaque_keys! { + pub struct SessionKeys {} } /// This runtime version. @@ -105,7 +63,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("cumulus-test-parachain"), impl_name: create_runtime_str!("cumulus-test-parachain"), authoring_version: 1, - spec_version: 1, + spec_version: 2, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -266,8 +224,8 @@ impl parachain_info::Trait for Runtime {} construct_runtime! { pub enum Runtime where Block = Block, - NodeBlock = opaque::Block, - UncheckedExtrinsic = UncheckedExtrinsic + NodeBlock = rococo_parachain_primitives::Block, + UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Module, Call, Storage, Config, Event}, Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent}, @@ -378,11 +336,11 @@ impl_runtime_apis! { fn decode_session_keys( encoded: Vec, ) -> Option, sp_core::crypto::KeyTypeId)>> { - opaque::SessionKeys::decode_into_raw_public_keys(&encoded) + SessionKeys::decode_into_raw_public_keys(&encoded) } fn generate_session_keys(seed: Option>) -> Vec { - opaque::SessionKeys::generate(seed) + SessionKeys::generate(seed) } } } diff --git a/rococo-parachains/src/chain_spec.rs b/rococo-parachains/src/chain_spec.rs index d8305029b8..00e01eacd0 100644 --- a/rococo-parachains/src/chain_spec.rs +++ b/rococo-parachains/src/chain_spec.rs @@ -15,19 +15,20 @@ // along with Cumulus. If not, see . use cumulus_primitives::ParaId; -use parachain_runtime::{ - AccountId, BalancesConfig, GenesisConfig, Signature, SudoConfig, SystemConfig, - ParachainInfoConfig, WASM_BINARY, -}; +use hex_literal::hex; +use rococo_parachain_primitives::{AccountId, Signature}; use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; use sc_service::ChainType; use serde::{Deserialize, Serialize}; use sp_core::{sr25519, Pair, Public}; use sp_runtime::traits::{IdentifyAccount, Verify}; -use hex_literal::hex; -/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. -pub type ChainSpec = sc_service::GenericChainSpec; +/// Specialized `ChainSpec` for the normal parachain runtime. +pub type ChainSpec = sc_service::GenericChainSpec; + +/// Specialized `ChainSpec` for the contracts parachain runtime. +pub type ContractsChainSpec = + sc_service::GenericChainSpec; /// Helper function to generate a crypto pair from seed pub fn get_from_seed(seed: &str) -> ::Public { @@ -99,6 +100,42 @@ pub fn get_chain_spec(id: ParaId) -> ChainSpec { ) } +pub fn get_contracts_chain_spec(id: ParaId) -> ContractsChainSpec { + ContractsChainSpec::from_genesis( + "Contracts Local Testnet", + "contracts_local_testnet", + ChainType::Local, + move || { + contracts_testnet_genesis( + get_account_id_from_seed::("Alice"), + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + id, + ) + }, + vec![], + None, + None, + None, + Extensions { + relay_chain: "westend-dev".into(), + para_id: id.into(), + }, + ) +} + pub fn staging_test_net(id: ParaId) -> ChainSpec { ChainSpec::from_genesis( "Staging Testnet", @@ -107,7 +144,9 @@ pub fn staging_test_net(id: ParaId) -> ChainSpec { move || { testnet_genesis( hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(), - vec![hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into()], + vec![ + hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(), + ], id, ) }, @@ -126,22 +165,47 @@ fn testnet_genesis( root_key: AccountId, endowed_accounts: Vec, id: ParaId, -) -> GenesisConfig { - GenesisConfig { - frame_system: Some(SystemConfig { - code: WASM_BINARY.expect("WASM binary was not build, please build it!").to_vec(), +) -> parachain_runtime::GenesisConfig { + parachain_runtime::GenesisConfig { + frame_system: Some(parachain_runtime::SystemConfig { + code: parachain_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), changes_trie_config: Default::default(), }), - pallet_balances: Some(BalancesConfig { + pallet_balances: Some(parachain_runtime::BalancesConfig { balances: endowed_accounts .iter() .cloned() .map(|k| (k, 1 << 60)) .collect(), }), - pallet_sudo: Some(SudoConfig { key: root_key }), - parachain_info: Some(ParachainInfoConfig { parachain_id: id }), - // TODO: add contracts genesis for the contracts runtime - // pallet_contracts: Some(parachain_runtime::ContractsConfig { current_schedule: Default::default() }), + pallet_sudo: Some(parachain_runtime::SudoConfig { key: root_key }), + parachain_info: Some(parachain_runtime::ParachainInfoConfig { parachain_id: id }), + } +} + +fn contracts_testnet_genesis( + root_key: AccountId, + endowed_accounts: Vec, + id: ParaId, +) -> parachain_contracts_runtime::GenesisConfig { + parachain_contracts_runtime::GenesisConfig { + frame_system: Some(parachain_contracts_runtime::SystemConfig { + code: parachain_contracts_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + changes_trie_config: Default::default(), + }), + pallet_balances: Some(parachain_contracts_runtime::BalancesConfig { + balances: endowed_accounts + .iter() + .cloned() + .map(|k| (k, 1 << 60)) + .collect(), + }), + pallet_sudo: Some(parachain_contracts_runtime::SudoConfig { key: root_key }), + parachain_info: Some(parachain_contracts_runtime::ParachainInfoConfig { parachain_id: id }), + cumulus_pallet_contracts: None, } } diff --git a/rococo-parachains/src/command.rs b/rococo-parachains/src/command.rs index 181fd272e5..8c3ee3d1b4 100644 --- a/rococo-parachains/src/command.rs +++ b/rococo-parachains/src/command.rs @@ -24,8 +24,8 @@ use log::info; use parachain_runtime::Block; use polkadot_parachain::primitives::AccountIdConversion; use sc_cli::{ - ChainSpec, CliConfiguration, ImportParams, KeystoreParams, NetworkParams, Result, - RuntimeVersion, SharedParams, SubstrateCli, DefaultConfigurationValues, + ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, + NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli, }; use sc_service::config::{BasePath, PrometheusConfig}; use sp_core::hexdisplay::HexDisplay; @@ -77,6 +77,9 @@ impl SubstrateCli for Cli { "track" => Ok(Box::new(chain_spec::ChainSpec::from_json_bytes( &include_bytes!("../res/track.json")[..], )?)), + "contracts" => Ok(Box::new(chain_spec::get_contracts_chain_spec( + self.run.parachain_id.unwrap_or(100).into(), + ))), "" => Ok(Box::new(chain_spec::get_chain_spec( self.run.parachain_id.unwrap_or(100).into(), ))), @@ -167,6 +170,10 @@ fn extract_genesis_wasm(chain_spec: &Box) -> Result) -> bool { + chain_spec.id().starts_with("trick") || chain_spec.id().starts_with("contracts") +} + /// Parse command line arguments into service configuration. pub fn run() -> Result<()> { let cli = Cli::from_args(); @@ -175,16 +182,35 @@ pub fn run() -> Result<()> { Some(Subcommand::Base(subcommand)) => { let runner = cli.create_runner(subcommand)?; - runner.run_subcommand(subcommand, |mut config| { - let params = crate::service::new_partial(&mut config)?; + if use_contracts_runtime(&runner.config().chain_spec) { + runner.run_subcommand(subcommand, |mut config| { + let params = crate::service::new_partial::< + parachain_contracts_runtime::RuntimeApi, + crate::service::ContractsRuntimeExecutor, + >(&mut config)?; - Ok(( - params.client, - params.backend, - params.import_queue, - params.task_manager, - )) - }) + Ok(( + params.client, + params.backend, + params.import_queue, + params.task_manager, + )) + }) + } else { + runner.run_subcommand(subcommand, |mut config| { + let params = crate::service::new_partial::< + parachain_runtime::RuntimeApi, + crate::service::RuntimeExecutor, + >(&mut config)?; + + Ok(( + params.client, + params.backend, + params.import_queue, + params.task_manager, + )) + }) + } } Some(Subcommand::ExportGenesisState(params)) => { sc_cli::init_logger(""); @@ -256,14 +282,23 @@ pub fn run() -> Result<()> { if cli.run.base.validator { "yes" } else { "no" } ); - crate::service::run_node( - config, - key, - polkadot_config, - id, - cli.run.base.validator, - ) - .map(|(x, _)| x) + if use_contracts_runtime(&config.chain_spec) { + crate::service::start_contracts_node( + config, + key, + polkadot_config, + id, + cli.run.base.validator, + ) + } else { + crate::service::start_node( + config, + key, + polkadot_config, + id, + cli.run.base.validator, + ).map(|r| r.0) + } }) } } diff --git a/rococo-parachains/src/integration_test.rs b/rococo-parachains/src/integration_test.rs index 1ae9d6c7a8..212fa001ba 100644 --- a/rococo-parachains/src/integration_test.rs +++ b/rococo-parachains/src/integration_test.rs @@ -60,7 +60,8 @@ async fn integration_test() { INTEGRATION_TEST_ALLOWED_TIME .and_then(|x| x.parse().ok()) .unwrap_or(600), - )).fuse(); + )) + .fuse(); let t2 = async { let para_id = ParaId::from(100); @@ -105,7 +106,7 @@ async fn integration_test() { let parachain_config = parachain_config(task_executor.clone(), Charlie, vec![], para_id).unwrap(); let (_service, charlie_client) = - crate::service::run_node(parachain_config, key, polkadot_config, para_id, true) + crate::service::start_node(parachain_config, key, polkadot_config, para_id, true) .unwrap(); sleep(Duration::from_secs(3)).await; charlie_client.wait_for_blocks(4).await; diff --git a/rococo-parachains/src/service.rs b/rococo-parachains/src/service.rs index 6891928453..c71caba91c 100644 --- a/rococo-parachains/src/service.rs +++ b/rococo-parachains/src/service.rs @@ -20,67 +20,74 @@ use cumulus_service::{ prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, }; use polkadot_primitives::v0::CollatorPair; +use rococo_parachain_primitives::Block; use sc_executor::native_executor_instance; pub use sc_executor::NativeExecutor; use sc_informant::OutputFormat; use sc_service::{Configuration, PartialComponents, Role, TFullBackend, TFullClient, TaskManager}; +use sp_api::ConstructRuntimeApi; use sp_runtime::traits::BlakeTwo256; use sp_trie::PrefixedMemoryDB; use std::sync::Arc; -// Our native executor instance. +// Native executor instance. native_executor_instance!( - pub Executor, + pub RuntimeExecutor, parachain_runtime::api::dispatch, parachain_runtime::native_version, ); +// Native executor instance for the contracts runtime. +native_executor_instance!( + pub ContractsRuntimeExecutor, + parachain_contracts_runtime::api::dispatch, + parachain_contracts_runtime::native_version, +); + /// Starts a `ServiceBuilder` for a full service. /// /// Use this macro if you don't actually need the full service, but just the builder in order to /// be able to perform chain operations. -pub fn new_partial( +pub fn new_partial( config: &mut Configuration, ) -> Result< PartialComponents< - TFullClient< - parachain_runtime::opaque::Block, - parachain_runtime::RuntimeApi, - crate::service::Executor, - >, - TFullBackend, + TFullClient, + TFullBackend, (), - sp_consensus::import_queue::BasicQueue< - parachain_runtime::opaque::Block, - PrefixedMemoryDB, - >, - sc_transaction_pool::FullPool< - parachain_runtime::opaque::Block, - TFullClient< - parachain_runtime::opaque::Block, - parachain_runtime::RuntimeApi, - crate::service::Executor, - >, - >, + sp_consensus::import_queue::BasicQueue>, + sc_transaction_pool::FullPool>, (), >, sc_service::Error, -> { +> +where + RuntimeApi: ConstructRuntimeApi> + + Send + + Sync + + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt< + Block, + Error = sp_blockchain::Error, + StateBackend = sc_client_api::StateBackendFor, Block>, + > + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder, + sc_client_api::StateBackendFor, Block>: sp_api::StateBackend, + Executor: sc_executor::NativeExecutionDispatch + 'static, +{ let inherent_data_providers = sp_inherents::InherentDataProviders::new(); - let (client, backend, keystore, task_manager) = sc_service::new_full_parts::< - parachain_runtime::opaque::Block, - parachain_runtime::RuntimeApi, - crate::service::Executor, - >(&config)?; + let (client, backend, keystore, task_manager) = + sc_service::new_full_parts::(&config)?; let client = Arc::new(client); - //let select_chain = sc_consensus::LongestChain::new(backend.clone()); let registry = config.prometheus_registry(); let transaction_pool = sc_transaction_pool::BasicPool::new_full( config.transaction_pool.clone(), - //std::sync::Arc::new(pool_api), config.prometheus_registry(), task_manager.spawn_handle(), client.clone(), @@ -109,25 +116,39 @@ pub fn new_partial( Ok(params) } -/// Run a node with the given parachain `Configuration` and relay chain `Configuration` +/// Start a node with the given parachain `Configuration` and relay chain `Configuration`. /// -/// This function blocks until done. -pub fn run_node( +/// This is the actual implementation that is abstract over the executor and the runtime api. +fn start_node_impl( parachain_config: Configuration, collator_key: Arc, mut polkadot_config: polkadot_collator::Configuration, id: polkadot_primitives::v0::Id, validator: bool, -) -> sc_service::error::Result<( - TaskManager, - Arc< - TFullClient< - parachain_runtime::opaque::Block, - parachain_runtime::RuntimeApi, - crate::service::Executor, - >, - >, -)> { + rpc_ext_builder: RB, +) -> sc_service::error::Result<(TaskManager, Arc>)> +where + RuntimeApi: ConstructRuntimeApi> + + Send + + Sync + + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt< + Block, + Error = sp_blockchain::Error, + StateBackend = sc_client_api::StateBackendFor, Block>, + > + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder, + sc_client_api::StateBackendFor, Block>: sp_api::StateBackend, + Executor: sc_executor::NativeExecutionDispatch + 'static, + RB: Fn( + Arc>, + ) -> jsonrpc_core::IoHandler + + Send + + 'static, +{ if matches!(parachain_config.role, Role::Light) { return Err("Light client not supported!".into()); } @@ -143,7 +164,7 @@ pub fn run_node( prefix: format!("[{}] ", Color::Blue.bold().paint("Relaychain")), }; - let params = new_partial(&mut parachain_config)?; + let params = new_partial::(&mut parachain_config)?; params .inherent_data_providers .register_provider(sp_timestamp::InherentDataProvider) @@ -163,32 +184,21 @@ pub fn run_node( let import_queue = params.import_queue; let (network, network_status_sinks, system_rpc_tx, start_network) = sc_service::build_network(sc_service::BuildNetworkParams { - config: ¶chain_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - spawn_handle: task_manager.spawn_handle(), - import_queue, - on_demand: None, - block_announce_validator_builder: Some(Box::new(block_announce_validator_builder)), - finality_proof_request_builder: None, - finality_proof_provider: None, + config: ¶chain_config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + spawn_handle: task_manager.spawn_handle(), + import_queue, + on_demand: None, + block_announce_validator_builder: Some(Box::new(block_announce_validator_builder)), + finality_proof_request_builder: None, + finality_proof_provider: None, })?; let rpc_extensions_builder = { - let _client = client.clone(); + let client = client.clone(); - Box::new(move |_deny_unsafe| { - let io = jsonrpc_core::IoHandler::default(); - - // TODO: add this rpc when running the contracts runtime - /* - use pallet_contracts_rpc::{Contracts, ContractsApi}; - io.extend_with( - ContractsApi::to_delegate(Contracts::new(client.clone())) - ); - */ - io - }) + Box::new(move |_deny_unsafe| rpc_ext_builder(client.clone())) }; sc_service::spawn_tasks(sc_service::SpawnTasksParams { @@ -249,3 +259,49 @@ pub fn run_node( Ok((task_manager, client)) } + +/// Start a normal parachain node. +pub fn start_node( + parachain_config: Configuration, + collator_key: Arc, + polkadot_config: polkadot_collator::Configuration, + id: polkadot_primitives::v0::Id, + validator: bool, +) -> sc_service::error::Result<( + TaskManager, + Arc>, +)> { + start_node_impl::( + parachain_config, + collator_key, + polkadot_config, + id, + validator, + |_| Default::default(), + ) +} + +/// Start a contracts parachain node. +pub fn start_contracts_node( + parachain_config: Configuration, + collator_key: Arc, + polkadot_config: polkadot_collator::Configuration, + id: polkadot_primitives::v0::Id, + validator: bool, +) -> sc_service::error::Result { + start_node_impl::( + parachain_config, + collator_key, + polkadot_config, + id, + validator, + |client| { + let mut io = jsonrpc_core::IoHandler::default(); + + use cumulus_pallet_contracts_rpc::{Contracts, ContractsApi}; + io.extend_with(ContractsApi::to_delegate(Contracts::new(client))); + io + }, + ) + .map(|r| r.0) +} diff --git a/runtime/src/validate_block/implementation.rs b/runtime/src/validate_block/implementation.rs index fd324f7592..5e165da092 100644 --- a/runtime/src/validate_block/implementation.rs +++ b/runtime/src/validate_block/implementation.rs @@ -51,7 +51,9 @@ static mut STORAGE: Option> = None; /// Panics if the [`STORAGE`] is not initialized. fn with_storage(call: impl FnOnce(&mut dyn Storage) -> R) -> R { let mut storage = unsafe { - STORAGE.take().expect("`STORAGE` needs to be set before calling this function.") + STORAGE + .take() + .expect("`STORAGE` needs to be set before calling this function.") }; let res = call(&mut *storage); @@ -142,7 +144,8 @@ pub fn validate_block>(params: ValidationParams) - // If in the course of block execution new validation code was set, insert // its scheduled upgrade so we can validate that block number later. - let new_validation_code = with_storage(|storage| storage.get(NEW_VALIDATION_CODE)).map(ValidationCode); + let new_validation_code = + with_storage(|storage| storage.get(NEW_VALIDATION_CODE)).map(ValidationCode); if new_validation_code.is_some() && validation_function_params.code_upgrade_allowed.is_none() { panic!("Attempt to upgrade validation function when not permitted!"); } @@ -154,9 +157,10 @@ pub fn validate_block>(params: ValidationParams) - None => Vec::new(), }; - let processed_downward_messages = with_storage(|storage| storage.get(PROCESSED_DOWNWARD_MESSAGES)) - .and_then(|v| Decode::decode(&mut &v[..]).ok()) - .unwrap_or_default(); + let processed_downward_messages = + with_storage(|storage| storage.get(PROCESSED_DOWNWARD_MESSAGES)) + .and_then(|v| Decode::decode(&mut &v[..]).ok()) + .unwrap_or_default(); ValidationResult { head_data, @@ -266,13 +270,11 @@ impl Storage for WitnessStorage { let witness_data = &self.witness_data; let storage_root = &self.storage_root; - let current_value = overlay.entry(key.to_vec()).or_insert_with(|| - read_trie_value::>, _>( - witness_data, - storage_root, - key, - ).ok().flatten() - ); + let current_value = overlay.entry(key.to_vec()).or_insert_with(|| { + read_trie_value::>, _>(witness_data, storage_root, key) + .ok() + .flatten() + }); let item = current_value.take().unwrap_or_default(); *current_value = Some( diff --git a/runtime/src/validate_block/tests.rs b/runtime/src/validate_block/tests.rs index d8656ec9dd..0f684ec82d 100644 --- a/runtime/src/validate_block/tests.rs +++ b/runtime/src/validate_block/tests.rs @@ -130,7 +130,7 @@ fn build_block_with_proof( built_block.block, built_block .proof - .expect("We enabled proof recording before.") + .expect("We enabled proof recording before."), ) }