difftreelog
Remove wrong pallet-contracts
in: master
48 files changed
pallets/contracts/CHANGELOG.mddiffbeforeafterboth--- a/pallets/contracts/CHANGELOG.md
+++ /dev/null
@@ -1,93 +0,0 @@
-# Changelog
-
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-The semantic versioning guarantees cover the interface to the substrate runtime which
-includes this pallet as a dependency. This module will also add storage migrations whenever
-changes require it. Stability with regard to offchain tooling is explicitly excluded from
-this guarantee: For example adding a new field to an in-storage data structure will require
-changes to frontends to properly display it. However, those changes will still be regarded
-as a minor version bump.
-
-The interface provided to smart contracts will adhere to semver with one exception: Even
-major version bumps will be backwards compatible with regard to already deployed contracts.
-In other words: Upgrading this pallet will not break pre-existing contracts.
-
-## [Unreleased]
-
-### Added
-
-- Add new `instantiate` RPC that allows clients to dry-run contract instantiation.
-
-- Make storage and fields of `Schedule` private to the crate.
-[1](https://github.com/paritytech/substrate/pull/8359)
-
-- Add new version of `seal_random` which exposes additional information.
-[1](https://github.com/paritytech/substrate/pull/8329)
-
-- Add `seal_rent_params` contract callable function.
-[1](https://github.com/paritytech/substrate/pull/8231)
-
-## [v3.0.0] 2021-02-25
-
-This version constitutes the first release that brings any stability guarantees (see above).
-
-### Added
-
-- Emit an event when a contract terminates (self-destructs).
-[1](https://github.com/paritytech/substrate/pull/8014)
-
-- Charge rent for code stored on the chain in addition to the already existing
-rent that is payed for data storage.
-[1](https://github.com/paritytech/substrate/pull/7935)
-
-- Allow the runtime to configure per storage item costs in addition
-to the already existing per byte costs.
-[1](https://github.com/paritytech/substrate/pull/7819)
-
-- Contracts are now deleted lazily so that the user who removes a contract
-does not need to pay for the deletion of the contract storage.
-[1](https://github.com/paritytech/substrate/pull/7740)
-
-- Allow runtime authors to define chain extensions in order to provide custom
-functionality to contracts.
-[1](https://github.com/paritytech/substrate/pull/7548)
-[2](https://github.com/paritytech/substrate/pull/8003)
-
-- Proper weights which are fully automated by benchmarking.
-[1](https://github.com/paritytech/substrate/pull/6715)
-[2](https://github.com/paritytech/substrate/pull/7017)
-[3](https://github.com/paritytech/substrate/pull/7361)
-
-### Changes
-
-- Collect the rent for one block during instantiation.
-[1](https://github.com/paritytech/substrate/pull/7847)
-
-- Instantiation takes a `salt` argument to allow for easier instantion of the
-same code by the same sender.
-[1](https://github.com/paritytech/substrate/pull/7482)
-
-- Improve the information returned by the `contracts_call` RPC.
-[1](https://github.com/paritytech/substrate/pull/7468)
-
-- Simplify the node configuration necessary to add this module.
-[1](https://github.com/paritytech/substrate/pull/7409)
-
-### Fixed
-
-- Consider the code size of a contract in the weight that is charged for
-loading a contract from storage.
-[1](https://github.com/paritytech/substrate/pull/8086)
-
-- Fix possible overflow in storage size calculation
-[1](https://github.com/paritytech/substrate/pull/7885)
-
-- Cap the surcharge reward that can be claimed.
-[1](https://github.com/paritytech/substrate/pull/7870)
-
-- Fix a possible DoS vector where contracts could allocate too large buffers.
-[1](https://github.com/paritytech/substrate/pull/7818)
pallets/contracts/COMPLEXITY.mddiffbeforeafterbothno changes
pallets/contracts/Cargo.tomldiffbeforeafterboth--- a/pallets/contracts/Cargo.toml
+++ /dev/null
@@ -1,75 +0,0 @@
-[package]
-name = "pallet-contracts"
-version = "3.0.0"
-authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2018"
-license = "Apache-2.0"
-homepage = "https://substrate.dev"
-repository = "https://github.com/paritytech/substrate/"
-description = "FRAME pallet for WASM contracts"
-readme = "README.md"
-
-[package.metadata.docs.rs]
-targets = ["x86_64-unknown-linux-gnu"]
-
-[dependencies]
-codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
-log = { version = "0.4", default-features = false }
-parity-wasm = { version = "0.42", default-features = false }
-pwasm-utils = { version = "0.17", default-features = false }
-serde = { version = "1", optional = true, features = ["derive"] }
-wasmi-validation = { version = "0.4", default-features = false }
-
-# Only used in benchmarking to generate random contract code
-rand = { version = "0.8", optional = true, default-features = false }
-rand_pcg = { version = "0.3", optional = true }
-
-# Substrate Dependencies
-frame-benchmarking = { version = "3.1.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3', optional = true }
-frame-support = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-frame-system = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-pallet-contracts-primitives = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-pallet-contracts-proc-macro = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-core = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-io = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-runtime = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-sandbox = { version = "0.9.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-std = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-
-[dev-dependencies]
-assert_matches = "1"
-hex-literal = "0.3"
-paste = "1"
-pretty_assertions = "0.7"
-wat = "1"
-
-# Substrate Dependencies
-pallet-balances = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-pallet-timestamp = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-pallet-randomness-collective-flip = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-
-[features]
-default = ["std"]
-std = [
- "serde",
- "codec/std",
- "sp-core/std",
- "sp-runtime/std",
- "sp-io/std",
- "sp-std/std",
- "sp-sandbox/std",
- "frame-support/std",
- "frame-system/std",
- "parity-wasm/std",
- "pwasm-utils/std",
- "wasmi-validation/std",
- "pallet-contracts-primitives/std",
- "pallet-contracts-proc-macro/full",
- "log/std",
-]
-runtime-benchmarks = [
- "frame-benchmarking",
- "rand",
- "rand_pcg",
-]
-
pallets/contracts/README.mddiffbeforeafterboth--- a/pallets/contracts/README.md
+++ /dev/null
@@ -1,75 +0,0 @@
-# Contract Module
-
-The Contract module provides functionality for the runtime to deploy and execute WebAssembly smart-contracts.
-
-- [`Call`](https://docs.rs/pallet-contracts/latest/pallet_contracts/enum.Call.html)
-- [`Config`](https://docs.rs/pallet-contracts/latest/pallet_contracts/trait.Config.html)
-- [`Error`](https://docs.rs/pallet-contracts/latest/pallet_contracts/enum.Error.html)
-- [`Event`](https://docs.rs/pallet-contracts/latest/pallet_contracts/enum.Event.html)
-
-## Overview
-
-This module extends accounts based on the `Currency` trait to have smart-contract functionality. It can
-be used with other modules that implement accounts based on `Currency`. These "smart-contract accounts"
-have the ability to instantiate smart-contracts and make calls to other contract and non-contract accounts.
-
-The smart-contract code is stored once in a `code_cache`, and later retrievable via its `code_hash`.
-This means that multiple smart-contracts can be instantiated from the same `code_cache`, without replicating
-the code each time.
-
-When a smart-contract is called, its associated code is retrieved via the code hash and gets executed.
-This call can alter the storage entries of the smart-contract account, instantiate new smart-contracts,
-or call other smart-contracts.
-
-Finally, when an account is reaped, its associated code and storage of the smart-contract account
-will also be deleted.
-
-### Gas
-
-Senders must specify a gas limit with every call, as all instructions invoked by the smart-contract require gas.
-Unused gas is refunded after the call, regardless of the execution outcome.
-
-If the gas limit is reached, then all calls and state changes (including balance transfers) are only
-reverted at the current call's contract level. For example, if contract A calls B and B runs out of gas mid-call,
-then all of B's calls are reverted. Assuming correct error handling by contract A, A's other calls and state
-changes still persist.
-
-One gas is equivalent to one [weight](https://substrate.dev/docs/en/knowledgebase/learn-substrate/weight)
-which is defined as one picosecond of execution time on the runtime's reference machine.
-
-### Notable Scenarios
-
-Contract call failures are not always cascading. When failures occur in a sub-call, they do not "bubble up",
-and the call will only revert at the specific contract level. For example, if contract A calls contract B, and B
-fails, A can decide how to handle that failure, either proceeding or reverting A's changes.
-
-## Interface
-
-### Dispatchable functions
-
-Those are documented in the [reference documentation](https://docs.rs/pallet-contracts/latest/pallet_contracts/#dispatchable-functions).
-
-## Usage
-
-This module executes WebAssembly smart contracts. These can potentially be written in any language
-that compiles to web assembly. However, using a language that specifically targets this module
-will make things a lot easier. One such language is [`ink`](https://github.com/paritytech/ink)
-which is an [`eDSL`](https://wiki.haskell.org/Embedded_domain_specific_language) that enables
-writing WebAssembly based smart contracts in the Rust programming language.
-
-## Debugging
-
-Contracts can emit messages to the node console when run on a development chain through the
-`seal_println` API. This is exposed in ink! via
-[`ink_env::debug_println()`](https://docs.rs/ink_env/latest/ink_env/fn.debug_println.html).
-
-In order to see these messages the log level for the `runtime::contracts` target needs to be raised
-to at least the `info` level which is the default. However, those messages are easy to overlook
-because of the noise generated by block production. A good starting point for contract debugging
-could be:
-
-```bash
-cargo run --release -- --dev --tmp -lerror,runtime::contracts
-```
-
-License: Apache-2.0
pallets/contracts/common/Cargo.tomldiffbeforeafterboth--- a/pallets/contracts/common/Cargo.toml
+++ /dev/null
@@ -1,33 +0,0 @@
-[package]
-name = "pallet-contracts-primitives"
-version = "3.0.0"
-authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2018"
-license = "Apache-2.0"
-homepage = "https://substrate.dev"
-repository = "https://github.com/paritytech/substrate/"
-description = "A crate that hosts a common definitions that are relevant for the pallet-contracts."
-readme = "README.md"
-
-[package.metadata.docs.rs]
-targets = ["x86_64-unknown-linux-gnu"]
-
-[dependencies]
-bitflags = "1.0"
-codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive"] }
-serde = { version = "1", features = ["derive"], optional = true }
-
-# Substrate Dependencies (This crate should not rely on frame)
-sp-core = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3', default-features = false }
-sp-std = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-runtime = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-
-[features]
-default = ["std"]
-std = [
- "codec/std",
- "sp-core/std",
- "sp-runtime/std",
- "sp-std/std",
- "serde",
-]
pallets/contracts/common/README.mddiffbeforeafterboth--- a/pallets/contracts/common/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-A crate that hosts a common definitions that are relevant for the pallet-contracts.
-
-License: Apache-2.0
\ No newline at end of file
pallets/contracts/common/src/lib.rsdiffbeforeafterboth--- a/pallets/contracts/common/src/lib.rs
+++ /dev/null
@@ -1,148 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! A crate that hosts a common definitions that are relevant for the pallet-contracts.
-
-#![cfg_attr(not(feature = "std"), no_std)]
-
-use bitflags::bitflags;
-use codec::{Decode, Encode};
-use sp_core::Bytes;
-use sp_runtime::{DispatchError, RuntimeDebug};
-use sp_std::prelude::*;
-
-#[cfg(feature = "std")]
-use serde::{Serialize, Deserialize};
-
-/// Result type of a `bare_call` or `bare_instantiate` call.
-///
-/// It contains the execution result together with some auxiliary information.
-#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)]
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
-pub struct ContractResult<T> {
- /// How much gas was consumed during execution.
- pub gas_consumed: u64,
- /// An optional debug message. This message is only non-empty when explicitly requested
- /// by the code that calls into the contract.
- ///
- /// The contained bytes are valid UTF-8. This is not declared as `String` because
- /// this type is not allowed within the runtime. A client should decode them in order
- /// to present the message to its users.
- ///
- /// # Note
- ///
- /// The debug message is never generated during on-chain execution. It is reserved for
- /// RPC calls.
- pub debug_message: Bytes,
- /// The execution result of the wasm code.
- pub result: T,
-}
-
-/// Result type of a `bare_call` call.
-pub type ContractExecResult = ContractResult<Result<ExecReturnValue, DispatchError>>;
-
-/// Result type of a `bare_instantiate` call.
-pub type ContractInstantiateResult<AccountId, BlockNumber> =
- ContractResult<Result<InstantiateReturnValue<AccountId, BlockNumber>, DispatchError>>;
-
-/// Result type of a `get_storage` call.
-pub type GetStorageResult = Result<Option<Vec<u8>>, ContractAccessError>;
-
-/// Result type of a `rent_projection` call.
-pub type RentProjectionResult<BlockNumber> =
- Result<RentProjection<BlockNumber>, ContractAccessError>;
-
-/// The possible errors that can happen querying the storage of a contract.
-#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)]
-pub enum ContractAccessError {
- /// The given address doesn't point to a contract.
- DoesntExist,
- /// The specified contract is a tombstone and thus cannot have any storage.
- IsTombstone,
-}
-
-#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)]
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
-pub enum RentProjection<BlockNumber> {
- /// Eviction is projected to happen at the specified block number.
- EvictionAt(BlockNumber),
- /// No eviction is scheduled.
- ///
- /// E.g. Contract accumulated enough funds to offset the rent storage costs.
- NoEviction,
-}
-
-bitflags! {
- /// Flags used by a contract to customize exit behaviour.
- #[derive(Encode, Decode)]
- #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
- #[cfg_attr(feature = "std", serde(rename_all = "camelCase", transparent))]
- pub struct ReturnFlags: u32 {
- /// If this bit is set all changes made by the contract execution are rolled back.
- const REVERT = 0x0000_0001;
- }
-}
-
-/// Output of a contract call or instantiation which ran to completion.
-#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)]
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
-pub struct ExecReturnValue {
- /// Flags passed along by `seal_return`. Empty when `seal_return` was never called.
- pub flags: ReturnFlags,
- /// Buffer passed along by `seal_return`. Empty when `seal_return` was never called.
- pub data: Bytes,
-}
-
-impl ExecReturnValue {
- /// We understand the absense of a revert flag as success.
- pub fn is_success(&self) -> bool {
- !self.flags.contains(ReturnFlags::REVERT)
- }
-}
-
-/// The result of a successful contract instantiation.
-#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)]
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
-pub struct InstantiateReturnValue<AccountId, BlockNumber> {
- /// The output of the called constructor.
- pub result: ExecReturnValue,
- /// The account id of the new contract.
- pub account_id: AccountId,
- /// Information about when and if the new project will be evicted.
- ///
- /// # Note
- ///
- /// `None` if `bare_instantiate` was called with
- /// `compute_projection` set to false. From the perspective of an RPC this means that
- /// the runtime API did not request this value and this feature is therefore unsupported.
- pub rent_projection: Option<RentProjection<BlockNumber>>,
-}
-
-/// Reference to an existing code hash or a new wasm module.
-#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)]
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
-pub enum Code<Hash> {
- /// A wasm module as raw bytes.
- Upload(Bytes),
- /// The code hash of an on-chain wasm blob.
- Existing(Hash),
-}
pallets/contracts/fixtures/call_return_code.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/call_return_code.wat
+++ /dev/null
@@ -1,42 +0,0 @@
-;; This calls the supplied dest and transfers 100 balance during this call and copies
-;; the return code of this call to the output buffer.
-;; It also forwards its input to the callee.
-(module
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "seal0" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32 i32) (result i32)))
- (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
- (import "env" "memory" (memory 1 1))
-
- ;; [0, 8) 100 balance
- (data (i32.const 0) "\64\00\00\00\00\00\00\00")
-
- ;; [8, 12) here we store the return code of the transfer
-
- ;; [12, 16) size of the input data
- (data (i32.const 12) "\24")
-
- ;; [16, inf) here we store the input data
- ;; 32 byte dest + 4 byte forward
-
- (func (export "deploy"))
-
- (func (export "call")
- (call $seal_input (i32.const 16) (i32.const 12))
- (i32.store
- (i32.const 8)
- (call $seal_call
- (i32.const 16) ;; Pointer to "callee" address.
- (i32.const 32) ;; Length of "callee" address.
- (i64.const 0) ;; How much gas to devote for the execution. 0 = all.
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer.
- (i32.const 48) ;; Pointer to input data buffer address
- (i32.const 4) ;; Length of input data buffer
- (i32.const 0xffffffff) ;; u32 max sentinel value: do not copy output
- (i32.const 0) ;; Ptr to output buffer len
- )
- )
- ;; exit with success and take transfer return code to the output buffer
- (call $seal_return (i32.const 0) (i32.const 8) (i32.const 4))
- )
-)
pallets/contracts/fixtures/caller_contract.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/caller_contract.wat
+++ /dev/null
@@ -1,293 +0,0 @@
-(module
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "seal0" "seal_balance" (func $seal_balance (param i32 i32)))
- (import "seal0" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32 i32) (result i32)))
- (import "seal0" "seal_instantiate" (func $seal_instantiate
- (param i32 i32 i64 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32)
- ))
- (import "seal0" "seal_println" (func $seal_println (param i32 i32)))
- (import "env" "memory" (memory 1 1))
-
- (func $assert (param i32)
- (block $ok
- (br_if $ok
- (get_local 0)
- )
- (unreachable)
- )
- )
-
- (func $current_balance (param $sp i32) (result i64)
- (i32.store
- (i32.sub (get_local $sp) (i32.const 16))
- (i32.const 8)
- )
- (call $seal_balance
- (i32.sub (get_local $sp) (i32.const 8))
- (i32.sub (get_local $sp) (i32.const 16))
- )
- (call $assert
- (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 16))) (i32.const 8))
- )
- (i64.load (i32.sub (get_local $sp) (i32.const 8)))
- )
-
- (func (export "deploy"))
-
- (func (export "call")
- (local $sp i32)
- (local $exit_code i32)
- (local $balance i64)
-
- ;; Length of the buffer
- (i32.store (i32.const 20) (i32.const 32))
-
- ;; Copy input to this contracts memory
- (call $seal_input (i32.const 24) (i32.const 20))
-
- ;; Input data is the code hash of the contract to be deployed.
- (call $assert
- (i32.eq
- (i32.load (i32.const 20))
- (i32.const 32)
- )
- )
-
- ;; Read current balance into local variable.
- (set_local $sp (i32.const 1024))
- (set_local $balance
- (call $current_balance (get_local $sp))
- )
-
- ;; Fail to deploy the contract since it returns a non-zero exit status.
- (set_local $exit_code
- (call $seal_instantiate
- (i32.const 24) ;; Pointer to the code hash.
- (i32.const 32) ;; Length of the code hash.
- (i64.const 0) ;; How much gas to devote for the execution. 0 = all.
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer.
- (i32.const 9) ;; Pointer to input data buffer address
- (i32.const 7) ;; Length of input data buffer
- (i32.const 4294967295) ;; u32 max sentinel value: do not copy address
- (i32.const 0) ;; Length is ignored in this case
- (i32.const 4294967295) ;; u32 max sentinel value: do not copy output
- (i32.const 0) ;; Length is ignored in this case
- (i32.const 0) ;; salt_ptr
- (i32.const 0) ;; salt_le
- )
- )
-
- ;; Check non-zero exit status.
- (call $assert
- (i32.eq (get_local $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted
- )
-
- ;; Check that balance has not changed.
- (call $assert
- (i64.eq (get_local $balance) (call $current_balance (get_local $sp)))
- )
-
- ;; Fail to deploy the contract due to insufficient gas.
- (set_local $exit_code
- (call $seal_instantiate
- (i32.const 24) ;; Pointer to the code hash.
- (i32.const 32) ;; Length of the code hash.
- (i64.const 1) ;; Supply too little gas
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer.
- (i32.const 8) ;; Pointer to input data buffer address
- (i32.const 8) ;; Length of input data buffer
- (i32.const 4294967295) ;; u32 max sentinel value: do not copy address
- (i32.const 0) ;; Length is ignored in this case
- (i32.const 4294967295) ;; u32 max sentinel value: do not copy output
- (i32.const 0) ;; Length is ignored in this case
- (i32.const 0) ;; salt_ptr
- (i32.const 0) ;; salt_le
-
- )
- )
-
- ;; Check for special trap exit status.
- (call $assert
- (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped
- )
-
- ;; Check that balance has not changed.
- (call $assert
- (i64.eq (get_local $balance) (call $current_balance (get_local $sp)))
- )
-
- ;; Length of the output buffer
- (i32.store
- (i32.sub (get_local $sp) (i32.const 4))
- (i32.const 256)
- )
-
- ;; Deploy the contract successfully.
- (set_local $exit_code
- (call $seal_instantiate
- (i32.const 24) ;; Pointer to the code hash.
- (i32.const 32) ;; Length of the code hash.
- (i64.const 0) ;; How much gas to devote for the execution. 0 = all.
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer.
- (i32.const 8) ;; Pointer to input data buffer address
- (i32.const 8) ;; Length of input data buffer
- (i32.const 16) ;; Pointer to the address output buffer
- (i32.sub (get_local $sp) (i32.const 4)) ;; Pointer to the address buffer length
- (i32.const 4294967295) ;; u32 max sentinel value: do not copy output
- (i32.const 0) ;; Length is ignored in this case
- (i32.const 0) ;; salt_ptr
- (i32.const 0) ;; salt_le
-
- )
- )
-
- ;; Check for success exit status.
- (call $assert
- (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success
- )
-
- ;; Check that address has the expected length
- (call $assert
- (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 4))) (i32.const 32))
- )
-
- ;; Check that balance has been deducted.
- (set_local $balance
- (i64.sub (get_local $balance) (i64.load (i32.const 0)))
- )
- (call $assert
- (i64.eq (get_local $balance) (call $current_balance (get_local $sp)))
- )
-
- ;; Zero out destination buffer of output
- (i32.store
- (i32.sub (get_local $sp) (i32.const 4))
- (i32.const 0)
- )
-
- ;; Length of the output buffer
- (i32.store
- (i32.sub (get_local $sp) (i32.const 8))
- (i32.const 4)
- )
-
- ;; Call the new contract and expect it to return failing exit code.
- (set_local $exit_code
- (call $seal_call
- (i32.const 16) ;; Pointer to "callee" address.
- (i32.const 32) ;; Length of "callee" address.
- (i64.const 0) ;; How much gas to devote for the execution. 0 = all.
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer.
- (i32.const 9) ;; Pointer to input data buffer address
- (i32.const 7) ;; Length of input data buffer
- (i32.sub (get_local $sp) (i32.const 4)) ;; Ptr to output buffer
- (i32.sub (get_local $sp) (i32.const 8)) ;; Ptr to output buffer len
- )
- )
-
- ;; Check non-zero exit status.
- (call $assert
- (i32.eq (get_local $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted
- )
-
- ;; Check that output buffer contains the expected return data.
- (call $assert
- (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 8))) (i32.const 3))
- )
- (call $assert
- (i32.eq
- (i32.load (i32.sub (get_local $sp) (i32.const 4)))
- (i32.const 0x00776655)
- )
- )
-
- ;; Check that balance has not changed.
- (call $assert
- (i64.eq (get_local $balance) (call $current_balance (get_local $sp)))
- )
-
- ;; Fail to call the contract due to insufficient gas.
- (set_local $exit_code
- (call $seal_call
- (i32.const 16) ;; Pointer to "callee" address.
- (i32.const 32) ;; Length of "callee" address.
- (i64.const 1) ;; Supply too little gas
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer.
- (i32.const 8) ;; Pointer to input data buffer address
- (i32.const 8) ;; Length of input data buffer
- (i32.const 4294967295) ;; u32 max sentinel value: do not copy output
- (i32.const 0) ;; Length is ignored in this cas
- )
- )
-
- ;; Check for special trap exit status.
- (call $assert
- (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped
- )
-
- ;; Check that balance has not changed.
- (call $assert
- (i64.eq (get_local $balance) (call $current_balance (get_local $sp)))
- )
-
- ;; Zero out destination buffer of output
- (i32.store
- (i32.sub (get_local $sp) (i32.const 4))
- (i32.const 0)
- )
-
- ;; Length of the output buffer
- (i32.store
- (i32.sub (get_local $sp) (i32.const 8))
- (i32.const 4)
- )
-
- ;; Call the contract successfully.
- (set_local $exit_code
- (call $seal_call
- (i32.const 16) ;; Pointer to "callee" address.
- (i32.const 32) ;; Length of "callee" address.
- (i64.const 0) ;; How much gas to devote for the execution. 0 = all.
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer.
- (i32.const 8) ;; Pointer to input data buffer address
- (i32.const 8) ;; Length of input data buffer
- (i32.sub (get_local $sp) (i32.const 4)) ;; Ptr to output buffer
- (i32.sub (get_local $sp) (i32.const 8)) ;; Ptr to output buffer len
- )
- )
-
- ;; Check for success exit status.
- (call $assert
- (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success
- )
-
- ;; Check that the output buffer contains the expected return data.
- (call $assert
- (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 8))) (i32.const 4))
- )
- (call $assert
- (i32.eq
- (i32.load (i32.sub (get_local $sp) (i32.const 4)))
- (i32.const 0x77665544)
- )
- )
-
- ;; Check that balance has been deducted.
- (set_local $balance
- (i64.sub (get_local $balance) (i64.load (i32.const 0)))
- )
- (call $assert
- (i64.eq (get_local $balance) (call $current_balance (get_local $sp)))
- )
- )
-
- (data (i32.const 0) "\00\80") ;; The value to transfer on instantiation and calls.
- ;; Chosen to be greater than existential deposit.
- (data (i32.const 8) "\00\01\22\33\44\55\66\77") ;; The input data to instantiations and calls.
-)
pallets/contracts/fixtures/chain_extension.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/chain_extension.wat
+++ /dev/null
@@ -1,46 +0,0 @@
-;; Call chain extension by passing through input and output of this contract
-(module
- (import "seal0" "seal_call_chain_extension"
- (func $seal_call_chain_extension (param i32 i32 i32 i32 i32) (result i32))
- )
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
- (import "env" "memory" (memory 16 16))
-
- (func $assert (param i32)
- (block $ok
- (br_if $ok (get_local 0))
- (unreachable)
- )
- )
-
- ;; [0, 4) len of input output
- (data (i32.const 0) "\02")
-
- ;; [4, 12) buffer for input
-
- ;; [12, 16) len of output buffer
- (data (i32.const 12) "\02")
-
- ;; [16, inf) buffer for output
-
- (func (export "deploy"))
-
- (func (export "call")
- (call $seal_input (i32.const 4) (i32.const 0))
-
- ;; the chain extension passes through the input and returns it as output
- (call $seal_call_chain_extension
- (i32.load8_u (i32.const 4)) ;; func_id
- (i32.const 4) ;; input_ptr
- (i32.load (i32.const 0)) ;; input_len
- (i32.const 16) ;; output_ptr
- (i32.const 12) ;; output_len_ptr
- )
-
- ;; the chain extension passes through the func_id
- (call $assert (i32.eq (i32.load8_u (i32.const 4))))
-
- (call $seal_return (i32.const 0) (i32.const 16) (i32.load (i32.const 12)))
- )
-)
pallets/contracts/fixtures/check_default_rent_allowance.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/check_default_rent_allowance.wat
+++ /dev/null
@@ -1,43 +0,0 @@
-(module
- (import "seal0" "seal_rent_allowance" (func $seal_rent_allowance (param i32 i32)))
- (import "env" "memory" (memory 1 1))
-
- ;; [0, 8) reserved for $seal_rent_allowance output
-
- ;; [8, 16) length of the buffer
- (data (i32.const 8) "\08")
-
- ;; [16, inf) zero initialized
-
- (func $assert (param i32)
- (block $ok
- (br_if $ok
- (get_local 0)
- )
- (unreachable)
- )
- )
-
- (func (export "call"))
-
- (func (export "deploy")
- ;; fill the buffer with the rent allowance.
- (call $seal_rent_allowance (i32.const 0) (i32.const 8))
-
- ;; assert len == 8
- (call $assert
- (i32.eq
- (i32.load (i32.const 8))
- (i32.const 8)
- )
- )
-
- ;; assert that contents of the buffer is equal to <BalanceOf<T>>::max_value().
- (call $assert
- (i64.eq
- (i64.load (i32.const 0))
- (i64.const 0xFFFFFFFFFFFFFFFF)
- )
- )
- )
-)
pallets/contracts/fixtures/crypto_hashes.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/crypto_hashes.wat
+++ /dev/null
@@ -1,81 +0,0 @@
-(module
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
-
- (import "seal0" "seal_hash_sha2_256" (func $seal_hash_sha2_256 (param i32 i32 i32)))
- (import "seal0" "seal_hash_keccak_256" (func $seal_hash_keccak_256 (param i32 i32 i32)))
- (import "seal0" "seal_hash_blake2_256" (func $seal_hash_blake2_256 (param i32 i32 i32)))
- (import "seal0" "seal_hash_blake2_128" (func $seal_hash_blake2_128 (param i32 i32 i32)))
-
- (import "env" "memory" (memory 1 1))
-
- (type $hash_fn_sig (func (param i32 i32 i32)))
- (table 8 funcref)
- (elem (i32.const 1)
- $seal_hash_sha2_256
- $seal_hash_keccak_256
- $seal_hash_blake2_256
- $seal_hash_blake2_128
- )
- (data (i32.const 1) "20202010201008") ;; Output sizes of the hashes in order in hex.
-
- ;; Not in use by the tests besides instantiating the contract.
- (func (export "deploy"))
-
- ;; Called by the tests.
- ;;
- ;; The `call` function expects data in a certain format in the input buffer.
- ;;
- ;; 1. The first byte encodes an identifier for the crypto hash function
- ;; under test. (*)
- ;; 2. The rest encodes the input data that is directly fed into the
- ;; crypto hash function chosen in 1.
- ;;
- ;; The `deploy` function then computes the chosen crypto hash function
- ;; given the input and puts the result into the output buffer.
- ;; After contract execution the test driver then asserts that the returned
- ;; values are equal to the expected bytes for the input and chosen hash
- ;; function.
- ;;
- ;; (*) The possible value for the crypto hash identifiers can be found below:
- ;;
- ;; | value | Algorithm | Bit Width |
- ;; |-------|-----------|-----------|
- ;; | 0 | SHA2 | 256 |
- ;; | 1 | KECCAK | 256 |
- ;; | 2 | BLAKE2 | 256 |
- ;; | 3 | BLAKE2 | 128 |
- ;; ---------------------------------
- (func (export "call")
- (local $chosen_hash_fn i32)
- (local $input_len_ptr i32)
- (local $input_ptr i32)
- (local $input_len i32)
- (local $output_ptr i32)
- (local $output_len i32)
- (local.set $input_len_ptr (i32.const 256))
- (local.set $input_ptr (i32.const 10))
- (i32.store (local.get $input_len_ptr) (i32.const 246))
- (call $seal_input (local.get $input_ptr) (local.get $input_len_ptr))
- (local.set $chosen_hash_fn (i32.load8_u (local.get $input_ptr)))
- (if (i32.gt_u (local.get $chosen_hash_fn) (i32.const 7))
- ;; We check that the chosen hash fn identifier is within bounds: [0,7]
- (unreachable)
- )
- (local.set $input_ptr (i32.add (local.get $input_ptr) (i32.const 1)))
- (local.set $input_len (i32.sub (i32.load (local.get $input_len_ptr)) (i32.const 1)))
- (local.set $output_len (i32.load8_u (local.get $chosen_hash_fn)))
- (call_indirect (type $hash_fn_sig)
- (local.get $input_ptr)
- (local.get $input_len)
- (local.get $input_ptr)
- (local.get $chosen_hash_fn) ;; Which crypto hash function to execute.
- )
- (call $seal_return
- (i32.const 0)
- (local.get $input_ptr) ;; Linear memory location of the output buffer.
- (local.get $output_len) ;; Number of output buffer bytes.
- )
- (unreachable)
- )
-)
pallets/contracts/fixtures/destroy_and_transfer.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/destroy_and_transfer.wat
+++ /dev/null
@@ -1,161 +0,0 @@
-(module
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "seal0" "seal_get_storage" (func $seal_get_storage (param i32 i32 i32) (result i32)))
- (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32)))
- (import "seal0" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32 i32) (result i32)))
- (import "seal0" "seal_transfer" (func $seal_transfer (param i32 i32 i32 i32) (result i32)))
- (import "seal0" "seal_instantiate" (func $seal_instantiate
- (param i32 i32 i64 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32)
- ))
- (import "env" "memory" (memory 1 1))
-
- ;; [0, 8) Endowment to send when creating contract.
- (data (i32.const 0) "\00\00\01")
-
- ;; [8, 16) Value to send when calling contract.
-
- ;; [16, 48) The key to store the contract address under.
-
- ;; [48, 80) Buffer where to store the input to the contract
-
- ;; [88, 96) Size of the buffer
- (data (i32.const 88) "\FF")
-
- ;; [96, 100) Size of the input buffer
- (data (i32.const 96) "\20")
-
- ;; [100, 132) Buffer where to store the address of the instantiated contract
-
- ;; [132, 134) Salt
- (data (i32.const 132) "\47\11")
-
-
- (func $assert (param i32)
- (block $ok
- (br_if $ok
- (get_local 0)
- )
- (unreachable)
- )
- )
-
- (func (export "deploy")
- ;; Input data is the code hash of the contract to be deployed.
- (call $seal_input (i32.const 48) (i32.const 96))
- (call $assert
- (i32.eq
- (i32.load (i32.const 96))
- (i32.const 32)
- )
- )
-
- ;; Deploy the contract with the provided code hash.
- (call $assert
- (i32.eq
- (call $seal_instantiate
- (i32.const 48) ;; Pointer to the code hash.
- (i32.const 32) ;; Length of the code hash.
- (i64.const 0) ;; How much gas to devote for the execution. 0 = all.
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer.
- (i32.const 0) ;; Pointer to input data buffer address
- (i32.const 0) ;; Length of input data buffer
- (i32.const 100) ;; Buffer where to store address of new contract
- (i32.const 88) ;; Pointer to the length of the buffer
- (i32.const 4294967295) ;; u32 max sentinel value: do not copy output
- (i32.const 0) ;; Length is ignored in this case
- (i32.const 132) ;; salt_ptr
- (i32.const 2) ;; salt_len
- )
- (i32.const 0)
- )
- )
-
- ;; Check that address has expected length
- (call $assert
- (i32.eq
- (i32.load (i32.const 88))
- (i32.const 32)
- )
- )
-
- ;; Store the return address.
- (call $seal_set_storage
- (i32.const 16) ;; Pointer to the key
- (i32.const 100) ;; Pointer to the value
- (i32.const 32) ;; Length of the value
- )
- )
-
- (func (export "call")
- ;; Read address of destination contract from storage.
- (call $assert
- (i32.eq
- (call $seal_get_storage
- (i32.const 16) ;; Pointer to the key
- (i32.const 100) ;; Pointer to the value
- (i32.const 88) ;; Pointer to the len of the value
- )
- (i32.const 0)
- )
- )
- (call $assert
- (i32.eq
- (i32.load (i32.const 88))
- (i32.const 32)
- )
- )
-
- ;; Calling the destination contract with non-empty input data should fail.
- (call $assert
- (i32.eq
- (call $seal_call
- (i32.const 100) ;; Pointer to destination address
- (i32.const 32) ;; Length of destination address
- (i64.const 0) ;; How much gas to devote for the execution. 0 = all.
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer
- (i32.const 0) ;; Pointer to input data buffer address
- (i32.const 1) ;; Length of input data buffer
- (i32.const 4294967295) ;; u32 max sentinel value: do not copy output
- (i32.const 0) ;; Length is ignored in this case
-
- )
- (i32.const 0x1)
- )
- )
-
- ;; Call the destination contract regularly, forcing it to self-destruct.
- (call $assert
- (i32.eq
- (call $seal_call
- (i32.const 100) ;; Pointer to destination address
- (i32.const 32) ;; Length of destination address
- (i64.const 0) ;; How much gas to devote for the execution. 0 = all.
- (i32.const 8) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer
- (i32.const 0) ;; Pointer to input data buffer address
- (i32.const 0) ;; Length of input data buffer
- (i32.const 4294967295) ;; u32 max sentinel value: do not copy output
- (i32.const 0) ;; Length is ignored in this case
- )
- (i32.const 0)
- )
- )
-
- ;; Calling the destination address with non-empty input data should now work since the
- ;; contract has been removed. Also transfer a balance to the address so we can ensure this
- ;; does not keep the contract alive.
- (call $assert
- (i32.eq
- (call $seal_transfer
- (i32.const 100) ;; Pointer to destination address
- (i32.const 32) ;; Length of destination address
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer
- )
- (i32.const 0)
- )
- )
- )
-)
pallets/contracts/fixtures/drain.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/drain.wat
+++ /dev/null
@@ -1,49 +0,0 @@
-(module
- (import "seal0" "seal_balance" (func $seal_balance (param i32 i32)))
- (import "seal0" "seal_transfer" (func $seal_transfer (param i32 i32 i32 i32) (result i32)))
- (import "env" "memory" (memory 1 1))
-
- ;; [0, 8) reserved for $seal_balance output
-
- ;; [8, 16) length of the buffer
- (data (i32.const 8) "\08")
-
- ;; [16, inf) zero initialized
-
- (func $assert (param i32)
- (block $ok
- (br_if $ok
- (get_local 0)
- )
- (unreachable)
- )
- )
-
- (func (export "deploy"))
-
- (func (export "call")
- ;; Send entire remaining balance to the 0 address.
- (call $seal_balance (i32.const 0) (i32.const 8))
-
- ;; Balance should be encoded as a u64.
- (call $assert
- (i32.eq
- (i32.load (i32.const 8))
- (i32.const 8)
- )
- )
-
- ;; Self-destruct by sending full balance to the 0 address.
- (call $assert
- (i32.eq
- (call $seal_transfer
- (i32.const 16) ;; Pointer to destination address
- (i32.const 32) ;; Length of destination address
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer
- )
- (i32.const 4) ;; ReturnCode::BelowSubsistenceThreshold
- )
- )
- )
-)
pallets/contracts/fixtures/event_size.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/event_size.wat
+++ /dev/null
@@ -1,39 +0,0 @@
-(module
- (import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32)))
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "env" "memory" (memory 16 16))
-
- ;; [0, 4) size of the input buffer
- (data (i32.const 0) "\04")
-
- (func $assert (param i32)
- (block $ok
- (br_if $ok
- (get_local 0)
- )
- (unreachable)
- )
- )
-
- (func (export "call")
- (call $seal_input (i32.const 4) (i32.const 0))
-
- ;; assert input size == 4
- (call $assert
- (i32.eq
- (i32.load (i32.const 0))
- (i32.const 4)
- )
- )
-
- ;; place a garbage value in storage, the size of which is specified by the call input.
- (call $seal_deposit_event
- (i32.const 0) ;; topics_ptr
- (i32.const 0) ;; topics_len
- (i32.const 0) ;; data_ptr
- (i32.load (i32.const 4)) ;; data_len
- )
- )
-
- (func (export "deploy"))
-)
pallets/contracts/fixtures/instantiate_return_code.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/instantiate_return_code.wat
+++ /dev/null
@@ -1,49 +0,0 @@
-;; This instantiats a contract and transfers 100 balance during this call and copies the return code
-;; of this call to the output buffer.
-;; The first 32 byte of input is the code hash to instantiate
-;; The rest of the input is forwarded to the constructor of the callee
-(module
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "seal0" "seal_instantiate" (func $seal_instantiate
- (param i32 i32 i64 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32)
- ))
- (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
- (import "env" "memory" (memory 1 1))
-
- ;; [0, 8) 10_000 balance
- (data (i32.const 0) "\10\27\00\00\00\00\00\00")
-
- ;; [8, 12) here we store the return code of the transfer
-
- ;; [12, 16) size of the input buffer
- (data (i32.const 12) "\24")
-
- ;; [16, inf) input buffer
- ;; 32 bye code hash + 4 byte forward
-
- (func (export "deploy"))
-
- (func (export "call")
- (call $seal_input (i32.const 16) (i32.const 12))
- (i32.store
- (i32.const 8)
- (call $seal_instantiate
- (i32.const 16) ;; Pointer to the code hash.
- (i32.const 32) ;; Length of the code hash.
- (i64.const 0) ;; How much gas to devote for the execution. 0 = all.
- (i32.const 0) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer.
- (i32.const 48) ;; Pointer to input data buffer address
- (i32.const 4) ;; Length of input data buffer
- (i32.const 0xffffffff) ;; u32 max sentinel value: do not copy address
- (i32.const 0) ;; Length is ignored in this case
- (i32.const 0xffffffff) ;; u32 max sentinel value: do not copy output
- (i32.const 0) ;; Length is ignored in this case
- (i32.const 0) ;; salt_ptr
- (i32.const 0) ;; salt_len
- )
- )
- ;; exit with success and take transfer return code to the output buffer
- (call $seal_return (i32.const 0) (i32.const 8) (i32.const 4))
- )
-)
pallets/contracts/fixtures/ok_trap_revert.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/ok_trap_revert.wat
+++ /dev/null
@@ -1,35 +0,0 @@
-(module
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
- (import "env" "memory" (memory 1 1))
-
- (func (export "deploy")
- (call $ok_trap_revert)
- )
-
- (func (export "call")
- (call $ok_trap_revert)
- )
-
- (func $ok_trap_revert
- (i32.store (i32.const 4) (i32.const 4))
- (call $seal_input (i32.const 0) (i32.const 4))
- (block $IF_2
- (block $IF_1
- (block $IF_0
- (br_table $IF_0 $IF_1 $IF_2
- (i32.load8_u (i32.const 0))
- )
- (unreachable)
- )
- ;; 0 = return with success
- return
- )
- ;; 1 = revert
- (call $seal_return (i32.const 1) (i32.const 0) (i32.const 0))
- (unreachable)
- )
- ;; 2 = trap
- (unreachable)
- )
-)
\ No newline at end of file
pallets/contracts/fixtures/restoration.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/restoration.wat
+++ /dev/null
@@ -1,75 +0,0 @@
-(module
- (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32)))
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "seal0" "seal_restore_to"
- (func $seal_restore_to
- (param i32 i32 i32 i32 i32 i32 i32 i32)
- )
- )
- (import "env" "memory" (memory 1 1))
-
- (func $assert (param i32)
- (block $ok
- (br_if $ok
- (get_local 0)
- )
- (unreachable)
- )
- )
-
- (func (export "call")
- ;; copy code hash to contract memory
- (call $seal_input (i32.const 308) (i32.const 304))
- (call $assert
- (i32.eq
- (i32.load (i32.const 304))
- (i32.const 64)
- )
- )
- (call $seal_restore_to
- ;; Pointer and length of the encoded dest buffer.
- (i32.const 340)
- (i32.const 32)
- ;; Pointer and length of the encoded code hash buffer
- (i32.const 308)
- (i32.const 32)
- ;; Pointer and length of the encoded rent_allowance buffer
- (i32.const 296)
- (i32.const 8)
- ;; Pointer and number of items in the delta buffer.
- ;; This buffer specifies multiple keys for removal before restoration.
- (i32.const 100)
- (i32.const 1)
- )
- )
- (func (export "deploy")
- ;; Data to restore
- (call $seal_set_storage
- (i32.const 0)
- (i32.const 0)
- (i32.const 4)
- )
-
- ;; ACL
- (call $seal_set_storage
- (i32.const 100)
- (i32.const 0)
- (i32.const 4)
- )
- )
-
- ;; Data to restore
- (data (i32.const 0) "\28")
-
- ;; Buffer that has ACL storage keys.
- (data (i32.const 100) "\01")
-
- ;; [296, 304) Rent allowance
- (data (i32.const 296) "\32\00\00\00\00\00\00\00")
-
- ;; [304, 308) Size of the buffer that holds code_hash + addr
- (data (i32.const 304) "\40")
-
- ;; [308, 340) code hash of bob (copied by seal_input)
- ;; [340, 372) addr of bob (copied by seal_input)
-)
pallets/contracts/fixtures/return_from_start_fn.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/return_from_start_fn.wat
+++ /dev/null
@@ -1,28 +0,0 @@
-(module
- (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
- (import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32)))
- (import "env" "memory" (memory 1 1))
-
- (start $start)
- (func $start
- (call $seal_deposit_event
- (i32.const 0) ;; The topics buffer
- (i32.const 0) ;; The topics buffer's length
- (i32.const 8) ;; The data buffer
- (i32.const 4) ;; The data buffer's length
- )
- (call $seal_return
- (i32.const 0)
- (i32.const 8)
- (i32.const 4)
- )
- (unreachable)
- )
-
- (func (export "call")
- (unreachable)
- )
- (func (export "deploy"))
-
- (data (i32.const 8) "\01\02\03\04")
-)
pallets/contracts/fixtures/return_with_data.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/return_with_data.wat
+++ /dev/null
@@ -1,33 +0,0 @@
-(module
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
- (import "env" "memory" (memory 1 1))
-
- ;; [0, 128) buffer where input is copied
-
- ;; [128, 132) length of the input buffer
- (data (i32.const 128) "\80")
-
- ;; Deploy routine is the same as call.
- (func (export "deploy")
- (call $call)
- )
-
- ;; Call reads the first 4 bytes (LE) as the exit status and returns the rest as output data.
- (func $call (export "call")
- ;; Copy input into this contracts memory.
- (call $seal_input (i32.const 0) (i32.const 128))
-
- ;; Copy all but the first 4 bytes of the input data as the output data.
- ;; Use the first byte as exit status
- (call $seal_return
- (i32.load8_u (i32.const 0)) ;; Exit status
- (i32.const 4) ;; Pointer to the data to return.
- (i32.sub ;; Count of bytes to copy.
- (i32.load (i32.const 128))
- (i32.const 4)
- )
- )
- (unreachable)
- )
-)
pallets/contracts/fixtures/run_out_of_gas.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/run_out_of_gas.wat
+++ /dev/null
@@ -1,7 +0,0 @@
-(module
- (func (export "call")
- (loop $inf (br $inf)) ;; just run out of gas
- (unreachable)
- )
- (func (export "deploy"))
-)
pallets/contracts/fixtures/self_destruct.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/self_destruct.wat
+++ /dev/null
@@ -1,83 +0,0 @@
-(module
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "seal0" "seal_address" (func $seal_address (param i32 i32)))
- (import "seal0" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32 i32) (result i32)))
- (import "seal0" "seal_terminate" (func $seal_terminate (param i32 i32)))
- (import "env" "memory" (memory 1 1))
-
- ;; [0, 32) reserved for $seal_address output
-
- ;; [32, 36) length of the buffer
- (data (i32.const 32) "\20")
-
- ;; [36, 68) Address of django
- (data (i32.const 36)
- "\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04"
- "\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04"
- )
-
- ;; [68, 72) reserved for output of $seal_input
-
- ;; [72, 76) length of the buffer
- (data (i32.const 72) "\04")
-
- ;; [76, inf) zero initialized
-
- (func $assert (param i32)
- (block $ok
- (br_if $ok
- (get_local 0)
- )
- (unreachable)
- )
- )
-
- (func (export "deploy"))
-
- (func (export "call")
- ;; If the input data is not empty, then recursively call self with empty input data.
- ;; This should trap instead of self-destructing since a contract cannot be removed live in
- ;; the execution stack cannot be removed. If the recursive call traps, then trap here as
- ;; well.
- (call $seal_input (i32.const 68) (i32.const 72))
- (if (i32.load (i32.const 72))
- (then
- (call $seal_address (i32.const 0) (i32.const 32))
-
- ;; Expect address to be 8 bytes.
- (call $assert
- (i32.eq
- (i32.load (i32.const 32))
- (i32.const 32)
- )
- )
-
- ;; Recursively call self with empty input data.
- (call $assert
- (i32.eq
- (call $seal_call
- (i32.const 0) ;; Pointer to own address
- (i32.const 32) ;; Length of own address
- (i64.const 0) ;; How much gas to devote for the execution. 0 = all.
- (i32.const 76) ;; Pointer to the buffer with value to transfer
- (i32.const 8) ;; Length of the buffer with value to transfer
- (i32.const 0) ;; Pointer to input data buffer address
- (i32.const 0) ;; Length of input data buffer
- (i32.const 4294967295) ;; u32 max sentinel value: do not copy output
- (i32.const 0) ;; Length is ignored in this case
- )
- (i32.const 0)
- )
- )
- )
- (else
- ;; Try to terminate and give balance to django.
- (call $seal_terminate
- (i32.const 36) ;; Pointer to beneficiary address
- (i32.const 32) ;; Length of beneficiary address
- )
- (unreachable) ;; seal_terminate never returns
- )
- )
- )
-)
pallets/contracts/fixtures/self_destructing_constructor.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/self_destructing_constructor.wat
+++ /dev/null
@@ -1,23 +0,0 @@
-(module
- (import "seal0" "seal_terminate" (func $seal_terminate (param i32 i32)))
- (import "env" "memory" (memory 1 1))
-
- (func $assert (param i32)
- (block $ok
- (br_if $ok
- (get_local 0)
- )
- (unreachable)
- )
- )
-
- (func (export "deploy")
- ;; Self-destruct by sending full balance to the 0 address.
- (call $seal_terminate
- (i32.const 0) ;; Pointer to destination address
- (i32.const 32) ;; Length of destination address
- )
- )
-
- (func (export "call"))
-)
pallets/contracts/fixtures/set_empty_storage.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/set_empty_storage.wat
+++ /dev/null
@@ -1,15 +0,0 @@
-;; This module stores a KV pair into the storage
-(module
- (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32)))
- (import "env" "memory" (memory 16 16))
-
- (func (export "call")
- )
- (func (export "deploy")
- (call $seal_set_storage
- (i32.const 0) ;; Pointer to storage key
- (i32.const 0) ;; Pointer to value
- (i32.load (i32.const 0)) ;; Size of value
- )
- )
-)
pallets/contracts/fixtures/set_rent.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/set_rent.wat
+++ /dev/null
@@ -1,105 +0,0 @@
-(module
- (import "seal0" "seal_transfer" (func $seal_transfer (param i32 i32 i32 i32) (result i32)))
- (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32)))
- (import "seal0" "seal_clear_storage" (func $seal_clear_storage (param i32)))
- (import "seal0" "seal_set_rent_allowance" (func $seal_set_rent_allowance (param i32 i32)))
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "env" "memory" (memory 1 1))
-
- ;; insert a value of 4 bytes into storage
- (func $call_0
- (call $seal_set_storage
- (i32.const 1)
- (i32.const 0)
- (i32.const 4)
- )
- )
-
- ;; remove the value inserted by call_1
- (func $call_1
- (call $seal_clear_storage
- (i32.const 1)
- )
- )
-
- ;; transfer 50 to CHARLIE
- (func $call_2
- (call $assert
- (i32.eq
- (call $seal_transfer (i32.const 136) (i32.const 32) (i32.const 100) (i32.const 8))
- (i32.const 0)
- )
- )
- )
-
- ;; do nothing
- (func $call_else)
-
- (func $assert (param i32)
- (block $ok
- (br_if $ok
- (get_local 0)
- )
- (unreachable)
- )
- )
-
- ;; Dispatch the call according to input size
- (func (export "call")
- (local $input_size i32)
- ;; 4 byte i32 for br_table followed by 32 byte destination for transfer
- (i32.store (i32.const 128) (i32.const 36))
- (call $seal_input (i32.const 132) (i32.const 128))
- (set_local $input_size
- (i32.load (i32.const 132))
- )
- (block $IF_ELSE
- (block $IF_2
- (block $IF_1
- (block $IF_0
- (br_table $IF_0 $IF_1 $IF_2 $IF_ELSE
- (get_local $input_size)
- )
- (unreachable)
- )
- (call $call_0)
- return
- )
- (call $call_1)
- return
- )
- (call $call_2)
- return
- )
- (call $call_else)
- )
-
- ;; Set into storage a 4 bytes value
- ;; Set call set_rent_allowance with input
- (func (export "deploy")
- (call $seal_set_storage
- (i32.const 0)
- (i32.const 0)
- (i32.const 4)
- )
- (i32.store (i32.const 128) (i32.const 64))
- (call $seal_input
- (i32.const 132)
- (i32.const 128)
- )
- (call $seal_set_rent_allowance
- (i32.const 132)
- (i32.load (i32.const 128))
- )
- )
-
- ;; Encoding of 10 in balance
- (data (i32.const 0) "\28")
-
- ;; encoding of 50 balance
- (data (i32.const 100) "\32")
-
- ;; [128, 132) size of seal input buffer
-
- ;; [132, inf) output buffer for seal input
-)
pallets/contracts/fixtures/storage_size.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/storage_size.wat
+++ /dev/null
@@ -1,68 +0,0 @@
-(module
- (import "seal0" "seal_get_storage" (func $seal_get_storage (param i32 i32 i32) (result i32)))
- (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32)))
- (import "seal0" "seal_input" (func $seal_input (param i32 i32)))
- (import "env" "memory" (memory 16 16))
-
- ;; [0, 32) storage key
- (data (i32.const 0) "\01")
-
- ;; [32, 36) buffer where input is copied (expected size of storage item)
-
- ;; [36, 40) size of the input buffer
- (data (i32.const 36) "\04")
-
- ;; [40, 44) size of buffer for seal_get_storage set to max
- (data (i32.const 40) "\FF\FF\FF\FF")
-
- ;; [44, inf) seal_get_storage buffer
-
- (func $assert (param i32)
- (block $ok
- (br_if $ok
- (get_local 0)
- )
- (unreachable)
- )
- )
-
- (func (export "call")
- (call $seal_input (i32.const 32) (i32.const 36))
-
- ;; assert input size == 4
- (call $assert
- (i32.eq
- (i32.load (i32.const 36))
- (i32.const 4)
- )
- )
-
- ;; place a garbage value in storage, the size of which is specified by the call input.
- (call $seal_set_storage
- (i32.const 0) ;; Pointer to storage key
- (i32.const 0) ;; Pointer to value
- (i32.load (i32.const 32)) ;; Size of value
- )
-
- (call $assert
- (i32.eq
- (call $seal_get_storage
- (i32.const 0) ;; Pointer to storage key
- (i32.const 44) ;; buffer where to copy result
- (i32.const 40) ;; pointer to size of buffer
- )
- (i32.const 0)
- )
- )
-
- (call $assert
- (i32.eq
- (i32.load (i32.const 40))
- (i32.load (i32.const 32))
- )
- )
- )
-
- (func (export "deploy"))
-
-)
pallets/contracts/fixtures/transfer_return_code.watdiffbeforeafterboth--- a/pallets/contracts/fixtures/transfer_return_code.wat
+++ /dev/null
@@ -1,34 +0,0 @@
-;; This transfers 100 balance to the zero account and copies the return code
-;; of this transfer to the output buffer.
-(module
- (import "seal0" "seal_transfer" (func $seal_transfer (param i32 i32 i32 i32) (result i32)))
- (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
- (import "env" "memory" (memory 1 1))
-
- ;; [0, 32) zero-adress
- (data (i32.const 0)
- "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
- "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
- )
-
- ;; [32, 40) 100 balance
- (data (i32.const 32) "\64\00\00\00\00\00\00\00")
-
- ;; [40, 44) here we store the return code of the transfer
-
- (func (export "deploy"))
-
- (func (export "call")
- (i32.store
- (i32.const 40)
- (call $seal_transfer
- (i32.const 0) ;; ptr to destination address
- (i32.const 32) ;; length of destination address
- (i32.const 32) ;; ptr to value to transfer
- (i32.const 8) ;; length of value to transfer
- )
- )
- ;; exit with success and take transfer return code to the output buffer
- (call $seal_return (i32.const 0) (i32.const 40) (i32.const 4))
- )
-)
pallets/contracts/proc-macro/Cargo.tomldiffbeforeafterboth--- a/pallets/contracts/proc-macro/Cargo.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[package]
-name = "pallet-contracts-proc-macro"
-version = "3.0.0"
-authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2018"
-license = "Apache-2.0"
-homepage = "https://substrate.dev"
-repository = "https://github.com/paritytech/substrate/"
-description = "Procedural macros used in pallet_contracts"
-
-[package.metadata.docs.rs]
-targets = ["x86_64-unknown-linux-gnu"]
-
-[lib]
-proc-macro = true
-
-[dependencies]
-proc-macro2 = "1"
-quote = "1"
-syn = "1"
-
-[dev-dependencies]
-
-[features]
-# If set the full output is generated. Do NOT set when generating for wasm runtime.
-full = []
pallets/contracts/proc-macro/src/lib.rsdiffbeforeafterboth--- a/pallets/contracts/proc-macro/src/lib.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Proc macros used in the contracts module.
-
-#![no_std]
-
-extern crate alloc;
-
-use proc_macro2::TokenStream;
-use quote::{quote, quote_spanned};
-use syn::spanned::Spanned;
-use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields, Ident};
-use alloc::string::ToString;
-
-/// This derives `Debug` for a struct where each field must be of some numeric type.
-/// It interprets each field as its represents some weight and formats it as times so that
-/// it is readable by humans.
-#[proc_macro_derive(WeightDebug)]
-pub fn derive_weight_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
- derive_debug(input, format_weight)
-}
-
-/// This is basically identical to the std libs Debug derive but without adding any
-/// bounds to existing generics.
-#[proc_macro_derive(ScheduleDebug)]
-pub fn derive_schedule_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
- derive_debug(input, format_default)
-}
-
-fn derive_debug(
- input: proc_macro::TokenStream,
- fmt: impl Fn(&Ident) -> TokenStream
-) -> proc_macro::TokenStream {
- let input = parse_macro_input!(input as DeriveInput);
- let name = &input.ident;
- let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
- let data = if let Data::Struct(data) = &input.data {
- data
- } else {
- return quote_spanned! {
- name.span() =>
- compile_error!("WeightDebug is only supported for structs.");
- }.into();
- };
-
- #[cfg(feature = "full")]
- let fields = iterate_fields(data, fmt);
-
- #[cfg(not(feature = "full"))]
- let fields = {
- drop(fmt);
- drop(data);
- TokenStream::new()
- };
-
- let tokens = quote! {
- impl #impl_generics core::fmt::Debug for #name #ty_generics #where_clause {
- fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- use ::sp_runtime::{FixedPointNumber, FixedU128 as Fixed};
- let mut formatter = formatter.debug_struct(stringify!(#name));
- #fields
- formatter.finish()
- }
- }
- };
-
- tokens.into()
-}
-
-/// This is only used then the `full` feature is activated.
-#[cfg(feature = "full")]
-fn iterate_fields(data: &DataStruct, fmt: impl Fn(&Ident) -> TokenStream) -> TokenStream {
- match &data.fields {
- Fields::Named(fields) => {
- let recurse = fields.named
- .iter()
- .filter_map(|f| {
- let name = f.ident.as_ref()?;
- if name.to_string().starts_with('_') {
- return None;
- }
- let value = fmt(name);
- let ret = quote_spanned!{ f.span() =>
- formatter.field(stringify!(#name), #value);
- };
- Some(ret)
- });
- quote!{
- #( #recurse )*
- }
- }
- Fields::Unnamed(fields) => quote_spanned!{
- fields.span() =>
- compile_error!("Unnamed fields are not supported")
- },
- Fields::Unit => quote!(),
- }
-}
-
-fn format_weight(field: &Ident) -> TokenStream {
- quote_spanned! { field.span() =>
- &if self.#field > 1_000_000_000 {
- format!(
- "{:.1?} ms",
- Fixed::saturating_from_rational(self.#field, 1_000_000_000).to_float()
- )
- } else if self.#field > 1_000_000 {
- format!(
- "{:.1?} µs",
- Fixed::saturating_from_rational(self.#field, 1_000_000).to_float()
- )
- } else if self.#field > 1_000 {
- format!(
- "{:.1?} ns",
- Fixed::saturating_from_rational(self.#field, 1_000).to_float()
- )
- } else {
- format!("{} ps", self.#field)
- }
- }
-}
-
-fn format_default(field: &Ident) -> TokenStream {
- quote_spanned! { field.span() =>
- &self.#field
- }
-}
pallets/contracts/rpc/Cargo.tomldiffbeforeafterboth--- a/pallets/contracts/rpc/Cargo.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-[package]
-name = "pallet-contracts-rpc"
-version = "3.0.0"
-authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2018"
-license = "Apache-2.0"
-homepage = "https://substrate.dev"
-repository = "https://github.com/paritytech/substrate/"
-description = "Node-specific RPC methods for interaction with contracts."
-readme = "README.md"
-
-[package.metadata.docs.rs]
-targets = ["x86_64-unknown-linux-gnu"]
-
-[dependencies]
-codec = { package = "parity-scale-codec", version = "2" }
-jsonrpc-core = "15"
-jsonrpc-core-client = "15"
-jsonrpc-derive = "15"
-serde = { version = "1", features = ["derive"] }
-
-# Substrate Dependencies
-pallet-contracts-primitives = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-pallet-contracts-rpc-runtime-api = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-api = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-blockchain = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-core = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-rpc = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-runtime = { version = "3.0.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-
-[dev-dependencies]
-serde_json = "1"
pallets/contracts/rpc/README.mddiffbeforeafterboth--- a/pallets/contracts/rpc/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Node-specific RPC methods for interaction with contracts.
-
-License: Apache-2.0
\ No newline at end of file
pallets/contracts/rpc/runtime-api/Cargo.tomldiffbeforeafterboth--- a/pallets/contracts/rpc/runtime-api/Cargo.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-[package]
-name = "pallet-contracts-rpc-runtime-api"
-version = "3.0.0"
-authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2018"
-license = "Apache-2.0"
-homepage = "https://substrate.dev"
-repository = "https://github.com/paritytech/substrate/"
-description = "Runtime API definition required by Contracts RPC extensions."
-readme = "README.md"
-
-[package.metadata.docs.rs]
-targets = ["x86_64-unknown-linux-gnu"]
-
-[dependencies]
-codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive"] }
-
-# Substrate Dependencies
-pallet-contracts-primitives = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-api = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-runtime = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-sp-std = { version = "3.0.0", default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.3' }
-
-[features]
-default = ["std"]
-std = [
- "sp-api/std",
- "codec/std",
- "sp-std/std",
- "sp-runtime/std",
- "pallet-contracts-primitives/std",
-]
pallets/contracts/rpc/runtime-api/README.mddiffbeforeafterboth--- a/pallets/contracts/rpc/runtime-api/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-Runtime API definition required by Contracts RPC extensions.
-
-This API should be imported and implemented by the runtime,
-of a node that wants to use the custom RPC extension
-adding Contracts access methods.
-
-License: Apache-2.0
\ No newline at end of file
pallets/contracts/rpc/runtime-api/src/lib.rsdiffbeforeafterboth--- a/pallets/contracts/rpc/runtime-api/src/lib.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Runtime API definition required by Contracts RPC extensions.
-//!
-//! This API should be imported and implemented by the runtime,
-//! of a node that wants to use the custom RPC extension
-//! adding Contracts access methods.
-
-#![cfg_attr(not(feature = "std"), no_std)]
-
-use codec::Codec;
-use sp_std::vec::Vec;
-use pallet_contracts_primitives::{
- ContractExecResult, GetStorageResult, RentProjectionResult, Code, ContractInstantiateResult,
-};
-
-sp_api::decl_runtime_apis! {
- /// The API to interact with contracts without using executive.
- pub trait ContractsApi<AccountId, Balance, BlockNumber, Hash> where
- AccountId: Codec,
- Balance: Codec,
- BlockNumber: Codec,
- Hash: Codec,
- {
- /// Perform a call from a specified account to a given contract.
- ///
- /// See [`pallet_contracts::Pallet::call`].
- fn call(
- origin: AccountId,
- dest: AccountId,
- value: Balance,
- gas_limit: u64,
- input_data: Vec<u8>,
- ) -> ContractExecResult;
-
- /// Instantiate a new contract.
- ///
- /// See [`pallet_contracts::Pallet::instantiate`].
- fn instantiate(
- origin: AccountId,
- endowment: Balance,
- gas_limit: u64,
- code: Code<Hash>,
- data: Vec<u8>,
- salt: Vec<u8>,
- ) -> ContractInstantiateResult<AccountId, BlockNumber>;
-
- /// Query a given storage key in a given contract.
- ///
- /// Returns `Ok(Some(Vec<u8>))` if the storage value exists under the given key in the
- /// specified account and `Ok(None)` if it doesn't. If the account specified by the address
- /// doesn't exist, or doesn't have a contract or if the contract is a tombstone, then `Err`
- /// is returned.
- fn get_storage(
- address: AccountId,
- key: [u8; 32],
- ) -> GetStorageResult;
-
- /// Returns the projected time a given contract will be able to sustain paying its rent.
- ///
- /// The returned projection is relevant for the current block, i.e. it is as if the contract
- /// was accessed at the current block.
- ///
- /// Returns `Err` if the contract is in a tombstone state or doesn't exist.
- fn rent_projection(address: AccountId) -> RentProjectionResult<BlockNumber>;
- }
-}
pallets/contracts/rpc/src/lib.rsdiffbeforeafterboth--- a/pallets/contracts/rpc/src/lib.rs
+++ /dev/null
@@ -1,434 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Node-specific RPC methods for interaction with contracts.
-
-use std::sync::Arc;
-
-use codec::Codec;
-use jsonrpc_core::{Error, ErrorCode, Result};
-use jsonrpc_derive::rpc;
-use pallet_contracts_primitives::RentProjection;
-use serde::{Deserialize, Serialize};
-use sp_api::ProvideRuntimeApi;
-use sp_blockchain::HeaderBackend;
-use sp_core::{Bytes, H256};
-use sp_rpc::number::NumberOrHex;
-use sp_runtime::{
- generic::BlockId,
- traits::{Block as BlockT, Header as HeaderT},
-};
-use std::convert::{TryFrom, TryInto};
-use pallet_contracts_primitives::{Code, ContractExecResult, ContractInstantiateResult};
-
-pub use pallet_contracts_rpc_runtime_api::ContractsApi as ContractsRuntimeApi;
-
-const RUNTIME_ERROR: i64 = 1;
-const CONTRACT_DOESNT_EXIST: i64 = 2;
-const CONTRACT_IS_A_TOMBSTONE: i64 = 3;
-
-pub type Weight = u64;
-
-/// A rough estimate of how much gas a decent hardware consumes per second,
-/// using native execution.
-/// This value is used to set the upper bound for maximal contract calls to
-/// prevent blocking the RPC for too long.
-///
-/// As 1 gas is equal to 1 weight we base this on the conducted benchmarks which
-/// determined runtime weights:
-/// https://github.com/paritytech/substrate/pull/5446
-const GAS_PER_SECOND: Weight = 1_000_000_000_000;
-
-/// The maximum amount of weight that the call and instantiate rpcs are allowed to consume.
-/// This puts a ceiling on the weight limit that is supplied to the rpc as an argument.
-const GAS_LIMIT: Weight = 5 * GAS_PER_SECOND;
-
-/// A private newtype for converting `ContractAccessError` into an RPC error.
-struct ContractAccessError(pallet_contracts_primitives::ContractAccessError);
-impl From<ContractAccessError> for Error {
- fn from(e: ContractAccessError) -> Error {
- use pallet_contracts_primitives::ContractAccessError::*;
- match e.0 {
- DoesntExist => Error {
- code: ErrorCode::ServerError(CONTRACT_DOESNT_EXIST),
- message: "The specified contract doesn't exist.".into(),
- data: None,
- },
- IsTombstone => Error {
- code: ErrorCode::ServerError(CONTRACT_IS_A_TOMBSTONE),
- message: "The contract is a tombstone and doesn't have any storage.".into(),
- data: None,
- },
- }
- }
-}
-
-/// A struct that encodes RPC parameters required for a call to a smart-contract.
-#[derive(Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-#[serde(deny_unknown_fields)]
-pub struct CallRequest<AccountId> {
- origin: AccountId,
- dest: AccountId,
- value: NumberOrHex,
- gas_limit: NumberOrHex,
- input_data: Bytes,
-}
-
-/// A struct that encodes RPC parameters required to instantiate a new smart-contract.
-#[derive(Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-#[serde(deny_unknown_fields)]
-pub struct InstantiateRequest<AccountId, Hash> {
- origin: AccountId,
- endowment: NumberOrHex,
- gas_limit: NumberOrHex,
- code: Code<Hash>,
- data: Bytes,
- salt: Bytes,
-}
-
-/// Contracts RPC methods.
-#[rpc]
-pub trait ContractsApi<BlockHash, BlockNumber, AccountId, Balance, Hash> {
- /// Executes a call to a contract.
- ///
- /// This call is performed locally without submitting any transactions. Thus executing this
- /// won't change any state. Nonetheless, the calling state-changing contracts is still possible.
- ///
- /// This method is useful for calling getter-like methods on contracts.
- #[rpc(name = "contracts_call")]
- fn call(
- &self,
- call_request: CallRequest<AccountId>,
- at: Option<BlockHash>,
- ) -> Result<ContractExecResult>;
-
- /// Instantiate a new contract.
- ///
- /// This call is performed locally without submitting any transactions. Thus the contract
- /// is not actually created.
- ///
- /// This method is useful for UIs to dry-run contract instantiations.
- #[rpc(name = "contracts_instantiate")]
- fn instantiate(
- &self,
- instantiate_request: InstantiateRequest<AccountId, Hash>,
- at: Option<BlockHash>,
- ) -> Result<ContractInstantiateResult<AccountId, BlockNumber>>;
-
- /// Returns the value under a specified storage `key` in a contract given by `address` param,
- /// or `None` if it is not set.
- #[rpc(name = "contracts_getStorage")]
- fn get_storage(
- &self,
- address: AccountId,
- key: H256,
- at: Option<BlockHash>,
- ) -> Result<Option<Bytes>>;
-
- /// Returns the projected time a given contract will be able to sustain paying its rent.
- ///
- /// The returned projection is relevant for the given block, i.e. it is as if the contract was
- /// accessed at the beginning of that block.
- ///
- /// Returns `None` if the contract is exempted from rent.
- #[rpc(name = "contracts_rentProjection")]
- fn rent_projection(
- &self,
- address: AccountId,
- at: Option<BlockHash>,
- ) -> Result<Option<BlockNumber>>;
-}
-
-/// An implementation of contract specific RPC methods.
-pub struct Contracts<C, B> {
- client: Arc<C>,
- _marker: std::marker::PhantomData<B>,
-}
-
-impl<C, B> Contracts<C, B> {
- /// Create new `Contracts` with the given reference to the client.
- pub fn new(client: Arc<C>) -> Self {
- Contracts {
- client,
- _marker: Default::default(),
- }
- }
-}
-impl<C, Block, AccountId, Balance, Hash>
- ContractsApi<
- <Block as BlockT>::Hash,
- <<Block as BlockT>::Header as HeaderT>::Number,
- AccountId,
- Balance,
- Hash,
- > for Contracts<C, Block>
-where
- Block: BlockT,
- C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
- C::Api: ContractsRuntimeApi<
- Block,
- AccountId,
- Balance,
- <<Block as BlockT>::Header as HeaderT>::Number,
- Hash,
- >,
- AccountId: Codec,
- Balance: Codec + TryFrom<NumberOrHex>,
- Hash: Codec,
-{
- fn call(
- &self,
- call_request: CallRequest<AccountId>,
- at: Option<<Block as BlockT>::Hash>,
- ) -> Result<ContractExecResult> {
- let api = self.client.runtime_api();
- let at = BlockId::hash(at.unwrap_or_else(||
- // If the block hash is not supplied assume the best block.
- self.client.info().best_hash));
-
- let CallRequest {
- origin,
- dest,
- value,
- gas_limit,
- input_data,
- } = call_request;
-
- let value: Balance = decode_hex(value, "balance")?;
- let gas_limit: Weight = decode_hex(gas_limit, "weight")?;
- limit_gas(gas_limit)?;
-
- let exec_result = api
- .call(&at, origin, dest, value, gas_limit, input_data.to_vec())
- .map_err(runtime_error_into_rpc_err)?;
-
- Ok(exec_result)
- }
-
- fn instantiate(
- &self,
- instantiate_request: InstantiateRequest<AccountId, Hash>,
- at: Option<<Block as BlockT>::Hash>,
- ) -> Result<ContractInstantiateResult<AccountId, <<Block as BlockT>::Header as HeaderT>::Number>> {
- let api = self.client.runtime_api();
- let at = BlockId::hash(at.unwrap_or_else(||
- // If the block hash is not supplied assume the best block.
- self.client.info().best_hash));
-
- let InstantiateRequest {
- origin,
- endowment,
- gas_limit,
- code,
- data,
- salt,
- } = instantiate_request;
-
- let endowment: Balance = decode_hex(endowment, "balance")?;
- let gas_limit: Weight = decode_hex(gas_limit, "weight")?;
- limit_gas(gas_limit)?;
-
- let exec_result = api
- .instantiate(&at, origin, endowment, gas_limit, code, data.to_vec(), salt.to_vec())
- .map_err(runtime_error_into_rpc_err)?;
-
- Ok(exec_result)
- }
-
- fn get_storage(
- &self,
- address: AccountId,
- key: H256,
- at: Option<<Block as BlockT>::Hash>,
- ) -> Result<Option<Bytes>> {
- let api = self.client.runtime_api();
- let at = BlockId::hash(at.unwrap_or_else(||
- // If the block hash is not supplied assume the best block.
- self.client.info().best_hash));
-
- let result = api
- .get_storage(&at, address, key.into())
- .map_err(runtime_error_into_rpc_err)?
- .map_err(ContractAccessError)?
- .map(Bytes);
-
- Ok(result)
- }
-
- fn rent_projection(
- &self,
- address: AccountId,
- at: Option<<Block as BlockT>::Hash>,
- ) -> Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>> {
- let api = self.client.runtime_api();
- let at = BlockId::hash(at.unwrap_or_else(||
- // If the block hash is not supplied assume the best block.
- self.client.info().best_hash));
-
- let result = api
- .rent_projection(&at, address)
- .map_err(runtime_error_into_rpc_err)?
- .map_err(ContractAccessError)?;
-
- Ok(match result {
- RentProjection::NoEviction => None,
- RentProjection::EvictionAt(block_num) => Some(block_num),
- })
- }
-}
-
-/// Converts a runtime trap into an RPC error.
-fn runtime_error_into_rpc_err(err: impl std::fmt::Debug) -> Error {
- Error {
- code: ErrorCode::ServerError(RUNTIME_ERROR),
- message: "Runtime error".into(),
- data: Some(format!("{:?}", err).into()),
- }
-}
-
-fn decode_hex<H: std::fmt::Debug + Copy, T: TryFrom<H>>(from: H, name: &str) -> Result<T> {
- from.try_into().map_err(|_| Error {
- code: ErrorCode::InvalidParams,
- message: format!("{:?} does not fit into the {} type", from, name),
- data: None,
- })
-}
-
-fn limit_gas(gas_limit: Weight) -> Result<()> {
- if gas_limit > GAS_LIMIT {
- Err(Error {
- code: ErrorCode::InvalidParams,
- message: format!(
- "Requested gas limit is greater than maximum allowed: {} > {}",
- gas_limit, GAS_LIMIT
- ),
- data: None,
- })
- } else {
- Ok(())
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use sp_core::U256;
-
- fn trim(json: &str) -> String {
- json.chars().filter(|c| !c.is_whitespace()).collect()
- }
-
- #[test]
- fn call_request_should_serialize_deserialize_properly() {
- type Req = CallRequest<String>;
- let req: Req = serde_json::from_str(r#"
- {
- "origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
- "dest": "5DRakbLVnjVrW6niwLfHGW24EeCEvDAFGEXrtaYS5M4ynoom",
- "value": "0x112210f4B16c1cb1",
- "gasLimit": 1000000000000,
- "inputData": "0x8c97db39"
- }
- "#).unwrap();
- assert_eq!(req.gas_limit.into_u256(), U256::from(0xe8d4a51000u64));
- assert_eq!(req.value.into_u256(), U256::from(1234567890987654321u128));
- }
-
- #[test]
- fn instantiate_request_should_serialize_deserialize_properly() {
- type Req = InstantiateRequest<String, String>;
- let req: Req = serde_json::from_str(r#"
- {
- "origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
- "endowment": "0x88",
- "gasLimit": 42,
- "code": { "existing": "0x1122" },
- "data": "0x4299",
- "salt": "0x9988"
- }
- "#).unwrap();
-
- assert_eq!(req.origin, "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL");
- assert_eq!(req.endowment.into_u256(), 0x88.into());
- assert_eq!(req.gas_limit.into_u256(), 42.into());
- assert_eq!(&*req.data, [0x42, 0x99].as_ref());
- assert_eq!(&*req.salt, [0x99, 0x88].as_ref());
- let code = match req.code {
- Code::Existing(hash) => hash,
- _ => panic!("json encoded an existing hash"),
- };
- assert_eq!(&code, "0x1122");
- }
-
- #[test]
- fn call_result_should_serialize_deserialize_properly() {
- fn test(expected: &str) {
- let res: ContractExecResult = serde_json::from_str(expected).unwrap();
- let actual = serde_json::to_string(&res).unwrap();
- assert_eq!(actual, trim(expected).as_str());
- }
- test(r#"{
- "gasConsumed": 5000,
- "debugMessage": "0x68656c704f6b",
- "result": {
- "Ok": {
- "flags": 5,
- "data": "0x1234"
- }
- }
- }"#);
- test(r#"{
- "gasConsumed": 3400,
- "debugMessage": "0x68656c70457272",
- "result": {
- "Err": "BadOrigin"
- }
- }"#);
- }
-
- #[test]
- fn instantiate_result_should_serialize_deserialize_properly() {
- fn test(expected: &str) {
- let res: ContractInstantiateResult<String, u64> = serde_json::from_str(expected).unwrap();
- let actual = serde_json::to_string(&res).unwrap();
- assert_eq!(actual, trim(expected).as_str());
- }
- test(r#"{
- "gasConsumed": 5000,
- "debugMessage": "0x68656c704f6b",
- "result": {
- "Ok": {
- "result": {
- "flags": 5,
- "data": "0x1234"
- },
- "accountId": "5CiPP",
- "rentProjection": null
- }
- }
- }"#);
- test(r#"{
- "gasConsumed": 3400,
- "debugMessage": "0x68656c70457272",
- "result": {
- "Err": "BadOrigin"
- }
- }"#);
- }
-}
pallets/contracts/src/benchmarking/code.rsdiffbeforeafterboth--- a/pallets/contracts/src/benchmarking/code.rs
+++ /dev/null
@@ -1,526 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Functions to procedurally construct contract code used for benchmarking.
-//!
-//! In order to be able to benchmark events that are triggered by contract execution
-//! (API calls into seal, individual instructions), we need to generate contracts that
-//! perform those events. Because those contracts can get very big we cannot simply define
-//! them as text (.wat) as this will be too slow and consume too much memory. Therefore
-//! we define this simple definition of a contract that can be passed to `create_code` that
-//! compiles it down into a `WasmModule` that can be used as a contract's code.
-
-use crate::{Config, CurrentSchedule};
-use parity_wasm::elements::{
- Instruction, Instructions, FuncBody, ValueType, BlockType, Section, CustomSection,
-};
-use pwasm_utils::stack_height::inject_limiter;
-use sp_core::crypto::UncheckedFrom;
-use sp_runtime::traits::Hash;
-use sp_sandbox::{EnvironmentDefinitionBuilder, Memory};
-use sp_std::{prelude::*, convert::TryFrom, borrow::ToOwned};
-
-/// Pass to `create_code` in order to create a compiled `WasmModule`.
-///
-/// This exists to have a more declarative way to describe a wasm module than to use
-/// parity-wasm directly. It is tailored to fit the structure of contracts that are
-/// needed for benchmarking.
-#[derive(Default)]
-pub struct ModuleDefinition {
- /// Imported memory attached to the module. No memory is imported if `None`.
- pub memory: Option<ImportedMemory>,
- /// Initializers for the imported memory.
- pub data_segments: Vec<DataSegment>,
- /// Creates the supplied amount of i64 mutable globals initialized with random values.
- pub num_globals: u32,
- /// List of functions that the module should import. They start with index 0.
- pub imported_functions: Vec<ImportedFunction>,
- /// Function body of the exported `deploy` function. Body is empty if `None`.
- /// Its index is `imported_functions.len()`.
- pub deploy_body: Option<FuncBody>,
- /// Function body of the exported `call` function. Body is empty if `None`.
- /// Its index is `imported_functions.len() + 1`.
- pub call_body: Option<FuncBody>,
- /// Function body of a non-exported function with index `imported_functions.len() + 2`.
- pub aux_body: Option<FuncBody>,
- /// The amount of I64 arguments the aux function should have.
- pub aux_arg_num: u32,
- /// If set to true the stack height limiter is injected into the the module. This is
- /// needed for instruction debugging because the cost of executing the stack height
- /// instrumentation should be included in the costs for the individual instructions
- /// that cause more metering code (only call).
- pub inject_stack_metering: bool,
- /// Create a table containing function pointers.
- pub table: Option<TableSegment>,
- /// Create a section named "dummy" of the specified size. This is useful in order to
- /// benchmark the overhead of loading and storing codes of specified sizes. The dummy
- /// section only contributes to the size of the contract but does not affect execution.
- pub dummy_section: u32,
-}
-
-pub struct TableSegment {
- /// How many elements should be created inside the table.
- pub num_elements: u32,
- /// The function index with which all table elements should be initialized.
- pub function_index: u32,
-}
-
-pub struct DataSegment {
- pub offset: u32,
- pub value: Vec<u8>,
-}
-
-#[derive(Clone)]
-pub struct ImportedMemory {
- pub min_pages: u32,
- pub max_pages: u32,
-}
-
-impl ImportedMemory {
- pub fn max<T: Config>() -> Self
- where
- T: Config,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
- {
- let pages = max_pages::<T>();
- Self {
- min_pages: pages,
- max_pages: pages,
- }
- }
-}
-
-pub struct ImportedFunction {
- pub name: &'static str,
- pub params: Vec<ValueType>,
- pub return_type: Option<ValueType>,
-}
-
-/// A wasm module ready to be put on chain.
-#[derive(Clone)]
-pub struct WasmModule<T: Config> {
- pub code: Vec<u8>,
- pub hash: <T::Hashing as Hash>::Output,
- memory: Option<ImportedMemory>,
-}
-
-impl<T: Config> From<ModuleDefinition> for WasmModule<T>
-where
- T: Config,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
-{
- fn from(def: ModuleDefinition) -> Self {
- // internal functions start at that offset.
- let func_offset = u32::try_from(def.imported_functions.len()).unwrap();
-
- // Every contract must export "deploy" and "call" functions
- let mut contract = parity_wasm::builder::module()
- // deploy function (first internal function)
- .function()
- .signature()
- .build()
- .with_body(
- def.deploy_body
- .unwrap_or_else(|| FuncBody::new(Vec::new(), Instructions::empty())),
- )
- .build()
- // call function (second internal function)
- .function()
- .signature()
- .build()
- .with_body(
- def.call_body
- .unwrap_or_else(|| FuncBody::new(Vec::new(), Instructions::empty())),
- )
- .build()
- .export()
- .field("deploy")
- .internal()
- .func(func_offset)
- .build()
- .export()
- .field("call")
- .internal()
- .func(func_offset + 1)
- .build();
-
- // If specified we add an additional internal function
- if let Some(body) = def.aux_body {
- let mut signature = contract.function().signature();
- for _ in 0..def.aux_arg_num {
- signature = signature.with_param(ValueType::I64);
- }
- contract = signature.build().with_body(body).build();
- }
-
- // Grant access to linear memory.
- if let Some(memory) = &def.memory {
- contract = contract
- .import()
- .module("env")
- .field("memory")
- .external()
- .memory(memory.min_pages, Some(memory.max_pages))
- .build();
- }
-
- // Import supervisor functions. They start with idx 0.
- for func in def.imported_functions {
- let sig = parity_wasm::builder::signature()
- .with_params(func.params)
- .with_results(func.return_type.into_iter().collect())
- .build_sig();
- let sig = contract.push_signature(sig);
- contract = contract
- .import()
- .module("seal0")
- .field(func.name)
- .with_external(parity_wasm::elements::External::Function(sig))
- .build();
- }
-
- // Initialize memory
- for data in def.data_segments {
- contract = contract
- .data()
- .offset(Instruction::I32Const(data.offset as i32))
- .value(data.value)
- .build()
- }
-
- // Add global variables
- if def.num_globals > 0 {
- use rand::{prelude::*, distributions::Standard};
- let rng = rand_pcg::Pcg32::seed_from_u64(3112244599778833558);
- for val in rng.sample_iter(Standard).take(def.num_globals as usize) {
- contract = contract
- .global()
- .value_type()
- .i64()
- .mutable()
- .init_expr(Instruction::I64Const(val))
- .build()
- }
- }
-
- // Add function pointer table
- if let Some(table) = def.table {
- contract = contract
- .table()
- .with_min(table.num_elements)
- .with_max(Some(table.num_elements))
- .with_element(0, vec![table.function_index; table.num_elements as usize])
- .build();
- }
-
- // Add the dummy section
- if def.dummy_section > 0 {
- contract = contract.with_section(Section::Custom(CustomSection::new(
- "dummy".to_owned(),
- vec![42; def.dummy_section as usize],
- )));
- }
-
- let mut code = contract.build();
-
- // Inject stack height metering
- if def.inject_stack_metering {
- code = inject_limiter(code, <CurrentSchedule<T>>::get().limits.stack_height).unwrap();
- }
-
- let code = code.to_bytes().unwrap();
- let hash = T::Hashing::hash(&code);
- Self {
- code,
- hash,
- memory: def.memory,
- }
- }
-}
-
-impl<T: Config> WasmModule<T>
-where
- T: Config,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
-{
- /// Creates a wasm module with an empty `call` and `deploy` function and nothing else.
- pub fn dummy() -> Self {
- ModuleDefinition::default().into()
- }
-
- /// Same as `dummy` but with maximum sized linear memory and a dummy section of specified size.
- pub fn dummy_with_bytes(dummy_bytes: u32) -> Self {
- ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- dummy_section: dummy_bytes,
- ..Default::default()
- }
- .into()
- }
-
- /// Creates a wasm module of `target_bytes` size. Used to benchmark the performance of
- /// `instantiate_with_code` for different sizes of wasm modules. The generated module maximizes
- /// instrumentation runtime by nesting blocks as deeply as possible given the byte budget.
- pub fn sized(target_bytes: u32) -> Self {
- use parity_wasm::elements::Instruction::{If, I32Const, Return, End};
- // Base size of a contract is 63 bytes and each expansion adds 6 bytes.
- // We do one expansion less to account for the code section and function body
- // size fields inside the binary wasm module representation which are leb128 encoded
- // and therefore grow in size when the contract grows. We are not allowed to overshoot
- // because of the maximum code size that is enforced by `instantiate_with_code`.
- let expansions = (target_bytes.saturating_sub(63) / 6).saturating_sub(1);
- const EXPANSION: [Instruction; 4] = [I32Const(0), If(BlockType::NoResult), Return, End];
- ModuleDefinition {
- call_body: Some(body::repeated(expansions, &EXPANSION)),
- memory: Some(ImportedMemory::max::<T>()),
- ..Default::default()
- }
- .into()
- }
-
- /// Creates a wasm module that calls the imported function named `getter_name` `repeat`
- /// times. The imported function is expected to have the "getter signature" of
- /// (out_ptr: u32, len_ptr: u32) -> ().
- pub fn getter(getter_name: &'static str, repeat: u32) -> Self {
- let pages = max_pages::<T>();
- ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: getter_name,
- params: vec![ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- // Write the output buffer size. The output size will be overwritten by the
- // supervisor with the real size when calling the getter. Since this size does not
- // change between calls it suffices to start with an initial value and then just
- // leave as whatever value was written there.
- data_segments: vec![DataSegment {
- offset: 0,
- value: (pages * 64 * 1024 - 4).to_le_bytes().to_vec(),
- }],
- call_body: Some(body::repeated(
- repeat,
- &[
- Instruction::I32Const(4), // ptr where to store output
- Instruction::I32Const(0), // ptr to length
- Instruction::Call(0), // call the imported function
- ],
- )),
- ..Default::default()
- }
- .into()
- }
-
- /// Creates a wasm module that calls the imported hash function named `name` `repeat` times
- /// with an input of size `data_size`. Hash functions have the signature
- /// (input_ptr: u32, input_len: u32, output_ptr: u32) -> ()
- pub fn hasher(name: &'static str, repeat: u32, data_size: u32) -> Self {
- ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name,
- params: vec![ValueType::I32, ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- call_body: Some(body::repeated(
- repeat,
- &[
- Instruction::I32Const(0), // input_ptr
- Instruction::I32Const(data_size as i32), // input_len
- Instruction::I32Const(0), // output_ptr
- Instruction::Call(0),
- ],
- )),
- ..Default::default()
- }
- .into()
- }
-
- /// Creates a memory instance for use in a sandbox with dimensions declared in this module
- /// and adds it to `env`. A reference to that memory is returned so that it can be used to
- /// access the memory contents from the supervisor.
- pub fn add_memory<S>(&self, env: &mut EnvironmentDefinitionBuilder<S>) -> Option<Memory> {
- let memory = if let Some(memory) = &self.memory {
- memory
- } else {
- return None;
- };
- let memory = Memory::new(memory.min_pages, Some(memory.max_pages)).unwrap();
- env.add_memory("env", "memory", memory.clone());
- Some(memory)
- }
-
- pub fn unary_instr(instr: Instruction, repeat: u32) -> Self {
- use body::DynInstr::{RandomI64Repeated, Regular};
- ModuleDefinition {
- call_body: Some(body::repeated_dyn(
- repeat,
- vec![
- RandomI64Repeated(1),
- Regular(instr),
- Regular(Instruction::Drop),
- ],
- )),
- ..Default::default()
- }
- .into()
- }
-
- pub fn binary_instr(instr: Instruction, repeat: u32) -> Self {
- use body::DynInstr::{RandomI64Repeated, Regular};
- ModuleDefinition {
- call_body: Some(body::repeated_dyn(
- repeat,
- vec![
- RandomI64Repeated(2),
- Regular(instr),
- Regular(Instruction::Drop),
- ],
- )),
- ..Default::default()
- }
- .into()
- }
-}
-
-/// Mechanisms to generate a function body that can be used inside a `ModuleDefinition`.
-pub mod body {
- use super::*;
-
- /// When generating contract code by repeating a wasm sequence, it's sometimes necessary
- /// to change those instructions on each repetition. The variants of this enum describe
- /// various ways in which this can happen.
- pub enum DynInstr {
- /// Insert the associated instruction.
- Regular(Instruction),
- /// Insert a I32Const with incrementing value for each insertion.
- /// (start_at, increment_by)
- Counter(u32, u32),
- /// Insert a I32Const with a random value in [low, high) not divisible by two.
- /// (low, high)
- RandomUnaligned(u32, u32),
- /// Insert a I32Const with a random value in [low, high).
- /// (low, high)
- RandomI32(i32, i32),
- /// Insert the specified amount of I32Const with a random value.
- RandomI32Repeated(usize),
- /// Insert the specified amount of I64Const with a random value.
- RandomI64Repeated(usize),
- /// Insert a GetLocal with a random offset in [low, high).
- /// (low, high)
- RandomGetLocal(u32, u32),
- /// Insert a SetLocal with a random offset in [low, high).
- /// (low, high)
- RandomSetLocal(u32, u32),
- /// Insert a TeeLocal with a random offset in [low, high).
- /// (low, high)
- RandomTeeLocal(u32, u32),
- /// Insert a GetGlobal with a random offset in [low, high).
- /// (low, high)
- RandomGetGlobal(u32, u32),
- /// Insert a SetGlobal with a random offset in [low, high).
- /// (low, high)
- RandomSetGlobal(u32, u32),
- }
-
- pub fn plain(instructions: Vec<Instruction>) -> FuncBody {
- FuncBody::new(Vec::new(), Instructions::new(instructions))
- }
-
- pub fn repeated(repetitions: u32, instructions: &[Instruction]) -> FuncBody {
- let instructions = Instructions::new(
- instructions
- .iter()
- .cycle()
- .take(instructions.len() * usize::try_from(repetitions).unwrap())
- .cloned()
- .chain(sp_std::iter::once(Instruction::End))
- .collect(),
- );
- FuncBody::new(Vec::new(), instructions)
- }
-
- pub fn repeated_dyn(repetitions: u32, mut instructions: Vec<DynInstr>) -> FuncBody {
- use rand::{prelude::*, distributions::Standard};
-
- // We do not need to be secure here.
- let mut rng = rand_pcg::Pcg32::seed_from_u64(8446744073709551615);
-
- // We need to iterate over indices because we cannot cycle over mutable references
- let body = (0..instructions.len())
- .cycle()
- .take(instructions.len() * usize::try_from(repetitions).unwrap())
- .flat_map(|idx| match &mut instructions[idx] {
- DynInstr::Regular(instruction) => vec![instruction.clone()],
- DynInstr::Counter(offset, increment_by) => {
- let current = *offset;
- *offset += *increment_by;
- vec![Instruction::I32Const(current as i32)]
- }
- DynInstr::RandomUnaligned(low, high) => {
- let unaligned = rng.gen_range(*low..*high) | 1;
- vec![Instruction::I32Const(unaligned as i32)]
- }
- DynInstr::RandomI32(low, high) => {
- vec![Instruction::I32Const(rng.gen_range(*low..*high))]
- }
- DynInstr::RandomI32Repeated(num) => (&mut rng)
- .sample_iter(Standard)
- .take(*num)
- .map(|val| Instruction::I32Const(val))
- .collect(),
- DynInstr::RandomI64Repeated(num) => (&mut rng)
- .sample_iter(Standard)
- .take(*num)
- .map(|val| Instruction::I64Const(val))
- .collect(),
- DynInstr::RandomGetLocal(low, high) => {
- vec![Instruction::GetLocal(rng.gen_range(*low..*high))]
- }
- DynInstr::RandomSetLocal(low, high) => {
- vec![Instruction::SetLocal(rng.gen_range(*low..*high))]
- }
- DynInstr::RandomTeeLocal(low, high) => {
- vec![Instruction::TeeLocal(rng.gen_range(*low..*high))]
- }
- DynInstr::RandomGetGlobal(low, high) => {
- vec![Instruction::GetGlobal(rng.gen_range(*low..*high))]
- }
- DynInstr::RandomSetGlobal(low, high) => {
- vec![Instruction::SetGlobal(rng.gen_range(*low..*high))]
- }
- })
- .chain(sp_std::iter::once(Instruction::End))
- .collect();
- FuncBody::new(Vec::new(), Instructions::new(body))
- }
-
- /// Replace the locals of the supplied `body` with `num` i64 locals.
- pub fn inject_locals(body: &mut FuncBody, num: u32) {
- use parity_wasm::elements::Local;
- *body.locals_mut() = (0..num).map(|i| Local::new(i, ValueType::I64)).collect()
- }
-}
-
-/// The maximum amount of pages any contract is allowed to have according to the current `Schedule`.
-pub fn max_pages<T: Config>() -> u32
-where
- T: Config,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
-{
- <CurrentSchedule<T>>::get().limits.memory_pages
-}
pallets/contracts/src/benchmarking/mod.rsdiffbeforeafterboth--- a/pallets/contracts/src/benchmarking/mod.rs
+++ /dev/null
@@ -1,2537 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Benchmarks for the contracts pallet
-
-#![cfg(feature = "runtime-benchmarks")]
-
-mod code;
-mod sandbox;
-
-use crate::{
- *, Pallet as Contracts,
- exec::StorageKey,
- rent::Rent,
- schedule::{API_BENCHMARK_BATCH_SIZE, INSTR_BENCHMARK_BATCH_SIZE},
- storage::Storage,
-};
-use self::{
- code::{
- body::{self, DynInstr::*},
- ModuleDefinition, DataSegment, ImportedMemory, ImportedFunction, WasmModule,
- },
- sandbox::Sandbox,
-};
-use codec::Encode;
-use frame_benchmarking::{benchmarks, account, whitelisted_caller, impl_benchmark_test_suite};
-use frame_system::{Pallet as System, RawOrigin};
-use parity_wasm::elements::{Instruction, ValueType, BlockType};
-use sp_runtime::traits::{Hash, Bounded, Zero};
-use sp_std::{
- default::Default,
- convert::{TryInto},
- vec::Vec,
- vec,
-};
-use pallet_contracts_primitives::RentProjection;
-use frame_support::weights::Weight;
-
-/// How many batches we do per API benchmark.
-const API_BENCHMARK_BATCHES: u32 = 20;
-
-/// How many batches we do per Instruction benchmark.
-const INSTR_BENCHMARK_BATCHES: u32 = 1;
-
-/// An instantiated and deployed contract.
-struct Contract<T: Config> {
- caller: T::AccountId,
- account_id: T::AccountId,
- addr: <T::Lookup as StaticLookup>::Source,
- endowment: BalanceOf<T>,
- code_hash: <T::Hashing as Hash>::Output,
-}
-
-/// Describes how much balance should be transferred on instantiate from the caller.
-enum Endow {
- /// Endow the contract with a maximum amount of balance. This value is described by
- /// `Contract::max_endowment`.
- Max,
- /// Endow so that the amount of balance that is transferred is big but not so big
- /// to offset the rent payment. This is needed in order to test rent collection.
- CollectRent,
-}
-
-impl Endow {
- /// The maximum amount of balance a caller can transfer without being brought below
- /// the existential deposit. This assumes that every caller is funded with the amount
- /// returned by `caller_funding`.
- fn max<T: Config>() -> BalanceOf<T> {
- caller_funding::<T>().saturating_sub(T::Currency::minimum_balance())
- }
-}
-
-impl<T: Config> Contract<T>
-where
- T: Config,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
-{
- /// Create new contract and use a default account id as instantiator.
- fn new(
- module: WasmModule<T>,
- data: Vec<u8>,
- endowment: Endow,
- ) -> Result<Contract<T>, &'static str> {
- Self::with_index(0, module, data, endowment)
- }
-
- /// Create new contract and use an account id derived from the supplied index as instantiator.
- fn with_index(
- index: u32,
- module: WasmModule<T>,
- data: Vec<u8>,
- endowment: Endow,
- ) -> Result<Contract<T>, &'static str> {
- Self::with_caller(account("instantiator", index, 0), module, data, endowment)
- }
-
- /// Create new contract and use the supplied `caller` as instantiator.
- fn with_caller(
- caller: T::AccountId,
- module: WasmModule<T>,
- data: Vec<u8>,
- endowment: Endow,
- ) -> Result<Contract<T>, &'static str> {
- let (storage_size, endowment) = match endowment {
- Endow::CollectRent => {
- // storage_size cannot be zero because otherwise a contract that is just above
- // the subsistence threshold does not pay rent given a large enough subsistence
- // threshold. But we need rent payments to occur in order to benchmark for worst cases.
- let storage_size = u32::max_value() / 10;
-
- // Endowment should be large but not as large to inhibit rent payments.
- // Balance will only cover half the storage
- let endowment = T::DepositPerStorageByte::get()
- .saturating_mul(<BalanceOf<T>>::from(storage_size) / 2u32.into())
- .saturating_add(T::DepositPerContract::get());
-
- (storage_size, endowment)
- }
- Endow::Max => (0u32.into(), Endow::max::<T>()),
- };
- T::Currency::make_free_balance_be(&caller, caller_funding::<T>());
- let salt = vec![0xff];
- let addr = Contracts::<T>::contract_address(&caller, &module.hash, &salt);
-
- // The default block number is zero. The benchmarking system bumps the block number
- // to one for the benchmarking closure when it is set to zero. In order to prevent this
- // undesired implicit bump (which messes with rent collection), we do the bump ourselves
- // in the setup closure so that both the instantiate and subsequent call are run with the
- // same block number.
- System::<T>::set_block_number(1u32.into());
-
- Contracts::<T>::store_code_raw(module.code)?;
- Contracts::<T>::instantiate(
- RawOrigin::Signed(caller.clone()).into(),
- endowment,
- Weight::max_value(),
- module.hash,
- data,
- salt,
- )?;
-
- let result = Contract {
- caller,
- account_id: addr.clone(),
- addr: T::Lookup::unlookup(addr),
- endowment,
- code_hash: module.hash.clone(),
- };
-
- let mut contract = result.alive_info()?;
- contract.storage_size = storage_size;
- ContractInfoOf::<T>::insert(&result.account_id, ContractInfo::Alive(contract));
-
- Ok(result)
- }
-
- /// Store the supplied storage items into this contracts storage.
- fn store(&self, items: &Vec<(StorageKey, Vec<u8>)>) -> Result<(), &'static str> {
- let info = self.alive_info()?;
- for item in items {
- Storage::<T>::write(
- &self.account_id,
- &info.trie_id,
- &item.0,
- Some(item.1.clone()),
- )
- .map_err(|_| "Failed to write storage to restoration dest")?;
- }
- Ok(())
- }
-
- /// Get the `AliveContractInfo` of the `addr` or an error if it is no longer alive.
- fn address_alive_info(addr: &T::AccountId) -> Result<AliveContractInfo<T>, &'static str> {
- ContractInfoOf::<T>::get(addr)
- .and_then(|c| c.get_alive())
- .ok_or("Expected contract to be alive at this point.")
- }
-
- /// Get the `AliveContractInfo` of this contract or an error if it is no longer alive.
- fn alive_info(&self) -> Result<AliveContractInfo<T>, &'static str> {
- Self::address_alive_info(&self.account_id)
- }
-
- /// Return an error if this contract is no tombstone.
- fn ensure_tombstone(&self) -> Result<(), &'static str> {
- ContractInfoOf::<T>::get(&self.account_id)
- .and_then(|c| c.get_tombstone())
- .ok_or("Expected contract to be a tombstone at this point.")
- .map(|_| ())
- }
-
- /// Get the block number when this contract will be evicted. Returns an error when
- /// the rent collection won't happen because the contract has to much endowment.
- fn eviction_at(&self) -> Result<T::BlockNumber, &'static str> {
- let projection = Rent::<T, PrefabWasmModule<T>>::compute_projection(&self.account_id)
- .map_err(|_| "Invalid acc for rent")?;
- match projection {
- RentProjection::EvictionAt(at) => Ok(at),
- _ => Err("Account does not pay rent.")?,
- }
- }
-}
-
-/// A `Contract` that contains some storage items.
-///
-/// This is used to benchmark contract destruction and resurection. Those operations'
-/// weight depend on the amount of storage accumulated.
-struct ContractWithStorage<T: Config> {
- /// The contract that was evicted.
- contract: Contract<T>,
- /// The storage the contract held when it was avicted.
- storage: Vec<(StorageKey, Vec<u8>)>,
-}
-
-impl<T: Config> ContractWithStorage<T>
-where
- T: Config,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
-{
- /// Same as [`Self::with_code`] but with dummy contract code.
- fn new(stor_num: u32, stor_size: u32) -> Result<Self, &'static str> {
- Self::with_code(WasmModule::dummy(), stor_num, stor_size)
- }
-
- /// Create and evict a new contract with the supplied storage item count and size each.
- fn with_code(code: WasmModule<T>, stor_num: u32, stor_size: u32) -> Result<Self, &'static str> {
- let contract = Contract::<T>::new(code, vec![], Endow::CollectRent)?;
- let storage_items = create_storage::<T>(stor_num, stor_size)?;
- contract.store(&storage_items)?;
- Ok(Self {
- contract,
- storage: storage_items,
- })
- }
-
- /// Increase the system block number so that this contract is eligible for eviction.
- fn set_block_num_for_eviction(&self) -> Result<(), &'static str> {
- System::<T>::set_block_number(
- self.contract.eviction_at()? + T::SignedClaimHandicap::get() + 5u32.into(),
- );
- Ok(())
- }
-
- /// Evict this contract.
- fn evict(&mut self) -> Result<(), &'static str> {
- self.set_block_num_for_eviction()?;
- Rent::<T, PrefabWasmModule<T>>::try_eviction(&self.contract.account_id, Zero::zero())?;
- self.contract.ensure_tombstone()
- }
-}
-
-/// Generate `stor_num` storage items. Each has the size `stor_size`.
-fn create_storage<T: Config>(
- stor_num: u32,
- stor_size: u32,
-) -> Result<Vec<(StorageKey, Vec<u8>)>, &'static str> {
- (0..stor_num)
- .map(|i| {
- let hash = T::Hashing::hash_of(&i)
- .as_ref()
- .try_into()
- .map_err(|_| "Hash too big for storage key")?;
- Ok((hash, vec![42u8; stor_size as usize]))
- })
- .collect::<Result<Vec<_>, &'static str>>()
-}
-
-/// The funding that each account that either calls or instantiates contracts is funded with.
-fn caller_funding<T: Config>() -> BalanceOf<T> {
- BalanceOf::<T>::max_value() / 2u32.into()
-}
-
-benchmarks! {
- where_clause { where
- T::AccountId: UncheckedFrom<T::Hash>,
- T::AccountId: AsRef<[u8]>,
- }
-
- // The base weight without any actual work performed apart from the setup costs.
- on_initialize {}: {
- Storage::<T>::process_deletion_queue_batch(Weight::max_value())
- }
-
- on_initialize_per_trie_key {
- let k in 0..1024;
- let instance = ContractWithStorage::<T>::new(k, T::MaxValueSize::get())?;
- Storage::<T>::queue_trie_for_deletion(&instance.contract.alive_info()?)?;
- }: {
- Storage::<T>::process_deletion_queue_batch(Weight::max_value())
- }
-
- on_initialize_per_queue_item {
- let q in 0..1024.min(T::DeletionQueueDepth::get());
- for i in 0 .. q {
- let instance = Contract::<T>::with_index(i, WasmModule::dummy(), vec![], Endow::Max)?;
- Storage::<T>::queue_trie_for_deletion(&instance.alive_info()?)?;
- ContractInfoOf::<T>::remove(instance.account_id);
- }
- }: {
- Storage::<T>::process_deletion_queue_batch(Weight::max_value())
- }
-
- // This benchmarks the additional weight that is charged when a contract is executed the
- // first time after a new schedule was deployed: For every new schedule a contract needs
- // to re-run the instrumentation once.
- instrument {
- let c in 0 .. T::MaxCodeSize::get() / 1024;
- let WasmModule { code, hash, .. } = WasmModule::<T>::sized(c * 1024);
- Contracts::<T>::store_code_raw(code)?;
- let mut module = PrefabWasmModule::from_storage_noinstr(hash)?;
- let schedule = <CurrentSchedule<T>>::get();
- }: {
- Contracts::<T>::reinstrument_module(&mut module, &schedule)?;
- }
-
- // This extrinsic is pretty much constant as it is only a simple setter.
- update_schedule {
- let schedule = Schedule {
- version: 1,
- .. Default::default()
- };
- }: _(RawOrigin::Root, schedule)
-
- // This constructs a contract that is maximal expensive to instrument.
- // It creates a maximum number of metering blocks per byte.
- // The size of the salt influences the runtime because is is hashed in order to
- // determine the contract address.
- // `c`: Size of the code in kilobytes.
- // `s`: Size of the salt in kilobytes.
- //
- // # Note
- //
- // We cannot let `c` grow to the maximum code size because the code is not allowed
- // to be larger than the maximum size **after instrumentation**.
- instantiate_with_code {
- let c in 0 .. Perbill::from_percent(50).mul_ceil(T::MaxCodeSize::get() / 1024);
- let s in 0 .. code::max_pages::<T>() * 64;
- let salt = vec![42u8; (s * 1024) as usize];
- let endowment = caller_funding::<T>() / 3u32.into();
- let caller = whitelisted_caller();
- T::Currency::make_free_balance_be(&caller, caller_funding::<T>());
- let WasmModule { code, hash, .. } = WasmModule::<T>::sized(c * 1024);
- let origin = RawOrigin::Signed(caller.clone());
- let addr = Contracts::<T>::contract_address(&caller, &hash, &salt);
- }: _(origin, endowment, Weight::max_value(), code, vec![], salt)
- verify {
- // endowment was removed from the caller
- assert_eq!(T::Currency::free_balance(&caller), caller_funding::<T>() - endowment);
- // contract has the full endowment because no rent collection happended
- assert_eq!(T::Currency::free_balance(&addr), endowment);
- // instantiate should leave a alive contract
- Contract::<T>::address_alive_info(&addr)?;
- }
-
- // Instantiate uses a dummy contract constructor to measure the overhead of the instantiate.
- // `c`: Size of the code in kilobytes.
- // `s`: Size of the salt in kilobytes.
- instantiate {
- let c in 0 .. T::MaxCodeSize::get() / 1024;
- let s in 0 .. code::max_pages::<T>() * 64;
- let salt = vec![42u8; (s * 1024) as usize];
- let endowment = caller_funding::<T>() / 3u32.into();
- let caller = whitelisted_caller();
- T::Currency::make_free_balance_be(&caller, caller_funding::<T>());
- let WasmModule { code, hash, .. } = WasmModule::<T>::dummy_with_bytes(c * 1024);
- let origin = RawOrigin::Signed(caller.clone());
- let addr = Contracts::<T>::contract_address(&caller, &hash, &salt);
- Contracts::<T>::store_code_raw(code)?;
- }: _(origin, endowment, Weight::max_value(), hash, vec![], salt)
- verify {
- // endowment was removed from the caller
- assert_eq!(T::Currency::free_balance(&caller), caller_funding::<T>() - endowment);
- // contract has the full endowment because no rent collection happended
- assert_eq!(T::Currency::free_balance(&addr), endowment);
- // instantiate should leave a alive contract
- Contract::<T>::address_alive_info(&addr)?;
- }
-
- // We just call a dummy contract to measure to overhead of the call extrinsic.
- // The size of the data has no influence on the costs of this extrinsic as long as the contract
- // won't call `seal_input` in its constructor to copy the data to contract memory.
- // The dummy contract used here does not do this. The costs for the data copy is billed as
- // part of `seal_input`.
- // `c`: Size of the code in kilobytes.
- call {
- let c in 0 .. T::MaxCodeSize::get() / 1024;
- let data = vec![42u8; 1024];
- let instance = Contract::<T>::with_caller(
- whitelisted_caller(), WasmModule::dummy_with_bytes(c * 1024), vec![], Endow::CollectRent
- )?;
- let value = T::Currency::minimum_balance() * 100u32.into();
- let origin = RawOrigin::Signed(instance.caller.clone());
- let callee = instance.addr.clone();
-
- // trigger rent collection for worst case performance of call
- System::<T>::set_block_number(instance.eviction_at()? - 5u32.into());
- let before = T::Currency::free_balance(&instance.account_id);
- }: _(origin, callee, value, Weight::max_value(), data)
- verify {
- // endowment and value transfered via call should be removed from the caller
- assert_eq!(
- T::Currency::free_balance(&instance.caller),
- caller_funding::<T>() - instance.endowment - value,
- );
- // rent should have lowered the amount of balance of the contract
- assert!(T::Currency::free_balance(&instance.account_id) < before + value);
- // but it should not have been evicted by the rent collection
- instance.alive_info()?;
- }
-
- // We benchmark the costs for sucessfully evicting an empty contract.
- // The actual costs are depending on how many storage items the evicted contract
- // does have. However, those costs are not to be payed by the sender but
- // will be distributed over multiple blocks using a scheduler. Otherwise there is
- // no incentive to remove large contracts when the removal is more expensive than
- // the reward for removing them.
- // `c`: Size of the code of the contract that should be evicted.
- claim_surcharge {
- let c in 0 .. T::MaxCodeSize::get() / 1024;
- let instance = Contract::<T>::with_caller(
- whitelisted_caller(), WasmModule::dummy_with_bytes(c * 1024), vec![], Endow::CollectRent
- )?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- let account_id = instance.account_id.clone();
-
- // instantiate should leave us with an alive contract
- instance.alive_info()?;
-
- // generate enough rent so that the contract is evicted
- System::<T>::set_block_number(
- instance.eviction_at()? + T::SignedClaimHandicap::get() + 5u32.into()
- );
- }: _(origin, account_id, None)
- verify {
- // the claim surcharge should have evicted the contract
- instance.ensure_tombstone()?;
-
- // the caller should get the reward for being a good snitch
- // this is capped by the maximum amount of rent payed. So we only now that it should
- // have increased by at most the surcharge reward.
- assert!(
- T::Currency::free_balance(&instance.caller) >
- caller_funding::<T>() - instance.endowment
- );
- assert!(
- T::Currency::free_balance(&instance.caller) <=
- caller_funding::<T>() - instance.endowment + <T as Config>::SurchargeReward::get(),
- );
- }
-
- seal_caller {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::getter(
- "seal_caller", r * API_BENCHMARK_BATCH_SIZE
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_address {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::getter(
- "seal_address", r * API_BENCHMARK_BATCH_SIZE
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_gas_left {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::getter(
- "seal_gas_left", r * API_BENCHMARK_BATCH_SIZE
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_balance {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::getter(
- "seal_balance", r * API_BENCHMARK_BATCH_SIZE
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_value_transferred {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::getter(
- "seal_value_transferred", r * API_BENCHMARK_BATCH_SIZE
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_minimum_balance {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::getter(
- "seal_minimum_balance", r * API_BENCHMARK_BATCH_SIZE
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_tombstone_deposit {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::getter(
- "seal_tombstone_deposit", r * API_BENCHMARK_BATCH_SIZE
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_rent_allowance {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::getter(
- "seal_rent_allowance", r * API_BENCHMARK_BATCH_SIZE
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_block_number {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::getter(
- "seal_block_number", r * API_BENCHMARK_BATCH_SIZE
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_now {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::getter(
- "seal_now", r * API_BENCHMARK_BATCH_SIZE
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_rent_params {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::getter(
- "seal_rent_params", r * API_BENCHMARK_BATCH_SIZE
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_weight_to_fee {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let pages = code::max_pages::<T>();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_weight_to_fee",
- params: vec![ValueType::I64, ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- data_segments: vec![DataSegment {
- offset: 0,
- value: (pages * 64 * 1024 - 4).to_le_bytes().to_vec(),
- }],
- call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[
- Instruction::I64Const(500_000),
- Instruction::I32Const(4),
- Instruction::I32Const(0),
- Instruction::Call(0),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_gas {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let code = WasmModule::<T>::from(ModuleDefinition {
- imported_functions: vec![ImportedFunction {
- name: "gas",
- params: vec![ValueType::I32],
- return_type: None,
- }],
- call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[
- Instruction::I32Const(42),
- Instruction::Call(0),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
-
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // We cannot call seal_input multiple times. Therefore our weight determination is not
- // as precise as with other APIs. Because this function can only be called once per
- // contract it cannot be used for Dos.
- seal_input {
- let r in 0 .. 1;
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_input",
- params: vec![ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: 0u32.to_le_bytes().to_vec(),
- },
- ],
- call_body: Some(body::repeated(r, &[
- Instruction::I32Const(4), // ptr where to store output
- Instruction::I32Const(0), // ptr to length
- Instruction::Call(0),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_input_per_kb {
- let n in 0 .. code::max_pages::<T>() * 64;
- let pages = code::max_pages::<T>();
- let buffer_size = pages * 64 * 1024 - 4;
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_input",
- params: vec![ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: buffer_size.to_le_bytes().to_vec(),
- },
- ],
- call_body: Some(body::plain(vec![
- Instruction::I32Const(4), // ptr where to store output
- Instruction::I32Const(0), // ptr to length
- Instruction::Call(0),
- Instruction::End,
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let data = vec![42u8; (n * 1024).min(buffer_size) as usize];
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), data)
-
- // The same argument as for `seal_input` is true here.
- seal_return {
- let r in 0 .. 1;
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_return",
- params: vec![ValueType::I32, ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- call_body: Some(body::repeated(r, &[
- Instruction::I32Const(0), // flags
- Instruction::I32Const(0), // data_ptr
- Instruction::I32Const(0), // data_len
- Instruction::Call(0),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_return_per_kb {
- let n in 0 .. code::max_pages::<T>() * 64;
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_return",
- params: vec![ValueType::I32, ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- call_body: Some(body::plain(vec![
- Instruction::I32Const(0), // flags
- Instruction::I32Const(0), // data_ptr
- Instruction::I32Const((n * 1024) as i32), // data_len
- Instruction::Call(0),
- Instruction::End,
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // The same argument as for `seal_input` is true here.
- seal_terminate {
- let r in 0 .. 1;
- let beneficiary = account::<T::AccountId>("beneficiary", 0, 0);
- let beneficiary_bytes = beneficiary.encode();
- let beneficiary_len = beneficiary_bytes.len();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_terminate",
- params: vec![ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: beneficiary_bytes,
- },
- ],
- call_body: Some(body::repeated(r, &[
- Instruction::I32Const(0), // beneficiary_ptr
- Instruction::I32Const(beneficiary_len as i32), // beneficiary_len
- Instruction::Call(0),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- assert_eq!(T::Currency::total_balance(&beneficiary), 0u32.into());
- assert_eq!(T::Currency::total_balance(&instance.account_id), Endow::max::<T>());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
- verify {
- if r > 0 {
- assert_eq!(T::Currency::total_balance(&instance.account_id), 0u32.into());
- assert_eq!(T::Currency::total_balance(&beneficiary), Endow::max::<T>());
- }
- }
-
- seal_terminate_per_code_kb {
- let c in 0 .. T::MaxCodeSize::get() / 1024;
- let beneficiary = account::<T::AccountId>("beneficiary", 0, 0);
- let beneficiary_bytes = beneficiary.encode();
- let beneficiary_len = beneficiary_bytes.len();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_terminate",
- params: vec![ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: beneficiary_bytes,
- },
- ],
- call_body: Some(body::repeated(1, &[
- Instruction::I32Const(0), // beneficiary_ptr
- Instruction::I32Const(beneficiary_len as i32), // beneficiary_len
- Instruction::Call(0),
- ])),
- dummy_section: c * 1024,
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- assert_eq!(T::Currency::total_balance(&beneficiary), 0u32.into());
- assert_eq!(T::Currency::total_balance(&instance.account_id), Endow::max::<T>());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
- verify {
- assert_eq!(T::Currency::total_balance(&instance.account_id), 0u32.into());
- assert_eq!(T::Currency::total_balance(&beneficiary), Endow::max::<T>());
- }
-
- seal_restore_to {
- let r in 0 .. 1;
-
- // Restore just moves the trie id from origin to destination and therefore
- // does not depend on the size of the destination contract. However, to not
- // trigger any edge case we won't use an empty contract as destination.
- let mut tombstone = ContractWithStorage::<T>::new(10, T::MaxValueSize::get())?;
- tombstone.evict()?;
-
- let dest = tombstone.contract.account_id.encode();
- let dest_len = dest.len();
- let code_hash = tombstone.contract.code_hash.encode();
- let code_hash_len = code_hash.len();
- let rent_allowance = BalanceOf::<T>::max_value().encode();
- let rent_allowance_len = rent_allowance.len();
-
- let dest_offset = 0;
- let code_hash_offset = dest_offset + dest_len;
- let rent_allowance_offset = code_hash_offset + code_hash_len;
-
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_restore_to",
- params: vec![
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: dest_offset as u32,
- value: dest,
- },
- DataSegment {
- offset: code_hash_offset as u32,
- value: code_hash,
- },
- DataSegment {
- offset: rent_allowance_offset as u32,
- value: rent_allowance,
- },
- ],
- call_body: Some(body::repeated(r, &[
- Instruction::I32Const(dest_offset as i32),
- Instruction::I32Const(dest_len as i32),
- Instruction::I32Const(code_hash_offset as i32),
- Instruction::I32Const(code_hash_len as i32),
- Instruction::I32Const(rent_allowance_offset as i32),
- Instruction::I32Const(rent_allowance_len as i32),
- Instruction::I32Const(0), // delta_ptr
- Instruction::I32Const(0), // delta_count
- Instruction::Call(0),
- ])),
- .. Default::default()
- });
-
- let instance = Contract::<T>::with_caller(
- account("origin", 0, 0), code, vec![], Endow::Max
- )?;
- instance.store(&tombstone.storage)?;
- System::<T>::set_block_number(System::<T>::block_number() + 1u32.into());
-
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
- verify {
- if r > 0 {
- tombstone.contract.alive_info()?;
- }
- }
-
- // `c`: Code size of caller contract
- // `t`: Code size of tombstone contract
- // `d`: Number of supplied delta keys
- seal_restore_to_per_code_kb_delta {
- let c in 0 .. T::MaxCodeSize::get() / 1024;
- let t in 0 .. T::MaxCodeSize::get() / 1024;
- let d in 0 .. API_BENCHMARK_BATCHES;
- let mut tombstone = ContractWithStorage::<T>::with_code(
- WasmModule::<T>::dummy_with_bytes(t * 1024), 0, 0
- )?;
- tombstone.evict()?;
- let delta = create_storage::<T>(d * API_BENCHMARK_BATCH_SIZE, T::MaxValueSize::get())?;
-
- let dest = tombstone.contract.account_id.encode();
- let dest_len = dest.len();
- let code_hash = tombstone.contract.code_hash.encode();
- let code_hash_len = code_hash.len();
- let rent_allowance = BalanceOf::<T>::max_value().encode();
- let rent_allowance_len = rent_allowance.len();
- let delta_keys = delta.iter().flat_map(|(key, _)| key).cloned().collect::<Vec<_>>();
-
- let dest_offset = 0;
- let code_hash_offset = dest_offset + dest_len;
- let rent_allowance_offset = code_hash_offset + code_hash_len;
- let delta_keys_offset = rent_allowance_offset + rent_allowance_len;
-
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_restore_to",
- params: vec![
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: dest_offset as u32,
- value: dest,
- },
- DataSegment {
- offset: code_hash_offset as u32,
- value: code_hash,
- },
- DataSegment {
- offset: rent_allowance_offset as u32,
- value: rent_allowance,
- },
- DataSegment {
- offset: delta_keys_offset as u32,
- value: delta_keys,
- },
- ],
- call_body: Some(body::plain(vec![
- Instruction::I32Const(dest_offset as i32),
- Instruction::I32Const(dest_len as i32),
- Instruction::I32Const(code_hash_offset as i32),
- Instruction::I32Const(code_hash_len as i32),
- Instruction::I32Const(rent_allowance_offset as i32),
- Instruction::I32Const(rent_allowance_len as i32),
- Instruction::I32Const(delta_keys_offset as i32), // delta_ptr
- Instruction::I32Const(delta.len() as i32), // delta_count
- Instruction::Call(0),
- Instruction::End,
- ])),
- dummy_section: c * 1024,
- .. Default::default()
- });
-
- let instance = Contract::<T>::with_caller(
- account("origin", 0, 0), code, vec![], Endow::Max
- )?;
- instance.store(&tombstone.storage)?;
- instance.store(&delta)?;
- System::<T>::set_block_number(System::<T>::block_number() + 1u32.into());
-
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
- verify {
- tombstone.contract.alive_info()?;
- }
-
- // We benchmark only for the maximum subject length. We assume that this is some lowish
- // number (< 1 KB). Therefore we are not overcharging too much in case a smaller subject is
- // used.
- seal_random {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let pages = code::max_pages::<T>();
- let subject_len = <CurrentSchedule<T>>::get().limits.subject_len;
- assert!(subject_len < 1024);
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_random",
- params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: (pages * 64 * 1024 - subject_len - 4).to_le_bytes().to_vec(),
- },
- ],
- call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[
- Instruction::I32Const(4), // subject_ptr
- Instruction::I32Const(subject_len as i32), // subject_len
- Instruction::I32Const((subject_len + 4) as i32), // out_ptr
- Instruction::I32Const(0), // out_len_ptr
- Instruction::Call(0),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // Overhead of calling the function without any topic.
- // We benchmark for the worst case (largest event).
- seal_deposit_event {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_deposit_event",
- params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[
- Instruction::I32Const(0), // topics_ptr
- Instruction::I32Const(0), // topics_len
- Instruction::I32Const(0), // data_ptr
- Instruction::I32Const(0), // data_len
- Instruction::Call(0),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // Benchmark the overhead that topics generate.
- // `t`: Number of topics
- // `n`: Size of event payload in kb
- seal_deposit_event_per_topic_and_kb {
- let t in 0 .. <CurrentSchedule<T>>::get().limits.event_topics;
- let n in 0 .. T::MaxValueSize::get() / 1024;
- let mut topics = (0..API_BENCHMARK_BATCH_SIZE)
- .map(|n| (n * t..n * t + t).map(|i| T::Hashing::hash_of(&i)).collect::<Vec<_>>().encode())
- .peekable();
- let topics_len = topics.peek().map(|i| i.len()).unwrap_or(0);
- let topics = topics.flatten().collect();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_deposit_event",
- params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: topics,
- },
- ],
- call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![
- Counter(0, topics_len as u32), // topics_ptr
- Regular(Instruction::I32Const(topics_len as i32)), // topics_len
- Regular(Instruction::I32Const(0)), // data_ptr
- Regular(Instruction::I32Const((n * 1024) as i32)), // data_len
- Regular(Instruction::Call(0)),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_set_rent_allowance {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let allowance = caller_funding::<T>().encode();
- let allowance_len = allowance.len();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory { min_pages: 1, max_pages: 1 }),
- imported_functions: vec![ImportedFunction {
- name: "seal_set_rent_allowance",
- params: vec![ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: allowance,
- },
- ],
- call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[
- Instruction::I32Const(0), // value_ptr
- Instruction::I32Const(allowance_len as i32), // value_len
- Instruction::Call(0),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // Only the overhead of calling the function itself with minimal arguments.
- // The contract is a bit more complex because I needs to use different keys in order
- // to generate unique storage accesses. However, it is still dominated by the storage
- // accesses.
- seal_set_storage {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE)
- .flat_map(|n| T::Hashing::hash_of(&n).as_ref().to_vec())
- .collect::<Vec<_>>();
- let key_len = sp_std::mem::size_of::<<T::Hashing as sp_runtime::traits::Hash>::Output>();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_set_storage",
- params: vec![ValueType::I32, ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: keys,
- },
- ],
- call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
- Counter(0, key_len as u32), // key_ptr
- Regular(Instruction::I32Const(0)), // value_ptr
- Regular(Instruction::I32Const(0)), // value_len
- Regular(Instruction::Call(0)),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_set_storage_per_kb {
- let n in 0 .. T::MaxValueSize::get() / 1024;
- let key = T::Hashing::hash_of(&1u32).as_ref().to_vec();
- let key_len = key.len();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_set_storage",
- params: vec![ValueType::I32, ValueType::I32, ValueType::I32],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: key,
- },
- ],
- call_body: Some(body::repeated(API_BENCHMARK_BATCH_SIZE, &[
- Instruction::I32Const(0), // key_ptr
- Instruction::I32Const(0), // value_ptr
- Instruction::I32Const((n * 1024) as i32), // value_len
- Instruction::Call(0),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // Similar to seal_set_storage. However, we store all the keys that we are about to
- // delete beforehand in order to prevent any optimizations that could occur when
- // deleting a non existing key.
- seal_clear_storage {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE)
- .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec())
- .collect::<Vec<_>>();
- let key_bytes = keys.iter().flatten().cloned().collect::<Vec<_>>();
- let key_len = sp_std::mem::size_of::<<T::Hashing as sp_runtime::traits::Hash>::Output>();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_clear_storage",
- params: vec![ValueType::I32],
- return_type: None,
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: key_bytes,
- },
- ],
- call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
- Counter(0, key_len as u32),
- Regular(Instruction::Call(0)),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let trie_id = instance.alive_info()?.trie_id;
- for key in keys {
- Storage::<T>::write(
- &instance.account_id,
- &trie_id,
- key.as_slice().try_into().map_err(|e| "Key has wrong length")?,
- Some(vec![42; T::MaxValueSize::get() as usize])
- )
- .map_err(|_| "Failed to write to storage during setup.")?;
- }
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // We make sure that all storage accesses are to unique keys.
- seal_get_storage {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let keys = (0 .. r * API_BENCHMARK_BATCH_SIZE)
- .map(|n| T::Hashing::hash_of(&n).as_ref().to_vec())
- .collect::<Vec<_>>();
- let key_len = sp_std::mem::size_of::<<T::Hashing as sp_runtime::traits::Hash>::Output>();
- let key_bytes = keys.iter().flatten().cloned().collect::<Vec<_>>();
- let key_bytes_len = key_bytes.len();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_get_storage",
- params: vec![ValueType::I32, ValueType::I32, ValueType::I32],
- return_type: Some(ValueType::I32),
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: key_bytes,
- },
- ],
- call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
- Counter(0, key_len as u32), // key_ptr
- Regular(Instruction::I32Const((key_bytes_len + 4) as i32)), // out_ptr
- Regular(Instruction::I32Const(key_bytes_len as i32)), // out_len_ptr
- Regular(Instruction::Call(0)),
- Regular(Instruction::Drop),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let trie_id = instance.alive_info()?.trie_id;
- for key in keys {
- Storage::<T>::write(
- &instance.account_id,
- &trie_id,
- key.as_slice().try_into().map_err(|e| "Key has wrong length")?,
- Some(vec![])
- )
- .map_err(|_| "Failed to write to storage during setup.")?;
- }
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_get_storage_per_kb {
- let n in 0 .. T::MaxValueSize::get() / 1024;
- let key = T::Hashing::hash_of(&1u32).as_ref().to_vec();
- let key_len = key.len();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_get_storage",
- params: vec![ValueType::I32, ValueType::I32, ValueType::I32],
- return_type: Some(ValueType::I32),
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: key.clone(),
- },
- DataSegment {
- offset: key_len as u32,
- value: T::MaxValueSize::get().to_le_bytes().into(),
- },
- ],
- call_body: Some(body::repeated(API_BENCHMARK_BATCH_SIZE, &[
- // call at key_ptr
- Instruction::I32Const(0), // key_ptr
- Instruction::I32Const((key_len + 4) as i32), // out_ptr
- Instruction::I32Const(key_len as i32), // out_len_ptr
- Instruction::Call(0),
- Instruction::Drop,
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let trie_id = instance.alive_info()?.trie_id;
- Storage::<T>::write(
- &instance.account_id,
- &trie_id,
- key.as_slice().try_into().map_err(|e| "Key has wrong length")?,
- Some(vec![42u8; (n * 1024) as usize])
- )
- .map_err(|_| "Failed to write to storage during setup.")?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // We transfer to unique accounts.
- seal_transfer {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let accounts = (0..r * API_BENCHMARK_BATCH_SIZE)
- .map(|i| account::<T::AccountId>("receiver", i, 0))
- .collect::<Vec<_>>();
- let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0);
- let account_bytes = accounts.iter().flat_map(|x| x.encode()).collect();
- let value = Contracts::<T>::subsistence_threshold();
- assert!(value > 0u32.into());
- let value_bytes = value.encode();
- let value_len = value_bytes.len();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_transfer",
- params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32],
- return_type: Some(ValueType::I32),
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: value_bytes,
- },
- DataSegment {
- offset: value_len as u32,
- value: account_bytes,
- },
- ],
- call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
- Counter(value_len as u32, account_len as u32), // account_ptr
- Regular(Instruction::I32Const(account_len as i32)), // account_len
- Regular(Instruction::I32Const(0)), // value_ptr
- Regular(Instruction::I32Const(value_len as i32)), // value_len
- Regular(Instruction::Call(0)),
- Regular(Instruction::Drop),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- for account in &accounts {
- assert_eq!(T::Currency::total_balance(account), 0u32.into());
- }
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
- verify {
- for account in &accounts {
- assert_eq!(T::Currency::total_balance(account), value);
- }
- }
-
- // We call unique accounts.
- seal_call {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let dummy_code = WasmModule::<T>::dummy_with_bytes(0);
- let callees = (0..r * API_BENCHMARK_BATCH_SIZE)
- .map(|i| Contract::with_index(i + 1, dummy_code.clone(), vec![], Endow::Max))
- .collect::<Result<Vec<_>, _>>()?;
- let callee_len = callees.get(0).map(|i| i.account_id.encode().len()).unwrap_or(0);
- let callee_bytes = callees.iter().flat_map(|x| x.account_id.encode()).collect();
- let value: BalanceOf<T> = 0u32.into();
- let value_bytes = value.encode();
- let value_len = value_bytes.len();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_call",
- params: vec![
- ValueType::I32,
- ValueType::I32,
- ValueType::I64,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ],
- return_type: Some(ValueType::I32),
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: value_bytes,
- },
- DataSegment {
- offset: value_len as u32,
- value: callee_bytes,
- },
- ],
- call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
- Counter(value_len as u32, callee_len as u32), // callee_ptr
- Regular(Instruction::I32Const(callee_len as i32)), // callee_len
- Regular(Instruction::I64Const(0)), // gas
- Regular(Instruction::I32Const(0)), // value_ptr
- Regular(Instruction::I32Const(value_len as i32)), // value_len
- Regular(Instruction::I32Const(0)), // input_data_ptr
- Regular(Instruction::I32Const(0)), // input_data_len
- Regular(Instruction::I32Const(u32::max_value() as i32)), // output_ptr
- Regular(Instruction::I32Const(0)), // output_len_ptr
- Regular(Instruction::Call(0)),
- Regular(Instruction::Drop),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- seal_call_per_code_transfer_input_output_kb {
- let c in 0 .. T::MaxCodeSize::get() / 1024;
- let t in 0 .. 1;
- let i in 0 .. code::max_pages::<T>() * 64;
- let o in 0 .. (code::max_pages::<T>() - 1) * 64;
- let callee_code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_return",
- params: vec![
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ],
- return_type: None,
- }],
- call_body: Some(body::plain(vec![
- Instruction::I32Const(0), // flags
- Instruction::I32Const(0), // data_ptr
- Instruction::I32Const((o * 1024) as i32), // data_len
- Instruction::Call(0),
- Instruction::End,
- ])),
- dummy_section: c * 1024,
- .. Default::default()
- });
- let callees = (0..API_BENCHMARK_BATCH_SIZE)
- .map(|i| Contract::with_index(i + 1, callee_code.clone(), vec![], Endow::Max))
- .collect::<Result<Vec<_>, _>>()?;
- let callee_len = callees.get(0).map(|i| i.account_id.encode().len()).unwrap_or(0);
- let callee_bytes = callees.iter().flat_map(|x| x.account_id.encode()).collect::<Vec<_>>();
- let callees_len = callee_bytes.len();
- let value: BalanceOf<T> = t.into();
- let value_bytes = value.encode();
- let value_len = value_bytes.len();
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_call",
- params: vec![
- ValueType::I32,
- ValueType::I32,
- ValueType::I64,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ],
- return_type: Some(ValueType::I32),
- }],
- data_segments: vec![
- DataSegment {
- offset: 0,
- value: value_bytes,
- },
- DataSegment {
- offset: value_len as u32,
- value: callee_bytes,
- },
- DataSegment {
- offset: (value_len + callees_len) as u32,
- value: (o * 1024).to_le_bytes().into(),
- },
- ],
- call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![
- Counter(value_len as u32, callee_len as u32), // callee_ptr
- Regular(Instruction::I32Const(callee_len as i32)), // callee_len
- Regular(Instruction::I64Const(0)), // gas
- Regular(Instruction::I32Const(0)), // value_ptr
- Regular(Instruction::I32Const(value_len as i32)), // value_len
- Regular(Instruction::I32Const(0)), // input_data_ptr
- Regular(Instruction::I32Const((i * 1024) as i32)), // input_data_len
- Regular(Instruction::I32Const((value_len + callees_len + 4) as i32)), // output_ptr
- Regular(Instruction::I32Const((value_len + callees_len) as i32)), // output_len_ptr
- Regular(Instruction::Call(0)),
- Regular(Instruction::Drop),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // We assume that every instantiate sends at least the subsistence amount.
- seal_instantiate {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let hashes = (0..r * API_BENCHMARK_BATCH_SIZE)
- .map(|i| {
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- call_body: Some(body::plain(vec![
- // we need to add this in order to make contracts unique
- // so that they can be deployed from the same sender
- Instruction::I32Const(i as i32),
- Instruction::Drop,
- Instruction::End,
- ])),
- .. Default::default()
- });
- Contracts::<T>::store_code_raw(code.code)?;
- Ok(code.hash)
- })
- .collect::<Result<Vec<_>, &'static str>>()?;
- let hash_len = hashes.get(0).map(|x| x.encode().len()).unwrap_or(0);
- let hashes_bytes = hashes.iter().flat_map(|x| x.encode()).collect::<Vec<_>>();
- let hashes_len = hashes_bytes.len();
- let value = Endow::max::<T>() / (r * API_BENCHMARK_BATCH_SIZE + 2).into();
- assert!(value > 0u32.into());
- let value_bytes = value.encode();
- let value_len = value_bytes.len();
- let addr_len = sp_std::mem::size_of::<T::AccountId>();
-
- // offsets where to place static data in contract memory
- let value_offset = 0;
- let hashes_offset = value_offset + value_len;
- let addr_len_offset = hashes_offset + hashes_len;
- let addr_offset = addr_len_offset + addr_len;
-
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_instantiate",
- params: vec![
- ValueType::I32,
- ValueType::I32,
- ValueType::I64,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ],
- return_type: Some(ValueType::I32),
- }],
- data_segments: vec![
- DataSegment {
- offset: value_offset as u32,
- value: value_bytes,
- },
- DataSegment {
- offset: hashes_offset as u32,
- value: hashes_bytes,
- },
- DataSegment {
- offset: addr_len_offset as u32,
- value: addr_len.to_le_bytes().into(),
- },
- ],
- call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
- Counter(hashes_offset as u32, hash_len as u32), // code_hash_ptr
- Regular(Instruction::I32Const(hash_len as i32)), // code_hash_len
- Regular(Instruction::I64Const(0)), // gas
- Regular(Instruction::I32Const(value_offset as i32)), // value_ptr
- Regular(Instruction::I32Const(value_len as i32)), // value_len
- Regular(Instruction::I32Const(0)), // input_data_ptr
- Regular(Instruction::I32Const(0)), // input_data_len
- Regular(Instruction::I32Const(addr_offset as i32)), // address_ptr
- Regular(Instruction::I32Const(addr_len_offset as i32)), // address_len_ptr
- Regular(Instruction::I32Const(u32::max_value() as i32)), // output_ptr
- Regular(Instruction::I32Const(0)), // output_len_ptr
- Regular(Instruction::I32Const(0)), // salt_ptr
- Regular(Instruction::I32Const(0)), // salt_ptr_len
- Regular(Instruction::Call(0)),
- Regular(Instruction::Drop),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- let callee = instance.addr.clone();
- let addresses = hashes
- .iter()
- .map(|hash| Contracts::<T>::contract_address(
- &instance.account_id, hash, &[],
- ))
- .collect::<Vec<_>>();
-
- for addr in &addresses {
- if let Some(_) = ContractInfoOf::<T>::get(&addr) {
- return Err("Expected that contract does not exist at this point.");
- }
- }
- }: call(origin, callee, 0u32.into(), Weight::max_value(), vec![])
- verify {
- for addr in &addresses {
- ContractInfoOf::<T>::get(&addr).and_then(|c| c.get_alive())
- .ok_or_else(|| "Contract should have been instantiated")?;
- }
- }
-
- seal_instantiate_per_code_input_output_salt_kb {
- let c in 0 .. T::MaxCodeSize::get() / 1024;
- let i in 0 .. (code::max_pages::<T>() - 1) * 64;
- let o in 0 .. (code::max_pages::<T>() - 1) * 64;
- let s in 0 .. (code::max_pages::<T>() - 1) * 64;
- let callee_code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_return",
- params: vec![
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ],
- return_type: None,
- }],
- deploy_body: Some(body::plain(vec![
- Instruction::I32Const(0), // flags
- Instruction::I32Const(0), // data_ptr
- Instruction::I32Const((o * 1024) as i32), // data_len
- Instruction::Call(0),
- Instruction::End,
- ])),
- dummy_section: c * 1024,
- .. Default::default()
- });
- let hash = callee_code.hash.clone();
- let hash_bytes = callee_code.hash.encode();
- let hash_len = hash_bytes.len();
- Contracts::<T>::store_code_raw(callee_code.code)?;
- let inputs = (0..API_BENCHMARK_BATCH_SIZE).map(|x| x.encode()).collect::<Vec<_>>();
- let input_len = inputs.get(0).map(|x| x.len()).unwrap_or(0);
- let input_bytes = inputs.iter().cloned().flatten().collect::<Vec<_>>();
- let inputs_len = input_bytes.len();
- let value = Endow::max::<T>() / (API_BENCHMARK_BATCH_SIZE + 2).into();
- assert!(value > 0u32.into());
- let value_bytes = value.encode();
- let value_len = value_bytes.len();
- let addr_len = sp_std::mem::size_of::<T::AccountId>();
-
- // offsets where to place static data in contract memory
- let input_offset = 0;
- let value_offset = inputs_len;
- let hash_offset = value_offset + value_len;
- let addr_len_offset = hash_offset + hash_len;
- let output_len_offset = addr_len_offset + 4;
- let output_offset = output_len_offset + 4;
-
- let code = WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- imported_functions: vec![ImportedFunction {
- name: "seal_instantiate",
- params: vec![
- ValueType::I32,
- ValueType::I32,
- ValueType::I64,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ValueType::I32,
- ],
- return_type: Some(ValueType::I32),
- }],
- data_segments: vec![
- DataSegment {
- offset: input_offset as u32,
- value: input_bytes,
- },
- DataSegment {
- offset: value_offset as u32,
- value: value_bytes,
- },
- DataSegment {
- offset: hash_offset as u32,
- value: hash_bytes,
- },
- DataSegment {
- offset: addr_len_offset as u32,
- value: (addr_len as u32).to_le_bytes().into(),
- },
- DataSegment {
- offset: output_len_offset as u32,
- value: (o * 1024).to_le_bytes().into(),
- },
- ],
- call_body: Some(body::repeated_dyn(API_BENCHMARK_BATCH_SIZE, vec![
- Regular(Instruction::I32Const(hash_offset as i32)), // code_hash_ptr
- Regular(Instruction::I32Const(hash_len as i32)), // code_hash_len
- Regular(Instruction::I64Const(0)), // gas
- Regular(Instruction::I32Const(value_offset as i32)), // value_ptr
- Regular(Instruction::I32Const(value_len as i32)), // value_len
- Counter(input_offset as u32, input_len as u32), // input_data_ptr
- Regular(Instruction::I32Const((i * 1024).max(input_len as u32) as i32)), // input_data_len
- Regular(Instruction::I32Const((addr_len_offset + addr_len) as i32)), // address_ptr
- Regular(Instruction::I32Const(addr_len_offset as i32)), // address_len_ptr
- Regular(Instruction::I32Const(output_offset as i32)), // output_ptr
- Regular(Instruction::I32Const(output_len_offset as i32)), // output_len_ptr
- Counter(input_offset as u32, input_len as u32), // salt_ptr
- Regular(Instruction::I32Const((s * 1024).max(input_len as u32) as i32)), // salt_len
- Regular(Instruction::Call(0)),
- Regular(Instruction::I32Eqz),
- Regular(Instruction::If(BlockType::NoResult)),
- Regular(Instruction::Nop),
- Regular(Instruction::Else),
- Regular(Instruction::Unreachable),
- Regular(Instruction::End),
- ])),
- .. Default::default()
- });
- let instance = Contract::<T>::new(code, vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // Only the overhead of calling the function itself with minimal arguments.
- seal_hash_sha2_256 {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::hasher(
- "seal_hash_sha2_256", r * API_BENCHMARK_BATCH_SIZE, 0,
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // `n`: Input to hash in kilobytes
- seal_hash_sha2_256_per_kb {
- let n in 0 .. code::max_pages::<T>() * 64;
- let instance = Contract::<T>::new(WasmModule::hasher(
- "seal_hash_sha2_256", API_BENCHMARK_BATCH_SIZE, n * 1024,
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // Only the overhead of calling the function itself with minimal arguments.
- seal_hash_keccak_256 {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::hasher(
- "seal_hash_keccak_256", r * API_BENCHMARK_BATCH_SIZE, 0,
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // `n`: Input to hash in kilobytes
- seal_hash_keccak_256_per_kb {
- let n in 0 .. code::max_pages::<T>() * 64;
- let instance = Contract::<T>::new(WasmModule::hasher(
- "seal_hash_keccak_256", API_BENCHMARK_BATCH_SIZE, n * 1024,
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // Only the overhead of calling the function itself with minimal arguments.
- seal_hash_blake2_256 {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::hasher(
- "seal_hash_blake2_256", r * API_BENCHMARK_BATCH_SIZE, 0,
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // `n`: Input to hash in kilobytes
- seal_hash_blake2_256_per_kb {
- let n in 0 .. code::max_pages::<T>() * 64;
- let instance = Contract::<T>::new(WasmModule::hasher(
- "seal_hash_blake2_256", API_BENCHMARK_BATCH_SIZE, n * 1024,
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // Only the overhead of calling the function itself with minimal arguments.
- seal_hash_blake2_128 {
- let r in 0 .. API_BENCHMARK_BATCHES;
- let instance = Contract::<T>::new(WasmModule::hasher(
- "seal_hash_blake2_128", r * API_BENCHMARK_BATCH_SIZE, 0,
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // `n`: Input to hash in kilobytes
- seal_hash_blake2_128_per_kb {
- let n in 0 .. code::max_pages::<T>() * 64;
- let instance = Contract::<T>::new(WasmModule::hasher(
- "seal_hash_blake2_128", API_BENCHMARK_BATCH_SIZE, n * 1024,
- ), vec![], Endow::Max)?;
- let origin = RawOrigin::Signed(instance.caller.clone());
- }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![])
-
- // We make the assumption that pushing a constant and dropping a value takes roughly
- // the same amount of time. We follow that `t.load` and `drop` both have the weight
- // of this benchmark / 2. We need to make this assumption because there is no way
- // to measure them on their own using a valid wasm module. We need their individual
- // values to derive the weight of individual instructions (by substraction) from
- // benchmarks that include those for parameter pushing and return type dropping.
- // We call the weight of `t.load` and `drop`: `w_param`.
- // The weight that would result from the respective benchmark we call: `w_bench`.
- //
- // w_i{32,64}const = w_drop = w_bench / 2
- instr_i64const {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_i{32,64}load = w_bench - 2 * w_param
- instr_i64load {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomUnaligned(0, code::max_pages::<T>() * 64 * 1024 - 8),
- Regular(Instruction::I64Load(3, 0)),
- Regular(Instruction::Drop),
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_i{32,64}store{...} = w_bench - 2 * w_param
- instr_i64store {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomUnaligned(0, code::max_pages::<T>() * 64 * 1024 - 8),
- RandomI64Repeated(1),
- Regular(Instruction::I64Store(3, 0)),
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_select = w_bench - 4 * w_param
- instr_select {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomI64Repeated(1),
- RandomI64Repeated(1),
- RandomI32(0, 2),
- Regular(Instruction::Select),
- Regular(Instruction::Drop),
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_if = w_bench - 3 * w_param
- instr_if {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomI32(0, 2),
- Regular(Instruction::If(BlockType::Value(ValueType::I64))),
- RandomI64Repeated(1),
- Regular(Instruction::Else),
- RandomI64Repeated(1),
- Regular(Instruction::End),
- Regular(Instruction::Drop),
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_br = w_bench - 2 * w_param
- instr_br {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- Regular(Instruction::Block(BlockType::NoResult)),
- Regular(Instruction::Block(BlockType::NoResult)),
- Regular(Instruction::Block(BlockType::NoResult)),
- Regular(Instruction::Br(1)),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_br_if = w_bench - 5 * w_param
- // The two additional pushes + drop are only executed 50% of the time.
- // Making it: 3 * w_param + (50% * 4 * w_param)
- instr_br_if {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- Regular(Instruction::Block(BlockType::NoResult)),
- Regular(Instruction::Block(BlockType::NoResult)),
- Regular(Instruction::Block(BlockType::NoResult)),
- RandomI32(0, 2),
- Regular(Instruction::BrIf(1)),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_br_table = w_bench - 3 * w_param
- // 1 * w_param + 0.5 * 2 * w_param + 0.25 * 4 * w_param
- instr_br_table {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let table = Box::new(parity_wasm::elements::BrTableData {
- table: Box::new([0, 1, 2]),
- default: 1,
- });
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- Regular(Instruction::Block(BlockType::NoResult)),
- Regular(Instruction::Block(BlockType::NoResult)),
- Regular(Instruction::Block(BlockType::NoResult)),
- RandomI32(0, 4),
- Regular(Instruction::BrTable(table)),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_br_table_per_entry = w_bench
- instr_br_table_per_entry {
- let e in 1 .. <CurrentSchedule<T>>::get().limits.br_table_size;
- let entry: Vec<u32> = [0, 1].iter()
- .cloned()
- .cycle()
- .take((e / 2) as usize).collect();
- let table = Box::new(parity_wasm::elements::BrTableData {
- table: entry.into_boxed_slice(),
- default: 0,
- });
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(body::repeated_dyn(INSTR_BENCHMARK_BATCH_SIZE, vec![
- Regular(Instruction::Block(BlockType::NoResult)),
- Regular(Instruction::Block(BlockType::NoResult)),
- Regular(Instruction::Block(BlockType::NoResult)),
- RandomI32(0, (e + 1) as i32), // Make sure the default entry is also used
- Regular(Instruction::BrTable(table)),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- RandomI64Repeated(1),
- Regular(Instruction::Drop),
- Regular(Instruction::End),
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_call = w_bench - 2 * w_param
- instr_call {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- // We need to make use of the stack here in order to trigger stack height
- // instrumentation.
- aux_body: Some(body::plain(vec![
- Instruction::I64Const(42),
- Instruction::Drop,
- Instruction::End,
- ])),
- call_body: Some(body::repeated(r * INSTR_BENCHMARK_BATCH_SIZE, &[
- Instruction::Call(2), // call aux
- ])),
- inject_stack_metering: true,
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_call_indrect = w_bench - 3 * w_param
- instr_call_indirect {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let num_elements = <CurrentSchedule<T>>::get().limits.table_size;
- use self::code::TableSegment;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- // We need to make use of the stack here in order to trigger stack height
- // instrumentation.
- aux_body: Some(body::plain(vec![
- Instruction::I64Const(42),
- Instruction::Drop,
- Instruction::End,
- ])),
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomI32(0, num_elements as i32),
- Regular(Instruction::CallIndirect(0, 0)), // we only have one sig: 0
- ])),
- inject_stack_metering: true,
- table: Some(TableSegment {
- num_elements,
- function_index: 2, // aux
- }),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_instr_call_indirect_per_param = w_bench - 1 * w_param
- // Calling a function indirectly causes it to go through a thunk function whose runtime
- // linearly depend on the amount of parameters to this function.
- // Please note that this is not necessary with a direct call.
- instr_call_indirect_per_param {
- let p in 0 .. <CurrentSchedule<T>>::get().limits.parameters;
- let num_elements = <CurrentSchedule<T>>::get().limits.table_size;
- use self::code::TableSegment;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- // We need to make use of the stack here in order to trigger stack height
- // instrumentation.
- aux_body: Some(body::plain(vec![
- Instruction::I64Const(42),
- Instruction::Drop,
- Instruction::End,
- ])),
- aux_arg_num: p,
- call_body: Some(body::repeated_dyn(INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomI64Repeated(p as usize),
- RandomI32(0, num_elements as i32),
- Regular(Instruction::CallIndirect(p.min(1), 0)), // aux signature: 1 or 0
- ])),
- inject_stack_metering: true,
- table: Some(TableSegment {
- num_elements,
- function_index: 2, // aux
- }),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_local_get = w_bench - 1 * w_param
- instr_local_get {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let max_locals = <CurrentSchedule<T>>::get().limits.stack_height;
- let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomGetLocal(0, max_locals),
- Regular(Instruction::Drop),
- ]);
- body::inject_locals(&mut call_body, max_locals);
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(call_body),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_local_set = w_bench - 1 * w_param
- instr_local_set {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let max_locals = <CurrentSchedule<T>>::get().limits.stack_height;
- let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomI64Repeated(1),
- RandomSetLocal(0, max_locals),
- ]);
- body::inject_locals(&mut call_body, max_locals);
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(call_body),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_local_tee = w_bench - 2 * w_param
- instr_local_tee {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let max_locals = <CurrentSchedule<T>>::get().limits.stack_height;
- let mut call_body = body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomI64Repeated(1),
- RandomTeeLocal(0, max_locals),
- Regular(Instruction::Drop),
- ]);
- body::inject_locals(&mut call_body, max_locals);
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(call_body),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_global_get = w_bench - 1 * w_param
- instr_global_get {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let max_globals = <CurrentSchedule<T>>::get().limits.globals;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomGetGlobal(0, max_globals),
- Regular(Instruction::Drop),
- ])),
- num_globals: max_globals,
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_global_set = w_bench - 1 * w_param
- instr_global_set {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let max_globals = <CurrentSchedule<T>>::get().limits.globals;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomI64Repeated(1),
- RandomSetGlobal(0, max_globals),
- ])),
- num_globals: max_globals,
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_memory_get = w_bench - 1 * w_param
- instr_memory_current {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory::max::<T>()),
- call_body: Some(body::repeated(r * INSTR_BENCHMARK_BATCH_SIZE, &[
- Instruction::CurrentMemory(0),
- Instruction::Drop
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // w_memory_grow = w_bench - 2 * w_param
- // We can only allow allocate as much memory as it is allowed in a a contract.
- // Therefore the repeat count is limited by the maximum memory any contract can have.
- // Using a contract with more memory will skew the benchmark because the runtime of grow
- // depends on how much memory is already allocated.
- instr_memory_grow {
- let r in 0 .. 1;
- let max_pages = ImportedMemory::max::<T>().max_pages;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- memory: Some(ImportedMemory {
- min_pages: 0,
- max_pages,
- }),
- call_body: Some(body::repeated(r * max_pages, &[
- Instruction::I32Const(1),
- Instruction::GrowMemory(0),
- Instruction::Drop,
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- // Unary numeric instructions.
- // All use w = w_bench - 2 * w_param.
-
- instr_i64clz {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::unary_instr(
- Instruction::I64Clz,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64ctz {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::unary_instr(
- Instruction::I64Ctz,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64popcnt {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::unary_instr(
- Instruction::I64Popcnt,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64eqz {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::unary_instr(
- Instruction::I64Eqz,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64extendsi32 {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomI32Repeated(1),
- Regular(Instruction::I64ExtendSI32),
- Regular(Instruction::Drop),
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- instr_i64extendui32 {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
- call_body: Some(body::repeated_dyn(r * INSTR_BENCHMARK_BATCH_SIZE, vec![
- RandomI32Repeated(1),
- Regular(Instruction::I64ExtendUI32),
- Regular(Instruction::Drop),
- ])),
- .. Default::default()
- }));
- }: {
- sbox.invoke();
- }
-
- instr_i32wrapi64 {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::unary_instr(
- Instruction::I32WrapI64,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- // Binary numeric instructions.
- // All use w = w_bench - 3 * w_param.
-
- instr_i64eq {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64Eq,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64ne {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64Ne,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64lts {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64LtS,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64ltu {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64LtU,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64gts {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64GtS,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64gtu {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64GtU,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64les {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64LeS,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64leu {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64LeU,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64ges {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64GeS,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64geu {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64GeU,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64add {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64Add,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64sub {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64Sub,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64mul {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64Mul,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64divs {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64DivS,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64divu {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64DivU,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64rems {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64RemS,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64remu {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64RemU,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64and {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64And,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64or {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64Or,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64xor {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64Xor,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64shl {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64Shl,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64shrs {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64ShrS,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64shru {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64ShrU,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64rotl {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64Rotl,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- instr_i64rotr {
- let r in 0 .. INSTR_BENCHMARK_BATCHES;
- let mut sbox = Sandbox::from(&WasmModule::<T>::binary_instr(
- Instruction::I64Rotr,
- r * INSTR_BENCHMARK_BATCH_SIZE,
- ));
- }: {
- sbox.invoke();
- }
-
- // This is no benchmark. It merely exist to have an easy way to pretty print the curently
- // configured `Schedule` during benchmark development.
- // It can be outputed using the following command:
- // cargo run --manifest-path=bin/node/cli/Cargo.toml --release \
- // --features runtime-benchmarks -- benchmark --dev --execution=native \
- // -p pallet_contracts -e print_schedule --no-median-slopes --no-min-squares
- #[extra]
- print_schedule {
- #[cfg(feature = "std")]
- {
- let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) -
- T::WeightInfo::on_initialize_per_trie_key(0);
- let weight_per_queue_item = T::WeightInfo::on_initialize_per_queue_item(1) -
- T::WeightInfo::on_initialize_per_queue_item(0);
- let weight_limit = T::DeletionWeightLimit::get();
- let queue_depth: u64 = T::DeletionQueueDepth::get().into();
- println!("{:#?}", Schedule::<T>::default());
- println!("###############################################");
- println!("Lazy deletion throughput per block (empty queue, full queue): {}, {}",
- weight_limit / weight_per_key,
- (weight_limit - weight_per_queue_item * queue_depth) / weight_per_key,
- );
- }
- #[cfg(not(feature = "std"))]
- return Err("Run this bench with a native runtime in order to see the schedule.");
- }: {}
-}
-
-impl_benchmark_test_suite!(
- Contracts,
- crate::tests::ExtBuilder::default().build(),
- crate::tests::Test,
-);
pallets/contracts/src/benchmarking/sandbox.rsdiffbeforeafterboth--- a/pallets/contracts/src/benchmarking/sandbox.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-///! For instruction benchmarking we do no instantiate a full contract but merely the
-///! sandbox to execute the wasm code. This is because we do not need the full
-///! environment that provides the seal interface as imported functions.
-use super::{Config, code::WasmModule};
-use sp_core::crypto::UncheckedFrom;
-use sp_sandbox::{EnvironmentDefinitionBuilder, Instance, Memory};
-
-/// Minimal execution environment without any exported functions.
-pub struct Sandbox {
- instance: Instance<()>,
- _memory: Option<Memory>,
-}
-
-impl Sandbox {
- /// Invoke the `call` function of a contract code and panic on any execution error.
- pub fn invoke(&mut self) {
- self.instance.invoke("call", &[], &mut ()).unwrap();
- }
-}
-
-impl<T: Config> From<&WasmModule<T>> for Sandbox
-where
- T: Config,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
-{
- /// Creates an instance from the supplied module and supplies as much memory
- /// to the instance as the module declares as imported.
- fn from(module: &WasmModule<T>) -> Self {
- let mut env_builder = EnvironmentDefinitionBuilder::new();
- let memory = module.add_memory(&mut env_builder);
- let instance = Instance::new(&module.code, &env_builder, &mut ())
- .expect("Failed to create benchmarking Sandbox instance");
- Self {
- instance,
- _memory: memory,
- }
- }
-}
pallets/contracts/src/chain_extension.rsdiffbeforeafterboth--- a/pallets/contracts/src/chain_extension.rs
+++ /dev/null
@@ -1,400 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2020 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! A mechanism for runtime authors to augment the functionality of contracts.
-//!
-//! The runtime is able to call into any contract and retrieve the result using
-//! [`bare_call`](crate::Pallet::bare_call). This already allows customization of runtime
-//! behaviour by user generated code (contracts). However, often it is more straightforward
-//! to allow the reverse behaviour: The contract calls into the runtime. We call the latter
-//! one a "chain extension" because it allows the chain to extend the set of functions that are
-//! callable by a contract.
-//!
-//! In order to create a chain extension the runtime author implements the [`ChainExtension`]
-//! trait and declares it in this pallet's [configuration Trait](crate::Config). All types
-//! required for this endeavour are defined or re-exported in this module. There is an
-//! implementation on `()` which can be used to signal that no chain extension is available.
-//!
-//! # Security
-//!
-//! The chain author alone is responsible for the security of the chain extension.
-//! This includes avoiding the exposure of exploitable functions and charging the
-//! appropriate amount of weight. In order to do so benchmarks must be written and the
-//! [`charge_weight`](Environment::charge_weight) function must be called **before**
-//! carrying out any action that causes the consumption of the chargeable weight.
-//! It cannot be overstated how delicate of a process the creation of a chain extension
-//! is. Check whether using [`bare_call`](crate::Pallet::bare_call) suffices for the
-//! use case at hand.
-//!
-//! # Benchmarking
-//!
-//! The builtin contract callable functions that pallet-contracts provides all have
-//! benchmarks that determine the correct weight that an invocation of these functions
-//! induces. In order to be able to charge the correct weight for the functions defined
-//! by a chain extension benchmarks must be written, too. In the near future this crate
-//! will provide the means for easier creation of those specialized benchmarks.
-//!
-//! # Example
-//!
-//! The ink! repository maintains an
-//! [end-to-end example](https://github.com/paritytech/ink/tree/master/examples/rand-extension)
-//! on how to use a chain extension in order to provide new features to ink! contracts.
-
-use crate::{
- Error,
- wasm::{Runtime, RuntimeToken},
-};
-use codec::Decode;
-use frame_support::weights::Weight;
-use sp_runtime::DispatchError;
-use sp_std::{marker::PhantomData, vec::Vec};
-
-pub use frame_system::Config as SysConfig;
-pub use pallet_contracts_primitives::ReturnFlags;
-pub use sp_core::crypto::UncheckedFrom;
-pub use crate::{Config, exec::Ext};
-pub use state::Init as InitState;
-
-/// Result that returns a [`DispatchError`] on error.
-pub type Result<T> = sp_std::result::Result<T, DispatchError>;
-
-/// A trait used to extend the set of contract callable functions.
-///
-/// In order to create a custom chain extension this trait must be implemented and supplied
-/// to the pallet contracts configuration trait as the associated type of the same name.
-/// Consult the [module documentation](self) for a general explanation of chain extensions.
-pub trait ChainExtension<C: Config> {
- /// Call the chain extension logic.
- ///
- /// This is the only function that needs to be implemented in order to write a
- /// chain extensions. It is called whenever a contract calls the `seal_call_chain_extension`
- /// imported wasm function.
- ///
- /// # Parameters
- /// - `func_id`: The first argument to `seal_call_chain_extension`. Usually used to
- /// determine which function to realize.
- /// - `env`: Access to the remaining arguments and the execution environment.
- ///
- /// # Return
- ///
- /// In case of `Err` the contract execution is immediately suspended and the passed error
- /// is returned to the caller. Otherwise the value of [`RetVal`] determines the exit
- /// behaviour.
- fn call<E>(func_id: u32, env: Environment<E, InitState>) -> Result<RetVal>
- where
- E: Ext<T = C>,
- <E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>;
-
- /// Determines whether chain extensions are enabled for this chain.
- ///
- /// The default implementation returns `true`. Therefore it is not necessary to overwrite
- /// this function when implementing a chain extension. In case of `false` the deployment of
- /// a contract that references `seal_call_chain_extension` will be denied and calling this
- /// function will return [`NoChainExtension`](Error::NoChainExtension) without first calling
- /// into [`call`](Self::call).
- fn enabled() -> bool {
- true
- }
-}
-
-/// Implementation that indicates that no chain extension is available.
-impl<C: Config> ChainExtension<C> for () {
- fn call<E>(_func_id: u32, mut _env: Environment<E, InitState>) -> Result<RetVal>
- where
- E: Ext<T = C>,
- <E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
- {
- // Never called since [`Self::enabled()`] is set to `false`. Because we want to
- // avoid panics at all costs we supply a sensible error value here instead
- // of an `unimplemented!`.
- Err(Error::<E::T>::NoChainExtension.into())
- }
-
- fn enabled() -> bool {
- false
- }
-}
-
-/// Determines the exit behaviour and return value of a chain extension.
-pub enum RetVal {
- /// The chain extensions returns the supplied value to its calling contract.
- Converging(u32),
- /// The control does **not** return to the calling contract.
- ///
- /// Use this to stop the execution of the contract when the chain extension returns.
- /// The semantic is the same as for calling `seal_return`: The control returns to
- /// the caller of the currently executing contract yielding the supplied buffer and
- /// flags.
- Diverging { flags: ReturnFlags, data: Vec<u8> },
-}
-
-/// Grants the chain extension access to its parameters and execution environment.
-///
-/// It uses [typestate programming](https://docs.rust-embedded.org/book/static-guarantees/typestate-programming.html)
-/// to enforce the correct usage of the parameters passed to the chain extension.
-pub struct Environment<'a, 'b, E: Ext, S: state::State> {
- /// The actual data of this type.
- inner: Inner<'a, 'b, E>,
- /// `S` is only used in the type system but never as value.
- phantom: PhantomData<S>,
-}
-
-/// Functions that are available in every state of this type.
-impl<'a, 'b, E: Ext, S: state::State> Environment<'a, 'b, E, S>
-where
- <E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
-{
- /// Charge the passed `amount` of weight from the overall limit.
- ///
- /// It returns `Ok` when there the remaining weight budget is larger than the passed
- /// `weight`. It returns `Err` otherwise. In this case the chain extension should
- /// abort the execution and pass through the error.
- ///
- /// # Note
- ///
- /// Weight is synonymous with gas in substrate.
- pub fn charge_weight(&mut self, amount: Weight) -> Result<()> {
- self.inner
- .runtime
- .charge_gas(RuntimeToken::ChainExtension(amount))
- .map(|_| ())
- }
-
- /// Grants access to the execution environment of the current contract call.
- ///
- /// Consult the functions on the returned type before re-implementing those functions.
- pub fn ext(&mut self) -> &mut E {
- self.inner.runtime.ext()
- }
-}
-
-/// Functions that are only available in the initial state of this type.
-///
-/// Those are the functions that determine how the arguments to the chain extensions
-/// should be consumed.
-impl<'a, 'b, E: Ext> Environment<'a, 'b, E, state::Init> {
- /// Creates a new environment for consumption by a chain extension.
- ///
- /// It is only available to this crate because only the wasm runtime module needs to
- /// ever create this type. Chain extensions merely consume it.
- pub(crate) fn new(
- runtime: &'a mut Runtime<'b, E>,
- input_ptr: u32,
- input_len: u32,
- output_ptr: u32,
- output_len_ptr: u32,
- ) -> Self {
- Environment {
- inner: Inner {
- runtime,
- input_ptr,
- input_len,
- output_ptr,
- output_len_ptr,
- },
- phantom: PhantomData,
- }
- }
-
- /// Use all arguments as integer values.
- pub fn only_in(self) -> Environment<'a, 'b, E, state::OnlyIn> {
- Environment {
- inner: self.inner,
- phantom: PhantomData,
- }
- }
-
- /// Use input arguments as integer and output arguments as pointer to a buffer.
- pub fn prim_in_buf_out(self) -> Environment<'a, 'b, E, state::PrimInBufOut> {
- Environment {
- inner: self.inner,
- phantom: PhantomData,
- }
- }
-
- /// Use input and output arguments as pointers to a buffer.
- pub fn buf_in_buf_out(self) -> Environment<'a, 'b, E, state::BufInBufOut> {
- Environment {
- inner: self.inner,
- phantom: PhantomData,
- }
- }
-}
-
-/// Functions to use the input arguments as integers.
-impl<'a, 'b, E: Ext, S: state::PrimIn> Environment<'a, 'b, E, S> {
- /// The `input_ptr` argument.
- pub fn val0(&self) -> u32 {
- self.inner.input_ptr
- }
-
- /// The `input_len` argument.
- pub fn val1(&self) -> u32 {
- self.inner.input_len
- }
-}
-
-/// Functions to use the output arguments as integers.
-impl<'a, 'b, E: Ext, S: state::PrimOut> Environment<'a, 'b, E, S> {
- /// The `output_ptr` argument.
- pub fn val2(&self) -> u32 {
- self.inner.output_ptr
- }
-
- /// The `output_len_ptr` argument.
- pub fn val3(&self) -> u32 {
- self.inner.output_len_ptr
- }
-}
-
-/// Functions to use the input arguments as pointer to a buffer.
-impl<'a, 'b, E: Ext, S: state::BufIn> Environment<'a, 'b, E, S>
-where
- <E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
-{
- /// Reads `min(max_len, in_len)` from contract memory.
- ///
- /// This does **not** charge any weight. The caller must make sure that the an
- /// appropriate amount of weight is charged **before** reading from contract memory.
- /// The reason for that is that usually the costs for reading data and processing
- /// said data cannot be separated in a benchmark. Therefore a chain extension would
- /// charge the overall costs either using `max_len` (worst case approximation) or using
- /// [`in_len()`](Self::in_len).
- pub fn read(&self, max_len: u32) -> Result<Vec<u8>> {
- self.inner
- .runtime
- .read_sandbox_memory(self.inner.input_ptr, self.inner.input_len.min(max_len))
- }
-
- /// Reads `min(buffer.len(), in_len) from contract memory.
- ///
- /// This takes a mutable pointer to a buffer fills it with data and shrinks it to
- /// the size of the actual data. Apart from supporting pre-allocated buffers it is
- /// equivalent to to [`read()`](Self::read).
- pub fn read_into(&self, buffer: &mut &mut [u8]) -> Result<()> {
- let len = buffer.len();
- let sliced = {
- let buffer = core::mem::take(buffer);
- &mut buffer[..len.min(self.inner.input_len as usize)]
- };
- self.inner
- .runtime
- .read_sandbox_memory_into_buf(self.inner.input_ptr, sliced)?;
- *buffer = sliced;
- Ok(())
- }
-
- /// Reads `in_len` from contract memory and scale decodes it.
- ///
- /// This function is secure and recommended for all input types of fixed size
- /// as long as the cost of reading the memory is included in the overall already charged
- /// weight of the chain extension. This should usually be the case when fixed input types
- /// are used. Non fixed size types (like everything using `Vec`) usually need to use
- /// [`in_len()`](Self::in_len) in order to properly charge the necessary weight.
- pub fn read_as<T: Decode>(&mut self) -> Result<T> {
- self.inner
- .runtime
- .read_sandbox_memory_as(self.inner.input_ptr, self.inner.input_len)
- }
-
- /// The length of the input as passed in as `input_len`.
- ///
- /// A chain extension would use this value to calculate the dynamic part of its
- /// weight. For example a chain extension that calculates the hash of some passed in
- /// bytes would use `in_len` to charge the costs of hashing that amount of bytes.
- /// This also subsumes the act of copying those bytes as a benchmarks measures both.
- pub fn in_len(&self) -> u32 {
- self.inner.input_len
- }
-}
-
-/// Functions to use the output arguments as pointer to a buffer.
-impl<'a, 'b, E: Ext, S: state::BufOut> Environment<'a, 'b, E, S>
-where
- <E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
-{
- /// Write the supplied buffer to contract memory.
- ///
- /// If the contract supplied buffer is smaller than the passed `buffer` an `Err` is returned.
- /// If `allow_skip` is set to true the contract is allowed to skip the copying of the buffer
- /// by supplying the guard value of `u32::max_value()` as `out_ptr`. The
- /// `weight_per_byte` is only charged when the write actually happens and is not skipped or
- /// failed due to a too small output buffer.
- pub fn write(
- &mut self,
- buffer: &[u8],
- allow_skip: bool,
- weight_per_byte: Option<Weight>,
- ) -> Result<()> {
- self.inner.runtime.write_sandbox_output(
- self.inner.output_ptr,
- self.inner.output_len_ptr,
- buffer,
- allow_skip,
- |len| {
- weight_per_byte.map(|w| RuntimeToken::ChainExtension(w.saturating_mul(len.into())))
- },
- )
- }
-}
-
-/// The actual data of an `Environment`.
-///
-/// All data is put into this struct to easily pass it around as part of the typestate
-/// pattern. Also it creates the opportunity to box this struct in the future in case it
-/// gets too large.
-struct Inner<'a, 'b, E: Ext> {
- /// The runtime contains all necessary functions to interact with the running contract.
- runtime: &'a mut Runtime<'b, E>,
- /// Verbatim argument passed to `seal_call_chain_extension`.
- input_ptr: u32,
- /// Verbatim argument passed to `seal_call_chain_extension`.
- input_len: u32,
- /// Verbatim argument passed to `seal_call_chain_extension`.
- output_ptr: u32,
- /// Verbatim argument passed to `seal_call_chain_extension`.
- output_len_ptr: u32,
-}
-
-/// Private submodule with public types to prevent other modules from naming them.
-mod state {
- pub trait State {}
-
- pub trait PrimIn: State {}
- pub trait PrimOut: State {}
- pub trait BufIn: State {}
- pub trait BufOut: State {}
-
- /// The initial state of an [`Environment`](`super::Environment`).
- /// See [typestate programming](https://docs.rust-embedded.org/book/static-guarantees/typestate-programming.html).
- pub enum Init {}
- pub enum OnlyIn {}
- pub enum PrimInBufOut {}
- pub enum BufInBufOut {}
-
- impl State for Init {}
- impl State for OnlyIn {}
- impl State for PrimInBufOut {}
- impl State for BufInBufOut {}
-
- impl PrimIn for OnlyIn {}
- impl PrimOut for OnlyIn {}
- impl PrimIn for PrimInBufOut {}
- impl BufOut for PrimInBufOut {}
- impl BufIn for BufInBufOut {}
- impl BufOut for BufInBufOut {}
-}
pallets/contracts/src/exec.rsdiffbeforeafterboth--- a/pallets/contracts/src/exec.rs
+++ /dev/null
@@ -1,1836 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use crate::{
- CodeHash, Event, Config, Pallet as Contracts, TrieId, BalanceOf, ContractInfo,
- gas::GasMeter,
- rent::Rent,
- storage::{self, Storage},
- Error, ContractInfoOf, Schedule, AliveContractInfo,
-};
-use sp_core::crypto::UncheckedFrom;
-use sp_std::{prelude::*, marker::PhantomData};
-use sp_runtime::{
- Perbill,
- traits::{Bounded, Zero, Convert, Saturating},
-};
-use frame_support::{
- dispatch::{DispatchResult, DispatchError},
- traits::{ExistenceRequirement, Currency, Time, Randomness, Get},
- weights::Weight,
- ensure,
-};
-use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags};
-
-pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
-pub type MomentOf<T> = <<T as Config>::Time as Time>::Moment;
-pub type SeedOf<T> = <T as frame_system::Config>::Hash;
-pub type BlockNumberOf<T> = <T as frame_system::Config>::BlockNumber;
-pub type StorageKey = [u8; 32];
-pub type ExecResult = Result<ExecReturnValue, ExecError>;
-
-/// A type that represents a topic of an event. At the moment a hash is used.
-pub type TopicOf<T> = <T as frame_system::Config>::Hash;
-
-/// Origin of the error.
-///
-/// Call or instantiate both called into other contracts and pass through errors happening
-/// in those to the caller. This enum is for the caller to distinguish whether the error
-/// happened during the execution of the callee or in the current execution context.
-#[cfg_attr(test, derive(Debug, PartialEq))]
-pub enum ErrorOrigin {
- /// Caller error origin.
- ///
- /// The error happened in the current exeuction context rather than in the one
- /// of the contract that is called into.
- Caller,
- /// The error happened during execution of the called contract.
- Callee,
-}
-
-/// Error returned by contract exection.
-#[cfg_attr(test, derive(Debug, PartialEq))]
-pub struct ExecError {
- /// The reason why the execution failed.
- pub error: DispatchError,
- /// Origin of the error.
- pub origin: ErrorOrigin,
-}
-
-impl<T: Into<DispatchError>> From<T> for ExecError {
- fn from(error: T) -> Self {
- Self {
- error: error.into(),
- origin: ErrorOrigin::Caller,
- }
- }
-}
-
-/// Information needed for rent calculations that can be requested by a contract.
-#[derive(codec::Encode)]
-#[cfg_attr(test, derive(Debug, PartialEq))]
-pub struct RentParams<T: Config> {
- /// The total balance of the contract. Includes the balance transferred from the caller.
- total_balance: BalanceOf<T>,
- /// The free balance of the contract. Includes the balance transferred from the caller.
- free_balance: BalanceOf<T>,
- /// See crate [`Contracts::subsistence_threshold()`].
- subsistence_threshold: BalanceOf<T>,
- /// See crate [`Config::DepositPerContract`].
- deposit_per_contract: BalanceOf<T>,
- /// See crate [`Config::DepositPerStorageByte`].
- deposit_per_storage_byte: BalanceOf<T>,
- /// See crate [`Config::DepositPerStorageItem`].
- deposit_per_storage_item: BalanceOf<T>,
- /// See crate [`Ext::rent_allowance()`].
- rent_allowance: BalanceOf<T>,
- /// See crate [`Config::RentFraction`].
- rent_fraction: Perbill,
- /// See crate [`AliveContractInfo::storage_size`].
- storage_size: u32,
- /// See crate [`Executable::aggregate_code_len()`].
- code_size: u32,
- /// See crate [`Executable::refcount()`].
- code_refcount: u32,
- /// Reserved for backwards compatible changes to this data structure.
- _reserved: Option<()>,
-}
-
-impl<T> RentParams<T>
-where
- T: Config,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
-{
- fn new<E: Executable<T>>(
- account_id: &T::AccountId,
- contract: &AliveContractInfo<T>,
- executable: &E,
- ) -> Self {
- Self {
- total_balance: T::Currency::total_balance(account_id),
- free_balance: T::Currency::free_balance(account_id),
- subsistence_threshold: <Contracts<T>>::subsistence_threshold(),
- deposit_per_contract: T::DepositPerContract::get(),
- deposit_per_storage_byte: T::DepositPerStorageByte::get(),
- deposit_per_storage_item: T::DepositPerStorageItem::get(),
- rent_allowance: contract.rent_allowance,
- rent_fraction: T::RentFraction::get(),
- storage_size: contract.storage_size,
- code_size: executable.aggregate_code_len(),
- code_refcount: executable.refcount(),
- _reserved: None,
- }
- }
-}
-
-/// We cannot derive `Default` because `T` does not necessarily implement `Default`.
-#[cfg(test)]
-impl<T: Config> Default for RentParams<T> {
- fn default() -> Self {
- Self {
- total_balance: Default::default(),
- free_balance: Default::default(),
- subsistence_threshold: Default::default(),
- deposit_per_contract: Default::default(),
- deposit_per_storage_byte: Default::default(),
- deposit_per_storage_item: Default::default(),
- rent_allowance: Default::default(),
- rent_fraction: Default::default(),
- storage_size: Default::default(),
- code_size: Default::default(),
- code_refcount: Default::default(),
- _reserved: Default::default(),
- }
- }
-}
-
-/// An interface that provides access to the external environment in which the
-/// smart-contract is executed.
-///
-/// This interface is specialized to an account of the executing code, so all
-/// operations are implicitly performed on that account.
-///
-/// # Note
-///
-/// This trait is sealed and cannot be implemented by downstream crates.
-pub trait Ext: sealing::Sealed {
- type T: Config;
-
- /// Returns the storage entry of the executing account by the given `key`.
- ///
- /// Returns `None` if the `key` wasn't previously set by `set_storage` or
- /// was deleted.
- fn get_storage(&self, key: &StorageKey) -> Option<Vec<u8>>;
-
- /// Sets the storage entry by the given key to the specified value. If `value` is `None` then
- /// the storage entry is deleted.
- fn set_storage(&mut self, key: StorageKey, value: Option<Vec<u8>>) -> DispatchResult;
-
- /// Instantiate a contract from the given code.
- ///
- /// Returns the original code size of the called contract.
- /// The newly created account will be associated with `code`. `value` specifies the amount of value
- /// transferred from this to the newly created account (also known as endowment).
- ///
- /// # Return Value
- ///
- /// Result<(AccountId, ExecReturnValue, CodeSize), (ExecError, CodeSize)>
- fn instantiate(
- &mut self,
- code: CodeHash<Self::T>,
- value: BalanceOf<Self::T>,
- gas_meter: &mut GasMeter<Self::T>,
- input_data: Vec<u8>,
- salt: &[u8],
- ) -> Result<(AccountIdOf<Self::T>, ExecReturnValue, u32), (ExecError, u32)>;
-
- /// Transfer some amount of funds into the specified account.
- fn transfer(&mut self, to: &AccountIdOf<Self::T>, value: BalanceOf<Self::T>) -> DispatchResult;
-
- /// Transfer all funds to `beneficiary` and delete the contract.
- ///
- /// Returns the original code size of the terminated contract.
- /// Since this function removes the self contract eagerly, if succeeded, no further actions should
- /// be performed on this `Ext` instance.
- ///
- /// This function will fail if the same contract is present on the contract
- /// call stack.
- ///
- /// # Return Value
- ///
- /// Result<CodeSize, (DispatchError, CodeSize)>
- fn terminate(
- &mut self,
- beneficiary: &AccountIdOf<Self::T>,
- ) -> Result<u32, (DispatchError, u32)>;
-
- /// Call (possibly transferring some amount of funds) into the specified account.
- ///
- /// Returns the original code size of the called contract.
- ///
- /// # Return Value
- ///
- /// Result<(ExecReturnValue, CodeSize), (ExecError, CodeSize)>
- fn call(
- &mut self,
- to: &AccountIdOf<Self::T>,
- value: BalanceOf<Self::T>,
- gas_meter: &mut GasMeter<Self::T>,
- input_data: Vec<u8>,
- ) -> Result<(ExecReturnValue, u32), (ExecError, u32)>;
-
- /// Restores the given destination contract sacrificing the current one.
- ///
- /// Since this function removes the self contract eagerly, if succeeded, no further actions should
- /// be performed on this `Ext` instance.
- ///
- /// This function will fail if the same contract is present
- /// on the contract call stack.
- ///
- /// # Return Value
- ///
- /// Result<(CallerCodeSize, DestCodeSize), (DispatchError, CallerCodeSize, DestCodesize)>
- fn restore_to(
- &mut self,
- dest: AccountIdOf<Self::T>,
- code_hash: CodeHash<Self::T>,
- rent_allowance: BalanceOf<Self::T>,
- delta: Vec<StorageKey>,
- ) -> Result<(u32, u32), (DispatchError, u32, u32)>;
-
- /// Returns a reference to the account id of the caller.
- fn caller(&self) -> &AccountIdOf<Self::T>;
-
- /// Returns a reference to the account id of the current contract.
- fn address(&self) -> &AccountIdOf<Self::T>;
-
- /// Returns the balance of the current contract.
- ///
- /// The `value_transferred` is already added.
- fn balance(&self) -> BalanceOf<Self::T>;
-
- /// Returns the value transferred along with this call or as endowment.
- fn value_transferred(&self) -> BalanceOf<Self::T>;
-
- /// Returns a reference to the timestamp of the current block
- fn now(&self) -> &MomentOf<Self::T>;
-
- /// Returns the minimum balance that is required for creating an account.
- fn minimum_balance(&self) -> BalanceOf<Self::T>;
-
- /// Returns the deposit required to create a tombstone upon contract eviction.
- fn tombstone_deposit(&self) -> BalanceOf<Self::T>;
-
- /// Returns a random number for the current block with the given subject.
- fn random(&self, subject: &[u8]) -> (SeedOf<Self::T>, BlockNumberOf<Self::T>);
-
- /// Deposit an event with the given topics.
- ///
- /// There should not be any duplicates in `topics`.
- fn deposit_event(&mut self, topics: Vec<TopicOf<Self::T>>, data: Vec<u8>);
-
- /// Set rent allowance of the contract
- fn set_rent_allowance(&mut self, rent_allowance: BalanceOf<Self::T>);
-
- /// Rent allowance of the contract
- fn rent_allowance(&self) -> BalanceOf<Self::T>;
-
- /// Returns the current block number.
- fn block_number(&self) -> BlockNumberOf<Self::T>;
-
- /// Returns the maximum allowed size of a storage item.
- fn max_value_size(&self) -> u32;
-
- /// Returns the price for the specified amount of weight.
- fn get_weight_price(&self, weight: Weight) -> BalanceOf<Self::T>;
-
- /// Get a reference to the schedule used by the current call.
- fn schedule(&self) -> &Schedule<Self::T>;
-
- /// Information needed for rent calculations.
- fn rent_params(&self) -> &RentParams<Self::T>;
-}
-
-/// Describes the different functions that can be exported by an [`Executable`].
-#[cfg_attr(test, derive(Clone, Copy, PartialEq))]
-pub enum ExportedFunction {
- /// The constructor function which is executed on deployment of a contract.
- Constructor,
- /// The function which is executed when a contract is called.
- Call,
-}
-
-/// A trait that represents something that can be executed.
-///
-/// In the on-chain environment this would be represented by a wasm module. This trait exists in
-/// order to be able to mock the wasm logic for testing.
-pub trait Executable<T: Config>: Sized {
- /// Load the executable from storage.
- fn from_storage(
- code_hash: CodeHash<T>,
- schedule: &Schedule<T>,
- gas_meter: &mut GasMeter<T>,
- ) -> Result<Self, DispatchError>;
-
- /// Load the module from storage without re-instrumenting it.
- ///
- /// A code module is re-instrumented on-load when it was originally instrumented with
- /// an older schedule. This skips this step for cases where the code storage is
- /// queried for purposes other than execution.
- fn from_storage_noinstr(code_hash: CodeHash<T>) -> Result<Self, DispatchError>;
-
- /// Decrements the refcount by one and deletes the code if it drops to zero.
- fn drop_from_storage(self);
-
- /// Increment the refcount by one. Fails if the code does not exist on-chain.
- ///
- /// Returns the size of the original code.
- fn add_user(code_hash: CodeHash<T>) -> Result<u32, DispatchError>;
-
- /// Decrement the refcount by one and remove the code when it drops to zero.
- ///
- /// Returns the size of the original code.
- fn remove_user(code_hash: CodeHash<T>) -> u32;
-
- /// Execute the specified exported function and return the result.
- ///
- /// When the specified function is `Constructor` the executable is stored and its
- /// refcount incremented.
- ///
- /// # Note
- ///
- /// This functions expects to be executed in a storage transaction that rolls back
- /// all of its emitted storage changes.
- fn execute<E: Ext<T = T>>(
- self,
- ext: E,
- function: &ExportedFunction,
- input_data: Vec<u8>,
- gas_meter: &mut GasMeter<T>,
- ) -> ExecResult;
-
- /// The code hash of the executable.
- fn code_hash(&self) -> &CodeHash<T>;
-
- /// The storage that is occupied by the instrumented executable and its pristine source.
- ///
- /// The returned size is already divided by the number of users who share the code.
- /// This is essentially `aggregate_code_len() / refcount()`.
- ///
- /// # Note
- ///
- /// This works with the current in-memory value of refcount. When calling any contract
- /// without refetching this from storage the result can be inaccurate as it might be
- /// working with a stale value. Usually this inaccuracy is tolerable.
- fn occupied_storage(&self) -> u32;
-
- /// Size of the instrumented code in bytes.
- fn code_len(&self) -> u32;
-
- /// Sum of instrumented and pristine code len.
- fn aggregate_code_len(&self) -> u32;
-
- // The number of contracts using this executable.
- fn refcount(&self) -> u32;
-}
-
-pub struct ExecutionContext<'a, T: Config + 'a, E> {
- caller: Option<&'a ExecutionContext<'a, T, E>>,
- self_account: T::AccountId,
- self_trie_id: Option<TrieId>,
- depth: usize,
- schedule: &'a Schedule<T>,
- timestamp: MomentOf<T>,
- block_number: T::BlockNumber,
- _phantom: PhantomData<E>,
-}
-
-impl<'a, T, E> ExecutionContext<'a, T, E>
-where
- T: Config,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
- E: Executable<T>,
-{
- /// Create the top level execution context.
- ///
- /// The specified `origin` address will be used as `sender` for. The `origin` must be a regular
- /// account (not a contract).
- pub fn top_level(origin: T::AccountId, schedule: &'a Schedule<T>) -> Self {
- ExecutionContext {
- caller: None,
- self_trie_id: None,
- self_account: origin,
- depth: 0,
- schedule,
- timestamp: T::Time::now(),
- block_number: <frame_system::Pallet<T>>::block_number(),
- _phantom: Default::default(),
- }
- }
-
- fn nested<'b, 'c: 'b>(
- &'c self,
- dest: T::AccountId,
- trie_id: TrieId,
- ) -> ExecutionContext<'b, T, E> {
- ExecutionContext {
- caller: Some(self),
- self_trie_id: Some(trie_id),
- self_account: dest,
- depth: self.depth + 1,
- schedule: self.schedule,
- timestamp: self.timestamp.clone(),
- block_number: self.block_number.clone(),
- _phantom: Default::default(),
- }
- }
-
- /// Make a call to the specified address, optionally transferring some funds.
- ///
- /// # Return Value
- ///
- /// Result<(ExecReturnValue, CodeSize), (ExecError, CodeSize)>
- pub fn call(
- &mut self,
- dest: T::AccountId,
- value: BalanceOf<T>,
- gas_meter: &mut GasMeter<T>,
- input_data: Vec<u8>,
- ) -> Result<(ExecReturnValue, u32), (ExecError, u32)> {
- if self.depth == T::MaxDepth::get() as usize {
- return Err((Error::<T>::MaxCallDepthReached.into(), 0));
- }
-
- let contract = <ContractInfoOf<T>>::get(&dest)
- .and_then(|contract| contract.get_alive())
- .ok_or((Error::<T>::NotCallable.into(), 0))?;
-
- let executable = E::from_storage(contract.code_hash, &self.schedule, gas_meter)
- .map_err(|e| (e.into(), 0))?;
- let code_len = executable.code_len();
-
- // This charges the rent and denies access to a contract that is in need of
- // eviction by returning `None`. We cannot evict eagerly here because those
- // changes would be rolled back in case this contract is called by another
- // contract.
- // See: https://github.com/paritytech/substrate/issues/6439#issuecomment-648754324
- let contract = Rent::<T, E>::charge(&dest, contract, executable.occupied_storage())
- .map_err(|e| (e.into(), code_len))?
- .ok_or((Error::<T>::NotCallable.into(), code_len))?;
-
- let transactor_kind = self.transactor_kind();
- let caller = self.self_account.clone();
-
- let result = self
- .with_nested_context(dest.clone(), contract.trie_id.clone(), |nested| {
- if value > BalanceOf::<T>::zero() {
- transfer::<T>(TransferCause::Call, transactor_kind, &caller, &dest, value)?
- }
-
- let call_context =
- nested.new_call_context(caller, &dest, value, &contract, &executable);
-
- let output = executable
- .execute(call_context, &ExportedFunction::Call, input_data, gas_meter)
- .map_err(|e| ExecError {
- error: e.error,
- origin: ErrorOrigin::Callee,
- })?;
- Ok(output)
- })
- .map_err(|e| (e, code_len))?;
- Ok((result, code_len))
- }
-
- pub fn instantiate(
- &mut self,
- endowment: BalanceOf<T>,
- gas_meter: &mut GasMeter<T>,
- executable: E,
- input_data: Vec<u8>,
- salt: &[u8],
- ) -> Result<(T::AccountId, ExecReturnValue), ExecError> {
- if self.depth == T::MaxDepth::get() as usize {
- Err(Error::<T>::MaxCallDepthReached)?
- }
-
- let transactor_kind = self.transactor_kind();
- let caller = self.self_account.clone();
- let dest = Contracts::<T>::contract_address(&caller, executable.code_hash(), salt);
-
- let output = frame_support::storage::with_transaction(|| {
- // Generate the trie id in a new transaction to only increment the counter on success.
- let dest_trie_id = Storage::<T>::generate_trie_id(&dest);
-
- let output = self.with_nested_context(dest.clone(), dest_trie_id, |nested| {
- let contract = Storage::<T>::place_contract(
- &dest,
- nested
- .self_trie_id
- .clone()
- .expect("the nested context always has to have self_trie_id"),
- executable.code_hash().clone(),
- )?;
-
- // Send funds unconditionally here. If the `endowment` is below existential_deposit
- // then error will be returned here.
- transfer::<T>(
- TransferCause::Instantiate,
- transactor_kind,
- &caller,
- &dest,
- endowment,
- )?;
-
- // Cache the value before calling into the constructor because that
- // consumes the value. If the constructor creates additional contracts using
- // the same code hash we still charge the "1 block rent" as if they weren't
- // spawned. This is OK as overcharging is always safe.
- let occupied_storage = executable.occupied_storage();
-
- let call_context = nested.new_call_context(
- caller.clone(),
- &dest,
- endowment,
- &contract,
- &executable,
- );
-
- let output = executable
- .execute(
- call_context,
- &ExportedFunction::Constructor,
- input_data,
- gas_meter,
- )
- .map_err(|e| ExecError {
- error: e.error,
- origin: ErrorOrigin::Callee,
- })?;
-
- // We need to re-fetch the contract because changes are written to storage
- // eagerly during execution.
- let contract = <ContractInfoOf<T>>::get(&dest)
- .and_then(|contract| contract.get_alive())
- .ok_or(Error::<T>::NotCallable)?;
-
- // Collect the rent for the first block to prevent the creation of very large
- // contracts that never intended to pay for even one block.
- // This also makes sure that it is above the subsistence threshold
- // in order to keep up the guarantuee that we always leave a tombstone behind
- // with the exception of a contract that called `seal_terminate`.
- Rent::<T, E>::charge(&dest, contract, occupied_storage)?
- .ok_or(Error::<T>::NewContractNotFunded)?;
-
- // Deposit an instantiation event.
- deposit_event::<T>(vec![], Event::Instantiated(caller.clone(), dest.clone()));
-
- Ok(output)
- });
-
- use frame_support::storage::TransactionOutcome::*;
- match output {
- Ok(_) => Commit(output),
- Err(_) => Rollback(output),
- }
- })?;
-
- Ok((dest, output))
- }
-
- fn new_call_context<'b>(
- &'b mut self,
- caller: T::AccountId,
- dest: &T::AccountId,
- value: BalanceOf<T>,
- contract: &AliveContractInfo<T>,
- executable: &E,
- ) -> CallContext<'b, 'a, T, E> {
- let timestamp = self.timestamp.clone();
- let block_number = self.block_number.clone();
- CallContext {
- ctx: self,
- caller,
- value_transferred: value,
- timestamp,
- block_number,
- rent_params: RentParams::new(dest, contract, executable),
- _phantom: Default::default(),
- }
- }
-
- /// Execute the given closure within a nested execution context.
- fn with_nested_context<F>(&mut self, dest: T::AccountId, trie_id: TrieId, func: F) -> ExecResult
- where
- F: FnOnce(&mut ExecutionContext<T, E>) -> ExecResult,
- {
- use frame_support::storage::TransactionOutcome::*;
- let mut nested = self.nested(dest, trie_id);
- frame_support::storage::with_transaction(|| {
- let output = func(&mut nested);
- match output {
- Ok(ref rv) if !rv.flags.contains(ReturnFlags::REVERT) => Commit(output),
- _ => Rollback(output),
- }
- })
- }
-
- /// 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))
- }
-
- fn transactor_kind(&self) -> TransactorKind {
- if self.depth == 0 {
- debug_assert!(self.self_trie_id.is_none());
- debug_assert!(self.caller.is_none());
- debug_assert!(ContractInfoOf::<T>::get(&self.self_account).is_none());
- TransactorKind::PlainAccount
- } else {
- TransactorKind::Contract
- }
- }
-}
-
-/// Describes whether we deal with a contract or a plain account.
-enum TransactorKind {
- /// Transaction was initiated from a plain account. That can be either be through a
- /// signed transaction or through RPC.
- PlainAccount,
- /// The call was initiated by a contract account.
- Contract,
-}
-
-/// Describes possible transfer causes.
-enum TransferCause {
- Call,
- Instantiate,
- Terminate,
-}
-
-/// Transfer some funds from `transactor` to `dest`.
-///
-/// We only allow allow for draining all funds of the sender if `cause` is
-/// is specified as `Terminate`. Otherwise, any transfer that would bring the sender below the
-/// subsistence threshold (for contracts) or the existential deposit (for plain accounts)
-/// results in an error.
-fn transfer<T: Config>(
- cause: TransferCause,
- origin: TransactorKind,
- transactor: &T::AccountId,
- dest: &T::AccountId,
- value: BalanceOf<T>,
-) -> DispatchResult
-where
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
-{
- use self::TransferCause::*;
- use self::TransactorKind::*;
-
- // Only seal_terminate is allowed to bring the sender below the subsistence
- // threshold or even existential deposit.
- let existence_requirement = match (cause, origin) {
- (Terminate, _) => ExistenceRequirement::AllowDeath,
- (_, Contract) => {
- ensure!(
- T::Currency::total_balance(transactor).saturating_sub(value)
- >= Contracts::<T>::subsistence_threshold(),
- Error::<T>::BelowSubsistenceThreshold,
- );
- ExistenceRequirement::KeepAlive
- }
- (_, PlainAccount) => ExistenceRequirement::KeepAlive,
- };
-
- T::Currency::transfer(transactor, dest, value, existence_requirement)
- .map_err(|_| Error::<T>::TransferFailed)?;
-
- Ok(())
-}
-
-/// A context that is active within a call.
-///
-/// This context has some invariants that must be held at all times. Specifically:
-///`ctx` always points to a context of an alive contract. That implies that it has an existent
-/// `self_trie_id`.
-///
-/// Be advised that there are brief time spans where these invariants could be invalidated.
-/// For example, when a contract requests self-termination the contract is removed eagerly. That
-/// implies that the control won't be returned to the contract anymore, but there is still some code
-/// on the path of the return from that call context. Therefore, care must be taken in these
-/// situations.
-struct CallContext<'a, 'b: 'a, T: Config + 'b, E> {
- ctx: &'a mut ExecutionContext<'b, T, E>,
- caller: T::AccountId,
- value_transferred: BalanceOf<T>,
- timestamp: MomentOf<T>,
- block_number: T::BlockNumber,
- rent_params: RentParams<T>,
- _phantom: PhantomData<E>,
-}
-
-impl<'a, 'b: 'a, T, E> Ext for CallContext<'a, 'b, T, E>
-where
- T: Config + 'b,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
- E: Executable<T>,
-{
- type T = T;
-
- fn get_storage(&self, key: &StorageKey) -> Option<Vec<u8>> {
- let trie_id = self.ctx.self_trie_id.as_ref().expect(
- "`ctx.self_trie_id` points to an alive contract within the `CallContext`;\
- it cannot be `None`;\
- expect can't fail;\
- qed",
- );
- Storage::<T>::read(trie_id, key)
- }
-
- fn set_storage(&mut self, key: StorageKey, value: Option<Vec<u8>>) -> DispatchResult {
- let trie_id = self.ctx.self_trie_id.as_ref().expect(
- "`ctx.self_trie_id` points to an alive contract within the `CallContext`;\
- it cannot be `None`;\
- expect can't fail;\
- qed",
- );
- // write panics if the passed account is not alive.
- // the contract must be in the alive state within the `CallContext`;\
- // the contract cannot be absent in storage;
- // write cannot return `None`;
- // qed
- Storage::<T>::write(&self.ctx.self_account, trie_id, &key, value)
- }
-
- fn instantiate(
- &mut self,
- code_hash: CodeHash<T>,
- endowment: BalanceOf<T>,
- gas_meter: &mut GasMeter<T>,
- input_data: Vec<u8>,
- salt: &[u8],
- ) -> Result<(AccountIdOf<T>, ExecReturnValue, u32), (ExecError, u32)> {
- let executable =
- E::from_storage(code_hash, &self.ctx.schedule, gas_meter).map_err(|e| (e.into(), 0))?;
- let code_len = executable.code_len();
- self.ctx
- .instantiate(endowment, gas_meter, executable, input_data, salt)
- .map(|r| (r.0, r.1, code_len))
- .map_err(|e| (e, code_len))
- }
-
- fn transfer(&mut self, to: &T::AccountId, value: BalanceOf<T>) -> DispatchResult {
- transfer::<T>(
- TransferCause::Call,
- TransactorKind::Contract,
- &self.ctx.self_account.clone(),
- to,
- value,
- )
- }
-
- fn terminate(
- &mut self,
- beneficiary: &AccountIdOf<Self::T>,
- ) -> Result<u32, (DispatchError, u32)> {
- let self_id = self.ctx.self_account.clone();
- let value = T::Currency::free_balance(&self_id);
- if let Some(caller_ctx) = self.ctx.caller {
- if caller_ctx.is_live(&self_id) {
- return Err((Error::<T>::ReentranceDenied.into(), 0));
- }
- }
- transfer::<T>(
- TransferCause::Terminate,
- TransactorKind::Contract,
- &self_id,
- beneficiary,
- value,
- )
- .map_err(|e| (e, 0))?;
- if let Some(ContractInfo::Alive(info)) = ContractInfoOf::<T>::take(&self_id) {
- Storage::<T>::queue_trie_for_deletion(&info).map_err(|e| (e, 0))?;
- let code_len = E::remove_user(info.code_hash);
- Contracts::<T>::deposit_event(Event::Terminated(self_id, beneficiary.clone()));
- Ok(code_len)
- } else {
- panic!(
- "this function is only invoked by in the context of a contract;\
- this contract is therefore alive;\
- qed"
- );
- }
- }
-
- fn call(
- &mut self,
- to: &T::AccountId,
- value: BalanceOf<T>,
- gas_meter: &mut GasMeter<T>,
- input_data: Vec<u8>,
- ) -> Result<(ExecReturnValue, u32), (ExecError, u32)> {
- self.ctx.call(to.clone(), value, gas_meter, input_data)
- }
-
- fn restore_to(
- &mut self,
- dest: AccountIdOf<Self::T>,
- code_hash: CodeHash<Self::T>,
- rent_allowance: BalanceOf<Self::T>,
- delta: Vec<StorageKey>,
- ) -> Result<(u32, u32), (DispatchError, u32, u32)> {
- if let Some(caller_ctx) = self.ctx.caller {
- if caller_ctx.is_live(&self.ctx.self_account) {
- return Err((Error::<T>::ReentranceDenied.into(), 0, 0));
- }
- }
-
- let result = Rent::<T, E>::restore_to(
- self.ctx.self_account.clone(),
- dest.clone(),
- code_hash.clone(),
- rent_allowance,
- delta,
- );
- if let Ok(_) = result {
- deposit_event::<Self::T>(
- vec![],
- Event::Restored(
- self.ctx.self_account.clone(),
- dest,
- code_hash,
- rent_allowance,
- ),
- );
- }
- result
- }
-
- fn address(&self) -> &T::AccountId {
- &self.ctx.self_account
- }
-
- fn caller(&self) -> &T::AccountId {
- &self.caller
- }
-
- fn balance(&self) -> BalanceOf<T> {
- T::Currency::free_balance(&self.ctx.self_account)
- }
-
- fn value_transferred(&self) -> BalanceOf<T> {
- self.value_transferred
- }
-
- fn random(&self, subject: &[u8]) -> (SeedOf<T>, BlockNumberOf<T>) {
- T::Randomness::random(subject)
- }
-
- fn now(&self) -> &MomentOf<T> {
- &self.timestamp
- }
-
- fn minimum_balance(&self) -> BalanceOf<T> {
- T::Currency::minimum_balance()
- }
-
- fn tombstone_deposit(&self) -> BalanceOf<T> {
- T::TombstoneDeposit::get()
- }
-
- fn deposit_event(&mut self, topics: Vec<T::Hash>, data: Vec<u8>) {
- deposit_event::<Self::T>(
- topics,
- Event::ContractEmitted(self.ctx.self_account.clone(), data),
- );
- }
-
- fn set_rent_allowance(&mut self, rent_allowance: BalanceOf<T>) {
- if let Err(storage::ContractAbsentError) =
- Storage::<T>::set_rent_allowance(&self.ctx.self_account, rent_allowance)
- {
- panic!(
- "`self_account` points to an alive contract within the `CallContext`;
- set_rent_allowance cannot return `Err`; qed"
- );
- }
- }
-
- fn rent_allowance(&self) -> BalanceOf<T> {
- Storage::<T>::rent_allowance(&self.ctx.self_account)
- .unwrap_or_else(|_| <BalanceOf<T>>::max_value()) // Must never be triggered actually
- }
-
- fn block_number(&self) -> T::BlockNumber {
- self.block_number
- }
-
- fn max_value_size(&self) -> u32 {
- T::MaxValueSize::get()
- }
-
- fn get_weight_price(&self, weight: Weight) -> BalanceOf<Self::T> {
- T::WeightPrice::convert(weight)
- }
-
- fn schedule(&self) -> &Schedule<Self::T> {
- &self.ctx.schedule
- }
-
- fn rent_params(&self) -> &RentParams<Self::T> {
- &self.rent_params
- }
-}
-
-fn deposit_event<T: Config>(topics: Vec<T::Hash>, event: Event<T>) {
- <frame_system::Pallet<T>>::deposit_event_indexed(
- &*topics,
- <T as Config>::Event::from(event).into(),
- )
-}
-
-mod sealing {
- use super::*;
-
- pub trait Sealed {}
-
- impl<'a, 'b: 'a, T: Config, E> Sealed for CallContext<'a, 'b, T, E> {}
-
- #[cfg(test)]
- impl Sealed for crate::wasm::MockExt {}
-
- #[cfg(test)]
- impl Sealed for &mut crate::wasm::MockExt {}
-}
-
-/// These tests exercise the executive layer.
-///
-/// In these tests the VM/loader are mocked. Instead of dealing with wasm bytecode they use simple closures.
-/// This allows you to tackle executive logic more thoroughly without writing a
-/// wasm VM code.
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::{
- gas::GasMeter,
- tests::{ExtBuilder, Test, Event as MetaEvent},
- storage::{Storage, ContractAbsentError},
- tests::{
- ALICE, BOB, CHARLIE,
- test_utils::{place_contract, set_balance, get_balance},
- },
- exec::ExportedFunction::*,
- Error, Weight, CurrentSchedule,
- };
- use sp_core::Bytes;
- use frame_support::assert_noop;
- use sp_runtime::DispatchError;
- use assert_matches::assert_matches;
- use std::{cell::RefCell, collections::HashMap, rc::Rc};
- use pretty_assertions::{assert_eq, assert_ne};
-
- type MockContext<'a> = ExecutionContext<'a, Test, MockExecutable>;
-
- const GAS_LIMIT: Weight = 10_000_000_000;
-
- thread_local! {
- static LOADER: RefCell<MockLoader> = RefCell::new(MockLoader::default());
- }
-
- fn events() -> Vec<Event<Test>> {
- <frame_system::Pallet<Test>>::events()
- .into_iter()
- .filter_map(|meta| match meta.event {
- MetaEvent::pallet_contracts(contract_event) => Some(contract_event),
- _ => None,
- })
- .collect()
- }
-
- struct MockCtx<'a> {
- ext: &'a mut dyn Ext<T = Test>,
- input_data: Vec<u8>,
- gas_meter: &'a mut GasMeter<Test>,
- }
-
- #[derive(Clone)]
- struct MockExecutable {
- func: Rc<dyn Fn(MockCtx, &Self) -> ExecResult + 'static>,
- func_type: ExportedFunction,
- code_hash: CodeHash<Test>,
- refcount: u64,
- }
-
- #[derive(Default)]
- struct MockLoader {
- map: HashMap<CodeHash<Test>, MockExecutable>,
- counter: u64,
- }
-
- impl MockLoader {
- fn insert(
- func_type: ExportedFunction,
- f: impl Fn(MockCtx, &MockExecutable) -> ExecResult + 'static,
- ) -> CodeHash<Test> {
- LOADER.with(|loader| {
- let mut loader = loader.borrow_mut();
- // Generate code hashes as monotonically increasing values.
- let hash = <Test as frame_system::Config>::Hash::from_low_u64_be(loader.counter);
- loader.counter += 1;
- loader.map.insert(
- hash,
- MockExecutable {
- func: Rc::new(f),
- func_type,
- code_hash: hash.clone(),
- refcount: 1,
- },
- );
- hash
- })
- }
-
- fn increment_refcount(code_hash: CodeHash<Test>) {
- LOADER.with(|loader| {
- let mut loader = loader.borrow_mut();
- loader
- .map
- .entry(code_hash)
- .and_modify(|executable| executable.refcount += 1)
- .or_insert_with(|| panic!("code_hash does not exist"));
- });
- }
-
- fn decrement_refcount(code_hash: CodeHash<Test>) {
- use std::collections::hash_map::Entry::Occupied;
- LOADER.with(|loader| {
- let mut loader = loader.borrow_mut();
- let mut entry = match loader.map.entry(code_hash) {
- Occupied(e) => e,
- _ => panic!("code_hash does not exist"),
- };
- let refcount = &mut entry.get_mut().refcount;
- *refcount -= 1;
- if *refcount == 0 {
- entry.remove();
- }
- });
- }
-
- fn refcount(code_hash: &CodeHash<Test>) -> u32 {
- LOADER.with(|loader| {
- loader
- .borrow()
- .map
- .get(code_hash)
- .expect("code_hash does not exist")
- .refcount()
- })
- }
- }
-
- impl Executable<Test> for MockExecutable {
- fn from_storage(
- code_hash: CodeHash<Test>,
- _schedule: &Schedule<Test>,
- _gas_meter: &mut GasMeter<Test>,
- ) -> Result<Self, DispatchError> {
- Self::from_storage_noinstr(code_hash)
- }
-
- fn from_storage_noinstr(code_hash: CodeHash<Test>) -> Result<Self, DispatchError> {
- LOADER.with(|loader| {
- loader
- .borrow_mut()
- .map
- .get(&code_hash)
- .cloned()
- .ok_or(Error::<Test>::CodeNotFound.into())
- })
- }
-
- fn drop_from_storage(self) {
- MockLoader::decrement_refcount(self.code_hash);
- }
-
- fn add_user(code_hash: CodeHash<Test>) -> Result<u32, DispatchError> {
- MockLoader::increment_refcount(code_hash);
- Ok(0)
- }
-
- fn remove_user(code_hash: CodeHash<Test>) -> u32 {
- MockLoader::decrement_refcount(code_hash);
- 0
- }
-
- fn execute<E: Ext<T = Test>>(
- self,
- mut ext: E,
- function: &ExportedFunction,
- input_data: Vec<u8>,
- gas_meter: &mut GasMeter<Test>,
- ) -> ExecResult {
- if let &Constructor = function {
- MockLoader::increment_refcount(self.code_hash);
- }
- if function == &self.func_type {
- (self.func)(
- MockCtx {
- ext: &mut ext,
- input_data,
- gas_meter,
- },
- &self,
- )
- } else {
- exec_success()
- }
- }
-
- fn code_hash(&self) -> &CodeHash<Test> {
- &self.code_hash
- }
-
- fn occupied_storage(&self) -> u32 {
- 0
- }
-
- fn code_len(&self) -> u32 {
- 0
- }
-
- fn aggregate_code_len(&self) -> u32 {
- 0
- }
-
- fn refcount(&self) -> u32 {
- self.refcount as u32
- }
- }
-
- fn exec_success() -> ExecResult {
- Ok(ExecReturnValue {
- flags: ReturnFlags::empty(),
- data: Bytes(Vec::new()),
- })
- }
-
- #[test]
- fn it_works() {
- thread_local! {
- static TEST_DATA: RefCell<Vec<usize>> = RefCell::new(vec![0]);
- }
-
- let value = Default::default();
- let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
- let exec_ch = MockLoader::insert(Call, |_ctx, _executable| {
- TEST_DATA.with(|data| data.borrow_mut().push(1));
- exec_success()
- });
-
- ExtBuilder::default().build().execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- place_contract(&BOB, exec_ch);
-
- assert_matches!(ctx.call(BOB, value, &mut gas_meter, vec![]), Ok(_));
- });
-
- TEST_DATA.with(|data| assert_eq!(*data.borrow(), vec![0, 1]));
- }
-
- #[test]
- fn transfer_works() {
- // This test verifies that a contract is able to transfer
- // some funds to another account.
- let origin = ALICE;
- let dest = BOB;
-
- ExtBuilder::default().build().execute_with(|| {
- set_balance(&origin, 100);
- set_balance(&dest, 0);
-
- super::transfer::<Test>(
- super::TransferCause::Call,
- super::TransactorKind::PlainAccount,
- &origin,
- &dest,
- 55,
- )
- .unwrap();
-
- assert_eq!(get_balance(&origin), 45);
- assert_eq!(get_balance(&dest), 55);
- });
- }
-
- #[test]
- fn changes_are_reverted_on_failing_call() {
- // This test verifies that changes are reverted on a call which fails (or equally, returns
- // a non-zero status code).
- let origin = ALICE;
- let dest = BOB;
-
- let return_ch = MockLoader::insert(Call, |_, _| {
- Ok(ExecReturnValue {
- flags: ReturnFlags::REVERT,
- data: Bytes(Vec::new()),
- })
- });
-
- ExtBuilder::default().build().execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(origin.clone(), &schedule);
- place_contract(&BOB, return_ch);
- set_balance(&origin, 100);
- let balance = get_balance(&dest);
-
- let output = ctx
- .call(
- dest.clone(),
- 55,
- &mut GasMeter::<Test>::new(GAS_LIMIT),
- vec![],
- )
- .unwrap();
-
- assert!(!output.0.is_success());
- assert_eq!(get_balance(&origin), 100);
-
- // the rent is still charged
- assert!(get_balance(&dest) < balance);
- });
- }
-
- #[test]
- fn balance_too_low() {
- // This test verifies that a contract can't send value if it's
- // balance is too low.
- let origin = ALICE;
- let dest = BOB;
-
- ExtBuilder::default().build().execute_with(|| {
- set_balance(&origin, 0);
-
- let result = super::transfer::<Test>(
- super::TransferCause::Call,
- super::TransactorKind::PlainAccount,
- &origin,
- &dest,
- 100,
- );
-
- assert_eq!(result, Err(Error::<Test>::TransferFailed.into()));
- assert_eq!(get_balance(&origin), 0);
- assert_eq!(get_balance(&dest), 0);
- });
- }
-
- #[test]
- fn output_is_returned_on_success() {
- // Verifies that if a contract returns data with a successful exit status, this data
- // is returned from the execution context.
- let origin = ALICE;
- let dest = BOB;
- let return_ch = MockLoader::insert(Call, |_, _| {
- Ok(ExecReturnValue {
- flags: ReturnFlags::empty(),
- data: Bytes(vec![1, 2, 3, 4]),
- })
- });
-
- ExtBuilder::default().build().execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(origin, &schedule);
- place_contract(&BOB, return_ch);
-
- let result = ctx.call(dest, 0, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);
-
- let output = result.unwrap();
- assert!(output.0.is_success());
- assert_eq!(output.0.data, Bytes(vec![1, 2, 3, 4]));
- });
- }
-
- #[test]
- fn output_is_returned_on_failure() {
- // Verifies that if a contract returns data with a failing exit status, this data
- // is returned from the execution context.
- let origin = ALICE;
- let dest = BOB;
- let return_ch = MockLoader::insert(Call, |_, _| {
- Ok(ExecReturnValue {
- flags: ReturnFlags::REVERT,
- data: Bytes(vec![1, 2, 3, 4]),
- })
- });
-
- ExtBuilder::default().build().execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(origin, &schedule);
- place_contract(&BOB, return_ch);
-
- let result = ctx.call(dest, 0, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);
-
- let output = result.unwrap();
- assert!(!output.0.is_success());
- assert_eq!(output.0.data, Bytes(vec![1, 2, 3, 4]));
- });
- }
-
- #[test]
- fn input_data_to_call() {
- let input_data_ch = MockLoader::insert(Call, |ctx, _| {
- assert_eq!(ctx.input_data, &[1, 2, 3, 4]);
- exec_success()
- });
-
- // This one tests passing the input data into a contract via call.
- ExtBuilder::default().build().execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- place_contract(&BOB, input_data_ch);
-
- let result = ctx.call(
- BOB,
- 0,
- &mut GasMeter::<Test>::new(GAS_LIMIT),
- vec![1, 2, 3, 4],
- );
- assert_matches!(result, Ok(_));
- });
- }
-
- #[test]
- fn input_data_to_instantiate() {
- let input_data_ch = MockLoader::insert(Constructor, |ctx, _| {
- assert_eq!(ctx.input_data, &[1, 2, 3, 4]);
- exec_success()
- });
-
- // This one tests passing the input data into a contract via instantiate.
- ExtBuilder::default().build().execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let subsistence = Contracts::<Test>::subsistence_threshold();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
- let executable =
- MockExecutable::from_storage(input_data_ch, &schedule, &mut gas_meter).unwrap();
-
- set_balance(&ALICE, subsistence * 10);
-
- let result = ctx.instantiate(
- subsistence * 3,
- &mut gas_meter,
- executable,
- vec![1, 2, 3, 4],
- &[],
- );
- assert_matches!(result, Ok(_));
- });
- }
-
- #[test]
- fn max_depth() {
- // This test verifies that when we reach the maximal depth creation of an
- // yet another context fails.
- thread_local! {
- static REACHED_BOTTOM: RefCell<bool> = RefCell::new(false);
- }
- let value = Default::default();
- let recurse_ch = MockLoader::insert(Call, |ctx, _| {
- // Try to call into yourself.
- let r = ctx.ext.call(&BOB, 0, ctx.gas_meter, vec![]);
-
- REACHED_BOTTOM.with(|reached_bottom| {
- let mut reached_bottom = reached_bottom.borrow_mut();
- if !*reached_bottom {
- // We are first time here, it means we just reached bottom.
- // Verify that we've got proper error and set `reached_bottom`.
- assert_eq!(r, Err((Error::<Test>::MaxCallDepthReached.into(), 0)));
- *reached_bottom = true;
- } else {
- // We just unwinding stack here.
- assert_matches!(r, Ok(_));
- }
- });
-
- exec_success()
- });
-
- ExtBuilder::default().build().execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- set_balance(&BOB, 1);
- place_contract(&BOB, recurse_ch);
-
- let result = ctx.call(BOB, value, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);
-
- assert_matches!(result, Ok(_));
- });
- }
-
- #[test]
- fn caller_returns_proper_values() {
- let origin = ALICE;
- let dest = BOB;
-
- thread_local! {
- static WITNESSED_CALLER_BOB: RefCell<Option<AccountIdOf<Test>>> = RefCell::new(None);
- static WITNESSED_CALLER_CHARLIE: RefCell<Option<AccountIdOf<Test>>> = RefCell::new(None);
- }
-
- let bob_ch = MockLoader::insert(Call, |ctx, _| {
- // Record the caller for bob.
- WITNESSED_CALLER_BOB
- .with(|caller| *caller.borrow_mut() = Some(ctx.ext.caller().clone()));
-
- // Call into CHARLIE contract.
- assert_matches!(ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), Ok(_));
- exec_success()
- });
- let charlie_ch = MockLoader::insert(Call, |ctx, _| {
- // Record the caller for charlie.
- WITNESSED_CALLER_CHARLIE
- .with(|caller| *caller.borrow_mut() = Some(ctx.ext.caller().clone()));
- exec_success()
- });
-
- ExtBuilder::default().build().execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(origin.clone(), &schedule);
- place_contract(&dest, bob_ch);
- place_contract(&CHARLIE, charlie_ch);
-
- let result = ctx.call(
- dest.clone(),
- 0,
- &mut GasMeter::<Test>::new(GAS_LIMIT),
- vec![],
- );
-
- assert_matches!(result, Ok(_));
- });
-
- WITNESSED_CALLER_BOB.with(|caller| assert_eq!(*caller.borrow(), Some(origin)));
- WITNESSED_CALLER_CHARLIE.with(|caller| assert_eq!(*caller.borrow(), Some(dest)));
- }
-
- #[test]
- fn address_returns_proper_values() {
- let bob_ch = MockLoader::insert(Call, |ctx, _| {
- // Verify that address matches BOB.
- assert_eq!(*ctx.ext.address(), BOB);
-
- // Call into charlie contract.
- assert_matches!(ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), Ok(_));
- exec_success()
- });
- let charlie_ch = MockLoader::insert(Call, |ctx, _| {
- assert_eq!(*ctx.ext.address(), CHARLIE);
- exec_success()
- });
-
- ExtBuilder::default().build().execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- place_contract(&BOB, bob_ch);
- place_contract(&CHARLIE, charlie_ch);
-
- let result = ctx.call(BOB, 0, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]);
-
- assert_matches!(result, Ok(_));
- });
- }
-
- #[test]
- fn refuse_instantiate_with_value_below_existential_deposit() {
- let dummy_ch = MockLoader::insert(Constructor, |_, _| exec_success());
-
- ExtBuilder::default()
- .existential_deposit(15)
- .build()
- .execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
- let executable =
- MockExecutable::from_storage(dummy_ch, &schedule, &mut gas_meter).unwrap();
-
- assert_matches!(
- ctx.instantiate(
- 0, // <- zero endowment
- &mut gas_meter,
- executable,
- vec![],
- &[],
- ),
- Err(_)
- );
- });
- }
-
- #[test]
- fn instantiation_work_with_success_output() {
- let dummy_ch = MockLoader::insert(Constructor, |_, _| {
- Ok(ExecReturnValue {
- flags: ReturnFlags::empty(),
- data: Bytes(vec![80, 65, 83, 83]),
- })
- });
-
- ExtBuilder::default()
- .existential_deposit(15)
- .build()
- .execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
- let executable =
- MockExecutable::from_storage(dummy_ch, &schedule, &mut gas_meter).unwrap();
- set_balance(&ALICE, 1000);
-
- let instantiated_contract_address = assert_matches!(
- ctx.instantiate(
- 100,
- &mut gas_meter,
- executable,
- vec![],
- &[],
- ),
- Ok((address, ref output)) if output.data == Bytes(vec![80, 65, 83, 83]) => address
- );
-
- // Check that the newly created account has the expected code hash and
- // there are instantiation event.
- assert_eq!(
- Storage::<Test>::code_hash(&instantiated_contract_address).unwrap(),
- dummy_ch
- );
- assert_eq!(
- &events(),
- &[Event::Instantiated(ALICE, instantiated_contract_address)]
- );
- });
- }
-
- #[test]
- fn instantiation_fails_with_failing_output() {
- let dummy_ch = MockLoader::insert(Constructor, |_, _| {
- Ok(ExecReturnValue {
- flags: ReturnFlags::REVERT,
- data: Bytes(vec![70, 65, 73, 76]),
- })
- });
-
- ExtBuilder::default()
- .existential_deposit(15)
- .build()
- .execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
- let executable =
- MockExecutable::from_storage(dummy_ch, &schedule, &mut gas_meter).unwrap();
- set_balance(&ALICE, 1000);
-
- let instantiated_contract_address = assert_matches!(
- ctx.instantiate(
- 100,
- &mut gas_meter,
- executable,
- vec![],
- &[],
- ),
- Ok((address, ref output)) if output.data == Bytes(vec![70, 65, 73, 76]) => address
- );
-
- // Check that the account has not been created.
- assert_noop!(
- Storage::<Test>::code_hash(&instantiated_contract_address),
- ContractAbsentError,
- );
- assert!(events().is_empty());
- });
- }
-
- #[test]
- fn instantiation_from_contract() {
- let dummy_ch = MockLoader::insert(Call, |_, _| exec_success());
- let instantiated_contract_address = Rc::new(RefCell::new(None::<AccountIdOf<Test>>));
- let instantiator_ch = MockLoader::insert(Call, {
- let dummy_ch = dummy_ch.clone();
- 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,
- Contracts::<Test>::subsistence_threshold() * 3,
- ctx.gas_meter,
- vec![],
- &[48, 49, 50],
- )
- .unwrap();
-
- *instantiated_contract_address.borrow_mut() = address.into();
- Ok(output)
- }
- });
-
- ExtBuilder::default()
- .existential_deposit(15)
- .build()
- .execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- set_balance(&ALICE, Contracts::<Test>::subsistence_threshold() * 100);
- place_contract(&BOB, instantiator_ch);
-
- assert_matches!(
- ctx.call(BOB, 20, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]),
- Ok(_)
- );
-
- 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!(
- Storage::<Test>::code_hash(&instantiated_contract_address).unwrap(),
- dummy_ch
- );
- assert_eq!(
- &events(),
- &[Event::Instantiated(BOB, instantiated_contract_address)]
- );
- });
- }
-
- #[test]
- fn instantiation_traps() {
- let dummy_ch = MockLoader::insert(Constructor, |_, _| Err("It's a trap!".into()));
- let instantiator_ch = MockLoader::insert(Call, {
- 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 {
- error: DispatchError::Other("It's a trap!"),
- origin: ErrorOrigin::Callee,
- },
- 0
- ))
- );
-
- exec_success()
- }
- });
-
- ExtBuilder::default()
- .existential_deposit(15)
- .build()
- .execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- set_balance(&ALICE, 1000);
- set_balance(&BOB, 100);
- place_contract(&BOB, instantiator_ch);
-
- assert_matches!(
- ctx.call(BOB, 20, &mut GasMeter::<Test>::new(GAS_LIMIT), vec![]),
- Ok(_)
- );
-
- // The contract wasn't instantiated so we don't expect to see an instantiation
- // event here.
- assert_eq!(&events(), &[]);
- });
- }
-
- #[test]
- fn termination_from_instantiate_fails() {
- let terminate_ch = MockLoader::insert(Constructor, |ctx, _| {
- ctx.ext.terminate(&ALICE).unwrap();
- exec_success()
- });
-
- ExtBuilder::default()
- .existential_deposit(15)
- .build()
- .execute_with(|| {
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
- let executable =
- MockExecutable::from_storage(terminate_ch, &schedule, &mut gas_meter).unwrap();
- set_balance(&ALICE, 1000);
-
- assert_eq!(
- ctx.instantiate(100, &mut gas_meter, executable, vec![], &[],),
- Err(Error::<Test>::NotCallable.into())
- );
-
- assert_eq!(&events(), &[]);
- });
- }
-
- #[test]
- fn rent_allowance() {
- let rent_allowance_ch = MockLoader::insert(Constructor, |ctx, _| {
- let subsistence = Contracts::<Test>::subsistence_threshold();
- let allowance = subsistence * 3;
- assert_eq!(ctx.ext.rent_allowance(), <BalanceOf<Test>>::max_value());
- ctx.ext.set_rent_allowance(allowance);
- assert_eq!(ctx.ext.rent_allowance(), allowance);
- exec_success()
- });
-
- ExtBuilder::default().build().execute_with(|| {
- let subsistence = Contracts::<Test>::subsistence_threshold();
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
- let executable =
- MockExecutable::from_storage(rent_allowance_ch, &schedule, &mut gas_meter).unwrap();
- set_balance(&ALICE, subsistence * 10);
-
- let result = ctx.instantiate(subsistence * 5, &mut gas_meter, executable, vec![], &[]);
- assert_matches!(result, Ok(_));
- });
- }
-
- #[test]
- fn rent_params_works() {
- let code_hash = MockLoader::insert(Call, |ctx, executable| {
- let address = ctx.ext.address();
- let contract = <ContractInfoOf<Test>>::get(address)
- .and_then(|c| c.get_alive())
- .unwrap();
- assert_eq!(
- ctx.ext.rent_params(),
- &RentParams::new(address, &contract, executable)
- );
- exec_success()
- });
-
- ExtBuilder::default().build().execute_with(|| {
- let subsistence = Contracts::<Test>::subsistence_threshold();
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
- set_balance(&ALICE, subsistence * 10);
- place_contract(&BOB, code_hash);
- ctx.call(BOB, 0, &mut gas_meter, vec![]).unwrap();
- });
- }
-
- #[test]
- fn rent_params_snapshotted() {
- let code_hash = MockLoader::insert(Call, |ctx, executable| {
- let subsistence = Contracts::<Test>::subsistence_threshold();
- let address = ctx.ext.address();
- let contract = <ContractInfoOf<Test>>::get(address)
- .and_then(|c| c.get_alive())
- .unwrap();
- let rent_params = RentParams::new(address, &contract, executable);
-
- // Changing the allowance during the call: rent params stay unchanged.
- let allowance = 42;
- assert_ne!(allowance, rent_params.rent_allowance);
- ctx.ext.set_rent_allowance(allowance);
- assert_eq!(ctx.ext.rent_params(), &rent_params);
-
- // Creating another instance from the same code_hash increases the refcount.
- // This is also not reflected in the rent params.
- assert_eq!(MockLoader::refcount(&executable.code_hash), 1);
- ctx.ext
- .instantiate(
- executable.code_hash,
- subsistence * 25,
- &mut GasMeter::<Test>::new(GAS_LIMIT),
- vec![],
- &[],
- )
- .unwrap();
- assert_eq!(MockLoader::refcount(&executable.code_hash), 2);
- assert_eq!(ctx.ext.rent_params(), &rent_params);
-
- exec_success()
- });
-
- ExtBuilder::default().build().execute_with(|| {
- let subsistence = Contracts::<Test>::subsistence_threshold();
- let schedule = <CurrentSchedule<Test>>::get();
- let mut ctx = MockContext::top_level(ALICE, &schedule);
- let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
- set_balance(&ALICE, subsistence * 100);
- place_contract(&BOB, code_hash);
- ctx.call(BOB, subsistence * 50, &mut gas_meter, vec![])
- .unwrap();
- });
- }
-}
pallets/contracts/src/gas.rsdiffbeforeafterboth--- a/pallets/contracts/src/gas.rs
+++ /dev/null
@@ -1,364 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use crate::{Config, Error, exec::ExecError};
-use sp_std::marker::PhantomData;
-use sp_runtime::traits::Zero;
-use frame_support::{
- dispatch::{
- DispatchResultWithPostInfo, PostDispatchInfo, DispatchErrorWithPostInfo, DispatchError,
- },
- weights::Weight,
-};
-use sp_core::crypto::UncheckedFrom;
-
-#[cfg(test)]
-use std::{any::Any, fmt::Debug};
-
-#[derive(Debug, PartialEq, Eq)]
-pub struct ChargedAmount(Weight);
-
-impl ChargedAmount {
- pub fn amount(&self) -> Weight {
- self.0
- }
-}
-
-#[cfg(not(test))]
-pub trait TestAuxiliaries {}
-#[cfg(not(test))]
-impl<T> TestAuxiliaries for T {}
-
-#[cfg(test)]
-pub trait TestAuxiliaries: Any + Debug + PartialEq + Eq {}
-#[cfg(test)]
-impl<T: Any + Debug + PartialEq + Eq> TestAuxiliaries for T {}
-
-/// This trait represents a token that can be used for charging `GasMeter`.
-/// There is no other way of charging it.
-///
-/// Implementing type is expected to be super lightweight hence `Copy` (`Clone` is added
-/// for consistency). If inlined there should be no observable difference compared
-/// to a hand-written code.
-pub trait Token<T: Config>: Copy + Clone + TestAuxiliaries {
- /// Metadata type, which the token can require for calculating the amount
- /// of gas to charge. Can be a some configuration type or
- /// just the `()`.
- type Metadata;
-
- /// Calculate amount of gas that should be taken by this token.
- ///
- /// This function should be really lightweight and must not fail. It is not
- /// expected that implementors will query the storage or do any kinds of heavy operations.
- ///
- /// That said, implementors of this function still can run into overflows
- /// while calculating the amount. In this case it is ok to use saturating operations
- /// since on overflow they will return `max_value` which should consume all gas.
- fn calculate_amount(&self, metadata: &Self::Metadata) -> Weight;
-}
-
-/// A wrapper around a type-erased trait object of what used to be a `Token`.
-#[cfg(test)]
-pub struct ErasedToken {
- pub description: String,
- pub token: Box<dyn Any>,
-}
-
-pub struct GasMeter<T: Config> {
- gas_limit: Weight,
- /// Amount of gas left from initial gas limit. Can reach zero.
- gas_left: Weight,
- _phantom: PhantomData<T>,
- #[cfg(test)]
- tokens: Vec<ErasedToken>,
-}
-
-impl<T: Config> GasMeter<T>
-where
- T::AccountId: UncheckedFrom<<T as frame_system::Config>::Hash> + AsRef<[u8]>,
-{
- pub fn new(gas_limit: Weight) -> Self {
- GasMeter {
- gas_limit,
- gas_left: gas_limit,
- _phantom: PhantomData,
- #[cfg(test)]
- tokens: Vec::new(),
- }
- }
-
- /// Account for used gas.
- ///
- /// Amount is calculated by the given `token`.
- ///
- /// Returns `OutOfGas` if there is not enough gas or addition of the specified
- /// amount of gas has lead to overflow. On success returns `Proceed`.
- ///
- /// NOTE that amount is always consumed, i.e. if there is not enough gas
- /// then the counter will be set to zero.
- #[inline]
- pub fn charge<Tok: Token<T>>(
- &mut self,
- metadata: &Tok::Metadata,
- token: Tok,
- ) -> Result<ChargedAmount, DispatchError> {
- #[cfg(test)]
- {
- // Unconditionally add the token to the storage.
- let erased_tok = ErasedToken {
- description: format!("{:?}", token),
- token: Box::new(token),
- };
- self.tokens.push(erased_tok);
- }
-
- let amount = token.calculate_amount(metadata);
- let new_value = self.gas_left.checked_sub(amount);
-
- // We always consume the gas even if there is not enough gas.
- self.gas_left = new_value.unwrap_or_else(Zero::zero);
-
- match new_value {
- Some(_) => Ok(ChargedAmount(amount)),
- None => Err(Error::<T>::OutOfGas.into()),
- }
- }
-
- /// Adjust a previously charged amount down to its actual amount.
- ///
- /// This is when a maximum a priori amount was charged and then should be partially
- /// refunded to match the actual amount.
- pub fn adjust_gas<Tok: Token<T>>(
- &mut self,
- charged_amount: ChargedAmount,
- metadata: &Tok::Metadata,
- token: Tok,
- ) {
- let adjustment = charged_amount
- .0
- .saturating_sub(token.calculate_amount(metadata));
- self.gas_left = self.gas_left.saturating_add(adjustment).min(self.gas_limit);
- }
-
- /// Refund previously charged gas back to the gas meter.
- ///
- /// This can be used if a gas worst case estimation must be charged before
- /// performing a certain action. This way the difference can be refundend when
- /// the worst case did not happen.
- pub fn refund(&mut self, amount: ChargedAmount) {
- self.gas_left = self.gas_left.saturating_add(amount.0).min(self.gas_limit)
- }
-
- /// Allocate some amount of gas and perform some work with
- /// a newly created nested gas meter.
- ///
- /// Invokes `f` with either the gas meter that has `amount` gas left or
- /// with `None`, if this gas meter has not enough gas to allocate given `amount`.
- ///
- /// All unused gas in the nested gas meter is returned to this gas meter.
- pub fn with_nested<R, F: FnOnce(Option<&mut GasMeter<T>>) -> R>(
- &mut self,
- amount: Weight,
- f: F,
- ) -> R {
- // NOTE that it is ok to allocate all available gas since it still ensured
- // by `charge` that it doesn't reach zero.
- if self.gas_left < amount {
- f(None)
- } else {
- self.gas_left = self.gas_left - amount;
- let mut nested = GasMeter::new(amount);
-
- let r = f(Some(&mut nested));
-
- self.gas_left = self.gas_left + nested.gas_left;
-
- r
- }
- }
-
- /// Returns how much gas was used.
- pub fn gas_spent(&self) -> Weight {
- self.gas_limit - self.gas_left
- }
-
- /// Returns how much gas left from the initial budget.
- pub fn gas_left(&self) -> Weight {
- self.gas_left
- }
-
- /// Turn this GasMeter into a DispatchResult that contains the actually used gas.
- pub fn into_dispatch_result<R, E>(
- self,
- result: Result<R, E>,
- base_weight: Weight,
- ) -> DispatchResultWithPostInfo
- where
- E: Into<ExecError>,
- {
- let post_info = PostDispatchInfo {
- actual_weight: Some(self.gas_spent().saturating_add(base_weight)),
- pays_fee: Default::default(),
- };
-
- result
- .map(|_| post_info)
- .map_err(|e| DispatchErrorWithPostInfo {
- post_info,
- error: e.into().error,
- })
- }
-
- #[cfg(test)]
- pub fn tokens(&self) -> &[ErasedToken] {
- &self.tokens
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::{GasMeter, Token};
- use crate::tests::Test;
-
- /// A simple utility macro that helps to match against a
- /// list of tokens.
- macro_rules! match_tokens {
- ($tokens_iter:ident,) => {
- };
- ($tokens_iter:ident, $x:expr, $($rest:tt)*) => {
- {
- let next = ($tokens_iter).next().unwrap();
- let pattern = $x;
-
- // Note that we don't specify the type name directly in this macro,
- // we only have some expression $x of some type. At the same time, we
- // have an iterator of Box<dyn Any> and to downcast we need to specify
- // the type which we want downcast to.
- //
- // So what we do is we assign `_pattern_typed_next_ref` to a variable which has
- // the required type.
- //
- // Then we make `_pattern_typed_next_ref = token.downcast_ref()`. This makes
- // rustc infer the type `T` (in `downcast_ref<T: Any>`) to be the same as in $x.
-
- let mut _pattern_typed_next_ref = &pattern;
- _pattern_typed_next_ref = match next.token.downcast_ref() {
- Some(p) => {
- assert_eq!(p, &pattern);
- p
- }
- None => {
- panic!("expected type {} got {}", stringify!($x), next.description);
- }
- };
- }
-
- match_tokens!($tokens_iter, $($rest)*);
- };
- }
-
- /// A trivial token that charges the specified number of gas units.
- #[derive(Copy, Clone, PartialEq, Eq, Debug)]
- struct SimpleToken(u64);
- impl Token<Test> for SimpleToken {
- type Metadata = ();
- fn calculate_amount(&self, _metadata: &()) -> u64 {
- self.0
- }
- }
-
- struct MultiplierTokenMetadata {
- multiplier: u64,
- }
- /// A simple token that charges for the given amount multiplied to
- /// a multiplier taken from a given metadata.
- #[derive(Copy, Clone, PartialEq, Eq, Debug)]
- struct MultiplierToken(u64);
-
- impl Token<Test> for MultiplierToken {
- type Metadata = MultiplierTokenMetadata;
- fn calculate_amount(&self, metadata: &MultiplierTokenMetadata) -> u64 {
- // Probably you want to use saturating mul in production code.
- self.0 * metadata.multiplier
- }
- }
-
- #[test]
- fn it_works() {
- let gas_meter = GasMeter::<Test>::new(50000);
- assert_eq!(gas_meter.gas_left(), 50000);
- }
-
- #[test]
- fn simple() {
- let mut gas_meter = GasMeter::<Test>::new(50000);
-
- let result = gas_meter.charge(
- &MultiplierTokenMetadata { multiplier: 3 },
- MultiplierToken(10),
- );
- assert!(!result.is_err());
-
- assert_eq!(gas_meter.gas_left(), 49_970);
- }
-
- #[test]
- fn tracing() {
- let mut gas_meter = GasMeter::<Test>::new(50000);
- assert!(!gas_meter.charge(&(), SimpleToken(1)).is_err());
- assert!(!gas_meter
- .charge(
- &MultiplierTokenMetadata { multiplier: 3 },
- MultiplierToken(10)
- )
- .is_err());
-
- let mut tokens = gas_meter.tokens()[0..2].iter();
- match_tokens!(tokens, SimpleToken(1), MultiplierToken(10),);
- }
-
- // This test makes sure that nothing can be executed if there is no gas.
- #[test]
- fn refuse_to_execute_anything_if_zero() {
- let mut gas_meter = GasMeter::<Test>::new(0);
- assert!(gas_meter.charge(&(), SimpleToken(1)).is_err());
- }
-
- // Make sure that if the gas meter is charged by exceeding amount then not only an error
- // returned for that charge, but also for all consequent charges.
- //
- // This is not strictly necessary, because the execution should be interrupted immediately
- // if the gas meter runs out of gas. However, this is just a nice property to have.
- #[test]
- fn overcharge_is_unrecoverable() {
- let mut gas_meter = GasMeter::<Test>::new(200);
-
- // The first charge is should lead to OOG.
- assert!(gas_meter.charge(&(), SimpleToken(300)).is_err());
-
- // The gas meter is emptied at this moment, so this should also fail.
- assert!(gas_meter.charge(&(), SimpleToken(1)).is_err());
- }
-
- // Charging the exact amount that the user paid for should be
- // possible.
- #[test]
- fn charge_exact_amount() {
- let mut gas_meter = GasMeter::<Test>::new(25);
- assert!(!gas_meter.charge(&(), SimpleToken(25)).is_err());
- }
-}
pallets/contracts/src/lib.rsdiffbeforeafterboth--- a/pallets/contracts/src/lib.rs
+++ /dev/null
@@ -1,831 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! # Contract Pallet
-//!
-//! The Contract module provides functionality for the runtime to deploy and execute WebAssembly smart-contracts.
-//!
-//! - [`Config`]
-//! - [`Call`]
-//!
-//! ## Overview
-//!
-//! This module extends accounts based on the [`Currency`] trait to have smart-contract functionality. It can
-//! be used with other modules that implement accounts based on [`Currency`]. These "smart-contract accounts"
-//! have the ability to instantiate smart-contracts and make calls to other contract and non-contract accounts.
-//!
-//! The smart-contract code is stored once in a code cache, and later retrievable via its hash.
-//! This means that multiple smart-contracts can be instantiated from the same hash, without replicating
-//! the code each time.
-//!
-//! When a smart-contract is called, its associated code is retrieved via the code hash and gets executed.
-//! This call can alter the storage entries of the smart-contract account, instantiate new smart-contracts,
-//! or call other smart-contracts.
-//!
-//! Finally, when an account is reaped, its associated code and storage of the smart-contract account
-//! will also be deleted.
-//!
-//! ### Gas
-//!
-//! Senders must specify a gas limit with every call, as all instructions invoked by the smart-contract require gas.
-//! Unused gas is refunded after the call, regardless of the execution outcome.
-//!
-//! If the gas limit is reached, then all calls and state changes (including balance transfers) are only
-//! reverted at the current call's contract level. For example, if contract A calls B and B runs out of gas mid-call,
-//! then all of B's calls are reverted. Assuming correct error handling by contract A, A's other calls and state
-//! changes still persist.
-//!
-//! ### Notable Scenarios
-//!
-//! Contract call failures are not always cascading. When failures occur in a sub-call, they do not "bubble up",
-//! and the call will only revert at the specific contract level. For example, if contract A calls contract B, and B
-//! fails, A can decide how to handle that failure, either proceeding or reverting A's changes.
-//!
-//! ## Interface
-//!
-//! ### Dispatchable functions
-//!
-//! * [`Pallet::update_schedule`] -
-//! ([Root Origin](https://substrate.dev/docs/en/knowledgebase/runtime/origin) Only) -
-//! Set a new [`Schedule`].
-//! * [`Pallet::instantiate_with_code`] - Deploys a new contract from the supplied wasm binary,
-//! optionally transferring
-//! some balance. This instantiates a new smart contract account with the supplied code and
-//! calls its constructor to initialize the contract.
-//! * [`Pallet::instantiate`] - The same as `instantiate_with_code` but instead of uploading new
-//! code an existing `code_hash` is supplied.
-//! * [`Pallet::call`] - Makes a call to an account, optionally transferring some balance.
-//! * [`Pallet::claim_surcharge`] - Evict a contract that cannot pay rent anymore.
-//!
-//! ## Usage
-//!
-//! The Contract module is a work in progress. The following examples show how this Contract module
-//! can be used to instantiate and call contracts.
-//!
-//! * [`ink`](https://github.com/paritytech/ink) is
-//! an [`eDSL`](https://wiki.haskell.org/Embedded_domain_specific_language) that enables writing
-//! WebAssembly based smart contracts in the Rust programming language. This is a work in progress.
-//!
-//! ## Related Modules
-//!
-//! * [Balances](../pallet_balances/index.html)
-
-#![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(feature = "runtime-benchmarks", recursion_limit = "512")]
-
-#[macro_use]
-mod gas;
-mod benchmarking;
-mod exec;
-mod migration;
-mod rent;
-mod schedule;
-mod storage;
-mod wasm;
-
-pub mod chain_extension;
-pub mod weights;
-
-#[cfg(test)]
-mod tests;
-
-pub use crate::{pallet::*, schedule::Schedule};
-use crate::{
- gas::GasMeter,
- exec::{ExecutionContext, Executable},
- rent::Rent,
- storage::{Storage, DeletedContract, ContractInfo, AliveContractInfo, TombstoneContractInfo},
- weights::WeightInfo,
- wasm::PrefabWasmModule,
-};
-use sp_core::{Bytes, crypto::UncheckedFrom};
-use sp_std::prelude::*;
-use sp_runtime::{
- traits::{Hash, StaticLookup, Convert, Saturating, Zero},
- Perbill,
-};
-use frame_support::{
- traits::{OnUnbalanced, Currency, Get, Time, Randomness},
- weights::{Weight, PostDispatchInfo, WithPostDispatchInfo},
-};
-use frame_system::Pallet as System;
-use pallet_contracts_primitives::{
- RentProjectionResult, GetStorageResult, ContractAccessError, ContractExecResult,
- ContractInstantiateResult, Code, InstantiateReturnValue,
-};
-
-type CodeHash<T> = <T as frame_system::Config>::Hash;
-type TrieId = Vec<u8>;
-type BalanceOf<T> =
- <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
-type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
- <T as frame_system::Config>::AccountId,
->>::NegativeImbalance;
-
-#[frame_support::pallet]
-pub mod pallet {
- use frame_support::pallet_prelude::*;
- use frame_system::pallet_prelude::*;
- use super::*;
-
- #[pallet::config]
- pub trait Config: frame_system::Config {
- /// The time implementation used to supply timestamps to conntracts through `seal_now`.
- type Time: Time;
-
- /// The generator used to supply randomness to contracts through `seal_random`.
- type Randomness: Randomness<Self::Hash, Self::BlockNumber>;
-
- /// The currency in which fees are paid and contract balances are held.
- type Currency: Currency<Self::AccountId>;
-
- /// The overarching event type.
- type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
-
- /// Handler for rent payments.
- type RentPayment: OnUnbalanced<NegativeImbalanceOf<Self>>;
-
- /// Number of block delay an extrinsic claim surcharge has.
- ///
- /// When claim surcharge is called by an extrinsic the rent is checked
- /// for current_block - delay
- #[pallet::constant]
- type SignedClaimHandicap: Get<Self::BlockNumber>;
-
- /// The minimum amount required to generate a tombstone.
- #[pallet::constant]
- type TombstoneDeposit: Get<BalanceOf<Self>>;
-
- /// The balance every contract needs to deposit to stay alive indefinitely.
- ///
- /// This is different from the [`Self::TombstoneDeposit`] because this only needs to be
- /// deposited while the contract is alive. Costs for additional storage are added to
- /// this base cost.
- ///
- /// This is a simple way to ensure that contracts with empty storage eventually get deleted by
- /// making them pay rent. This creates an incentive to remove them early in order to save rent.
- #[pallet::constant]
- type DepositPerContract: Get<BalanceOf<Self>>;
-
- /// The balance a contract needs to deposit per storage byte to stay alive indefinitely.
- ///
- /// Let's suppose the deposit is 1,000 BU (balance units)/byte and the rent is 1 BU/byte/day,
- /// then a contract with 1,000,000 BU that uses 1,000 bytes of storage would pay no rent.
- /// But if the balance reduced to 500,000 BU and the storage stayed the same at 1,000,
- /// then it would pay 500 BU/day.
- #[pallet::constant]
- type DepositPerStorageByte: Get<BalanceOf<Self>>;
-
- /// The balance a contract needs to deposit per storage item to stay alive indefinitely.
- ///
- /// It works the same as [`Self::DepositPerStorageByte`] but for storage items.
- #[pallet::constant]
- type DepositPerStorageItem: Get<BalanceOf<Self>>;
-
- /// The fraction of the deposit that should be used as rent per block.
- ///
- /// When a contract hasn't enough balance deposited to stay alive indefinitely it needs
- /// to pay per block for the storage it consumes that is not covered by the deposit.
- /// This determines how high this rent payment is per block as a fraction of the deposit.
- #[pallet::constant]
- type RentFraction: Get<Perbill>;
-
- /// Reward that is received by the party whose touch has led
- /// to removal of a contract.
- #[pallet::constant]
- type SurchargeReward: Get<BalanceOf<Self>>;
-
- /// The maximum nesting level of a call/instantiate stack.
- #[pallet::constant]
- type MaxDepth: Get<u32>;
-
- /// The maximum size of a storage value and event payload in bytes.
- #[pallet::constant]
- type MaxValueSize: Get<u32>;
-
- /// Used to answer contracts' queries regarding the current weight price. This is **not**
- /// used to calculate the actual fee and is only for informational purposes.
- type WeightPrice: Convert<Weight, BalanceOf<Self>>;
-
- /// Describes the weights of the dispatchables of this module and is also used to
- /// construct a default cost schedule.
- type WeightInfo: WeightInfo;
-
- /// Type that allows the runtime authors to add new host functions for a contract to call.
- type ChainExtension: chain_extension::ChainExtension<Self>;
-
- /// The maximum number of tries that can be queued for deletion.
- #[pallet::constant]
- type DeletionQueueDepth: Get<u32>;
-
- /// The maximum amount of weight that can be consumed per block for lazy trie removal.
- #[pallet::constant]
- type DeletionWeightLimit: Get<Weight>;
-
- /// The maximum length of a contract code in bytes. This limit applies to the instrumented
- /// version of the code. Therefore `instantiate_with_code` can fail even when supplying
- /// a wasm binary below this maximum size.
- #[pallet::constant]
- type MaxCodeSize: Get<u32>;
- }
-
- #[pallet::pallet]
- pub struct Pallet<T>(PhantomData<T>);
-
- #[pallet::hooks]
- impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T>
- where
- T::AccountId: UncheckedFrom<T::Hash>,
- T::AccountId: AsRef<[u8]>,
- {
- fn on_initialize(_block: T::BlockNumber) -> Weight {
- // We do not want to go above the block limit and rather avoid lazy deletion
- // in that case. This should only happen on runtime upgrades.
- let weight_limit = T::BlockWeights::get()
- .max_block
- .saturating_sub(System::<T>::block_weight().total())
- .min(T::DeletionWeightLimit::get());
- Storage::<T>::process_deletion_queue_batch(weight_limit)
- .saturating_add(T::WeightInfo::on_initialize())
- }
-
- fn on_runtime_upgrade() -> Weight {
- migration::migrate::<T>()
- }
- }
-
- #[pallet::call]
- impl<T: Config> Pallet<T>
- where
- T::AccountId: UncheckedFrom<T::Hash>,
- T::AccountId: AsRef<[u8]>,
- {
- /// Updates the schedule for metering contracts.
- ///
- /// The schedule's version cannot be less than the version of the stored schedule.
- /// If a schedule does not change the instruction weights the version does not
- /// need to be increased. Therefore we allow storing a schedule that has the same
- /// version as the stored one.
- #[pallet::weight(T::WeightInfo::update_schedule())]
- pub fn update_schedule(
- origin: OriginFor<T>,
- schedule: Schedule<T>,
- ) -> DispatchResultWithPostInfo {
- ensure_root(origin)?;
- if <CurrentSchedule<T>>::get().version > schedule.version {
- Err(Error::<T>::InvalidScheduleVersion)?
- }
- Self::deposit_event(Event::ScheduleUpdated(schedule.version));
- CurrentSchedule::put(schedule);
- Ok(().into())
- }
-
- /// Makes a call to an account, optionally transferring some balance.
- ///
- /// * If the account is a smart-contract account, the associated code will be
- /// executed and any value will be transferred.
- /// * If the account is a regular account, any value will be transferred.
- /// * If no account exists and the call value is not less than `existential_deposit`,
- /// a regular account will be created and any value will be transferred.
- #[pallet::weight(T::WeightInfo::call(T::MaxCodeSize::get() / 1024).saturating_add(*gas_limit))]
- pub fn call(
- origin: OriginFor<T>,
- dest: <T::Lookup as StaticLookup>::Source,
- #[pallet::compact] value: BalanceOf<T>,
- #[pallet::compact] gas_limit: Weight,
- data: Vec<u8>,
- ) -> DispatchResultWithPostInfo {
- let origin = ensure_signed(origin)?;
- let dest = T::Lookup::lookup(dest)?;
- let mut gas_meter = GasMeter::new(gas_limit);
- let schedule = <CurrentSchedule<T>>::get();
- let mut ctx = ExecutionContext::<T, PrefabWasmModule<T>>::top_level(origin, &schedule);
- let (result, code_len) = match ctx.call(dest, value, &mut gas_meter, data) {
- Ok((output, len)) => (Ok(output), len),
- Err((err, len)) => (Err(err), len),
- };
- gas_meter.into_dispatch_result(result, T::WeightInfo::call(code_len / 1024))
- }
-
- /// Instantiates a new contract from the supplied `code` optionally transferring
- /// some balance.
- ///
- /// This is the only function that can deploy new code to the chain.
- ///
- /// # Parameters
- ///
- /// * `endowment`: The balance to transfer from the `origin` to the newly created contract.
- /// * `gas_limit`: The gas limit enforced when executing the constructor.
- /// * `code`: The contract code to deploy in raw bytes.
- /// * `data`: The input data to pass to the contract constructor.
- /// * `salt`: Used for the address derivation. See [`Pallet::contract_address`].
- ///
- /// Instantiation is executed as follows:
- ///
- /// - The supplied `code` is instrumented, deployed, and a `code_hash` is created for that code.
- /// - If the `code_hash` already exists on the chain the underlying `code` will be shared.
- /// - The destination address is computed based on the sender, code_hash and the salt.
- /// - The smart-contract account is created at the computed address.
- /// - The `endowment` is transferred to the new account.
- /// - The `deploy` function is executed in the context of the newly-created account.
- #[pallet::weight(
- T::WeightInfo::instantiate_with_code(
- code.len() as u32 / 1024,
- salt.len() as u32 / 1024,
- )
- .saturating_add(*gas_limit)
- )]
- pub fn instantiate_with_code(
- origin: OriginFor<T>,
- #[pallet::compact] endowment: BalanceOf<T>,
- #[pallet::compact] gas_limit: Weight,
- code: Vec<u8>,
- data: Vec<u8>,
- salt: Vec<u8>,
- ) -> DispatchResultWithPostInfo {
- let origin = ensure_signed(origin)?;
- let code_len = code.len() as u32;
- ensure!(code_len <= T::MaxCodeSize::get(), Error::<T>::CodeTooLarge);
- let mut gas_meter = GasMeter::new(gas_limit);
- let schedule = <CurrentSchedule<T>>::get();
- let executable = PrefabWasmModule::from_code(code, &schedule)?;
- let code_len = executable.code_len();
- ensure!(code_len <= T::MaxCodeSize::get(), Error::<T>::CodeTooLarge);
- let mut ctx = ExecutionContext::<T, PrefabWasmModule<T>>::top_level(origin, &schedule);
- let result = ctx
- .instantiate(endowment, &mut gas_meter, executable, data, &salt)
- .map(|(_address, output)| output);
- gas_meter.into_dispatch_result(
- result,
- T::WeightInfo::instantiate_with_code(code_len / 1024, salt.len() as u32 / 1024),
- )
- }
-
- /// Instantiates a contract from a previously deployed wasm binary.
- ///
- /// This function is identical to [`Self::instantiate_with_code`] but without the
- /// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary
- /// must be supplied.
- #[pallet::weight(
- T::WeightInfo::instantiate(T::MaxCodeSize::get() / 1024, salt.len() as u32 / 1024)
- .saturating_add(*gas_limit)
- )]
- pub fn instantiate(
- origin: OriginFor<T>,
- #[pallet::compact] endowment: BalanceOf<T>,
- #[pallet::compact] gas_limit: Weight,
- code_hash: CodeHash<T>,
- data: Vec<u8>,
- salt: Vec<u8>,
- ) -> DispatchResultWithPostInfo {
- let origin = ensure_signed(origin)?;
- let mut gas_meter = GasMeter::new(gas_limit);
- let schedule = <CurrentSchedule<T>>::get();
- let executable = PrefabWasmModule::from_storage(code_hash, &schedule, &mut gas_meter)?;
- let mut ctx = ExecutionContext::<T, PrefabWasmModule<T>>::top_level(origin, &schedule);
- let code_len = executable.code_len();
- let result = ctx
- .instantiate(endowment, &mut gas_meter, executable, data, &salt)
- .map(|(_address, output)| output);
- gas_meter.into_dispatch_result(
- result,
- T::WeightInfo::instantiate(code_len / 1024, salt.len() as u32 / 1024),
- )
- }
-
- /// Allows block producers to claim a small reward for evicting a contract. If a block
- /// producer fails to do so, a regular users will be allowed to claim the reward.
- ///
- /// In case of a successful eviction no fees are charged from the sender. However, the
- /// reward is capped by the total amount of rent that was payed by the contract while
- /// it was alive.
- ///
- /// If contract is not evicted as a result of this call, [`Error::ContractNotEvictable`]
- /// is returned and the sender is not eligible for the reward.
- #[pallet::weight(T::WeightInfo::claim_surcharge(T::MaxCodeSize::get() / 1024))]
- pub fn claim_surcharge(
- origin: OriginFor<T>,
- dest: T::AccountId,
- aux_sender: Option<T::AccountId>,
- ) -> DispatchResultWithPostInfo {
- let origin = origin.into();
- let (signed, rewarded) = match (origin, aux_sender) {
- (Ok(frame_system::RawOrigin::Signed(account)), None) => (true, account),
- (Ok(frame_system::RawOrigin::None), Some(aux_sender)) => (false, aux_sender),
- _ => Err(Error::<T>::InvalidSurchargeClaim)?,
- };
-
- // Add some advantage for block producers (who send unsigned extrinsics) by
- // adding a handicap: for signed extrinsics we use a slightly older block number
- // for the eviction check. This can be viewed as if we pushed regular users back in past.
- let handicap = if signed {
- T::SignedClaimHandicap::get()
- } else {
- Zero::zero()
- };
-
- // If poking the contract has lead to eviction of the contract, give out the rewards.
- match Rent::<T, PrefabWasmModule<T>>::try_eviction(&dest, handicap)? {
- (Some(rent_payed), code_len) => T::Currency::deposit_into_existing(
- &rewarded,
- T::SurchargeReward::get().min(rent_payed),
- )
- .map(|_| PostDispatchInfo {
- actual_weight: Some(T::WeightInfo::claim_surcharge(code_len / 1024)),
- pays_fee: Pays::No,
- })
- .map_err(Into::into),
- (None, code_len) => Err(Error::<T>::ContractNotEvictable
- .with_weight(T::WeightInfo::claim_surcharge(code_len / 1024))),
- }
- }
- }
-
- #[pallet::event]
- #[pallet::generate_deposit(pub(super) fn deposit_event)]
- #[pallet::metadata(T::AccountId = "AccountId", T::Hash = "Hash", BalanceOf<T> = "Balance")]
- pub enum Event<T: Config> {
- /// Contract deployed by address at the specified address. \[deployer, contract\]
- Instantiated(T::AccountId, T::AccountId),
-
- /// Contract has been evicted and is now in tombstone state. \[contract\]
- Evicted(T::AccountId),
-
- /// Contract has been terminated without leaving a tombstone.
- /// \[contract, beneficiary\]
- ///
- /// # Params
- ///
- /// - `contract`: The contract that was terminated.
- /// - `beneficiary`: The account that received the contracts remaining balance.
- ///
- /// # Note
- ///
- /// The only way for a contract to be removed without a tombstone and emitting
- /// this event is by calling `seal_terminate`.
- Terminated(T::AccountId, T::AccountId),
-
- /// Restoration of a contract has been successful.
- /// \[restorer, dest, code_hash, rent_allowance\]
- ///
- /// # Params
- ///
- /// - `restorer`: Account ID of the restoring contract.
- /// - `dest`: Account ID of the restored contract.
- /// - `code_hash`: Code hash of the restored contract.
- /// - `rent_allowance`: Rent allowance of the restored contract.
- Restored(T::AccountId, T::AccountId, T::Hash, BalanceOf<T>),
-
- /// Code with the specified hash has been stored. \[code_hash\]
- CodeStored(T::Hash),
-
- /// Triggered when the current schedule is updated.
- /// \[version\]
- ///
- /// # Params
- ///
- /// - `version`: The version of the newly set schedule.
- ScheduleUpdated(u32),
-
- /// A custom event emitted by the contract.
- /// \[contract, data\]
- ///
- /// # Params
- ///
- /// - `contract`: The contract that emitted the event.
- /// - `data`: Data supplied by the contract. Metadata generated during contract
- /// compilation is needed to decode it.
- ContractEmitted(T::AccountId, Vec<u8>),
-
- /// A code with the specified hash was removed.
- /// \[code_hash\]
- ///
- /// This happens when the last contract that uses this code hash was removed or evicted.
- CodeRemoved(T::Hash),
- }
-
- #[pallet::error]
- pub enum Error<T> {
- /// A new schedule must have a greater version than the current one.
- InvalidScheduleVersion,
- /// An origin must be signed or inherent and auxiliary sender only provided on inherent.
- InvalidSurchargeClaim,
- /// Cannot restore from nonexisting or tombstone contract.
- InvalidSourceContract,
- /// Cannot restore to nonexisting or alive contract.
- InvalidDestinationContract,
- /// Tombstones don't match.
- InvalidTombstone,
- /// An origin TrieId written in the current block.
- InvalidContractOrigin,
- /// The executed contract exhausted its gas limit.
- OutOfGas,
- /// The output buffer supplied to a contract API call was too small.
- OutputBufferTooSmall,
- /// Performing the requested transfer would have brought the contract below
- /// the subsistence threshold. No transfer is allowed to do this in order to allow
- /// for a tombstone to be created. Use `seal_terminate` to remove a contract without
- /// leaving a tombstone behind.
- BelowSubsistenceThreshold,
- /// The newly created contract is below the subsistence threshold after executing
- /// its contructor. No contracts are allowed to exist below that threshold.
- NewContractNotFunded,
- /// Performing the requested transfer failed for a reason originating in the
- /// chosen currency implementation of the runtime. Most probably the balance is
- /// too low or locks are placed on it.
- TransferFailed,
- /// Performing a call was denied because the calling depth reached the limit
- /// of what is specified in the schedule.
- MaxCallDepthReached,
- /// The contract that was called is either no contract at all (a plain account)
- /// or is a tombstone.
- NotCallable,
- /// The code supplied to `instantiate_with_code` exceeds the limit specified in the
- /// current schedule.
- CodeTooLarge,
- /// No code could be found at the supplied code hash.
- CodeNotFound,
- /// A buffer outside of sandbox memory was passed to a contract API function.
- OutOfBounds,
- /// Input passed to a contract API function failed to decode as expected type.
- DecodingFailed,
- /// Contract trapped during execution.
- ContractTrapped,
- /// The size defined in `T::MaxValueSize` was exceeded.
- ValueTooLarge,
- /// The action performed is not allowed while the contract performing it is already
- /// on the call stack. Those actions are contract self destruction and restoration
- /// of a tombstone.
- ReentranceDenied,
- /// `seal_input` was called twice from the same contract execution context.
- InputAlreadyRead,
- /// The subject passed to `seal_random` exceeds the limit.
- RandomSubjectTooLong,
- /// The amount of topics passed to `seal_deposit_events` exceeds the limit.
- TooManyTopics,
- /// The topics passed to `seal_deposit_events` contains at least one duplicate.
- DuplicateTopics,
- /// The chain does not provide a chain extension. Calling the chain extension results
- /// in this error. Note that this usually shouldn't happen as deploying such contracts
- /// is rejected.
- NoChainExtension,
- /// Removal of a contract failed because the deletion queue is full.
- ///
- /// This can happen when either calling [`Pallet::claim_surcharge`] or `seal_terminate`.
- /// The queue is filled by deleting contracts and emptied by a fixed amount each block.
- /// Trying again during another block is the only way to resolve this issue.
- DeletionQueueFull,
- /// A contract could not be evicted because it has enough balance to pay rent.
- ///
- /// This can be returned from [`Pallet::claim_surcharge`] because the target
- /// contract has enough balance to pay for its rent.
- ContractNotEvictable,
- /// A storage modification exhausted the 32bit type that holds the storage size.
- ///
- /// This can either happen when the accumulated storage in bytes is too large or
- /// when number of storage items is too large.
- StorageExhausted,
- /// A contract with the same AccountId already exists.
- DuplicateContract,
- }
-
- /// Current cost schedule for contracts.
- #[pallet::storage]
- pub(crate) type CurrentSchedule<T: Config> = StorageValue<_, Schedule<T>, ValueQuery>;
-
- /// A mapping from an original code hash to the original code, untouched by instrumentation.
- #[pallet::storage]
- pub(crate) type PristineCode<T: Config> = StorageMap<_, Identity, CodeHash<T>, Vec<u8>>;
-
- /// A mapping between an original code hash and instrumented wasm code, ready for execution.
- #[pallet::storage]
- pub(crate) type CodeStorage<T: Config> =
- StorageMap<_, Identity, CodeHash<T>, PrefabWasmModule<T>>;
-
- /// The subtrie counter.
- #[pallet::storage]
- pub(crate) type AccountCounter<T: Config> = StorageValue<_, u64, ValueQuery>;
-
- /// The code associated with a given account.
- ///
- /// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
- #[pallet::storage]
- pub(crate) type ContractInfoOf<T: Config> =
- StorageMap<_, Twox64Concat, T::AccountId, ContractInfo<T>>;
-
- /// Evicted contracts that await child trie deletion.
- ///
- /// Child trie deletion is a heavy operation depending on the amount of storage items
- /// stored in said trie. Therefore this operation is performed lazily in `on_initialize`.
- #[pallet::storage]
- pub(crate) type DeletionQueue<T: Config> = StorageValue<_, Vec<DeletedContract>, ValueQuery>;
-
- #[pallet::genesis_config]
- pub struct GenesisConfig<T: Config> {
- #[doc = "Current cost schedule for contracts."]
- pub current_schedule: Schedule<T>,
- }
-
- #[cfg(feature = "std")]
- impl<T: Config> Default for GenesisConfig<T> {
- fn default() -> Self {
- Self {
- current_schedule: Default::default(),
- }
- }
- }
-
- #[pallet::genesis_build]
- impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
- fn build(&self) {
- <CurrentSchedule<T>>::put(&self.current_schedule);
- }
- }
-}
-
-impl<T: Config> Pallet<T>
-where
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
-{
- /// Perform a call to a specified contract.
- ///
- /// This function is similar to [`Self::call`], but doesn't perform any address lookups
- /// and better suitable for calling directly from Rust.
- ///
- /// It returns the execution result and the amount of used weight.
- pub fn bare_call(
- origin: T::AccountId,
- dest: T::AccountId,
- value: BalanceOf<T>,
- gas_limit: Weight,
- input_data: Vec<u8>,
- ) -> ContractExecResult {
- let mut gas_meter = GasMeter::new(gas_limit);
- let schedule = <CurrentSchedule<T>>::get();
- let mut ctx = ExecutionContext::<T, PrefabWasmModule<T>>::top_level(origin, &schedule);
- let result = ctx.call(dest, value, &mut gas_meter, input_data);
- let gas_consumed = gas_meter.gas_spent();
- ContractExecResult {
- result: result.map(|r| r.0).map_err(|r| r.0.error),
- gas_consumed,
- debug_message: Bytes(Vec::new()).to_vec(),
- }
- }
-
- /// Instantiate a new contract.
- ///
- /// This function is similar to [`Self::instantiate`], but doesn't perform any address lookups
- /// and better suitable for calling directly from Rust.
- ///
- /// It returns the execution result, account id and the amount of used weight.
- ///
- /// If `compute_projection` is set to `true` the result also contains the rent projection.
- /// This is optional because some non trivial and stateful work is performed to compute
- /// the projection. See [`Self::rent_projection`].
- pub fn bare_instantiate(
- origin: T::AccountId,
- endowment: BalanceOf<T>,
- gas_limit: Weight,
- code: Code<CodeHash<T>>,
- data: Vec<u8>,
- salt: Vec<u8>,
- compute_projection: bool,
- ) -> ContractInstantiateResult<T::AccountId, T::BlockNumber> {
- let mut gas_meter = GasMeter::new(gas_limit);
- let schedule = <CurrentSchedule<T>>::get();
- let mut ctx = ExecutionContext::<T, PrefabWasmModule<T>>::top_level(origin, &schedule);
- let executable = match code {
- Code::Upload(Bytes(binary)) => PrefabWasmModule::from_code(binary, &schedule),
- Code::Existing(hash) => PrefabWasmModule::from_storage(hash, &schedule, &mut gas_meter),
- };
- let executable = match executable {
- Ok(executable) => executable,
- Err(error) => {
- return ContractInstantiateResult {
- result: Err(error.into()),
- gas_consumed: gas_meter.gas_spent(),
- debug_message: Bytes(Vec::new()).to_vec(),
- }
- }
- };
- let result = ctx
- .instantiate(endowment, &mut gas_meter, executable, data, &salt)
- .and_then(|(account_id, result)| {
- let rent_projection = if compute_projection {
- Some(
- Rent::<T, PrefabWasmModule<T>>::compute_projection(&account_id)
- .map_err(|_| <Error<T>>::NewContractNotFunded)?,
- )
- } else {
- None
- };
-
- Ok(InstantiateReturnValue {
- result,
- account_id,
- rent_projection,
- })
- });
- ContractInstantiateResult {
- result: result.map_err(|e| e.error),
- gas_consumed: gas_meter.gas_spent(),
- debug_message: Bytes(Vec::new()).to_vec(),
- }
- }
-
- /// Query storage of a specified contract under a specified key.
- pub fn get_storage(address: T::AccountId, key: [u8; 32]) -> GetStorageResult {
- let contract_info = ContractInfoOf::<T>::get(&address)
- .ok_or(ContractAccessError::DoesntExist)?
- .get_alive()
- .ok_or(ContractAccessError::IsTombstone)?;
-
- let maybe_value = Storage::<T>::read(&contract_info.trie_id, &key);
- Ok(maybe_value)
- }
-
- /// Query how many blocks the contract stays alive given that the amount endowment
- /// and consumed storage does not change.
- pub fn rent_projection(address: T::AccountId) -> RentProjectionResult<T::BlockNumber> {
- Rent::<T, PrefabWasmModule<T>>::compute_projection(&address)
- }
-
- /// Determine the address of a contract,
- ///
- /// This is the address generation function used by contract instantiation. Its result
- /// is only dependend on its inputs. It can therefore be used to reliably predict the
- /// address of a contract. This is akin to the formular of eth's CREATE2 opcode. There
- /// is no CREATE equivalent because CREATE2 is strictly more powerful.
- ///
- /// Formula: `hash(deploying_address ++ code_hash ++ salt)`
- pub fn contract_address(
- deploying_address: &T::AccountId,
- code_hash: &CodeHash<T>,
- salt: &[u8],
- ) -> T::AccountId {
- let buf: Vec<_> = deploying_address
- .as_ref()
- .iter()
- .chain(code_hash.as_ref())
- .chain(salt)
- .cloned()
- .collect();
- UncheckedFrom::unchecked_from(T::Hashing::hash(&buf))
- }
-
- /// Subsistence threshold is the extension of the minimum balance (aka existential deposit)
- /// by the tombstone deposit, required for leaving a tombstone.
- ///
- /// Rent or any contract initiated balance transfer mechanism cannot make the balance lower
- /// than the subsistence threshold in order to guarantee that a tombstone is created.
- ///
- /// The only way to completely kill a contract without a tombstone is calling `seal_terminate`.
- pub fn subsistence_threshold() -> BalanceOf<T> {
- T::Currency::minimum_balance().saturating_add(T::TombstoneDeposit::get())
- }
-
- /// The in-memory size in bytes of the data structure associated with each contract.
- ///
- /// The data structure is also put into storage for each contract. The in-storage size
- /// is never larger than the in-memory representation and usually smaller due to compact
- /// encoding and lack of padding.
- ///
- /// # Note
- ///
- /// This returns the in-memory size because the in-storage size (SCALE encoded) cannot
- /// be efficiently determined. Treat this as an upper bound of the in-storage size.
- pub fn contract_info_size() -> u32 {
- sp_std::mem::size_of::<ContractInfo<T>>() as u32
- }
-
- /// Store code for benchmarks which does not check nor instrument the code.
- #[cfg(feature = "runtime-benchmarks")]
- fn store_code_raw(code: Vec<u8>) -> frame_support::dispatch::DispatchResult {
- let schedule = <CurrentSchedule<T>>::get();
- PrefabWasmModule::store_code_unchecked(code, &schedule)?;
- Ok(())
- }
-
- /// This exists so that benchmarks can determine the weight of running an instrumentation.
- #[cfg(feature = "runtime-benchmarks")]
- fn reinstrument_module(
- module: &mut PrefabWasmModule<T>,
- schedule: &Schedule<T>,
- ) -> frame_support::dispatch::DispatchResult {
- self::wasm::reinstrument(module, schedule)
- }
-}
pallets/contracts/src/migration.rsdiffbeforeafterboth--- a/pallets/contracts/src/migration.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use crate::{Config, Weight, CurrentSchedule, Pallet, Schedule};
-use frame_support::traits::{GetPalletVersion, PalletVersion, Get};
-
-pub fn migrate<T: Config>() -> Weight {
- let mut weight: Weight = 0;
-
- match <Pallet<T>>::storage_version() {
- // Replace the schedule with the new default and increment its version.
- Some(version) if version == PalletVersion::new(3, 0, 0) => {
- weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));
- let _ = <CurrentSchedule<T>>::translate::<u32, _>(|version| {
- version.map(|version| Schedule {
- version: version.saturating_add(1),
- // Default limits were not decreased. Therefore it is OK to overwrite
- // the schedule with the new defaults.
- ..Default::default()
- })
- });
- }
- _ => (),
- }
-
- weight
-}
pallets/contracts/src/rent.rsdiffbeforeafterboth--- a/pallets/contracts/src/rent.rs
+++ /dev/null
@@ -1,553 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! A module responsible for computing the right amount of weight and charging it.
-
-use crate::{
- AliveContractInfo, BalanceOf, ContractInfo, ContractInfoOf, Pallet, Event,
- TombstoneContractInfo, Config, CodeHash, Error, storage::Storage, wasm::PrefabWasmModule,
- exec::Executable,
-};
-use sp_std::prelude::*;
-use sp_io::hashing::blake2_256;
-use sp_core::crypto::UncheckedFrom;
-use frame_support::{
- storage::child,
- traits::{Currency, ExistenceRequirement, Get, OnUnbalanced, WithdrawReasons},
-};
-use pallet_contracts_primitives::{ContractAccessError, RentProjection, RentProjectionResult};
-use sp_runtime::{
- DispatchError,
- traits::{Bounded, CheckedDiv, CheckedMul, SaturatedConversion, Saturating, Zero},
-};
-
-/// The amount to charge.
-///
-/// This amount respects the contract's rent allowance and the subsistence deposit.
-/// Because of that, charging the amount cannot remove the contract.
-struct OutstandingAmount<T: Config> {
- amount: BalanceOf<T>,
-}
-
-impl<T: Config> OutstandingAmount<T> {
- /// Create the new outstanding amount.
- ///
- /// The amount should be always withdrawable and it should not kill the account.
- fn new(amount: BalanceOf<T>) -> Self {
- Self { amount }
- }
-
- /// Returns the amount this instance wraps.
- fn peek(&self) -> BalanceOf<T> {
- self.amount
- }
-
- /// Withdraws the outstanding amount from the given account.
- fn withdraw(self, account: &T::AccountId) {
- if let Ok(imbalance) = T::Currency::withdraw(
- account,
- self.amount,
- WithdrawReasons::FEE,
- ExistenceRequirement::KeepAlive,
- ) {
- // This should never fail. However, let's err on the safe side.
- T::RentPayment::on_unbalanced(imbalance);
- }
- }
-}
-
-enum Verdict<T: Config> {
- /// The contract is exempted from paying rent.
- ///
- /// For example, it already paid its rent in the current block, or it has enough deposit for not
- /// paying rent at all.
- Exempt,
- /// The contract cannot afford payment within its rent budget so it gets evicted. However,
- /// because its balance is greater than the subsistence threshold it leaves a tombstone.
- Evict {
- amount: Option<OutstandingAmount<T>>,
- },
- /// Everything is OK, we just only take some charge.
- Charge { amount: OutstandingAmount<T> },
-}
-
-pub struct Rent<T, E>(sp_std::marker::PhantomData<(T, E)>);
-
-impl<T, E> Rent<T, E>
-where
- T: Config,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
- E: Executable<T>,
-{
- /// Returns a fee charged per block from the contract.
- ///
- /// This function accounts for the storage rent deposit. I.e. if the contract possesses enough funds
- /// then the fee can drop to zero.
- fn compute_fee_per_block(
- free_balance: &BalanceOf<T>,
- contract: &AliveContractInfo<T>,
- code_size_share: u32,
- ) -> BalanceOf<T> {
- let uncovered_by_balance = T::DepositPerStorageByte::get()
- .saturating_mul(contract.storage_size.saturating_add(code_size_share).into())
- .saturating_add(
- T::DepositPerStorageItem::get().saturating_mul(contract.pair_count.into()),
- )
- .saturating_add(T::DepositPerContract::get())
- .saturating_sub(*free_balance);
- T::RentFraction::get().mul_ceil(uncovered_by_balance)
- }
-
- /// Returns amount of funds available to consume by rent mechanism.
- ///
- /// Rent mechanism cannot consume more than `rent_allowance` set by the contract and it cannot make
- /// the balance lower than [`subsistence_threshold`].
- ///
- /// In case the toal_balance is below the subsistence threshold, this function returns `None`.
- fn rent_budget(
- total_balance: &BalanceOf<T>,
- free_balance: &BalanceOf<T>,
- contract: &AliveContractInfo<T>,
- ) -> Option<BalanceOf<T>> {
- let subsistence_threshold = Pallet::<T>::subsistence_threshold();
- // Reserved balance contributes towards the subsistence threshold to stay consistent
- // with the existential deposit where the reserved balance is also counted.
- if *total_balance < subsistence_threshold {
- return None;
- }
-
- // However, reserved balance cannot be charged so we need to use the free balance
- // to calculate the actual budget (which can be 0).
- let rent_allowed_to_charge = free_balance.saturating_sub(subsistence_threshold);
- Some(<BalanceOf<T>>::min(
- contract.rent_allowance,
- rent_allowed_to_charge,
- ))
- }
-
- /// Consider the case for rent payment of the given account and returns a `Verdict`.
- ///
- /// Use `handicap` in case you want to change the reference block number. (To get more details see
- /// `try_eviction` ).
- fn consider_case(
- account: &T::AccountId,
- current_block_number: T::BlockNumber,
- handicap: T::BlockNumber,
- contract: &AliveContractInfo<T>,
- code_size: u32,
- ) -> Verdict<T> {
- // How much block has passed since the last deduction for the contract.
- let blocks_passed = {
- // Calculate an effective block number, i.e. after adjusting for handicap.
- let effective_block_number = current_block_number.saturating_sub(handicap);
- effective_block_number.saturating_sub(contract.deduct_block)
- };
- if blocks_passed.is_zero() {
- // Rent has already been paid
- return Verdict::Exempt;
- }
-
- let total_balance = T::Currency::total_balance(account);
- let free_balance = T::Currency::free_balance(account);
-
- // An amount of funds to charge per block for storage taken up by the contract.
- let fee_per_block = Self::compute_fee_per_block(&free_balance, contract, code_size);
- if fee_per_block.is_zero() {
- // The rent deposit offset reduced the fee to 0. This means that the contract
- // gets the rent for free.
- return Verdict::Exempt;
- }
-
- let rent_budget = match Self::rent_budget(&total_balance, &free_balance, contract) {
- Some(rent_budget) => rent_budget,
- None => {
- // All functions that allow a contract to transfer balance enforce
- // that the contract always stays above the subsistence threshold.
- // We want the rent system to always leave a tombstone to prevent the
- // accidental loss of a contract. Ony `seal_terminate` can remove a
- // contract without a tombstone. Therefore this case should be never
- // hit.
- log::error!(
- target: "runtime::contracts",
- "Tombstoned a contract that is below the subsistence threshold: {:?}",
- account,
- );
- 0u32.into()
- }
- };
-
- let dues = fee_per_block
- .checked_mul(&blocks_passed.saturated_into::<u32>().into())
- .unwrap_or_else(|| <BalanceOf<T>>::max_value());
- let insufficient_rent = rent_budget < dues;
-
- // If the rent payment cannot be withdrawn due to locks on the account balance, then evict the
- // account.
- //
- // NOTE: This seems problematic because it provides a way to tombstone an account while
- // avoiding the last rent payment. In effect, someone could retroactively set rent_allowance
- // for their contract to 0.
- let dues_limited = dues.min(rent_budget);
- let can_withdraw_rent = T::Currency::ensure_can_withdraw(
- account,
- dues_limited,
- WithdrawReasons::FEE,
- free_balance.saturating_sub(dues_limited),
- )
- .is_ok();
-
- if insufficient_rent || !can_withdraw_rent {
- // The contract cannot afford the rent payment and has a balance above the subsistence
- // threshold, so it leaves a tombstone.
- let amount = if can_withdraw_rent {
- Some(OutstandingAmount::new(dues_limited))
- } else {
- None
- };
- return Verdict::Evict { amount };
- }
-
- return Verdict::Charge {
- // We choose to use `dues_limited` here instead of `dues` just to err on the safer side.
- amount: OutstandingAmount::new(dues_limited),
- };
- }
-
- /// Enacts the given verdict and returns the updated `ContractInfo`.
- ///
- /// `alive_contract_info` should be from the same address as `account`.
- ///
- /// # Note
- ///
- /// if `evictable_code` is `None` an `Evict` verdict will not be enacted. This is for
- /// when calling this function during a `call` where access to the soon to be evicted
- /// contract should be denied but storage should be left unmodified.
- fn enact_verdict(
- account: &T::AccountId,
- alive_contract_info: AliveContractInfo<T>,
- current_block_number: T::BlockNumber,
- verdict: Verdict<T>,
- evictable_code: Option<PrefabWasmModule<T>>,
- ) -> Result<Option<AliveContractInfo<T>>, DispatchError> {
- match (verdict, evictable_code) {
- (Verdict::Evict { amount }, Some(code)) => {
- // We need to remove the trie first because it is the only operation
- // that can fail and this function is called without a storage
- // transaction when called through `claim_surcharge`.
- Storage::<T>::queue_trie_for_deletion(&alive_contract_info)?;
-
- if let Some(amount) = amount {
- amount.withdraw(account);
- }
-
- // Note: this operation is heavy.
- let child_storage_root = child::root(&alive_contract_info.child_trie_info());
-
- let tombstone = <TombstoneContractInfo<T>>::new(
- &child_storage_root[..],
- alive_contract_info.code_hash,
- );
- let tombstone_info = ContractInfo::Tombstone(tombstone);
- <ContractInfoOf<T>>::insert(account, &tombstone_info);
- code.drop_from_storage();
- <Pallet<T>>::deposit_event(Event::Evicted(account.clone()));
- Ok(None)
- }
- (Verdict::Evict { amount: _ }, None) => Ok(None),
- (Verdict::Exempt, _) => {
- let contract = ContractInfo::Alive(AliveContractInfo::<T> {
- deduct_block: current_block_number,
- ..alive_contract_info
- });
- <ContractInfoOf<T>>::insert(account, &contract);
- Ok(Some(
- contract
- .get_alive()
- .expect("We just constructed it as alive. qed"),
- ))
- }
- (Verdict::Charge { amount }, _) => {
- let contract = ContractInfo::Alive(AliveContractInfo::<T> {
- rent_allowance: alive_contract_info.rent_allowance - amount.peek(),
- deduct_block: current_block_number,
- rent_payed: alive_contract_info.rent_payed.saturating_add(amount.peek()),
- ..alive_contract_info
- });
- <ContractInfoOf<T>>::insert(account, &contract);
- amount.withdraw(account);
- Ok(Some(
- contract
- .get_alive()
- .expect("We just constructed it as alive. qed"),
- ))
- }
- }
- }
-
- /// Make account paying the rent for the current block number
- ///
- /// This functions does **not** evict the contract. It returns `None` in case the
- /// contract is in need of eviction. [`try_eviction`] must
- /// be called to perform the eviction.
- pub fn charge(
- account: &T::AccountId,
- contract: AliveContractInfo<T>,
- code_size: u32,
- ) -> Result<Option<AliveContractInfo<T>>, DispatchError> {
- let current_block_number = <frame_system::Pallet<T>>::block_number();
- let verdict = Self::consider_case(
- account,
- current_block_number,
- Zero::zero(),
- &contract,
- code_size,
- );
- Self::enact_verdict(account, contract, current_block_number, verdict, None)
- }
-
- /// Process a report that a contract under the given address should be evicted.
- ///
- /// Enact the eviction right away if the contract should be evicted and return the amount
- /// of rent that the contract payed over its lifetime.
- /// Otherwise, **do nothing** and return None.
- ///
- /// The `handicap` parameter gives a way to check the rent to a moment in the past instead
- /// of current block. E.g. if the contract is going to be evicted at the current block,
- /// `handicap = 1` can defer the eviction for 1 block. This is useful to handicap certain snitchers
- /// relative to others.
- ///
- /// NOTE this function performs eviction eagerly. All changes are read and written directly to
- /// storage.
- pub fn try_eviction(
- account: &T::AccountId,
- handicap: T::BlockNumber,
- ) -> Result<(Option<BalanceOf<T>>, u32), DispatchError> {
- let contract = <ContractInfoOf<T>>::get(account);
- let contract = match contract {
- None | Some(ContractInfo::Tombstone(_)) => return Ok((None, 0)),
- Some(ContractInfo::Alive(contract)) => contract,
- };
- let module = PrefabWasmModule::<T>::from_storage_noinstr(contract.code_hash)?;
- let code_len = module.code_len();
- let current_block_number = <frame_system::Pallet<T>>::block_number();
- let verdict = Self::consider_case(
- account,
- current_block_number,
- handicap,
- &contract,
- module.occupied_storage(),
- );
-
- // Enact the verdict only if the contract gets removed.
- match verdict {
- Verdict::Evict { ref amount } => {
- // The outstanding `amount` is withdrawn inside `enact_verdict`.
- let rent_payed = amount
- .as_ref()
- .map(|a| a.peek())
- .unwrap_or_else(|| <BalanceOf<T>>::zero())
- .saturating_add(contract.rent_payed);
- Self::enact_verdict(
- account,
- contract,
- current_block_number,
- verdict,
- Some(module),
- )?;
- Ok((Some(rent_payed), code_len))
- }
- _ => Ok((None, code_len)),
- }
- }
-
- /// Returns the projected time a given contract will be able to sustain paying its rent. The
- /// returned projection is relevant for the current block, i.e. it is as if the contract was
- /// accessed at the beginning of the current block. Returns `None` in case if the contract was
- /// evicted before or as a result of the rent collection.
- ///
- /// The returned value is only an estimation. It doesn't take into account any top ups, changing the
- /// rent allowance, or any problems coming from withdrawing the dues.
- ///
- /// NOTE that this is not a side-effect free function! It will actually collect rent and then
- /// compute the projection. This function is only used for implementation of an RPC method through
- /// `RuntimeApi` meaning that the changes will be discarded anyway.
- pub fn compute_projection(account: &T::AccountId) -> RentProjectionResult<T::BlockNumber> {
- use ContractAccessError::IsTombstone;
-
- let contract_info = <ContractInfoOf<T>>::get(account);
- let alive_contract_info = match contract_info {
- None | Some(ContractInfo::Tombstone(_)) => return Err(IsTombstone),
- Some(ContractInfo::Alive(contract)) => contract,
- };
- let module = <PrefabWasmModule<T>>::from_storage_noinstr(alive_contract_info.code_hash)
- .map_err(|_| IsTombstone)?;
- let code_size = module.occupied_storage();
- let current_block_number = <frame_system::Pallet<T>>::block_number();
- let verdict = Self::consider_case(
- account,
- current_block_number,
- Zero::zero(),
- &alive_contract_info,
- code_size,
- );
-
- // We skip the eviction in case one is in order.
- // Evictions should only be performed by [`try_eviction`].
- let new_contract_info = Self::enact_verdict(
- account,
- alive_contract_info,
- current_block_number,
- verdict,
- None,
- );
-
- // Check what happened after enaction of the verdict.
- let alive_contract_info = new_contract_info
- .map_err(|_| IsTombstone)?
- .ok_or_else(|| IsTombstone)?;
-
- // Compute how much would the fee per block be with the *updated* balance.
- let total_balance = T::Currency::total_balance(account);
- let free_balance = T::Currency::free_balance(account);
- let fee_per_block =
- Self::compute_fee_per_block(&free_balance, &alive_contract_info, code_size);
- if fee_per_block.is_zero() {
- return Ok(RentProjection::NoEviction);
- }
-
- // Then compute how much the contract will sustain under these circumstances.
- let rent_budget = Self::rent_budget(&total_balance, &free_balance, &alive_contract_info)
- .expect(
- "the contract exists and in the alive state;
- the updated balance must be greater than subsistence deposit;
- this function doesn't return `None`;
- qed
- ",
- );
- let blocks_left = match rent_budget.checked_div(&fee_per_block) {
- Some(blocks_left) => blocks_left,
- None => {
- // `fee_per_block` is not zero here, so `checked_div` can return `None` if
- // there is an overflow. This cannot happen with integers though. Return
- // `NoEviction` here just in case.
- return Ok(RentProjection::NoEviction);
- }
- };
-
- let blocks_left = blocks_left.saturated_into::<u32>().into();
- Ok(RentProjection::EvictionAt(
- current_block_number + blocks_left,
- ))
- }
-
- /// Restores the destination account using the origin as prototype.
- ///
- /// The restoration will be performed iff:
- /// - the supplied code_hash does still exist on-chain
- /// - origin exists and is alive,
- /// - the origin's storage is not written in the current block
- /// - the restored account has tombstone
- /// - the tombstone matches the hash of the origin storage root, and code hash.
- ///
- /// Upon succesful restoration, `origin` will be destroyed, all its funds are transferred to
- /// the restored account. The restored account will inherit the last write block and its last
- /// deduct block will be set to the current block.
- ///
- /// # Return Value
- ///
- /// Result<(CallerCodeSize, DestCodeSize), (DispatchError, CallerCodeSize, DestCodesize)>
- pub fn restore_to(
- origin: T::AccountId,
- dest: T::AccountId,
- code_hash: CodeHash<T>,
- rent_allowance: BalanceOf<T>,
- delta: Vec<crate::exec::StorageKey>,
- ) -> Result<(u32, u32), (DispatchError, u32, u32)> {
- let mut origin_contract = <ContractInfoOf<T>>::get(&origin)
- .and_then(|c| c.get_alive())
- .ok_or((Error::<T>::InvalidSourceContract.into(), 0, 0))?;
-
- let child_trie_info = origin_contract.child_trie_info();
-
- let current_block = <frame_system::Pallet<T>>::block_number();
-
- if origin_contract.last_write == Some(current_block) {
- return Err((Error::<T>::InvalidContractOrigin.into(), 0, 0));
- }
-
- let dest_tombstone = <ContractInfoOf<T>>::get(&dest)
- .and_then(|c| c.get_tombstone())
- .ok_or((Error::<T>::InvalidDestinationContract.into(), 0, 0))?;
-
- let last_write = if !delta.is_empty() {
- Some(current_block)
- } else {
- origin_contract.last_write
- };
-
- // Fails if the code hash does not exist on chain
- let caller_code_len = E::add_user(code_hash).map_err(|e| (e, 0, 0))?;
-
- // We are allowed to eagerly modify storage even though the function can
- // fail later due to tombstones not matching. This is because the restoration
- // is always called from a contract and therefore in a storage transaction.
- // The failure of this function will lead to this transaction's rollback.
- let bytes_taken: u32 = delta
- .iter()
- .filter_map(|key| {
- let key = blake2_256(key);
- child::get_raw(&child_trie_info, &key).map(|value| {
- child::kill(&child_trie_info, &key);
- value.len() as u32
- })
- })
- .sum();
-
- let tombstone = <TombstoneContractInfo<T>>::new(
- // This operation is cheap enough because last_write (delta not included)
- // is not this block as it has been checked earlier.
- &child::root(&child_trie_info)[..],
- code_hash,
- );
-
- if tombstone != dest_tombstone {
- return Err((Error::<T>::InvalidTombstone.into(), caller_code_len, 0));
- }
-
- origin_contract.storage_size -= bytes_taken;
-
- <ContractInfoOf<T>>::remove(&origin);
- let tombstone_code_len = E::remove_user(origin_contract.code_hash);
- <ContractInfoOf<T>>::insert(
- &dest,
- ContractInfo::Alive(AliveContractInfo::<T> {
- code_hash,
- rent_allowance,
- rent_payed: <BalanceOf<T>>::zero(),
- deduct_block: current_block,
- last_write,
- ..origin_contract
- }),
- );
-
- let origin_free_balance = T::Currency::free_balance(&origin);
- T::Currency::make_free_balance_be(&origin, <BalanceOf<T>>::zero());
- T::Currency::deposit_creating(&dest, origin_free_balance);
-
- Ok((caller_code_len, tombstone_code_len))
- }
-}
pallets/contracts/src/schedule.rsdiffbeforeafterboth--- a/pallets/contracts/src/schedule.rs
+++ /dev/null
@@ -1,806 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! This module contains the cost schedule and supporting code that constructs a
-//! sane default schedule from a `WeightInfo` implementation.
-
-use crate::{Config, weights::WeightInfo};
-
-#[cfg(feature = "std")]
-use serde::{Serialize, Deserialize};
-use pallet_contracts_proc_macro::{ScheduleDebug, WeightDebug};
-use frame_support::weights::Weight;
-use sp_std::{marker::PhantomData, vec::Vec};
-use codec::{Encode, Decode};
-use parity_wasm::elements;
-use pwasm_utils::rules;
-use sp_runtime::RuntimeDebug;
-
-/// How many API calls are executed in a single batch. The reason for increasing the amount
-/// of API calls in batches (per benchmark component increase) is so that the linear regression
-/// has an easier time determining the contribution of that component.
-pub const API_BENCHMARK_BATCH_SIZE: u32 = 100;
-
-/// How many instructions are executed in a single batch. The reasoning is the same
-/// as for `API_BENCHMARK_BATCH_SIZE`.
-pub const INSTR_BENCHMARK_BATCH_SIZE: u32 = 1_000;
-
-/// Definition of the cost schedule and other parameterizations for the wasm vm.
-///
-/// Its fields are private to the crate in order to allow addition of new contract
-/// callable functions without bumping to a new major version. A genesis config should
-/// rely on public functions of this type.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[cfg_attr(feature = "std", serde(bound(serialize = "", deserialize = "")))]
-#[derive(Clone, Encode, Decode, PartialEq, Eq, ScheduleDebug)]
-pub struct Schedule<T: Config> {
- /// Version of the schedule.
- ///
- /// # Note
- ///
- /// Must be incremented whenever the [`self.instruction_weights`] are changed. The
- /// reason is that changes to instruction weights require a re-instrumentation
- /// of all contracts which are triggered by a version comparison on call.
- /// Changes to other parts of the schedule should not increment the version in
- /// order to avoid unnecessary re-instrumentations.
- pub(crate) version: u32,
-
- /// Whether the `seal_println` function is allowed to be used contracts.
- /// MUST only be enabled for `dev` chains, NOT for production chains
- pub(crate) enable_println: bool,
-
- /// Describes the upper limits on various metrics.
- pub(crate) limits: Limits,
-
- /// The weights for individual wasm instructions.
- pub(crate) instruction_weights: InstructionWeights<T>,
-
- /// The weights for each imported function a contract is allowed to call.
- pub(crate) host_fn_weights: HostFnWeights<T>,
-}
-
-/// Describes the upper limits on various metrics.
-///
-/// # Note
-///
-/// The values in this struct should only ever be increased for a deployed chain. The reason
-/// is that decreasing those values will break existing contracts which are above the new limits.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)]
-pub struct Limits {
- /// The maximum number of topics supported by an event.
- pub event_topics: u32,
-
- /// Maximum allowed stack height in number of elements.
- ///
- /// See <https://wiki.parity.io/WebAssembly-StackHeight> to find out
- /// how the stack frame cost is calculated. Each element can be of one of the
- /// wasm value types. This means the maximum size per element is 64bit.
- pub stack_height: u32,
-
- /// Maximum number of globals a module is allowed to declare.
- ///
- /// Globals are not limited through the `stack_height` as locals are. Neither does
- /// the linear memory limit `memory_pages` applies to them.
- pub globals: u32,
-
- /// Maximum numbers of parameters a function can have.
- ///
- /// Those need to be limited to prevent a potentially exploitable interaction with
- /// the stack height instrumentation: The costs of executing the stack height
- /// instrumentation for an indirectly called function scales linearly with the amount
- /// of parameters of this function. Because the stack height instrumentation itself is
- /// is not weight metered its costs must be static (via this limit) and included in
- /// the costs of the instructions that cause them (call, call_indirect).
- pub parameters: u32,
-
- /// Maximum number of memory pages allowed for a contract.
- pub memory_pages: u32,
-
- /// Maximum number of elements allowed in a table.
- ///
- /// Currently, the only type of element that is allowed in a table is funcref.
- pub table_size: u32,
-
- /// Maximum number of elements that can appear as immediate value to the br_table instruction.
- pub br_table_size: u32,
-
- /// The maximum length of a subject in bytes used for PRNG generation.
- pub subject_len: u32,
-}
-
-impl Limits {
- /// The maximum memory size in bytes that a contract can occupy.
- pub fn max_memory_size(&self) -> u32 {
- self.memory_pages * 64 * 1024
- }
-}
-
-/// Describes the weight for all categories of supported wasm instructions.
-///
-/// There there is one field for each wasm instruction that describes the weight to
-/// execute one instruction of that name. There are a few execptions:
-///
-/// 1. If there is a i64 and a i32 variant of an instruction we use the weight
-/// of the former for both.
-/// 2. The following instructions are free of charge because they merely structure the
-/// wasm module and cannot be spammed without making the module invalid (and rejected):
-/// End, Unreachable, Return, Else
-/// 3. The following instructions cannot be benchmarked because they are removed by any
-/// real world execution engine as a preprocessing step and therefore don't yield a
-/// meaningful benchmark result. However, in contrast to the instructions mentioned
-/// in 2. they can be spammed. We price them with the same weight as the "default"
-/// instruction (i64.const): Block, Loop, Nop
-/// 4. We price both i64.const and drop as InstructionWeights.i64const / 2. The reason
-/// for that is that we cannot benchmark either of them on its own but we need their
-/// individual values to derive (by subtraction) the weight of all other instructions
-/// that use them as supporting instructions. Supporting means mainly pushing arguments
-/// and dropping return values in order to maintain a valid module.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Clone, Encode, Decode, PartialEq, Eq, WeightDebug)]
-pub struct InstructionWeights<T: Config> {
- pub i64const: u32,
- pub i64load: u32,
- pub i64store: u32,
- pub select: u32,
- pub r#if: u32,
- pub br: u32,
- pub br_if: u32,
- pub br_table: u32,
- pub br_table_per_entry: u32,
- pub call: u32,
- pub call_indirect: u32,
- pub call_indirect_per_param: u32,
- pub local_get: u32,
- pub local_set: u32,
- pub local_tee: u32,
- pub global_get: u32,
- pub global_set: u32,
- pub memory_current: u32,
- pub memory_grow: u32,
- pub i64clz: u32,
- pub i64ctz: u32,
- pub i64popcnt: u32,
- pub i64eqz: u32,
- pub i64extendsi32: u32,
- pub i64extendui32: u32,
- pub i32wrapi64: u32,
- pub i64eq: u32,
- pub i64ne: u32,
- pub i64lts: u32,
- pub i64ltu: u32,
- pub i64gts: u32,
- pub i64gtu: u32,
- pub i64les: u32,
- pub i64leu: u32,
- pub i64ges: u32,
- pub i64geu: u32,
- pub i64add: u32,
- pub i64sub: u32,
- pub i64mul: u32,
- pub i64divs: u32,
- pub i64divu: u32,
- pub i64rems: u32,
- pub i64remu: u32,
- pub i64and: u32,
- pub i64or: u32,
- pub i64xor: u32,
- pub i64shl: u32,
- pub i64shrs: u32,
- pub i64shru: u32,
- pub i64rotl: u32,
- pub i64rotr: u32,
- /// The type parameter is used in the default implementation.
- #[codec(skip)]
- pub _phantom: PhantomData<T>,
-}
-
-/// Describes the weight for each imported function that a contract is allowed to call.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Clone, Encode, Decode, PartialEq, Eq, WeightDebug)]
-pub struct HostFnWeights<T: Config> {
- /// Weight of calling `seal_caller`.
- pub caller: Weight,
-
- /// Weight of calling `seal_address`.
- pub address: Weight,
-
- /// Weight of calling `seal_gas_left`.
- pub gas_left: Weight,
-
- /// Weight of calling `seal_balance`.
- pub balance: Weight,
-
- /// Weight of calling `seal_value_transferred`.
- pub value_transferred: Weight,
-
- /// Weight of calling `seal_minimum_balance`.
- pub minimum_balance: Weight,
-
- /// Weight of calling `seal_tombstone_deposit`.
- pub tombstone_deposit: Weight,
-
- /// Weight of calling `seal_rent_allowance`.
- pub rent_allowance: Weight,
-
- /// Weight of calling `seal_block_number`.
- pub block_number: Weight,
-
- /// Weight of calling `seal_now`.
- pub now: Weight,
-
- /// Weight of calling `seal_weight_to_fee`.
- pub weight_to_fee: Weight,
-
- /// Weight of calling `gas`.
- pub gas: Weight,
-
- /// Weight of calling `seal_input`.
- pub input: Weight,
-
- /// Weight per input byte copied to contract memory by `seal_input`.
- pub input_per_byte: Weight,
-
- /// Weight of calling `seal_return`.
- pub r#return: Weight,
-
- /// Weight per byte returned through `seal_return`.
- pub return_per_byte: Weight,
-
- /// Weight of calling `seal_terminate`.
- pub terminate: Weight,
-
- /// Weight per byte of the terminated contract.
- pub terminate_per_code_byte: Weight,
-
- /// Weight of calling `seal_restore_to`.
- pub restore_to: Weight,
-
- /// Weight per byte of the restoring contract.
- pub restore_to_per_caller_code_byte: Weight,
-
- /// Weight per byte of the restored contract.
- pub restore_to_per_tombstone_code_byte: Weight,
-
- /// Weight per delta key supplied to `seal_restore_to`.
- pub restore_to_per_delta: Weight,
-
- /// Weight of calling `seal_random`.
- pub random: Weight,
-
- /// Weight of calling `seal_reposit_event`.
- pub deposit_event: Weight,
-
- /// Weight per topic supplied to `seal_deposit_event`.
- pub deposit_event_per_topic: Weight,
-
- /// Weight per byte of an event deposited through `seal_deposit_event`.
- pub deposit_event_per_byte: Weight,
-
- /// Weight of calling `seal_set_rent_allowance`.
- pub set_rent_allowance: Weight,
-
- /// Weight of calling `seal_set_storage`.
- pub set_storage: Weight,
-
- /// Weight per byte of an item stored with `seal_set_storage`.
- pub set_storage_per_byte: Weight,
-
- /// Weight of calling `seal_clear_storage`.
- pub clear_storage: Weight,
-
- /// Weight of calling `seal_get_storage`.
- pub get_storage: Weight,
-
- /// Weight per byte of an item received via `seal_get_storage`.
- pub get_storage_per_byte: Weight,
-
- /// Weight of calling `seal_transfer`.
- pub transfer: Weight,
-
- /// Weight of calling `seal_call`.
- pub call: Weight,
-
- /// Weight per byte of the called contract.
- pub call_per_code_byte: Weight,
-
- /// Weight surcharge that is claimed if `seal_call` does a balance transfer.
- pub call_transfer_surcharge: Weight,
-
- /// Weight per input byte supplied to `seal_call`.
- pub call_per_input_byte: Weight,
-
- /// Weight per output byte received through `seal_call`.
- pub call_per_output_byte: Weight,
-
- /// Weight of calling `seal_instantiate`.
- pub instantiate: Weight,
-
- /// Weight per byte of the instantiated contract.
- pub instantiate_per_code_byte: Weight,
-
- /// Weight per input byte supplied to `seal_instantiate`.
- pub instantiate_per_input_byte: Weight,
-
- /// Weight per output byte received through `seal_instantiate`.
- pub instantiate_per_output_byte: Weight,
-
- /// Weight per salt byte supplied to `seal_instantiate`.
- pub instantiate_per_salt_byte: Weight,
-
- /// Weight of calling `seal_hash_sha_256`.
- pub hash_sha2_256: Weight,
-
- /// Weight per byte hashed by `seal_hash_sha_256`.
- pub hash_sha2_256_per_byte: Weight,
-
- /// Weight of calling `seal_hash_keccak_256`.
- pub hash_keccak_256: Weight,
-
- /// Weight per byte hashed by `seal_hash_keccak_256`.
- pub hash_keccak_256_per_byte: Weight,
-
- /// Weight of calling `seal_hash_blake2_256`.
- pub hash_blake2_256: Weight,
-
- /// Weight per byte hashed by `seal_hash_blake2_256`.
- pub hash_blake2_256_per_byte: Weight,
-
- /// Weight of calling `seal_hash_blake2_128`.
- pub hash_blake2_128: Weight,
-
- /// Weight per byte hashed by `seal_hash_blake2_128`.
- pub hash_blake2_128_per_byte: Weight,
-
- /// Weight of calling `seal_rent_params`.
- pub rent_params: Weight,
-
- /// The type parameter is used in the default implementation.
- #[codec(skip)]
- pub _phantom: PhantomData<T>,
-}
-
-macro_rules! replace_token {
- ($_in:tt $replacement:tt) => {
- $replacement
- };
-}
-
-macro_rules! call_zero {
- ($name:ident, $( $arg:expr ),*) => {
- T::WeightInfo::$name($( replace_token!($arg 0) ),*)
- };
-}
-
-macro_rules! cost_args {
- ($name:ident, $( $arg: expr ),+) => {
- (T::WeightInfo::$name($( $arg ),+).saturating_sub(call_zero!($name, $( $arg ),+)))
- }
-}
-
-macro_rules! cost_batched_args {
- ($name:ident, $( $arg: expr ),+) => {
- cost_args!($name, $( $arg ),+) / Weight::from(API_BENCHMARK_BATCH_SIZE)
- }
-}
-
-macro_rules! cost_instr_no_params_with_batch_size {
- ($name:ident, $batch_size:expr) => {
- (cost_args!($name, 1) / Weight::from($batch_size)) as u32
- };
-}
-
-macro_rules! cost_instr_with_batch_size {
- ($name:ident, $num_params:expr, $batch_size:expr) => {
- cost_instr_no_params_with_batch_size!($name, $batch_size).saturating_sub(
- (cost_instr_no_params_with_batch_size!(instr_i64const, $batch_size) / 2)
- .saturating_mul($num_params),
- )
- };
-}
-
-macro_rules! cost_instr {
- ($name:ident, $num_params:expr) => {
- cost_instr_with_batch_size!($name, $num_params, INSTR_BENCHMARK_BATCH_SIZE)
- };
-}
-
-macro_rules! cost_byte_args {
- ($name:ident, $( $arg: expr ),+) => {
- cost_args!($name, $( $arg ),+) / 1024
- }
-}
-
-macro_rules! cost_byte_batched_args {
- ($name:ident, $( $arg: expr ),+) => {
- cost_batched_args!($name, $( $arg ),+) / 1024
- }
-}
-
-macro_rules! cost {
- ($name:ident) => {
- cost_args!($name, 1)
- };
-}
-
-macro_rules! cost_batched {
- ($name:ident) => {
- cost_batched_args!($name, 1)
- };
-}
-
-macro_rules! cost_byte {
- ($name:ident) => {
- cost_byte_args!($name, 1)
- };
-}
-
-macro_rules! cost_byte_batched {
- ($name:ident) => {
- cost_byte_batched_args!($name, 1)
- };
-}
-
-impl<T: Config> Default for Schedule<T> {
- fn default() -> Self {
- Self {
- version: 0,
- enable_println: false,
- limits: Default::default(),
- instruction_weights: Default::default(),
- host_fn_weights: Default::default(),
- }
- }
-}
-
-impl Default for Limits {
- fn default() -> Self {
- Self {
- event_topics: 4,
- // 512 * sizeof(i64) will give us a 4k stack.
- stack_height: 512,
- globals: 256,
- parameters: 128,
- memory_pages: 16,
- // 4k function pointers (This is in count not bytes).
- table_size: 4096,
- br_table_size: 256,
- subject_len: 32,
- }
- }
-}
-
-impl<T: Config> Default for InstructionWeights<T> {
- fn default() -> Self {
- let max_pages = Limits::default().memory_pages;
- Self {
- i64const: cost_instr!(instr_i64const, 1),
- i64load: cost_instr!(instr_i64load, 2),
- i64store: cost_instr!(instr_i64store, 2),
- select: cost_instr!(instr_select, 4),
- r#if: cost_instr!(instr_if, 3),
- br: cost_instr!(instr_br, 2),
- br_if: cost_instr!(instr_br_if, 5),
- br_table: cost_instr!(instr_br_table, 3),
- br_table_per_entry: cost_instr!(instr_br_table_per_entry, 0),
- call: cost_instr!(instr_call, 2),
- call_indirect: cost_instr!(instr_call_indirect, 3),
- call_indirect_per_param: cost_instr!(instr_call_indirect_per_param, 1),
- local_get: cost_instr!(instr_local_get, 1),
- local_set: cost_instr!(instr_local_set, 1),
- local_tee: cost_instr!(instr_local_tee, 2),
- global_get: cost_instr!(instr_global_get, 1),
- global_set: cost_instr!(instr_global_set, 1),
- memory_current: cost_instr!(instr_memory_current, 1),
- memory_grow: cost_instr_with_batch_size!(instr_memory_grow, 1, max_pages),
- i64clz: cost_instr!(instr_i64clz, 2),
- i64ctz: cost_instr!(instr_i64ctz, 2),
- i64popcnt: cost_instr!(instr_i64popcnt, 2),
- i64eqz: cost_instr!(instr_i64eqz, 2),
- i64extendsi32: cost_instr!(instr_i64extendsi32, 2),
- i64extendui32: cost_instr!(instr_i64extendui32, 2),
- i32wrapi64: cost_instr!(instr_i32wrapi64, 2),
- i64eq: cost_instr!(instr_i64eq, 3),
- i64ne: cost_instr!(instr_i64ne, 3),
- i64lts: cost_instr!(instr_i64lts, 3),
- i64ltu: cost_instr!(instr_i64ltu, 3),
- i64gts: cost_instr!(instr_i64gts, 3),
- i64gtu: cost_instr!(instr_i64gtu, 3),
- i64les: cost_instr!(instr_i64les, 3),
- i64leu: cost_instr!(instr_i64leu, 3),
- i64ges: cost_instr!(instr_i64ges, 3),
- i64geu: cost_instr!(instr_i64geu, 3),
- i64add: cost_instr!(instr_i64add, 3),
- i64sub: cost_instr!(instr_i64sub, 3),
- i64mul: cost_instr!(instr_i64mul, 3),
- i64divs: cost_instr!(instr_i64divs, 3),
- i64divu: cost_instr!(instr_i64divu, 3),
- i64rems: cost_instr!(instr_i64rems, 3),
- i64remu: cost_instr!(instr_i64remu, 3),
- i64and: cost_instr!(instr_i64and, 3),
- i64or: cost_instr!(instr_i64or, 3),
- i64xor: cost_instr!(instr_i64xor, 3),
- i64shl: cost_instr!(instr_i64shl, 3),
- i64shrs: cost_instr!(instr_i64shrs, 3),
- i64shru: cost_instr!(instr_i64shru, 3),
- i64rotl: cost_instr!(instr_i64rotl, 3),
- i64rotr: cost_instr!(instr_i64rotr, 3),
- _phantom: PhantomData,
- }
- }
-}
-
-impl<T: Config> Default for HostFnWeights<T> {
- fn default() -> Self {
- Self {
- caller: cost_batched!(seal_caller),
- address: cost_batched!(seal_address),
- gas_left: cost_batched!(seal_gas_left),
- balance: cost_batched!(seal_balance),
- value_transferred: cost_batched!(seal_value_transferred),
- minimum_balance: cost_batched!(seal_minimum_balance),
- tombstone_deposit: cost_batched!(seal_tombstone_deposit),
- rent_allowance: cost_batched!(seal_rent_allowance),
- block_number: cost_batched!(seal_block_number),
- now: cost_batched!(seal_now),
- weight_to_fee: cost_batched!(seal_weight_to_fee),
- gas: cost_batched!(seal_gas),
- input: cost!(seal_input),
- input_per_byte: cost_byte!(seal_input_per_kb),
- r#return: cost!(seal_return),
- return_per_byte: cost_byte!(seal_return_per_kb),
- terminate: cost!(seal_terminate),
- terminate_per_code_byte: cost_byte!(seal_terminate_per_code_kb),
- restore_to: cost!(seal_restore_to),
- restore_to_per_caller_code_byte: cost_byte_args!(
- seal_restore_to_per_code_kb_delta,
- 1,
- 0,
- 0
- ),
- restore_to_per_tombstone_code_byte: cost_byte_args!(
- seal_restore_to_per_code_kb_delta,
- 0,
- 1,
- 0
- ),
- restore_to_per_delta: cost_batched_args!(seal_restore_to_per_code_kb_delta, 0, 0, 1),
- random: cost_batched!(seal_random),
- deposit_event: cost_batched!(seal_deposit_event),
- deposit_event_per_topic: cost_batched_args!(seal_deposit_event_per_topic_and_kb, 1, 0),
- deposit_event_per_byte: cost_byte_batched_args!(
- seal_deposit_event_per_topic_and_kb,
- 0,
- 1
- ),
- set_rent_allowance: cost_batched!(seal_set_rent_allowance),
- set_storage: cost_batched!(seal_set_storage),
- set_storage_per_byte: cost_byte_batched!(seal_set_storage_per_kb),
- clear_storage: cost_batched!(seal_clear_storage),
- get_storage: cost_batched!(seal_get_storage),
- get_storage_per_byte: cost_byte_batched!(seal_get_storage_per_kb),
- transfer: cost_batched!(seal_transfer),
- call: cost_batched!(seal_call),
- call_per_code_byte: cost_byte_batched_args!(
- seal_call_per_code_transfer_input_output_kb,
- 1,
- 0,
- 0,
- 0
- ),
- call_transfer_surcharge: cost_batched_args!(
- seal_call_per_code_transfer_input_output_kb,
- 0,
- 1,
- 0,
- 0
- ),
- call_per_input_byte: cost_byte_batched_args!(
- seal_call_per_code_transfer_input_output_kb,
- 0,
- 0,
- 1,
- 0
- ),
- call_per_output_byte: cost_byte_batched_args!(
- seal_call_per_code_transfer_input_output_kb,
- 0,
- 0,
- 0,
- 1
- ),
- instantiate: cost_batched!(seal_instantiate),
- instantiate_per_code_byte: cost_byte_batched_args!(
- seal_instantiate_per_code_input_output_salt_kb,
- 1,
- 0,
- 0,
- 0
- ),
- instantiate_per_input_byte: cost_byte_batched_args!(
- seal_instantiate_per_code_input_output_salt_kb,
- 0,
- 1,
- 0,
- 0
- ),
- instantiate_per_output_byte: cost_byte_batched_args!(
- seal_instantiate_per_code_input_output_salt_kb,
- 0,
- 0,
- 1,
- 0
- ),
- instantiate_per_salt_byte: cost_byte_batched_args!(
- seal_instantiate_per_code_input_output_salt_kb,
- 0,
- 0,
- 0,
- 1
- ),
- hash_sha2_256: cost_batched!(seal_hash_sha2_256),
- hash_sha2_256_per_byte: cost_byte_batched!(seal_hash_sha2_256_per_kb),
- hash_keccak_256: cost_batched!(seal_hash_keccak_256),
- hash_keccak_256_per_byte: cost_byte_batched!(seal_hash_keccak_256_per_kb),
- hash_blake2_256: cost_batched!(seal_hash_blake2_256),
- hash_blake2_256_per_byte: cost_byte_batched!(seal_hash_blake2_256_per_kb),
- hash_blake2_128: cost_batched!(seal_hash_blake2_128),
- hash_blake2_128_per_byte: cost_byte_batched!(seal_hash_blake2_128_per_kb),
- rent_params: cost_batched!(seal_rent_params),
- _phantom: PhantomData,
- }
- }
-}
-
-struct ScheduleRules<'a, T: Config> {
- schedule: &'a Schedule<T>,
- params: Vec<u32>,
-}
-
-impl<T: Config> Schedule<T> {
- /// Allow contracts to call `seal_println` in order to print messages to the console.
- ///
- /// This should only ever be activated in development chains. The printed messages
- /// can be observed on the console by setting the environment variable
- /// `RUST_LOG=runtime=debug` when running the node.
- ///
- /// # Note
- ///
- /// Is set to `false` by default.
- pub fn enable_println(mut self, enable: bool) -> Self {
- self.enable_println = enable;
- self
- }
-
- pub(crate) fn rules(&self, module: &elements::Module) -> impl rules::Rules + '_ {
- ScheduleRules {
- schedule: &self,
- params: module
- .type_section()
- .iter()
- .flat_map(|section| section.types())
- .map(|func| {
- let elements::Type::Function(func) = func;
- func.params().len() as u32
- })
- .collect(),
- }
- }
-}
-
-impl<'a, T: Config> rules::Rules for ScheduleRules<'a, T> {
- fn instruction_cost(&self, instruction: &elements::Instruction) -> Option<u32> {
- use parity_wasm::elements::Instruction::*;
- let w = &self.schedule.instruction_weights;
- let max_params = self.schedule.limits.parameters;
-
- let weight = match *instruction {
- End | Unreachable | Return | Else => 0,
- I32Const(_) | I64Const(_) | Block(_) | Loop(_) | Nop | Drop => w.i64const,
- I32Load(_, _)
- | I32Load8S(_, _)
- | I32Load8U(_, _)
- | I32Load16S(_, _)
- | I32Load16U(_, _)
- | I64Load(_, _)
- | I64Load8S(_, _)
- | I64Load8U(_, _)
- | I64Load16S(_, _)
- | I64Load16U(_, _)
- | I64Load32S(_, _)
- | I64Load32U(_, _) => w.i64load,
- I32Store(_, _)
- | I32Store8(_, _)
- | I32Store16(_, _)
- | I64Store(_, _)
- | I64Store8(_, _)
- | I64Store16(_, _)
- | I64Store32(_, _) => w.i64store,
- Select => w.select,
- If(_) => w.r#if,
- Br(_) => w.br,
- BrIf(_) => w.br_if,
- Call(_) => w.call,
- GetLocal(_) => w.local_get,
- SetLocal(_) => w.local_set,
- TeeLocal(_) => w.local_tee,
- GetGlobal(_) => w.global_get,
- SetGlobal(_) => w.global_set,
- CurrentMemory(_) => w.memory_current,
- GrowMemory(_) => w.memory_grow,
- CallIndirect(idx, _) => *self.params.get(idx as usize).unwrap_or(&max_params),
- BrTable(ref data) => w
- .br_table
- .saturating_add(w.br_table_per_entry.saturating_mul(data.table.len() as u32)),
- I32Clz | I64Clz => w.i64clz,
- I32Ctz | I64Ctz => w.i64ctz,
- I32Popcnt | I64Popcnt => w.i64popcnt,
- I32Eqz | I64Eqz => w.i64eqz,
- I64ExtendSI32 => w.i64extendsi32,
- I64ExtendUI32 => w.i64extendui32,
- I32WrapI64 => w.i32wrapi64,
- I32Eq | I64Eq => w.i64eq,
- I32Ne | I64Ne => w.i64ne,
- I32LtS | I64LtS => w.i64lts,
- I32LtU | I64LtU => w.i64ltu,
- I32GtS | I64GtS => w.i64gts,
- I32GtU | I64GtU => w.i64gtu,
- I32LeS | I64LeS => w.i64les,
- I32LeU | I64LeU => w.i64leu,
- I32GeS | I64GeS => w.i64ges,
- I32GeU | I64GeU => w.i64geu,
- I32Add | I64Add => w.i64add,
- I32Sub | I64Sub => w.i64sub,
- I32Mul | I64Mul => w.i64mul,
- I32DivS | I64DivS => w.i64divs,
- I32DivU | I64DivU => w.i64divu,
- I32RemS | I64RemS => w.i64rems,
- I32RemU | I64RemU => w.i64remu,
- I32And | I64And => w.i64and,
- I32Or | I64Or => w.i64or,
- I32Xor | I64Xor => w.i64xor,
- I32Shl | I64Shl => w.i64shl,
- I32ShrS | I64ShrS => w.i64shrs,
- I32ShrU | I64ShrU => w.i64shru,
- I32Rotl | I64Rotl => w.i64rotl,
- I32Rotr | I64Rotr => w.i64rotr,
-
- // Returning None makes the gas instrumentation fail which we intend for
- // unsupported or unknown instructions.
- _ => return None,
- };
- Some(weight)
- }
-
- fn memory_grow_cost(&self) -> Option<rules::MemoryGrowCost> {
- // We benchmarked the memory.grow instruction with the maximum allowed pages.
- // The cost for growing is therefore already included in the instruction cost.
- None
- }
-}
-
-#[cfg(test)]
-mod test {
- use crate::tests::Test;
- use super::*;
-
- #[test]
- fn print_test_schedule() {
- let schedule = Schedule::<Test>::default();
- println!("{:#?}", schedule);
- }
-}
pallets/contracts/src/storage.rsdiffbeforeafterboth--- a/pallets/contracts/src/storage.rs
+++ /dev/null
@@ -1,440 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! This module contains routines for accessing and altering a contract related state.
-
-use crate::{
- exec::{AccountIdOf, StorageKey},
- BalanceOf, CodeHash, ContractInfoOf, Config, TrieId, AccountCounter, DeletionQueue, Error,
- weights::WeightInfo,
-};
-use codec::{Codec, Encode, Decode};
-use sp_std::prelude::*;
-use sp_std::{marker::PhantomData, fmt::Debug};
-use sp_io::hashing::blake2_256;
-use sp_runtime::{
- RuntimeDebug,
- traits::{Bounded, Saturating, Zero, Hash, Member, MaybeSerializeDeserialize},
-};
-use sp_core::crypto::UncheckedFrom;
-use frame_support::{
- dispatch::{DispatchError, DispatchResult},
- storage::child::{self, KillChildStorageResult, ChildInfo},
- traits::Get,
- weights::Weight,
-};
-
-pub type AliveContractInfo<T> =
- RawAliveContractInfo<CodeHash<T>, BalanceOf<T>, <T as frame_system::Config>::BlockNumber>;
-pub type TombstoneContractInfo<T> = RawTombstoneContractInfo<
- <T as frame_system::Config>::Hash,
- <T as frame_system::Config>::Hashing,
->;
-
-/// Information for managing an account and its sub trie abstraction.
-/// This is the required info to cache for an account
-#[derive(Encode, Decode, RuntimeDebug)]
-pub enum ContractInfo<T: Config> {
- Alive(AliveContractInfo<T>),
- Tombstone(TombstoneContractInfo<T>),
-}
-
-impl<T: Config> ContractInfo<T> {
- /// If contract is alive then return some alive info
- pub fn get_alive(self) -> Option<AliveContractInfo<T>> {
- if let ContractInfo::Alive(alive) = self {
- Some(alive)
- } else {
- None
- }
- }
- /// If contract is alive then return some reference to alive info
- pub fn as_alive(&self) -> Option<&AliveContractInfo<T>> {
- if let ContractInfo::Alive(ref alive) = self {
- Some(alive)
- } else {
- None
- }
- }
-
- /// If contract is tombstone then return some tombstone info
- pub fn get_tombstone(self) -> Option<TombstoneContractInfo<T>> {
- if let ContractInfo::Tombstone(tombstone) = self {
- Some(tombstone)
- } else {
- None
- }
- }
-}
-
-/// Information for managing an account and its sub trie abstraction.
-/// This is the required info to cache for an account.
-#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
-pub struct RawAliveContractInfo<CodeHash, Balance, BlockNumber> {
- /// Unique ID for the subtree encoded as a bytes vector.
- pub trie_id: TrieId,
- /// The total number of bytes used by this contract.
- ///
- /// It is a sum of each key-value pair stored by this contract.
- pub storage_size: u32,
- /// The total number of key-value pairs in storage of this contract.
- pub pair_count: u32,
- /// The code associated with a given account.
- pub code_hash: CodeHash,
- /// Pay rent at most up to this value.
- pub rent_allowance: Balance,
- /// The amount of rent that was payed by the contract over its whole lifetime.
- ///
- /// A restored contract starts with a value of zero just like a new contract.
- pub rent_payed: Balance,
- /// Last block rent has been payed.
- pub deduct_block: BlockNumber,
- /// Last block child storage has been written.
- pub last_write: Option<BlockNumber>,
- /// This field is reserved for future evolution of format.
- pub _reserved: Option<()>,
-}
-
-impl<CodeHash, Balance, BlockNumber> RawAliveContractInfo<CodeHash, Balance, BlockNumber> {
- /// Associated child trie unique id is built from the hash part of the trie id.
- pub fn child_trie_info(&self) -> ChildInfo {
- child_trie_info(&self.trie_id[..])
- }
-}
-
-/// Associated child trie unique id is built from the hash part of the trie id.
-fn child_trie_info(trie_id: &[u8]) -> ChildInfo {
- ChildInfo::new_default(trie_id)
-}
-
-#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug)]
-pub struct RawTombstoneContractInfo<H, Hasher>(H, PhantomData<Hasher>);
-
-impl<H, Hasher> RawTombstoneContractInfo<H, Hasher>
-where
- H: Member
- + MaybeSerializeDeserialize
- + Debug
- + AsRef<[u8]>
- + AsMut<[u8]>
- + Copy
- + Default
- + sp_std::hash::Hash
- + Codec,
- Hasher: Hash<Output = H>,
-{
- pub fn new(storage_root: &[u8], code_hash: H) -> Self {
- let mut buf = Vec::new();
- storage_root.using_encoded(|encoded| buf.extend_from_slice(encoded));
- buf.extend_from_slice(code_hash.as_ref());
- RawTombstoneContractInfo(<Hasher as Hash>::hash(&buf[..]), PhantomData)
- }
-}
-
-impl<T: Config> From<AliveContractInfo<T>> for ContractInfo<T> {
- fn from(alive_info: AliveContractInfo<T>) -> Self {
- Self::Alive(alive_info)
- }
-}
-
-/// An error that means that the account requested either doesn't exist or represents a tombstone
-/// account.
-#[cfg_attr(test, derive(PartialEq, Eq, Debug))]
-pub struct ContractAbsentError;
-
-#[derive(Encode, Decode)]
-pub struct DeletedContract {
- pair_count: u32,
- trie_id: TrieId,
-}
-
-pub struct Storage<T>(PhantomData<T>);
-
-impl<T> Storage<T>
-where
- T: Config,
- T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
-{
- /// Reads a storage kv pair of a contract.
- ///
- /// The read is performed from the `trie_id` only. The `address` is not necessary. If the contract
- /// doesn't store under the given `key` `None` is returned.
- pub fn read(trie_id: &TrieId, key: &StorageKey) -> Option<Vec<u8>> {
- child::get_raw(&child_trie_info(&trie_id), &blake2_256(key))
- }
-
- /// Update a storage entry into a contract's kv storage.
- ///
- /// If the `opt_new_value` is `None` then the kv pair is removed.
- ///
- /// This function also updates the bookkeeping info such as: number of total non-empty pairs a
- /// contract owns, the last block the storage was written to, etc. That's why, in contrast to
- /// `read`, this function also requires the `account` ID.
- ///
- /// If the contract specified by the id `account` doesn't exist `Err` is returned.`
- ///
- /// # Panics
- ///
- /// Panics iff the `account` specified is not alive and in storage.
- pub fn write(
- account: &AccountIdOf<T>,
- trie_id: &TrieId,
- key: &StorageKey,
- opt_new_value: Option<Vec<u8>>,
- ) -> DispatchResult {
- let mut new_info = match <ContractInfoOf<T>>::get(account) {
- Some(ContractInfo::Alive(alive)) => alive,
- None | Some(ContractInfo::Tombstone(_)) => panic!("Contract not found"),
- };
-
- let hashed_key = blake2_256(key);
- let child_trie_info = &child_trie_info(&trie_id);
-
- let opt_prev_len = child::len(&child_trie_info, &hashed_key);
-
- // Update the total number of KV pairs and the number of empty pairs.
- match (&opt_prev_len, &opt_new_value) {
- (Some(_), None) => {
- new_info.pair_count = new_info
- .pair_count
- .checked_sub(1)
- .ok_or_else(|| Error::<T>::StorageExhausted)?;
- }
- (None, Some(_)) => {
- new_info.pair_count = new_info
- .pair_count
- .checked_add(1)
- .ok_or_else(|| Error::<T>::StorageExhausted)?;
- }
- (Some(_), Some(_)) => {}
- (None, None) => {}
- }
-
- // Update the total storage size.
- let prev_value_len = opt_prev_len.unwrap_or(0);
- let new_value_len = opt_new_value
- .as_ref()
- .map(|new_value| new_value.len() as u32)
- .unwrap_or(0);
- new_info.storage_size = new_info
- .storage_size
- .checked_sub(prev_value_len)
- .and_then(|val| val.checked_add(new_value_len))
- .ok_or_else(|| Error::<T>::StorageExhausted)?;
-
- new_info.last_write = Some(<frame_system::Pallet<T>>::block_number());
- <ContractInfoOf<T>>::insert(&account, ContractInfo::Alive(new_info));
-
- // Finally, perform the change on the storage.
- match opt_new_value {
- Some(new_value) => child::put_raw(&child_trie_info, &hashed_key, &new_value[..]),
- None => child::kill(&child_trie_info, &hashed_key),
- }
-
- Ok(())
- }
-
- /// Returns the rent allowance set for the contract give by the account id.
- pub fn rent_allowance(account: &AccountIdOf<T>) -> Result<BalanceOf<T>, ContractAbsentError> {
- <ContractInfoOf<T>>::get(account)
- .and_then(|i| i.as_alive().map(|i| i.rent_allowance))
- .ok_or(ContractAbsentError)
- }
-
- /// Set the rent allowance for the contract given by the account id.
- ///
- /// Returns `Err` if the contract doesn't exist or is a tombstone.
- pub fn set_rent_allowance(
- account: &AccountIdOf<T>,
- rent_allowance: BalanceOf<T>,
- ) -> Result<(), ContractAbsentError> {
- <ContractInfoOf<T>>::mutate(account, |maybe_contract_info| match maybe_contract_info {
- Some(ContractInfo::Alive(ref mut alive_info)) => {
- alive_info.rent_allowance = rent_allowance;
- Ok(())
- }
- _ => Err(ContractAbsentError),
- })
- }
-
- /// Creates a new contract descriptor in the storage with the given code hash at the given address.
- ///
- /// Returns `Err` if there is already a contract (or a tombstone) exists at the given address.
- pub fn place_contract(
- account: &AccountIdOf<T>,
- trie_id: TrieId,
- ch: CodeHash<T>,
- ) -> Result<AliveContractInfo<T>, DispatchError> {
- <ContractInfoOf<T>>::try_mutate(account, |existing| {
- if existing.is_some() {
- return Err(Error::<T>::DuplicateContract.into());
- }
-
- let contract = AliveContractInfo::<T> {
- code_hash: ch,
- storage_size: 0,
- trie_id,
- deduct_block:
- // We want to charge rent for the first block in advance. Therefore we
- // treat the contract as if it was created in the last block and then
- // charge rent for it during instantiation.
- <frame_system::Pallet<T>>::block_number().saturating_sub(1u32.into()),
- rent_allowance: <BalanceOf<T>>::max_value(),
- rent_payed: <BalanceOf<T>>::zero(),
- pair_count: 0,
- last_write: None,
- _reserved: None,
- };
-
- *existing = Some(contract.clone().into());
-
- Ok(contract)
- })
- }
-
- /// Push a contract's trie to the deletion queue for lazy removal.
- ///
- /// You must make sure that the contract is also removed or converted into a tombstone
- /// when queuing the trie for deletion.
- pub fn queue_trie_for_deletion(contract: &AliveContractInfo<T>) -> DispatchResult {
- if <DeletionQueue<T>>::decode_len().unwrap_or(0) >= T::DeletionQueueDepth::get() as usize {
- Err(Error::<T>::DeletionQueueFull.into())
- } else {
- <DeletionQueue<T>>::append(DeletedContract {
- pair_count: contract.pair_count,
- trie_id: contract.trie_id.clone(),
- });
- Ok(())
- }
- }
-
- /// Calculates the weight that is necessary to remove one key from the trie and how many
- /// of those keys can be deleted from the deletion queue given the supplied queue length
- /// and weight limit.
- pub fn deletion_budget(queue_len: usize, weight_limit: Weight) -> (u64, u32) {
- let base_weight = T::WeightInfo::on_initialize();
- let weight_per_queue_item = T::WeightInfo::on_initialize_per_queue_item(1)
- - T::WeightInfo::on_initialize_per_queue_item(0);
- let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1)
- - T::WeightInfo::on_initialize_per_trie_key(0);
- let decoding_weight = weight_per_queue_item.saturating_mul(queue_len as Weight);
-
- // `weight_per_key` being zero makes no sense and would constitute a failure to
- // benchmark properly. We opt for not removing any keys at all in this case.
- let key_budget = weight_limit
- .saturating_sub(base_weight)
- .saturating_sub(decoding_weight)
- .checked_div(weight_per_key)
- .unwrap_or(0) as u32;
-
- (weight_per_key, key_budget)
- }
-
- /// Delete as many items from the deletion queue possible within the supplied weight limit.
- ///
- /// It returns the amount of weight used for that task or `None` when no weight was used
- /// apart from the base weight.
- pub fn process_deletion_queue_batch(weight_limit: Weight) -> Weight {
- let queue_len = <DeletionQueue<T>>::decode_len().unwrap_or(0);
- if queue_len == 0 {
- return weight_limit;
- }
-
- let (weight_per_key, mut remaining_key_budget) =
- Self::deletion_budget(queue_len, weight_limit);
-
- // We want to check whether we have enough weight to decode the queue before
- // proceeding. Too little weight for decoding might happen during runtime upgrades
- // which consume the whole block before the other `on_initialize` blocks are called.
- if remaining_key_budget == 0 {
- return weight_limit;
- }
-
- let mut queue = <DeletionQueue<T>>::get();
-
- while !queue.is_empty() && remaining_key_budget > 0 {
- // Cannot panic due to loop condition
- let trie = &mut queue[0];
- let pair_count = trie.pair_count;
- let outcome =
- child::kill_storage(&child_trie_info(&trie.trie_id), Some(remaining_key_budget));
- if pair_count > remaining_key_budget {
- // Cannot underflow because of the if condition
- trie.pair_count -= remaining_key_budget;
- } else {
- // We do not care to preserve order. The contract is deleted already and
- // noone waits for the trie to be deleted.
- let removed = queue.swap_remove(0);
- match outcome {
- // This should not happen as our budget was large enough to remove all keys.
- KillChildStorageResult::SomeRemaining(_) => {
- log::error!(
- target: "runtime::contracts",
- "After deletion keys are remaining in this child trie: {:?}",
- removed.trie_id,
- );
- }
- KillChildStorageResult::AllRemoved(_) => (),
- }
- }
- remaining_key_budget =
- remaining_key_budget.saturating_sub(remaining_key_budget.min(pair_count));
- }
-
- <DeletionQueue<T>>::put(queue);
- weight_limit.saturating_sub(weight_per_key.saturating_mul(remaining_key_budget as Weight))
- }
-
- /// This generator uses inner counter for account id and applies the hash over `AccountId +
- /// accountid_counter`.
- pub fn generate_trie_id(account_id: &AccountIdOf<T>) -> TrieId {
- // Note that skipping a value due to error is not an issue here.
- // We only need uniqueness, not sequence.
- let new_seed = <AccountCounter<T>>::mutate(|v| {
- *v = v.wrapping_add(1);
- *v
- });
-
- let buf: Vec<_> = account_id
- .as_ref()
- .iter()
- .chain(&new_seed.to_le_bytes())
- .cloned()
- .collect();
- T::Hashing::hash(&buf).as_ref().into()
- }
-
- /// Returns the code hash of the contract specified by `account` ID.
- #[cfg(test)]
- pub fn code_hash(account: &AccountIdOf<T>) -> Result<CodeHash<T>, ContractAbsentError> {
- <ContractInfoOf<T>>::get(account)
- .and_then(|i| i.as_alive().map(|i| i.code_hash))
- .ok_or(ContractAbsentError)
- }
-
- /// Fill up the queue in order to exercise the limits during testing.
- #[cfg(test)]
- pub fn fill_queue_with_dummies() {
- let queue: Vec<_> = (0..T::DeletionQueueDepth::get())
- .map(|_| DeletedContract {
- pair_count: 0,
- trie_id: vec![],
- })
- .collect();
- <DeletionQueue<T>>::put(queue);
- }
-}
pallets/contracts/src/tests.rsdiffbeforeafterboth--- a/pallets/contracts/src/tests.rs
+++ /dev/null
@@ -1,2971 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use crate::{
- BalanceOf, ContractInfo, ContractInfoOf, Pallet, Config, Schedule, Error,
- storage::Storage,
- chain_extension::{
- Result as ExtensionResult, Environment, ChainExtension, Ext, SysConfig, RetVal,
- UncheckedFrom, InitState, ReturnFlags,
- },
- exec::{AccountIdOf, Executable},
- wasm::PrefabWasmModule,
- weights::WeightInfo,
- wasm::ReturnCode as RuntimeReturnCode,
- storage::RawAliveContractInfo,
-};
-use assert_matches::assert_matches;
-use codec::Encode;
-use sp_core::Bytes;
-use sp_runtime::{
- traits::{BlakeTwo256, Hash, IdentityLookup, Convert},
- testing::{Header, H256},
- AccountId32, Perbill,
-};
-use sp_io::hashing::blake2_256;
-use frame_support::{
- assert_ok, assert_err, assert_err_ignore_postinfo, parameter_types, assert_storage_noop,
- traits::{Currency, ReservableCurrency, OnInitialize, GenesisBuild},
- weights::{Weight, PostDispatchInfo, DispatchClass, constants::WEIGHT_PER_SECOND},
- dispatch::DispatchErrorWithPostInfo,
- storage::child,
-};
-use frame_system::{self as system, EventRecord, Phase};
-use pretty_assertions::assert_eq;
-
-use crate as pallet_contracts;
-
-type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
-type Block = frame_system::mocking::MockBlock<Test>;
-
-frame_support::construct_runtime!(
- pub enum Test where
- Block = Block,
- NodeBlock = Block,
- UncheckedExtrinsic = UncheckedExtrinsic,
- {
- System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
- Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
- Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
- Randomness: pallet_randomness_collective_flip::{Pallet, Call, Storage},
- Contracts: pallet_contracts::{Pallet, Call, Config<T>, Storage, Event<T>},
- }
-);
-
-#[macro_use]
-pub mod test_utils {
- use super::{Test, Balances};
- use crate::{
- ContractInfoOf, CodeHash,
- storage::Storage,
- exec::{StorageKey, AccountIdOf},
- Pallet as Contracts,
- };
- use frame_support::traits::Currency;
-
- pub fn set_storage(addr: &AccountIdOf<Test>, key: &StorageKey, value: Option<Vec<u8>>) {
- let contract_info = <ContractInfoOf<Test>>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- Storage::<Test>::write(addr, &contract_info.trie_id, key, value).unwrap();
- }
- pub fn get_storage(addr: &AccountIdOf<Test>, key: &StorageKey) -> Option<Vec<u8>> {
- let contract_info = <ContractInfoOf<Test>>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- Storage::<Test>::read(&contract_info.trie_id, key)
- }
- pub fn place_contract(address: &AccountIdOf<Test>, code_hash: CodeHash<Test>) {
- let trie_id = Storage::<Test>::generate_trie_id(address);
- set_balance(address, Contracts::<Test>::subsistence_threshold() * 10);
- Storage::<Test>::place_contract(&address, trie_id, code_hash).unwrap();
- }
- pub fn set_balance(who: &AccountIdOf<Test>, amount: u64) {
- let imbalance = Balances::deposit_creating(who, amount);
- drop(imbalance);
- }
- pub fn get_balance(who: &AccountIdOf<Test>) -> u64 {
- Balances::free_balance(who)
- }
- macro_rules! assert_return_code {
- ( $x:expr , $y:expr $(,)? ) => {{
- use sp_std::convert::TryInto;
- assert_eq!(
- u32::from_le_bytes($x.data[..].try_into().unwrap()),
- $y as u32
- );
- }};
- }
- macro_rules! assert_refcount {
- ( $code_hash:expr , $should:expr $(,)? ) => {{
- let is = crate::CodeStorage::<Test>::get($code_hash)
- .map(|m| m.refcount())
- .unwrap_or(0);
- assert_eq!(is, $should);
- }};
- }
-}
-
-thread_local! {
- static TEST_EXTENSION: sp_std::cell::RefCell<TestExtension> = Default::default();
-}
-
-pub struct TestExtension {
- enabled: bool,
- last_seen_buffer: Vec<u8>,
- last_seen_inputs: (u32, u32, u32, u32),
-}
-
-impl TestExtension {
- fn disable() {
- TEST_EXTENSION.with(|e| e.borrow_mut().enabled = false)
- }
-
- fn last_seen_buffer() -> Vec<u8> {
- TEST_EXTENSION.with(|e| e.borrow().last_seen_buffer.clone())
- }
-
- fn last_seen_inputs() -> (u32, u32, u32, u32) {
- TEST_EXTENSION.with(|e| e.borrow().last_seen_inputs.clone())
- }
-}
-
-impl Default for TestExtension {
- fn default() -> Self {
- Self {
- enabled: true,
- last_seen_buffer: vec![],
- last_seen_inputs: (0, 0, 0, 0),
- }
- }
-}
-
-impl ChainExtension<Test> for TestExtension {
- fn call<E>(func_id: u32, env: Environment<E, InitState>) -> ExtensionResult<RetVal>
- where
- E: Ext<T = Test>,
- <E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
- {
- match func_id {
- 0 => {
- let mut env = env.buf_in_buf_out();
- let input = env.read(2)?;
- env.write(&input, false, None)?;
- TEST_EXTENSION.with(|e| e.borrow_mut().last_seen_buffer = input);
- Ok(RetVal::Converging(func_id))
- }
- 1 => {
- let env = env.only_in();
- TEST_EXTENSION.with(|e| {
- e.borrow_mut().last_seen_inputs =
- (env.val0(), env.val1(), env.val2(), env.val3())
- });
- Ok(RetVal::Converging(func_id))
- }
- 2 => {
- let mut env = env.buf_in_buf_out();
- let weight = env.read(2)?[1].into();
- env.charge_weight(weight)?;
- Ok(RetVal::Converging(func_id))
- }
- 3 => Ok(RetVal::Diverging {
- flags: ReturnFlags::REVERT,
- data: vec![42, 99],
- }),
- _ => {
- panic!(
- "Passed unknown func_id to test chain extension: {}",
- func_id
- );
- }
- }
- }
-
- fn enabled() -> bool {
- TEST_EXTENSION.with(|e| e.borrow().enabled)
- }
-}
-
-parameter_types! {
- pub const BlockHashCount: u64 = 250;
- pub BlockWeights: frame_system::limits::BlockWeights =
- frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND);
- pub static ExistentialDeposit: u64 = 0;
-}
-impl frame_system::Config for Test {
- type BaseCallFilter = ();
- type BlockWeights = BlockWeights;
- type BlockLength = ();
- type DbWeight = ();
- type Origin = Origin;
- type Index = u64;
- type BlockNumber = u64;
- type Hash = H256;
- type Call = Call;
- type Hashing = BlakeTwo256;
- type AccountId = AccountId32;
- type Lookup = IdentityLookup<Self::AccountId>;
- type Header = Header;
- type Event = Event;
- type BlockHashCount = BlockHashCount;
- type Version = ();
- type PalletInfo = PalletInfo;
- type AccountData = pallet_balances::AccountData<u64>;
- type OnNewAccount = ();
- type OnKilledAccount = ();
- type SystemWeightInfo = ();
- type SS58Prefix = ();
- type OnSetCode = ();
-}
-impl pallet_balances::Config for Test {
- type MaxLocks = ();
- type Balance = u64;
- type Event = Event;
- type DustRemoval = ();
- type ExistentialDeposit = ExistentialDeposit;
- type AccountStore = System;
- type WeightInfo = ();
-}
-parameter_types! {
- pub const MinimumPeriod: u64 = 1;
-}
-impl pallet_timestamp::Config for Test {
- type Moment = u64;
- type OnTimestampSet = ();
- type MinimumPeriod = MinimumPeriod;
- type WeightInfo = ();
-}
-parameter_types! {
- pub const SignedClaimHandicap: u64 = 2;
- pub const TombstoneDeposit: u64 = 16;
- pub const DepositPerContract: u64 = 8 * DepositPerStorageByte::get();
- pub const DepositPerStorageByte: u64 = 10_000;
- pub const DepositPerStorageItem: u64 = 10_000;
- pub RentFraction: Perbill = Perbill::from_rational(4u32, 10_000u32);
- pub const SurchargeReward: u64 = 500_000;
- pub const MaxDepth: u32 = 100;
- pub const MaxValueSize: u32 = 16_384;
- pub const DeletionQueueDepth: u32 = 1024;
- pub const DeletionWeightLimit: Weight = 500_000_000_000;
- pub const MaxCodeSize: u32 = 2 * 1024;
-}
-
-parameter_types! {
- pub const TransactionByteFee: u64 = 0;
-}
-
-impl Convert<Weight, BalanceOf<Self>> for Test {
- fn convert(w: Weight) -> BalanceOf<Self> {
- w
- }
-}
-
-impl Config for Test {
- type Time = Timestamp;
- type Randomness = Randomness;
- type Currency = Balances;
- type Event = Event;
- type RentPayment = ();
- type SignedClaimHandicap = SignedClaimHandicap;
- type TombstoneDeposit = TombstoneDeposit;
- type DepositPerContract = DepositPerContract;
- type DepositPerStorageByte = DepositPerStorageByte;
- type DepositPerStorageItem = DepositPerStorageItem;
- type RentFraction = RentFraction;
- type SurchargeReward = SurchargeReward;
- type MaxDepth = MaxDepth;
- type MaxValueSize = MaxValueSize;
- type WeightPrice = Self;
- type WeightInfo = ();
- type ChainExtension = TestExtension;
- type DeletionQueueDepth = DeletionQueueDepth;
- type DeletionWeightLimit = DeletionWeightLimit;
- type MaxCodeSize = MaxCodeSize;
-}
-
-pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]);
-pub const BOB: AccountId32 = AccountId32::new([2u8; 32]);
-pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]);
-pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]);
-
-const GAS_LIMIT: Weight = 10_000_000_000;
-
-pub struct ExtBuilder {
- existential_deposit: u64,
-}
-impl Default for ExtBuilder {
- fn default() -> Self {
- Self {
- existential_deposit: 1,
- }
- }
-}
-impl ExtBuilder {
- pub fn existential_deposit(mut self, existential_deposit: u64) -> Self {
- self.existential_deposit = existential_deposit;
- self
- }
- pub fn set_associated_consts(&self) {
- EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit);
- }
- pub fn build(self) -> sp_io::TestExternalities {
- self.set_associated_consts();
- let mut t = frame_system::GenesisConfig::default()
- .build_storage::<Test>()
- .unwrap();
- pallet_balances::GenesisConfig::<Test> { balances: vec![] }
- .assimilate_storage(&mut t)
- .unwrap();
- pallet_contracts::GenesisConfig {
- current_schedule: Schedule::<Test> {
- enable_println: true,
- ..Default::default()
- },
- }
- .assimilate_storage(&mut t)
- .unwrap();
- let mut ext = sp_io::TestExternalities::new(t);
- ext.execute_with(|| System::set_block_number(1));
- ext
- }
-}
-
-/// Load a given wasm module represented by a .wat file and returns a wasm binary contents along
-/// with it's hash.
-///
-/// The fixture files are located under the `fixtures/` directory.
-fn compile_module<T>(fixture_name: &str) -> wat::Result<(Vec<u8>, <T::Hashing as Hash>::Output)>
-where
- T: frame_system::Config,
-{
- let fixture_path = ["fixtures/", fixture_name, ".wat"].concat();
- let wasm_binary = wat::parse_file(fixture_path)?;
- let code_hash = T::Hashing::hash(&wasm_binary);
- Ok((wasm_binary, code_hash))
-}
-
-// Perform a call to a plain account.
-// The actual transfer fails because we can only call contracts.
-// Then we check that at least the base costs where charged (no runtime gas costs.)
-#[test]
-fn calling_plain_account_fails() {
- ExtBuilder::default().build().execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 100_000_000);
- let base_cost = <<Test as Config>::WeightInfo as WeightInfo>::call(0);
-
- assert_eq!(
- Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, Vec::new()),
- Err(DispatchErrorWithPostInfo {
- error: Error::<Test>::NotCallable.into(),
- post_info: PostDispatchInfo {
- actual_weight: Some(base_cost),
- pays_fee: Default::default(),
- },
- })
- );
- });
-}
-
-#[test]
-fn account_removal_does_not_remove_storage() {
- use self::test_utils::{set_storage, get_storage};
-
- ExtBuilder::default()
- .existential_deposit(100)
- .build()
- .execute_with(|| {
- let trie_id1 = Storage::<Test>::generate_trie_id(&ALICE);
- let trie_id2 = Storage::<Test>::generate_trie_id(&BOB);
- let key1 = &[1; 32];
- let key2 = &[2; 32];
-
- // Set up two accounts with free balance above the existential threshold.
- {
- let alice_contract_info = ContractInfo::Alive(RawAliveContractInfo {
- trie_id: trie_id1.clone(),
- storage_size: 0,
- pair_count: 0,
- deduct_block: System::block_number(),
- code_hash: H256::repeat_byte(1),
- rent_allowance: 40,
- rent_payed: 0,
- last_write: None,
- _reserved: None,
- });
- let _ = Balances::deposit_creating(&ALICE, 110);
- ContractInfoOf::<Test>::insert(ALICE, &alice_contract_info);
- set_storage(&ALICE, &key1, Some(b"1".to_vec()));
- set_storage(&ALICE, &key2, Some(b"2".to_vec()));
-
- let bob_contract_info = ContractInfo::Alive(RawAliveContractInfo {
- trie_id: trie_id2.clone(),
- storage_size: 0,
- pair_count: 0,
- deduct_block: System::block_number(),
- code_hash: H256::repeat_byte(2),
- rent_allowance: 40,
- rent_payed: 0,
- last_write: None,
- _reserved: None,
- });
- let _ = Balances::deposit_creating(&BOB, 110);
- ContractInfoOf::<Test>::insert(BOB, &bob_contract_info);
- set_storage(&BOB, &key1, Some(b"3".to_vec()));
- set_storage(&BOB, &key2, Some(b"4".to_vec()));
- }
-
- // Transfer funds from ALICE account of such amount that after this transfer
- // the balance of the ALICE account 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 `seal_terminate`. There is no external event that can remove
- // the account appart from that.
- assert_ok!(Balances::transfer(Origin::signed(ALICE), BOB, 20));
-
- // Verify that no entries are removed.
- {
- assert_eq!(get_storage(&ALICE, key1), Some(b"1".to_vec()));
- assert_eq!(get_storage(&ALICE, key2), Some(b"2".to_vec()));
-
- assert_eq!(get_storage(&BOB, key1), Some(b"3".to_vec()));
- assert_eq!(get_storage(&BOB, key2), Some(b"4".to_vec()));
- }
- });
-}
-
-#[test]
-fn instantiate_and_call_and_deposit_event() {
- let (wasm, code_hash) = compile_module::<Test>("return_from_start_fn").unwrap();
-
- ExtBuilder::default()
- .existential_deposit(100)
- .build()
- .execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- let subsistence = Pallet::<Test>::subsistence_threshold();
-
- // Check at the end to get hash on error easily
- let creation = Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- );
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
-
- assert_eq!(
- System::events(),
- vec![
- EventRecord {
- phase: Phase::Initialization,
- event: Event::frame_system(frame_system::Event::NewAccount(ALICE.clone())),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(pallet_balances::Event::Endowed(
- ALICE, 1_000_000
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::frame_system(frame_system::Event::NewAccount(addr.clone())),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(pallet_balances::Event::Endowed(
- addr.clone(),
- subsistence * 100
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(pallet_balances::Event::Transfer(
- ALICE,
- addr.clone(),
- subsistence * 100
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::CodeStored(code_hash.into())),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::ContractEmitted(
- addr.clone(),
- vec![1, 2, 3, 4]
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::Instantiated(
- ALICE,
- addr.clone()
- )),
- topics: vec![],
- },
- ]
- );
-
- assert_ok!(creation);
- assert!(ContractInfoOf::<Test>::contains_key(&addr));
- });
-}
-
-#[test]
-fn deposit_event_max_value_limit() {
- let (wasm, code_hash) = compile_module::<Test>("event_size").unwrap();
-
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 30_000,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
-
- // Call contract with allowed storage value.
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT * 2, // we are copying a huge buffer,
- <Test as Config>::MaxValueSize::get().encode(),
- ));
-
- // Call contract with too large a storage value.
- assert_err_ignore_postinfo!(
- Contracts::call(
- Origin::signed(ALICE),
- addr,
- 0,
- GAS_LIMIT,
- (<Test as Config>::MaxValueSize::get() + 1).encode(),
- ),
- Error::<Test>::ValueTooLarge,
- );
- });
-}
-
-#[test]
-fn run_out_of_gas() {
- let (wasm, code_hash) = compile_module::<Test>("run_out_of_gas").unwrap();
- let subsistence = Pallet::<Test>::subsistence_threshold();
-
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 100 * subsistence,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
-
- // Call the contract with a fixed gas limit. It must run out of gas because it just
- // loops forever.
- assert_err_ignore_postinfo!(
- Contracts::call(
- Origin::signed(ALICE),
- addr, // newly created account
- 0,
- 67_500_000,
- vec![],
- ),
- Error::<Test>::OutOfGas,
- );
- });
-}
-
-/// Input data for each call in set_rent code
-mod call {
- use super::{AccountIdOf, Test};
- pub fn set_storage_4_byte() -> Vec<u8> {
- 0u32.to_le_bytes().to_vec()
- }
- pub fn remove_storage_4_byte() -> Vec<u8> {
- 1u32.to_le_bytes().to_vec()
- }
- #[allow(dead_code)]
- pub fn transfer(to: &AccountIdOf<Test>) -> Vec<u8> {
- 2u32.to_le_bytes()
- .iter()
- .chain(AsRef::<[u8]>::as_ref(to))
- .cloned()
- .collect()
- }
- pub fn null() -> Vec<u8> {
- 3u32.to_le_bytes().to_vec()
- }
-}
-
-#[test]
-fn storage_size() {
- let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();
-
- // Storage size
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 30_000,
- GAS_LIMIT,
- wasm,
- // rent_allowance
- <Test as pallet_balances::Config>::Balance::from(10_000u32).encode(),
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
- let bob_contract = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- assert_eq!(bob_contract.storage_size, 4);
- assert_eq!(bob_contract.pair_count, 1,);
-
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- call::set_storage_4_byte()
- ));
- let bob_contract = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- assert_eq!(bob_contract.storage_size, 4 + 4);
- assert_eq!(bob_contract.pair_count, 2,);
-
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- call::remove_storage_4_byte()
- ));
- let bob_contract = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- assert_eq!(bob_contract.storage_size, 4);
- assert_eq!(bob_contract.pair_count, 1,);
- });
-}
-
-#[test]
-fn empty_kv_pairs() {
- let (wasm, code_hash) = compile_module::<Test>("set_empty_storage").unwrap();
-
- ExtBuilder::default().build().execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 30_000,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
- let bob_contract = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
-
- assert_eq!(bob_contract.storage_size, 0,);
- assert_eq!(bob_contract.pair_count, 1,);
- });
-}
-
-fn initialize_block(number: u64) {
- System::initialize(
- &number,
- &[0u8; 32].into(),
- &Default::default(),
- Default::default(),
- );
-}
-
-#[test]
-fn deduct_blocks() {
- let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();
- let endowment: BalanceOf<Test> = 100_000;
- let allowance: BalanceOf<Test> = 70_000;
-
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- endowment,
- GAS_LIMIT,
- wasm,
- allowance.encode(),
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
- let contract = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- let code_len: BalanceOf<Test> =
- PrefabWasmModule::<Test>::from_storage_noinstr(contract.code_hash)
- .unwrap()
- .occupied_storage()
- .into();
-
- // The instantiation deducted the rent for one block immediately
- let rent0 = <Test as Config>::RentFraction::get()
- // (base_deposit(8) + bytes in storage(4) + size of code) * byte_price
- // + 1 storage item (10_000) - free_balance
- .mul_ceil((8 + 4 + code_len) * 10_000 + 10_000 - endowment)
- // blocks to rent
- * 1;
- assert!(rent0 > 0);
- assert_eq!(contract.rent_allowance, allowance - rent0);
- assert_eq!(contract.deduct_block, 1);
- assert_eq!(Balances::free_balance(&addr), endowment - rent0);
-
- // Advance 4 blocks
- initialize_block(5);
-
- // Trigger rent through call
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- call::null()
- ));
-
- // Check result
- let rent = <Test as Config>::RentFraction::get()
- .mul_ceil((8 + 4 + code_len) * 10_000 + 10_000 - (endowment - rent0))
- * 4;
- let contract = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- assert_eq!(contract.rent_allowance, allowance - rent0 - rent);
- assert_eq!(contract.deduct_block, 5);
- assert_eq!(Balances::free_balance(&addr), endowment - rent0 - rent);
-
- // Advance 2 blocks more
- initialize_block(7);
-
- // Trigger rent through call
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- call::null()
- ));
-
- // Check result
- let rent_2 = <Test as Config>::RentFraction::get()
- .mul_ceil((8 + 4 + code_len) * 10_000 + 10_000 - (endowment - rent0 - rent))
- * 2;
- let contract = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- assert_eq!(contract.rent_allowance, allowance - rent0 - rent - rent_2);
- assert_eq!(contract.deduct_block, 7);
- assert_eq!(
- Balances::free_balance(&addr),
- endowment - rent0 - rent - rent_2
- );
-
- // Second call on same block should have no effect on rent
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- call::null()
- ));
- let contract = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- assert_eq!(contract.rent_allowance, allowance - rent0 - rent - rent_2);
- assert_eq!(contract.deduct_block, 7);
- assert_eq!(
- Balances::free_balance(&addr),
- endowment - rent0 - rent - rent_2
- )
- });
-}
-
-#[test]
-fn inherent_claim_surcharge_contract_removals() {
- removals(|addr| Contracts::claim_surcharge(Origin::none(), addr, Some(ALICE)).is_ok());
-}
-
-#[test]
-fn signed_claim_surcharge_contract_removals() {
- removals(|addr| Contracts::claim_surcharge(Origin::signed(ALICE), addr, None).is_ok());
-}
-
-#[test]
-fn claim_surcharge_malus() {
- // Test surcharge malus for inherent
- claim_surcharge(
- 8,
- |addr| Contracts::claim_surcharge(Origin::none(), addr, Some(ALICE)).is_ok(),
- true,
- );
- claim_surcharge(
- 7,
- |addr| Contracts::claim_surcharge(Origin::none(), addr, Some(ALICE)).is_ok(),
- true,
- );
- claim_surcharge(
- 6,
- |addr| Contracts::claim_surcharge(Origin::none(), addr, Some(ALICE)).is_ok(),
- true,
- );
- claim_surcharge(
- 5,
- |addr| Contracts::claim_surcharge(Origin::none(), addr, Some(ALICE)).is_ok(),
- false,
- );
-
- // Test surcharge malus for signed
- claim_surcharge(
- 8,
- |addr| Contracts::claim_surcharge(Origin::signed(ALICE), addr, None).is_ok(),
- true,
- );
- claim_surcharge(
- 7,
- |addr| Contracts::claim_surcharge(Origin::signed(ALICE), addr, None).is_ok(),
- false,
- );
- claim_surcharge(
- 6,
- |addr| Contracts::claim_surcharge(Origin::signed(ALICE), addr, None).is_ok(),
- false,
- );
- claim_surcharge(
- 5,
- |addr| Contracts::claim_surcharge(Origin::signed(ALICE), addr, None).is_ok(),
- false,
- );
-}
-
-/// Claim surcharge with the given trigger_call at the given blocks.
-/// If `removes` is true then assert that the contract is a tombstone.
-fn claim_surcharge(blocks: u64, trigger_call: impl Fn(AccountIdOf<Test>) -> bool, removes: bool) {
- let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();
-
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 100_000,
- GAS_LIMIT,
- wasm,
- <Test as pallet_balances::Config>::Balance::from(30_000u32).encode(), // rent allowance
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
-
- // Advance blocks
- initialize_block(blocks);
-
- // Trigger rent through call
- assert_eq!(trigger_call(addr.clone()), removes);
-
- if removes {
- assert!(ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_tombstone()
- .is_some());
- } else {
- assert!(ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .is_some());
- }
- });
-}
-
-/// Test for all kind of removals for the given trigger:
-/// * if balance is reached and balance > subsistence threshold
-/// * if allowance is exceeded
-/// * if balance is reached and balance < subsistence threshold
-/// * this case cannot be triggered by a contract: we check whether a tombstone is left
-fn removals(trigger_call: impl Fn(AccountIdOf<Test>) -> bool) {
- let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();
-
- // Balance reached and superior to subsistence threshold
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 70_000,
- GAS_LIMIT,
- wasm.clone(),
- <Test as pallet_balances::Config>::Balance::from(100_000u32).encode(), // rent allowance
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
- let allowance = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap()
- .rent_allowance;
- let balance = Balances::free_balance(&addr);
-
- let subsistence_threshold = Pallet::<Test>::subsistence_threshold();
-
- // Trigger rent must have no effect
- assert!(!trigger_call(addr.clone()));
- assert_eq!(
- ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap()
- .rent_allowance,
- allowance,
- );
- assert_eq!(Balances::free_balance(&addr), balance);
-
- // Advance blocks
- initialize_block(27);
-
- // Trigger rent through call (should remove the contract)
- assert!(trigger_call(addr.clone()));
- assert!(ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_tombstone()
- .is_some());
- assert_eq!(Balances::free_balance(&addr), subsistence_threshold);
-
- // Advance blocks
- initialize_block(30);
-
- // Trigger rent must have no effect
- assert!(!trigger_call(addr.clone()));
- assert!(ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_tombstone()
- .is_some());
- assert_eq!(Balances::free_balance(&addr), subsistence_threshold);
- });
-
- // Allowance exceeded
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 100_000,
- GAS_LIMIT,
- wasm.clone(),
- <Test as pallet_balances::Config>::Balance::from(70_000u32).encode(), // rent allowance
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
- let allowance = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap()
- .rent_allowance;
- let balance = Balances::free_balance(&addr);
-
- // Trigger rent must have no effect
- assert!(!trigger_call(addr.clone()));
- assert_eq!(
- ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap()
- .rent_allowance,
- allowance,
- );
- assert_eq!(Balances::free_balance(&addr), balance);
-
- // Advance blocks
- initialize_block(27);
-
- // Trigger rent through call
- assert!(trigger_call(addr.clone()));
- assert!(ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_tombstone()
- .is_some());
- // Balance should be initial balance - initial rent_allowance
- assert_eq!(Balances::free_balance(&addr), 30_000);
-
- // Advance blocks
- initialize_block(20);
-
- // Trigger rent must have no effect
- assert!(!trigger_call(addr.clone()));
- assert!(ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_tombstone()
- .is_some());
- assert_eq!(Balances::free_balance(&addr), 30_000);
- });
-
- // Balance reached and inferior to subsistence threshold
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let subsistence_threshold = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, subsistence_threshold * 1000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence_threshold * 100,
- GAS_LIMIT,
- wasm,
- (subsistence_threshold * 100).encode(), // rent allowance
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
- let allowance = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap()
- .rent_allowance;
- let balance = Balances::free_balance(&addr);
-
- // Trigger rent must have no effect
- assert!(!trigger_call(addr.clone()));
- assert_eq!(
- ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap()
- .rent_allowance,
- allowance,
- );
- assert_eq!(Balances::free_balance(&addr), balance,);
-
- // Make contract have exactly the subsistence threshold
- Balances::make_free_balance_be(&addr, subsistence_threshold);
- assert_eq!(Balances::free_balance(&addr), subsistence_threshold);
-
- // Advance blocks (should remove as balance is exactly subsistence)
- initialize_block(10);
-
- // Trigger rent through call
- assert!(trigger_call(addr.clone()));
- assert_matches!(
- ContractInfoOf::<Test>::get(&addr),
- Some(ContractInfo::Tombstone(_))
- );
- assert_eq!(Balances::free_balance(&addr), subsistence_threshold);
-
- // Advance blocks
- initialize_block(20);
-
- // Trigger rent must have no effect
- assert!(!trigger_call(addr.clone()));
- assert_matches!(
- ContractInfoOf::<Test>::get(&addr),
- Some(ContractInfo::Tombstone(_))
- );
- assert_eq!(Balances::free_balance(&addr), subsistence_threshold);
- });
-}
-
-#[test]
-fn call_removed_contract() {
- let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();
-
- // Balance reached and superior to subsistence threshold
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 30_000,
- GAS_LIMIT,
- wasm,
- // rent allowance
- <Test as pallet_balances::Config>::Balance::from(10_000u32).encode(),
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
-
- // Calling contract should succeed.
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- call::null()
- ));
-
- // Advance blocks
- initialize_block(27);
-
- // Calling contract should deny access because rent cannot be paid.
- assert_err_ignore_postinfo!(
- Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- call::null()
- ),
- Error::<Test>::NotCallable
- );
- // No event is generated because the contract is not actually removed.
- assert_eq!(System::events(), vec![]);
-
- // Subsequent contract calls should also fail.
- assert_err_ignore_postinfo!(
- Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- call::null()
- ),
- Error::<Test>::NotCallable
- );
-
- // A snitch can now remove the contract
- assert_ok!(Contracts::claim_surcharge(
- Origin::none(),
- addr.clone(),
- Some(ALICE)
- ));
- assert!(ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_tombstone()
- .is_some());
- })
-}
-
-#[test]
-fn default_rent_allowance_on_instantiate() {
- let (wasm, code_hash) = compile_module::<Test>("check_default_rent_allowance").unwrap();
-
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 30_000,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
- let contract = ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- let code_len: BalanceOf<Test> =
- PrefabWasmModule::<Test>::from_storage_noinstr(contract.code_hash)
- .unwrap()
- .occupied_storage()
- .into();
-
- // The instantiation deducted the rent for one block immediately
- let first_rent = <Test as Config>::RentFraction::get()
- // (base_deposit(8) + code_len) * byte_price - free_balance
- .mul_ceil((8 + code_len) * 10_000 - 30_000)
- // blocks to rent
- * 1;
- assert_eq!(
- contract.rent_allowance,
- <BalanceOf<Test>>::max_value() - first_rent
- );
-
- // Advance blocks
- initialize_block(5);
-
- // Trigger rent through call
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- call::null()
- ));
-
- // Check contract is still alive
- let contract = ContractInfoOf::<Test>::get(&addr).unwrap().get_alive();
- assert!(contract.is_some())
- });
-}
-
-#[test]
-fn restorations_dirty_storage_and_different_storage() {
- restoration(true, true, false);
-}
-
-#[test]
-fn restorations_dirty_storage() {
- restoration(false, true, false);
-}
-
-#[test]
-fn restoration_different_storage() {
- restoration(true, false, false);
-}
-
-#[test]
-fn restoration_code_evicted() {
- restoration(false, false, true);
-}
-
-#[test]
-fn restoration_success() {
- restoration(false, false, false);
-}
-
-fn restoration(
- test_different_storage: bool,
- test_restore_to_with_dirty_storage: bool,
- test_code_evicted: bool,
-) {
- let (set_rent_wasm, set_rent_code_hash) = compile_module::<Test>("set_rent").unwrap();
- let (restoration_wasm, restoration_code_hash) = compile_module::<Test>("restoration").unwrap();
- let allowance: <Test as pallet_balances::Config>::Balance = 10_000;
-
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
-
- // Create an account with address `BOB` with code `CODE_SET_RENT`.
- // The input parameter sets the rent allowance to 0.
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 30_000,
- GAS_LIMIT,
- set_rent_wasm.clone(),
- allowance.encode(),
- vec![],
- ));
- let addr_bob = Contracts::contract_address(&ALICE, &set_rent_code_hash, &[]);
-
- let mut events = vec![
- EventRecord {
- phase: Phase::Initialization,
- event: Event::frame_system(frame_system::Event::NewAccount(ALICE)),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(pallet_balances::Event::Endowed(
- ALICE, 1_000_000,
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::frame_system(frame_system::Event::NewAccount(addr_bob.clone())),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(pallet_balances::Event::Endowed(
- addr_bob.clone(),
- 30_000,
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(pallet_balances::Event::Transfer(
- ALICE,
- addr_bob.clone(),
- 30_000,
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::CodeStored(
- set_rent_code_hash.into(),
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::Instantiated(
- ALICE,
- addr_bob.clone(),
- )),
- topics: vec![],
- },
- ];
-
- // Create another contract from the same code in order to increment the codes
- // refcounter so that it stays on chain.
- if !test_code_evicted {
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 20_000,
- GAS_LIMIT,
- set_rent_wasm,
- allowance.encode(),
- vec![1],
- ));
- assert_refcount!(set_rent_code_hash, 2);
- let addr_dummy = Contracts::contract_address(&ALICE, &set_rent_code_hash, &[1]);
- events.extend(
- [
- EventRecord {
- phase: Phase::Initialization,
- event: Event::frame_system(frame_system::Event::NewAccount(
- addr_dummy.clone(),
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(pallet_balances::Event::Endowed(
- addr_dummy.clone(),
- 20_000,
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(pallet_balances::Event::Transfer(
- ALICE,
- addr_dummy.clone(),
- 20_000,
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::Instantiated(
- ALICE,
- addr_dummy.clone(),
- )),
- topics: vec![],
- },
- ]
- .iter()
- .cloned(),
- );
- }
-
- assert_eq!(System::events(), events);
-
- // Check if `BOB` was created successfully and that the rent allowance is below what
- // we specified as the first rent was already collected.
- let bob_contract = ContractInfoOf::<Test>::get(&addr_bob)
- .unwrap()
- .get_alive()
- .unwrap();
- assert!(bob_contract.rent_allowance < allowance);
-
- if test_different_storage {
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr_bob.clone(),
- 0,
- GAS_LIMIT,
- call::set_storage_4_byte()
- ));
- }
-
- // Advance blocks in order to make the contract run out of money for rent.
- initialize_block(27);
-
- // Call `BOB`, which makes it pay rent. Since the rent allowance is set to 20_000
- // we expect that it is no longer callable but keeps existing until someone
- // calls `claim_surcharge`.
- assert_err_ignore_postinfo!(
- Contracts::call(
- Origin::signed(ALICE),
- addr_bob.clone(),
- 0,
- GAS_LIMIT,
- call::null()
- ),
- Error::<Test>::NotCallable
- );
- assert!(System::events().is_empty());
- assert!(ContractInfoOf::<Test>::get(&addr_bob)
- .unwrap()
- .get_alive()
- .is_some());
- assert_ok!(Contracts::claim_surcharge(
- Origin::none(),
- addr_bob.clone(),
- Some(ALICE)
- ));
- assert!(ContractInfoOf::<Test>::get(&addr_bob)
- .unwrap()
- .get_tombstone()
- .is_some());
- if test_code_evicted {
- assert_refcount!(set_rent_code_hash, 0);
- } else {
- assert_refcount!(set_rent_code_hash, 1);
- }
-
- // Create another account with the address `DJANGO` with `CODE_RESTORATION`.
- //
- // Note that we can't use `ALICE` for creating `DJANGO` so we create yet another
- // account `CHARLIE` and create `DJANGO` with it.
- let _ = Balances::deposit_creating(&CHARLIE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(CHARLIE),
- 30_000,
- GAS_LIMIT,
- restoration_wasm,
- vec![],
- vec![],
- ));
- let addr_django = Contracts::contract_address(&CHARLIE, &restoration_code_hash, &[]);
-
- // Before performing a call to `DJANGO` save its original trie id.
- let django_trie_id = ContractInfoOf::<Test>::get(&addr_django)
- .unwrap()
- .get_alive()
- .unwrap()
- .trie_id;
-
- // The trie is regarded as 'dirty' when it was written to in the current block.
- if !test_restore_to_with_dirty_storage {
- // Advance 1 block.
- initialize_block(28);
- }
-
- // Perform a call to `DJANGO`. This should either perform restoration successfully or
- // fail depending on the test parameters.
- let perform_the_restoration = || {
- Contracts::call(
- Origin::signed(ALICE),
- addr_django.clone(),
- 0,
- GAS_LIMIT,
- set_rent_code_hash
- .as_ref()
- .iter()
- .chain(AsRef::<[u8]>::as_ref(&addr_bob))
- .cloned()
- .collect(),
- )
- };
-
- // The key that is used in the restorer contract but is not in the target contract.
- // Is supplied as delta to the restoration. We need it to check whether the key
- // is properly removed on success but still there on failure.
- let delta_key = {
- let mut key = [0u8; 32];
- key[0] = 1;
- key
- };
-
- if test_different_storage || test_restore_to_with_dirty_storage || test_code_evicted {
- // Parametrization of the test imply restoration failure. Check that `DJANGO` aka
- // restoration contract is still in place and also that `BOB` doesn't exist.
- let result = perform_the_restoration();
- assert!(ContractInfoOf::<Test>::get(&addr_bob)
- .unwrap()
- .get_tombstone()
- .is_some());
- let django_contract = ContractInfoOf::<Test>::get(&addr_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());
- assert_eq!(
- Storage::<Test>::read(&django_trie_id, &delta_key),
- Some(vec![40, 0, 0, 0]),
- );
- match (
- test_different_storage,
- test_restore_to_with_dirty_storage,
- test_code_evicted,
- ) {
- (true, false, false) => {
- assert_err_ignore_postinfo!(result, Error::<Test>::InvalidTombstone,);
- assert_eq!(System::events(), vec![]);
- }
- (_, true, false) => {
- assert_err_ignore_postinfo!(result, Error::<Test>::InvalidContractOrigin,);
- assert_eq!(
- System::events(),
- vec![
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::Evicted(addr_bob)),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::frame_system(frame_system::Event::NewAccount(
- CHARLIE
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(pallet_balances::Event::Endowed(
- CHARLIE, 1_000_000
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::frame_system(frame_system::Event::NewAccount(
- addr_django.clone()
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(pallet_balances::Event::Endowed(
- addr_django.clone(),
- 30_000
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(
- pallet_balances::Event::Transfer(
- CHARLIE,
- addr_django.clone(),
- 30_000
- )
- ),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::CodeStored(
- restoration_code_hash
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::Instantiated(
- CHARLIE,
- addr_django.clone()
- )),
- topics: vec![],
- },
- ]
- );
- }
- (false, false, true) => {
- assert_err_ignore_postinfo!(result, Error::<Test>::CodeNotFound,);
- assert_refcount!(set_rent_code_hash, 0);
- assert_eq!(System::events(), vec![]);
- }
- _ => unreachable!(),
- }
- } else {
- assert_ok!(perform_the_restoration());
- assert_refcount!(set_rent_code_hash, 2);
-
- // Here we expect that the restoration is succeeded. Check that the restoration
- // contract `DJANGO` ceased to exist and that `BOB` returned back.
- let bob_contract = ContractInfoOf::<Test>::get(&addr_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::<Test>::get(&addr_django).is_none());
- assert_matches!(Storage::<Test>::read(&django_trie_id, &delta_key), None);
- assert_eq!(
- System::events(),
- vec![
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::CodeRemoved(
- restoration_code_hash
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::frame_system(system::Event::KilledAccount(
- addr_django.clone()
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::Restored(
- addr_django,
- addr_bob,
- bob_contract.code_hash,
- 50
- )),
- topics: vec![],
- },
- ]
- );
- }
- });
-}
-
-#[test]
-fn storage_max_value_limit() {
- let (wasm, code_hash) = compile_module::<Test>("storage_size").unwrap();
-
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 30_000,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
- ContractInfoOf::<Test>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
-
- // Call contract with allowed storage value.
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT * 2, // we are copying a huge buffer
- <Test as Config>::MaxValueSize::get().encode(),
- ));
-
- // Call contract with too large a storage value.
- assert_err_ignore_postinfo!(
- Contracts::call(
- Origin::signed(ALICE),
- addr,
- 0,
- GAS_LIMIT,
- (<Test as Config>::MaxValueSize::get() + 1).encode(),
- ),
- Error::<Test>::ValueTooLarge,
- );
- });
-}
-
-#[test]
-fn deploy_and_call_other_contract() {
- let (callee_wasm, callee_code_hash) = compile_module::<Test>("return_with_data").unwrap();
- let (caller_wasm, caller_code_hash) = compile_module::<Test>("caller_contract").unwrap();
-
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 100_000,
- GAS_LIMIT,
- caller_wasm,
- vec![],
- vec![],
- ));
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 100_000,
- GAS_LIMIT,
- callee_wasm,
- 0u32.to_le_bytes().encode(),
- vec![42],
- ));
-
- // Call BOB contract, which attempts to instantiate and call the callee contract and
- // makes various assertions on the results from those calls.
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- Contracts::contract_address(&ALICE, &caller_code_hash, &[]),
- 0,
- GAS_LIMIT,
- callee_code_hash.as_ref().to_vec(),
- ));
- });
-}
-
-#[test]
-fn cannot_self_destruct_through_draning() {
- let (wasm, code_hash) = compile_module::<Test>("drain").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
-
- // Instantiate the BOB contract.
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 100_000,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
-
- // Check that the BOB contract has been instantiated.
- assert_matches!(
- ContractInfoOf::<Test>::get(&addr),
- Some(ContractInfo::Alive(_))
- );
-
- // Call BOB which makes it send all funds to the zero address
- // The contract code asserts that the correct error value is returned.
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr,
- 0,
- GAS_LIMIT,
- vec![],
- ));
- });
-}
-
-#[test]
-fn cannot_self_destruct_while_live() {
- let (wasm, code_hash) = compile_module::<Test>("self_destruct").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
-
- // Instantiate the BOB contract.
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 100_000,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
-
- // Check that the BOB contract has been instantiated.
- assert_matches!(
- ContractInfoOf::<Test>::get(&addr),
- Some(ContractInfo::Alive(_))
- );
-
- // 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), addr.clone(), 0, GAS_LIMIT, vec![0],),
- Error::<Test>::ContractTrapped,
- );
-
- // Check that BOB is still alive.
- assert_matches!(
- ContractInfoOf::<Test>::get(&addr),
- Some(ContractInfo::Alive(_))
- );
- });
-}
-
-#[test]
-fn self_destruct_works() {
- let (wasm, code_hash) = compile_module::<Test>("self_destruct").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- let _ = Balances::deposit_creating(&DJANGO, 1_000_000);
-
- // Instantiate the BOB contract.
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 100_000,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
-
- // Check that the BOB contract has been instantiated.
- assert_matches!(
- ContractInfoOf::<Test>::get(&addr),
- Some(ContractInfo::Alive(_))
- );
-
- // Drop all previous events
- initialize_block(2);
-
- // Call BOB without input data which triggers termination.
- assert_matches!(
- Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![],),
- Ok(_)
- );
-
- pretty_assertions::assert_eq!(
- System::events(),
- vec![
- EventRecord {
- phase: Phase::Initialization,
- event: Event::frame_system(frame_system::Event::KilledAccount(
- addr.clone()
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_balances(pallet_balances::Event::Transfer(
- addr.clone(),
- DJANGO,
- 93_086
- )),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::CodeRemoved(code_hash)),
- topics: vec![],
- },
- EventRecord {
- phase: Phase::Initialization,
- event: Event::pallet_contracts(crate::Event::Terminated(
- addr.clone(),
- DJANGO
- )),
- topics: vec![],
- },
- ]
- );
-
- // Check that account is gone
- assert!(ContractInfoOf::<Test>::get(&addr).is_none());
-
- // check that the beneficiary (django) got remaining balance
- // some rent was deducted before termination
- assert_eq!(Balances::free_balance(DJANGO), 1_093_086);
- });
-}
-
-// This tests that one contract cannot prevent another from self-destructing by sending it
-// additional funds after it has been drained.
-#[test]
-fn destroy_contract_and_transfer_funds() {
- let (callee_wasm, callee_code_hash) = compile_module::<Test>("self_destruct").unwrap();
- let (caller_wasm, caller_code_hash) = compile_module::<Test>("destroy_and_transfer").unwrap();
-
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 200_000,
- GAS_LIMIT,
- callee_wasm,
- vec![],
- vec![42]
- ));
-
- // This deploys the BOB contract, which in turn deploys the CHARLIE contract during
- // construction.
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 200_000,
- GAS_LIMIT,
- caller_wasm,
- callee_code_hash.as_ref().to_vec(),
- vec![],
- ));
- let addr_bob = Contracts::contract_address(&ALICE, &caller_code_hash, &[]);
- let addr_charlie =
- Contracts::contract_address(&addr_bob, &callee_code_hash, &[0x47, 0x11]);
-
- // Check that the CHARLIE contract has been instantiated.
- assert_matches!(
- ContractInfoOf::<Test>::get(&addr_charlie),
- Some(ContractInfo::Alive(_))
- );
-
- // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct.
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr_bob,
- 0,
- GAS_LIMIT,
- addr_charlie.encode(),
- ));
-
- // Check that CHARLIE has moved on to the great beyond (ie. died).
- assert!(ContractInfoOf::<Test>::get(&addr_charlie).is_none());
- });
-}
-
-#[test]
-fn cannot_self_destruct_in_constructor() {
- let (wasm, _) = compile_module::<Test>("self_destructing_constructor").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
-
- // Fail to instantiate the BOB because the contructor calls seal_terminate.
- assert_err_ignore_postinfo!(
- Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 100_000,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- ),
- Error::<Test>::NotCallable,
- );
- });
-}
-
-#[test]
-fn crypto_hashes() {
- let (wasm, code_hash) = compile_module::<Test>("crypto_hashes").unwrap();
-
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
-
- // Instantiate the CRYPTO_HASHES contract.
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 100_000,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
- // Perform the call.
- let input = b"_DEAD_BEEF";
- use sp_io::hashing::*;
- // Wraps a hash function into a more dynamic form usable for testing.
- macro_rules! dyn_hash_fn {
- ($name:ident) => {
- Box::new(|input| $name(input).as_ref().to_vec().into_boxed_slice())
- };
- }
- // All hash functions and their associated output byte lengths.
- let test_cases: &[(Box<dyn Fn(&[u8]) -> Box<[u8]>>, usize)] = &[
- (dyn_hash_fn!(sha2_256), 32),
- (dyn_hash_fn!(keccak_256), 32),
- (dyn_hash_fn!(blake2_256), 32),
- (dyn_hash_fn!(blake2_128), 16),
- ];
- // Test the given hash functions for the input: "_DEAD_BEEF"
- for (n, (hash_fn, expected_size)) in test_cases.iter().enumerate() {
- // We offset data in the contract tables by 1.
- let mut params = vec![(n + 1) as u8];
- params.extend_from_slice(input);
- let result = <Pallet<Test>>::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, params)
- .result
- .unwrap();
- assert!(result.is_success());
- let expected = hash_fn(input.as_ref());
- assert_eq!(&result.data[..*expected_size], &*expected);
- }
- })
-}
-
-#[test]
-fn transfer_return_code() {
- let (wasm, code_hash) = compile_module::<Test>("transfer_return_code").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- wasm,
- vec![],
- vec![],
- ),);
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
-
- // Contract has only the minimal balance so any transfer will return BelowSubsistence.
- Balances::make_free_balance_be(&addr, subsistence);
- let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![])
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold);
-
- // Contract has enough total balance in order to not go below the subsistence
- // threshold when transfering 100 balance but this balance is reserved so
- // the transfer still fails but with another return code.
- Balances::make_free_balance_be(&addr, subsistence + 100);
- Balances::reserve(&addr, subsistence + 100).unwrap();
- let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, vec![])
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::TransferFailed);
- });
-}
-
-#[test]
-fn call_return_code() {
- let (caller_code, caller_hash) = compile_module::<Test>("call_return_code").unwrap();
- let (callee_code, callee_hash) = compile_module::<Test>("ok_trap_revert").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);
- let _ = Balances::deposit_creating(&CHARLIE, 1000 * subsistence);
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- caller_code,
- vec![0],
- vec![],
- ),);
- let addr_bob = Contracts::contract_address(&ALICE, &caller_hash, &[]);
- Balances::make_free_balance_be(&addr_bob, subsistence);
-
- // Contract calls into Django which is no valid contract
- let result = Contracts::bare_call(
- ALICE,
- addr_bob.clone(),
- 0,
- GAS_LIMIT,
- AsRef::<[u8]>::as_ref(&DJANGO).to_vec(),
- )
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::NotCallable);
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(CHARLIE),
- subsistence * 100,
- GAS_LIMIT,
- callee_code,
- vec![0],
- vec![],
- ),);
- let addr_django = Contracts::contract_address(&CHARLIE, &callee_hash, &[]);
- Balances::make_free_balance_be(&addr_django, subsistence);
-
- // Contract has only the minimal balance so any transfer will return BelowSubsistence.
- let result = Contracts::bare_call(
- ALICE,
- addr_bob.clone(),
- 0,
- GAS_LIMIT,
- AsRef::<[u8]>::as_ref(&addr_django)
- .iter()
- .chain(&0u32.to_le_bytes())
- .cloned()
- .collect(),
- )
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold);
-
- // Contract has enough total balance in order to not go below the subsistence
- // threshold when transfering 100 balance but this balance is reserved so
- // the transfer still fails but with another return code.
- Balances::make_free_balance_be(&addr_bob, subsistence + 100);
- Balances::reserve(&addr_bob, subsistence + 100).unwrap();
- let result = Contracts::bare_call(
- ALICE,
- addr_bob.clone(),
- 0,
- GAS_LIMIT,
- AsRef::<[u8]>::as_ref(&addr_django)
- .iter()
- .chain(&0u32.to_le_bytes())
- .cloned()
- .collect(),
- )
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::TransferFailed);
-
- // Contract has enough balance but callee reverts because "1" is passed.
- Balances::make_free_balance_be(&addr_bob, subsistence + 1000);
- let result = Contracts::bare_call(
- ALICE,
- addr_bob.clone(),
- 0,
- GAS_LIMIT,
- AsRef::<[u8]>::as_ref(&addr_django)
- .iter()
- .chain(&1u32.to_le_bytes())
- .cloned()
- .collect(),
- )
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::CalleeReverted);
-
- // Contract has enough balance but callee traps because "2" is passed.
- let result = Contracts::bare_call(
- ALICE,
- addr_bob,
- 0,
- GAS_LIMIT,
- AsRef::<[u8]>::as_ref(&addr_django)
- .iter()
- .chain(&2u32.to_le_bytes())
- .cloned()
- .collect(),
- )
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::CalleeTrapped);
- });
-}
-
-#[test]
-fn instantiate_return_code() {
- let (caller_code, caller_hash) = compile_module::<Test>("instantiate_return_code").unwrap();
- let (callee_code, callee_hash) = compile_module::<Test>("ok_trap_revert").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);
- let _ = Balances::deposit_creating(&CHARLIE, 1000 * subsistence);
- let callee_hash = callee_hash.as_ref().to_vec();
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- callee_code,
- vec![],
- vec![],
- ),);
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- caller_code,
- vec![],
- vec![],
- ),);
- let addr = Contracts::contract_address(&ALICE, &caller_hash, &[]);
-
- // Contract has only the minimal balance so any transfer will return BelowSubsistence.
- Balances::make_free_balance_be(&addr, subsistence);
- let result =
- Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, callee_hash.clone())
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold);
-
- // Contract has enough total balance in order to not go below the subsistence
- // threshold when transfering the balance but this balance is reserved so
- // the transfer still fails but with another return code.
- Balances::make_free_balance_be(&addr, subsistence + 10_000);
- Balances::reserve(&addr, subsistence + 10_000).unwrap();
- let result =
- Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, callee_hash.clone())
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::TransferFailed);
-
- // Contract has enough balance but the passed code hash is invalid
- Balances::make_free_balance_be(&addr, subsistence + 10_000);
- let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![0; 33])
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::CodeNotFound);
-
- // Contract has enough balance but callee reverts because "1" is passed.
- let result = Contracts::bare_call(
- ALICE,
- addr.clone(),
- 0,
- GAS_LIMIT,
- callee_hash
- .iter()
- .chain(&1u32.to_le_bytes())
- .cloned()
- .collect(),
- )
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::CalleeReverted);
-
- // Contract has enough balance but callee traps because "2" is passed.
- let result = Contracts::bare_call(
- ALICE,
- addr,
- 0,
- GAS_LIMIT,
- callee_hash
- .iter()
- .chain(&2u32.to_le_bytes())
- .cloned()
- .collect(),
- )
- .result
- .unwrap();
- assert_return_code!(result, RuntimeReturnCode::CalleeTrapped);
- });
-}
-
-#[test]
-fn disabled_chain_extension_wont_deploy() {
- let (code, _hash) = compile_module::<Test>("chain_extension").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);
- TestExtension::disable();
- assert_err_ignore_postinfo!(
- Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 3 * subsistence,
- GAS_LIMIT,
- code,
- vec![],
- vec![],
- ),
- "module uses chain extensions but chain extensions are disabled",
- );
- });
-}
-
-#[test]
-fn disabled_chain_extension_errors_on_call() {
- let (code, hash) = compile_module::<Test>("chain_extension").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- code,
- vec![],
- vec![],
- ),);
- let addr = Contracts::contract_address(&ALICE, &hash, &[]);
- TestExtension::disable();
- assert_err_ignore_postinfo!(
- Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![],),
- Error::<Test>::NoChainExtension,
- );
- });
-}
-
-#[test]
-fn chain_extension_works() {
- let (code, hash) = compile_module::<Test>("chain_extension").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- code,
- vec![],
- vec![],
- ),);
- let addr = Contracts::contract_address(&ALICE, &hash, &[]);
-
- // The contract takes a up to 2 byte buffer where the first byte passed is used as
- // as func_id to the chain extension which behaves differently based on the
- // func_id.
-
- // 0 = read input buffer and pass it through as output
- let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![0, 99]);
- let gas_consumed = result.gas_consumed;
- assert_eq!(TestExtension::last_seen_buffer(), vec![0, 99]);
- assert_eq!(result.result.unwrap().data, Bytes(vec![0, 99]));
-
- // 1 = treat inputs as integer primitives and store the supplied integers
- Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![1])
- .result
- .unwrap();
- // those values passed in the fixture
- assert_eq!(TestExtension::last_seen_inputs(), (4, 1, 16, 12));
-
- // 2 = charge some extra weight (amount supplied in second byte)
- let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![2, 42]);
- assert_ok!(result.result);
- assert_eq!(result.gas_consumed, gas_consumed + 42);
-
- // 3 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer
- let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![3])
- .result
- .unwrap();
- assert_eq!(result.flags, ReturnFlags::REVERT);
- assert_eq!(result.data, Bytes(vec![42, 99]));
- });
-}
-
-#[test]
-fn lazy_removal_works() {
- let (code, hash) = compile_module::<Test>("self_destruct").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- code,
- vec![],
- vec![],
- ),);
-
- let addr = Contracts::contract_address(&ALICE, &hash, &[]);
- let info = <ContractInfoOf<Test>>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- let trie = &info.child_trie_info();
-
- // Put value into the contracts child trie
- child::put(trie, &[99], &42);
-
- // Terminate the contract
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- vec![],
- ));
-
- // Contract info should be gone
- assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));
-
- // But value should be still there as the lazy removal did not run, yet.
- assert_matches!(child::get(trie, &[99]), Some(42));
-
- // Run the lazy removal
- Contracts::on_initialize(Weight::max_value());
-
- // Value should be gone now
- assert_matches!(child::get::<i32>(trie, &[99]), None);
- });
-}
-
-#[test]
-fn lazy_removal_partial_remove_works() {
- let (code, hash) = compile_module::<Test>("self_destruct").unwrap();
-
- // We create a contract with some extra keys above the weight limit
- let extra_keys = 7u32;
- let weight_limit = 5_000_000_000;
- let (_, max_keys) = Storage::<Test>::deletion_budget(1, weight_limit);
- let vals: Vec<_> = (0..max_keys + extra_keys)
- .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode()))
- .collect();
-
- let mut ext = ExtBuilder::default().existential_deposit(50).build();
-
- let trie = ext.execute_with(|| {
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- code,
- vec![],
- vec![],
- ),);
-
- let addr = Contracts::contract_address(&ALICE, &hash, &[]);
- let info = <ContractInfoOf<Test>>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- let trie = &info.child_trie_info();
-
- // Put value into the contracts child trie
- for val in &vals {
- Storage::<Test>::write(&addr, &info.trie_id, &val.0, Some(val.2.clone())).unwrap();
- }
-
- // Terminate the contract
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- vec![],
- ));
-
- // Contract info should be gone
- assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));
-
- // But value should be still there as the lazy removal did not run, yet.
- for val in &vals {
- assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), Some(val.1));
- }
-
- trie.clone()
- });
-
- // The lazy removal limit only applies to the backend but not to the overlay.
- // This commits all keys from the overlay to the backend.
- ext.commit_all().unwrap();
-
- ext.execute_with(|| {
- // Run the lazy removal
- let weight_used = Storage::<Test>::process_deletion_queue_batch(weight_limit);
-
- // Weight should be exhausted because we could not even delete all keys
- assert_eq!(weight_used, weight_limit);
-
- let mut num_deleted = 0u32;
- let mut num_remaining = 0u32;
-
- for val in &vals {
- match child::get::<u32>(&trie, &blake2_256(&val.0)) {
- None => num_deleted += 1,
- Some(x) if x == val.1 => num_remaining += 1,
- Some(_) => panic!("Unexpected value in contract storage"),
- }
- }
-
- // All but one key is removed
- assert_eq!(num_deleted + num_remaining, vals.len() as u32);
- assert_eq!(num_deleted, max_keys);
- assert_eq!(num_remaining, extra_keys);
- });
-}
-
-#[test]
-fn lazy_removal_does_no_run_on_full_block() {
- let (code, hash) = compile_module::<Test>("self_destruct").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- code,
- vec![],
- vec![],
- ),);
-
- let addr = Contracts::contract_address(&ALICE, &hash, &[]);
- let info = <ContractInfoOf<Test>>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- let trie = &info.child_trie_info();
- let max_keys = 30;
-
- // Create some storage items for the contract.
- let vals: Vec<_> = (0..max_keys)
- .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode()))
- .collect();
-
- // Put value into the contracts child trie
- for val in &vals {
- Storage::<Test>::write(&addr, &info.trie_id, &val.0, Some(val.2.clone())).unwrap();
- }
-
- // Terminate the contract
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- vec![],
- ));
-
- // Contract info should be gone
- assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));
-
- // But value should be still there as the lazy removal did not run, yet.
- for val in &vals {
- assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), Some(val.1));
- }
-
- // Fill up the block which should prevent the lazy storage removal from running.
- System::register_extra_weight_unchecked(
- <Test as system::Config>::BlockWeights::get().max_block,
- DispatchClass::Mandatory,
- );
-
- // Run the lazy removal without any limit so that all keys would be removed if there
- // had been some weight left in the block.
- let weight_used = Contracts::on_initialize(Weight::max_value());
- let base = <<Test as Config>::WeightInfo as WeightInfo>::on_initialize();
- assert_eq!(weight_used, base);
-
- // All the keys are still in place
- for val in &vals {
- assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), Some(val.1));
- }
-
- // Run the lazy removal directly which disregards the block limits
- Storage::<Test>::process_deletion_queue_batch(Weight::max_value());
-
- // Now the keys should be gone
- for val in &vals {
- assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), None);
- }
- });
-}
-
-#[test]
-fn lazy_removal_does_not_use_all_weight() {
- let (code, hash) = compile_module::<Test>("self_destruct").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- code,
- vec![],
- vec![],
- ),);
-
- let addr = Contracts::contract_address(&ALICE, &hash, &[]);
- let info = <ContractInfoOf<Test>>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- let trie = &info.child_trie_info();
- let weight_limit = 5_000_000_000;
- let (weight_per_key, max_keys) = Storage::<Test>::deletion_budget(1, weight_limit);
-
- // We create a contract with one less storage item than we can remove within the limit
- let vals: Vec<_> = (0..max_keys - 1)
- .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode()))
- .collect();
-
- // Put value into the contracts child trie
- for val in &vals {
- Storage::<Test>::write(&addr, &info.trie_id, &val.0, Some(val.2.clone())).unwrap();
- }
-
- // Terminate the contract
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr.clone(),
- 0,
- GAS_LIMIT,
- vec![],
- ));
-
- // Contract info should be gone
- assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));
-
- // But value should be still there as the lazy removal did not run, yet.
- for val in &vals {
- assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), Some(val.1));
- }
-
- // Run the lazy removal
- let weight_used = Storage::<Test>::process_deletion_queue_batch(weight_limit);
-
- // We have one less key in our trie than our weight limit suffices for
- assert_eq!(weight_used, weight_limit - weight_per_key);
-
- // All the keys are removed
- for val in vals {
- assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), None);
- }
- });
-}
-
-#[test]
-fn deletion_queue_full() {
- let (code, hash) = compile_module::<Test>("self_destruct").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- code,
- vec![],
- vec![],
- ),);
-
- let addr = Contracts::contract_address(&ALICE, &hash, &[]);
-
- // fill the deletion queue up until its limit
- Storage::<Test>::fill_queue_with_dummies();
-
- // Terminate the contract should fail
- assert_err_ignore_postinfo!(
- Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![],),
- Error::<Test>::DeletionQueueFull,
- );
-
- // Contract should be alive because removal failed
- <ContractInfoOf<Test>>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
-
- // make the contract ripe for eviction
- initialize_block(5);
-
- // eviction should fail for the same reason as termination
- assert_err!(
- Contracts::claim_surcharge(Origin::none(), addr.clone(), Some(ALICE)),
- Error::<Test>::DeletionQueueFull,
- );
-
- // Contract should be alive because removal failed
- <ContractInfoOf<Test>>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- });
-}
-
-#[test]
-fn not_deployed_if_endowment_too_low_for_first_rent() {
- let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();
-
- // The instantiation deducted the rent for one block immediately
- let first_rent = <Test as Config>::RentFraction::get()
- // base_deposit + deploy_set_storage (4 bytes in 1 item) - free_balance
- .mul_ceil(80_000u32 + 40_000 + 10_000 - 30_000)
- // blocks to rent
- * 1;
-
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- // Create
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_storage_noop!(assert_err_ignore_postinfo!(
- Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 30_000,
- GAS_LIMIT,
- wasm,
- (BalanceOf::<Test>::from(first_rent) - BalanceOf::<Test>::from(1u32)).encode(), // rent allowance
- vec![],
- ),
- Error::<Test>::NewContractNotFunded,
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
- assert_matches!(ContractInfoOf::<Test>::get(&addr), None);
- });
-}
-
-#[test]
-fn surcharge_reward_is_capped() {
- let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- 30_000,
- GAS_LIMIT,
- wasm,
- <BalanceOf<Test>>::from(10_000u32).encode(), // rent allowance
- vec![],
- ));
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
- let contract = <ContractInfoOf<Test>>::get(&addr)
- .unwrap()
- .get_alive()
- .unwrap();
- let balance = Balances::free_balance(&ALICE);
- let reward = <Test as Config>::SurchargeReward::get();
-
- // some rent should have payed due to instantiation
- assert_ne!(contract.rent_payed, 0);
-
- // the reward should be parameterized sufficiently high to make this test useful
- assert!(reward > contract.rent_payed);
-
- // make contract eligible for eviction
- initialize_block(40);
-
- // this should have removed the contract
- assert_ok!(Contracts::claim_surcharge(
- Origin::none(),
- addr.clone(),
- Some(ALICE)
- ));
-
- // this reward does not take into account the last rent payment collected during eviction
- let capped_reward = reward.min(contract.rent_payed);
-
- // this is smaller than the actual reward because it does not take into account the
- // rent collected during eviction
- assert!(Balances::free_balance(&ALICE) > balance + capped_reward);
-
- // the full reward is not payed out because of the cap introduced by rent_payed
- assert!(Balances::free_balance(&ALICE) < balance + reward);
- });
-}
-
-#[test]
-fn refcounter() {
- let (wasm, code_hash) = compile_module::<Test>("self_destruct").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- let subsistence = Pallet::<Test>::subsistence_threshold();
-
- // Create two contracts with the same code and check that they do in fact share it.
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- wasm.clone(),
- vec![],
- vec![0],
- ));
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- wasm.clone(),
- vec![],
- vec![1],
- ));
- assert_refcount!(code_hash, 2);
-
- // Sharing should also work with the usual instantiate call
- assert_ok!(Contracts::instantiate(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- code_hash,
- vec![],
- vec![2],
- ));
- assert_refcount!(code_hash, 3);
-
- // addresses of all three existing contracts
- let addr0 = Contracts::contract_address(&ALICE, &code_hash, &[0]);
- let addr1 = Contracts::contract_address(&ALICE, &code_hash, &[1]);
- let addr2 = Contracts::contract_address(&ALICE, &code_hash, &[2]);
-
- // Terminating one contract should decrement the refcount
- assert_ok!(Contracts::call(
- Origin::signed(ALICE),
- addr0,
- 0,
- GAS_LIMIT,
- vec![],
- ));
- assert_refcount!(code_hash, 2);
-
- // make remaining contracts eligible for eviction
- initialize_block(40);
-
- // remove one of them
- assert_ok!(Contracts::claim_surcharge(
- Origin::none(),
- addr1,
- Some(ALICE)
- ));
- assert_refcount!(code_hash, 1);
-
- // Pristine code should still be there
- crate::PristineCode::<Test>::get(code_hash).unwrap();
-
- // remove the last contract
- assert_ok!(Contracts::claim_surcharge(
- Origin::none(),
- addr2,
- Some(ALICE)
- ));
- assert_refcount!(code_hash, 0);
-
- // all code should be gone
- assert_matches!(crate::PristineCode::<Test>::get(code_hash), None);
- assert_matches!(crate::CodeStorage::<Test>::get(code_hash), None);
- });
-}
-
-#[test]
-fn reinstrument_does_charge() {
- let (wasm, code_hash) = compile_module::<Test>("return_with_data").unwrap();
- ExtBuilder::default()
- .existential_deposit(50)
- .build()
- .execute_with(|| {
- let _ = Balances::deposit_creating(&ALICE, 1_000_000);
- let subsistence = Pallet::<Test>::subsistence_threshold();
- let zero = 0u32.to_le_bytes().encode();
- let code_len = wasm.len() as u32;
-
- assert_ok!(Contracts::instantiate_with_code(
- Origin::signed(ALICE),
- subsistence * 100,
- GAS_LIMIT,
- wasm,
- zero.clone(),
- vec![],
- ));
-
- let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
-
- // Call the contract two times without reinstrument
-
- let result0 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, zero.clone());
- assert!(result0.result.unwrap().is_success());
-
- let result1 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, zero.clone());
- assert!(result1.result.unwrap().is_success());
-
- // They should match because both where called with the same schedule.
- assert_eq!(result0.gas_consumed, result1.gas_consumed);
-
- // Update the schedule version but keep the rest the same
- crate::CurrentSchedule::mutate(|old: &mut Schedule<Test>| {
- old.version += 1;
- });
-
- // This call should trigger reinstrumentation
- let result2 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, zero.clone());
- assert!(result2.result.unwrap().is_success());
- assert!(result2.gas_consumed > result1.gas_consumed);
- assert_eq!(
- result2.gas_consumed,
- result1.gas_consumed + <Test as Config>::WeightInfo::instrument(code_len / 1024),
- );
- });
-}
pallets/contracts/src/weights.rsdiffbeforeafterboth--- a/pallets/contracts/src/weights.rs
+++ /dev/null
@@ -1,1417 +0,0 @@
-// This file is part of Substrate.
-
-// Copyright (C) 2021 Parity Technologies (UK) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Autogenerated weights for pallet_contracts
-//!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0
-//! DATE: 2021-02-18, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: [], HIGH RANGE: []
-//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128
-
-// Executed Command:
-// target/release/substrate
-// benchmark
-// --chain=dev
-// --steps=50
-// --repeat=20
-// --pallet=pallet_contracts
-// --extrinsic=*
-// --execution=wasm
-// --wasm-execution=compiled
-// --heap-pages=4096
-// --output=./frame/contracts/src/weights.rs
-// --template=./.maintain/frame-weight-template.hbs
-
-#![allow(unused_parens)]
-#![allow(unused_imports)]
-
-use frame_support::{
- traits::Get,
- weights::{Weight, constants::RocksDbWeight},
-};
-use sp_std::marker::PhantomData;
-
-/// Weight functions needed for pallet_contracts.
-pub trait WeightInfo {
- fn on_initialize() -> Weight;
- fn on_initialize_per_trie_key(k: u32) -> Weight;
- fn on_initialize_per_queue_item(q: u32) -> Weight;
- fn instrument(c: u32) -> Weight;
- fn update_schedule() -> Weight;
- fn instantiate_with_code(c: u32, s: u32) -> Weight;
- fn instantiate(c: u32, s: u32) -> Weight;
- fn call(c: u32) -> Weight;
- fn claim_surcharge(c: u32) -> Weight;
- fn seal_caller(r: u32) -> Weight;
- fn seal_address(r: u32) -> Weight;
- fn seal_gas_left(r: u32) -> Weight;
- fn seal_balance(r: u32) -> Weight;
- fn seal_value_transferred(r: u32) -> Weight;
- fn seal_minimum_balance(r: u32) -> Weight;
- fn seal_tombstone_deposit(r: u32) -> Weight;
- fn seal_rent_allowance(r: u32) -> Weight;
- fn seal_block_number(r: u32) -> Weight;
- fn seal_now(r: u32) -> Weight;
- fn seal_rent_params(r: u32) -> Weight;
- fn seal_weight_to_fee(r: u32) -> Weight;
- fn seal_gas(r: u32) -> Weight;
- fn seal_input(r: u32) -> Weight;
- fn seal_input_per_kb(n: u32) -> Weight;
- fn seal_return(r: u32) -> Weight;
- fn seal_return_per_kb(n: u32) -> Weight;
- fn seal_terminate(r: u32) -> Weight;
- fn seal_terminate_per_code_kb(c: u32) -> Weight;
- fn seal_restore_to(r: u32) -> Weight;
- fn seal_restore_to_per_code_kb_delta(c: u32, t: u32, d: u32) -> Weight;
- fn seal_random(r: u32) -> Weight;
- fn seal_deposit_event(r: u32) -> Weight;
- fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32) -> Weight;
- fn seal_set_rent_allowance(r: u32) -> Weight;
- fn seal_set_storage(r: u32) -> Weight;
- fn seal_set_storage_per_kb(n: u32) -> Weight;
- fn seal_clear_storage(r: u32) -> Weight;
- fn seal_get_storage(r: u32) -> Weight;
- fn seal_get_storage_per_kb(n: u32) -> Weight;
- fn seal_transfer(r: u32) -> Weight;
- fn seal_call(r: u32) -> Weight;
- fn seal_call_per_code_transfer_input_output_kb(c: u32, t: u32, i: u32, o: u32) -> Weight;
- fn seal_instantiate(r: u32) -> Weight;
- fn seal_instantiate_per_code_input_output_salt_kb(c: u32, i: u32, o: u32, s: u32) -> Weight;
- fn seal_hash_sha2_256(r: u32) -> Weight;
- fn seal_hash_sha2_256_per_kb(n: u32) -> Weight;
- fn seal_hash_keccak_256(r: u32) -> Weight;
- fn seal_hash_keccak_256_per_kb(n: u32) -> Weight;
- fn seal_hash_blake2_256(r: u32) -> Weight;
- fn seal_hash_blake2_256_per_kb(n: u32) -> Weight;
- fn seal_hash_blake2_128(r: u32) -> Weight;
- fn seal_hash_blake2_128_per_kb(n: u32) -> Weight;
- fn instr_i64const(r: u32) -> Weight;
- fn instr_i64load(r: u32) -> Weight;
- fn instr_i64store(r: u32) -> Weight;
- fn instr_select(r: u32) -> Weight;
- fn instr_if(r: u32) -> Weight;
- fn instr_br(r: u32) -> Weight;
- fn instr_br_if(r: u32) -> Weight;
- fn instr_br_table(r: u32) -> Weight;
- fn instr_br_table_per_entry(e: u32) -> Weight;
- fn instr_call(r: u32) -> Weight;
- fn instr_call_indirect(r: u32) -> Weight;
- fn instr_call_indirect_per_param(p: u32) -> Weight;
- fn instr_local_get(r: u32) -> Weight;
- fn instr_local_set(r: u32) -> Weight;
- fn instr_local_tee(r: u32) -> Weight;
- fn instr_global_get(r: u32) -> Weight;
- fn instr_global_set(r: u32) -> Weight;
- fn instr_memory_current(r: u32) -> Weight;
- fn instr_memory_grow(r: u32) -> Weight;
- fn instr_i64clz(r: u32) -> Weight;
- fn instr_i64ctz(r: u32) -> Weight;
- fn instr_i64popcnt(r: u32) -> Weight;
- fn instr_i64eqz(r: u32) -> Weight;
- fn instr_i64extendsi32(r: u32) -> Weight;
- fn instr_i64extendui32(r: u32) -> Weight;
- fn instr_i32wrapi64(r: u32) -> Weight;
- fn instr_i64eq(r: u32) -> Weight;
- fn instr_i64ne(r: u32) -> Weight;
- fn instr_i64lts(r: u32) -> Weight;
- fn instr_i64ltu(r: u32) -> Weight;
- fn instr_i64gts(r: u32) -> Weight;
- fn instr_i64gtu(r: u32) -> Weight;
- fn instr_i64les(r: u32) -> Weight;
- fn instr_i64leu(r: u32) -> Weight;
- fn instr_i64ges(r: u32) -> Weight;
- fn instr_i64geu(r: u32) -> Weight;
- fn instr_i64add(r: u32) -> Weight;
- fn instr_i64sub(r: u32) -> Weight;
- fn instr_i64mul(r: u32) -> Weight;
- fn instr_i64divs(r: u32) -> Weight;
- fn instr_i64divu(r: u32) -> Weight;
- fn instr_i64rems(r: u32) -> Weight;
- fn instr_i64remu(r: u32) -> Weight;
- fn instr_i64and(r: u32) -> Weight;
- fn instr_i64or(r: u32) -> Weight;
- fn instr_i64xor(r: u32) -> Weight;
- fn instr_i64shl(r: u32) -> Weight;
- fn instr_i64shrs(r: u32) -> Weight;
- fn instr_i64shru(r: u32) -> Weight;
- fn instr_i64rotl(r: u32) -> Weight;
- fn instr_i64rotr(r: u32) -> Weight;
-}
-
-/// Weights for pallet_contracts using the Substrate node and recommended hardware.
-pub struct SubstrateWeight<T>(PhantomData<T>);
-impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
- fn on_initialize() -> Weight {
- (3_850_000 as Weight).saturating_add(T::DbWeight::get().reads(1 as Weight))
- }
- fn on_initialize_per_trie_key(k: u32) -> Weight {
- (52_925_000 as Weight)
- // Standard Error: 5_000
- .saturating_add((2_297_000 as Weight).saturating_mul(k as Weight))
- .saturating_add(T::DbWeight::get().reads(1 as Weight))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
- .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight)))
- }
- fn on_initialize_per_queue_item(q: u32) -> Weight {
- (434_698_000 as Weight)
- // Standard Error: 210_000
- .saturating_add((166_559_000 as Weight).saturating_mul(q as Weight))
- .saturating_add(T::DbWeight::get().reads(1 as Weight))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
- }
- fn instrument(c: u32) -> Weight {
- (29_918_000 as Weight)
- // Standard Error: 185_000
- .saturating_add((123_774_000 as Weight).saturating_mul(c as Weight))
- .saturating_add(T::DbWeight::get().reads(1 as Weight))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
- }
- fn update_schedule() -> Weight {
- (29_795_000 as Weight)
- .saturating_add(T::DbWeight::get().reads(1 as Weight))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
- }
- fn instantiate_with_code(c: u32, s: u32) -> Weight {
- (225_834_000 as Weight)
- // Standard Error: 144_000
- .saturating_add((165_632_000 as Weight).saturating_mul(c as Weight))
- // Standard Error: 9_000
- .saturating_add((2_563_000 as Weight).saturating_mul(s as Weight))
- .saturating_add(T::DbWeight::get().reads(6 as Weight))
- .saturating_add(T::DbWeight::get().writes(5 as Weight))
- }
- fn instantiate(c: u32, s: u32) -> Weight {
- (190_482_000 as Weight)
- // Standard Error: 12_000
- .saturating_add((8_724_000 as Weight).saturating_mul(c as Weight))
- // Standard Error: 1_000
- .saturating_add((2_512_000 as Weight).saturating_mul(s as Weight))
- .saturating_add(T::DbWeight::get().reads(6 as Weight))
- .saturating_add(T::DbWeight::get().writes(4 as Weight))
- }
- fn call(c: u32) -> Weight {
- (195_414_000 as Weight)
- // Standard Error: 2_000
- .saturating_add((3_920_000 as Weight).saturating_mul(c as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- .saturating_add(T::DbWeight::get().writes(2 as Weight))
- }
- fn claim_surcharge(c: u32) -> Weight {
- (336_867_000 as Weight)
- // Standard Error: 10_000
- .saturating_add((5_262_000 as Weight).saturating_mul(c as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- .saturating_add(T::DbWeight::get().writes(4 as Weight))
- }
- fn seal_caller(r: u32) -> Weight {
- (143_935_000 as Weight)
- // Standard Error: 128_000
- .saturating_add((266_876_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_address(r: u32) -> Weight {
- (150_342_000 as Weight)
- // Standard Error: 127_000
- .saturating_add((266_051_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_gas_left(r: u32) -> Weight {
- (144_833_000 as Weight)
- // Standard Error: 124_000
- .saturating_add((259_279_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_balance(r: u32) -> Weight {
- (152_032_000 as Weight)
- // Standard Error: 218_000
- .saturating_add((573_038_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_value_transferred(r: u32) -> Weight {
- (148_831_000 as Weight)
- // Standard Error: 147_000
- .saturating_add((260_718_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_minimum_balance(r: u32) -> Weight {
- (142_925_000 as Weight)
- // Standard Error: 130_000
- .saturating_add((260_426_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_tombstone_deposit(r: u32) -> Weight {
- (143_151_000 as Weight)
- // Standard Error: 119_000
- .saturating_add((260_964_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_rent_allowance(r: u32) -> Weight {
- (155_126_000 as Weight)
- // Standard Error: 225_000
- .saturating_add((599_056_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_block_number(r: u32) -> Weight {
- (144_566_000 as Weight)
- // Standard Error: 110_000
- .saturating_add((257_620_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_now(r: u32) -> Weight {
- (147_274_000 as Weight)
- // Standard Error: 115_000
- .saturating_add((258_627_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_rent_params(r: u32) -> Weight {
- (168_575_000 as Weight)
- // Standard Error: 394_000
- .saturating_add((397_754_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_weight_to_fee(r: u32) -> Weight {
- (148_102_000 as Weight)
- // Standard Error: 201_000
- .saturating_add((537_088_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(6 as Weight))
- }
- fn seal_gas(r: u32) -> Weight {
- (125_122_000 as Weight)
- // Standard Error: 89_000
- .saturating_add((122_350_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_input(r: u32) -> Weight {
- (137_334_000 as Weight)
- // Standard Error: 99_000
- .saturating_add((7_359_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_input_per_kb(n: u32) -> Weight {
- (145_094_000 as Weight)
- // Standard Error: 0
- .saturating_add((283_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_return(r: u32) -> Weight {
- (127_544_000 as Weight)
- // Standard Error: 138_000
- .saturating_add((4_640_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_return_per_kb(n: u32) -> Weight {
- (137_517_000 as Weight)
- // Standard Error: 0
- .saturating_add((783_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_terminate(r: u32) -> Weight {
- (138_292_000 as Weight)
- // Standard Error: 689_000
- .saturating_add((111_698_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(r as Weight)))
- .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_terminate_per_code_kb(c: u32) -> Weight {
- (263_507_000 as Weight)
- // Standard Error: 12_000
- .saturating_add((8_409_000 as Weight).saturating_mul(c as Weight))
- .saturating_add(T::DbWeight::get().reads(7 as Weight))
- .saturating_add(T::DbWeight::get().writes(5 as Weight))
- }
- fn seal_restore_to(r: u32) -> Weight {
- (232_291_000 as Weight)
- // Standard Error: 301_000
- .saturating_add((136_379_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight)))
- .saturating_add(T::DbWeight::get().writes((6 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_restore_to_per_code_kb_delta(c: u32, t: u32, d: u32) -> Weight {
- (0 as Weight)
- // Standard Error: 162_000
- .saturating_add((8_619_000 as Weight).saturating_mul(c as Weight))
- // Standard Error: 162_000
- .saturating_add((4_877_000 as Weight).saturating_mul(t as Weight))
- // Standard Error: 1_433_000
- .saturating_add((3_762_810_000 as Weight).saturating_mul(d as Weight))
- .saturating_add(T::DbWeight::get().reads(8 as Weight))
- .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(d as Weight)))
- .saturating_add(T::DbWeight::get().writes(7 as Weight))
- .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(d as Weight)))
- }
- fn seal_random(r: u32) -> Weight {
- (153_634_000 as Weight)
- // Standard Error: 267_000
- .saturating_add((650_160_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(6 as Weight))
- }
- fn seal_deposit_event(r: u32) -> Weight {
- (137_080_000 as Weight)
- // Standard Error: 1_009_000
- .saturating_add((949_228_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32) -> Weight {
- (1_259_129_000 as Weight)
- // Standard Error: 2_542_000
- .saturating_add((609_859_000 as Weight).saturating_mul(t as Weight))
- // Standard Error: 501_000
- .saturating_add((249_496_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight)))
- .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(t as Weight)))
- }
- fn seal_set_rent_allowance(r: u32) -> Weight {
- (170_417_000 as Weight)
- // Standard Error: 434_000
- .saturating_add((721_511_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
- }
- fn seal_set_storage(r: u32) -> Weight {
- (1_870_542_000 as Weight)
- // Standard Error: 26_871_000
- .saturating_add((18_312_239_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight)))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
- .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_set_storage_per_kb(n: u32) -> Weight {
- (1_763_732_000 as Weight)
- // Standard Error: 258_000
- .saturating_add((74_848_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(T::DbWeight::get().reads(6 as Weight))
- .saturating_add(T::DbWeight::get().writes(2 as Weight))
- }
- fn seal_clear_storage(r: u32) -> Weight {
- (0 as Weight)
- // Standard Error: 2_745_000
- .saturating_add((2_316_433_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight)))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
- .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_get_storage(r: u32) -> Weight {
- (87_218_000 as Weight)
- // Standard Error: 745_000
- .saturating_add((948_121_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_get_storage_per_kb(n: u32) -> Weight {
- (719_050_000 as Weight)
- // Standard Error: 266_000
- .saturating_add((154_812_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(T::DbWeight::get().reads(6 as Weight))
- }
- fn seal_transfer(r: u32) -> Weight {
- (19_439_000 as Weight)
- // Standard Error: 2_468_000
- .saturating_add((5_674_822_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight)))
- .saturating_add(T::DbWeight::get().writes(1 as Weight))
- .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_call(r: u32) -> Weight {
- (0 as Weight)
- // Standard Error: 7_465_000
- .saturating_add((11_066_530_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(6 as Weight))
- .saturating_add(T::DbWeight::get().reads((200 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_call_per_code_transfer_input_output_kb(c: u32, t: u32, i: u32, o: u32) -> Weight {
- (9_916_288_000 as Weight)
- // Standard Error: 552_000
- .saturating_add((397_842_000 as Weight).saturating_mul(c as Weight))
- // Standard Error: 229_902_000
- .saturating_add((5_243_673_000 as Weight).saturating_mul(t as Weight))
- // Standard Error: 72_000
- .saturating_add((59_737_000 as Weight).saturating_mul(i as Weight))
- // Standard Error: 77_000
- .saturating_add((82_259_000 as Weight).saturating_mul(o as Weight))
- .saturating_add(T::DbWeight::get().reads(206 as Weight))
- .saturating_add(T::DbWeight::get().writes((101 as Weight).saturating_mul(t as Weight)))
- }
- fn seal_instantiate(r: u32) -> Weight {
- (0 as Weight)
- // Standard Error: 32_016_000
- .saturating_add((22_206_489_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(6 as Weight))
- .saturating_add(T::DbWeight::get().reads((300 as Weight).saturating_mul(r as Weight)))
- .saturating_add(T::DbWeight::get().writes(2 as Weight))
- .saturating_add(T::DbWeight::get().writes((300 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_instantiate_per_code_input_output_salt_kb(c: u32, i: u32, o: u32, s: u32) -> Weight {
- (9_991_947_000 as Weight)
- // Standard Error: 637_000
- .saturating_add((881_981_000 as Weight).saturating_mul(c as Weight))
- // Standard Error: 90_000
- .saturating_add((63_638_000 as Weight).saturating_mul(i as Weight))
- // Standard Error: 90_000
- .saturating_add((87_288_000 as Weight).saturating_mul(o as Weight))
- // Standard Error: 90_000
- .saturating_add((311_808_000 as Weight).saturating_mul(s as Weight))
- .saturating_add(T::DbWeight::get().reads(207 as Weight))
- .saturating_add(T::DbWeight::get().writes(203 as Weight))
- }
- fn seal_hash_sha2_256(r: u32) -> Weight {
- (132_452_000 as Weight)
- // Standard Error: 227_000
- .saturating_add((239_671_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_sha2_256_per_kb(n: u32) -> Weight {
- (756_802_000 as Weight)
- // Standard Error: 48_000
- .saturating_add((429_454_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_keccak_256(r: u32) -> Weight {
- (139_440_000 as Weight)
- // Standard Error: 128_000
- .saturating_add((249_514_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_keccak_256_per_kb(n: u32) -> Weight {
- (658_595_000 as Weight)
- // Standard Error: 35_000
- .saturating_add((343_814_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_blake2_256(r: u32) -> Weight {
- (138_124_000 as Weight)
- // Standard Error: 140_000
- .saturating_add((223_189_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_blake2_256_per_kb(n: u32) -> Weight {
- (689_667_000 as Weight)
- // Standard Error: 41_000
- .saturating_add((160_006_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_blake2_128(r: u32) -> Weight {
- (140_225_000 as Weight)
- // Standard Error: 156_000
- .saturating_add((223_696_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_blake2_128_per_kb(n: u32) -> Weight {
- (693_756_000 as Weight)
- // Standard Error: 40_000
- .saturating_add((159_996_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(T::DbWeight::get().reads(5 as Weight))
- }
- fn instr_i64const(r: u32) -> Weight {
- (24_250_000 as Weight)
- // Standard Error: 14_000
- .saturating_add((3_134_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64load(r: u32) -> Weight {
- (26_509_000 as Weight)
- // Standard Error: 27_000
- .saturating_add((161_556_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64store(r: u32) -> Weight {
- (26_499_000 as Weight)
- // Standard Error: 59_000
- .saturating_add((233_755_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_select(r: u32) -> Weight {
- (24_175_000 as Weight)
- // Standard Error: 16_000
- .saturating_add((12_450_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_if(r: u32) -> Weight {
- (24_219_000 as Weight)
- // Standard Error: 26_000
- .saturating_add((12_058_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_br(r: u32) -> Weight {
- (24_146_000 as Weight)
- // Standard Error: 20_000
- .saturating_add((6_017_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_br_if(r: u32) -> Weight {
- (24_229_000 as Weight)
- // Standard Error: 24_000
- .saturating_add((13_726_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_br_table(r: u32) -> Weight {
- (24_219_000 as Weight)
- // Standard Error: 27_000
- .saturating_add((15_115_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_br_table_per_entry(e: u32) -> Weight {
- (34_981_000 as Weight)
- // Standard Error: 1_000
- .saturating_add((156_000 as Weight).saturating_mul(e as Weight))
- }
- fn instr_call(r: u32) -> Weight {
- (24_599_000 as Weight)
- // Standard Error: 102_000
- .saturating_add((95_771_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_call_indirect(r: u32) -> Weight {
- (32_584_000 as Weight)
- // Standard Error: 176_000
- .saturating_add((193_216_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_call_indirect_per_param(p: u32) -> Weight {
- (240_739_000 as Weight)
- // Standard Error: 6_000
- .saturating_add((3_407_000 as Weight).saturating_mul(p as Weight))
- }
- fn instr_local_get(r: u32) -> Weight {
- (41_963_000 as Weight)
- // Standard Error: 15_000
- .saturating_add((3_110_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_local_set(r: u32) -> Weight {
- (41_956_000 as Weight)
- // Standard Error: 9_000
- .saturating_add((3_460_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_local_tee(r: u32) -> Weight {
- (42_002_000 as Weight)
- // Standard Error: 20_000
- .saturating_add((4_591_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_global_get(r: u32) -> Weight {
- (27_646_000 as Weight)
- // Standard Error: 23_000
- .saturating_add((7_821_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_global_set(r: u32) -> Weight {
- (27_615_000 as Weight)
- // Standard Error: 27_000
- .saturating_add((11_807_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_memory_current(r: u32) -> Weight {
- (27_106_000 as Weight)
- // Standard Error: 78_000
- .saturating_add((2_952_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_memory_grow(r: u32) -> Weight {
- (24_956_000 as Weight)
- // Standard Error: 3_541_000
- .saturating_add((2_332_414_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64clz(r: u32) -> Weight {
- (24_183_000 as Weight)
- // Standard Error: 18_000
- .saturating_add((5_166_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64ctz(r: u32) -> Weight {
- (24_142_000 as Weight)
- // Standard Error: 17_000
- .saturating_add((5_146_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64popcnt(r: u32) -> Weight {
- (24_161_000 as Weight)
- // Standard Error: 23_000
- .saturating_add((5_807_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64eqz(r: u32) -> Weight {
- (24_167_000 as Weight)
- // Standard Error: 24_000
- .saturating_add((5_288_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64extendsi32(r: u32) -> Weight {
- (24_252_000 as Weight)
- // Standard Error: 9_000
- .saturating_add((5_091_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64extendui32(r: u32) -> Weight {
- (24_243_000 as Weight)
- // Standard Error: 16_000
- .saturating_add((5_076_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i32wrapi64(r: u32) -> Weight {
- (24_227_000 as Weight)
- // Standard Error: 15_000
- .saturating_add((5_135_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64eq(r: u32) -> Weight {
- (24_278_000 as Weight)
- // Standard Error: 15_000
- .saturating_add((7_124_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64ne(r: u32) -> Weight {
- (24_254_000 as Weight)
- // Standard Error: 19_000
- .saturating_add((7_067_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64lts(r: u32) -> Weight {
- (24_220_000 as Weight)
- // Standard Error: 14_000
- .saturating_add((7_122_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64ltu(r: u32) -> Weight {
- (24_221_000 as Weight)
- // Standard Error: 19_000
- .saturating_add((7_221_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64gts(r: u32) -> Weight {
- (24_259_000 as Weight)
- // Standard Error: 13_000
- .saturating_add((7_135_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64gtu(r: u32) -> Weight {
- (24_245_000 as Weight)
- // Standard Error: 10_000
- .saturating_add((7_193_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64les(r: u32) -> Weight {
- (24_289_000 as Weight)
- // Standard Error: 22_000
- .saturating_add((7_023_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64leu(r: u32) -> Weight {
- (24_239_000 as Weight)
- // Standard Error: 21_000
- .saturating_add((7_065_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64ges(r: u32) -> Weight {
- (24_256_000 as Weight)
- // Standard Error: 13_000
- .saturating_add((7_119_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64geu(r: u32) -> Weight {
- (24_240_000 as Weight)
- // Standard Error: 18_000
- .saturating_add((7_225_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64add(r: u32) -> Weight {
- (24_266_000 as Weight)
- // Standard Error: 24_000
- .saturating_add((6_996_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64sub(r: u32) -> Weight {
- (24_265_000 as Weight)
- // Standard Error: 17_000
- .saturating_add((6_974_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64mul(r: u32) -> Weight {
- (24_232_000 as Weight)
- // Standard Error: 15_000
- .saturating_add((7_103_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64divs(r: u32) -> Weight {
- (24_245_000 as Weight)
- // Standard Error: 20_000
- .saturating_add((12_915_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64divu(r: u32) -> Weight {
- (24_177_000 as Weight)
- // Standard Error: 21_000
- .saturating_add((12_232_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64rems(r: u32) -> Weight {
- (24_171_000 as Weight)
- // Standard Error: 15_000
- .saturating_add((12_939_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64remu(r: u32) -> Weight {
- (24_788_000 as Weight)
- // Standard Error: 22_000
- .saturating_add((11_657_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64and(r: u32) -> Weight {
- (24_252_000 as Weight)
- // Standard Error: 19_000
- .saturating_add((7_003_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64or(r: u32) -> Weight {
- (24_263_000 as Weight)
- // Standard Error: 12_000
- .saturating_add((7_005_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64xor(r: u32) -> Weight {
- (24_239_000 as Weight)
- // Standard Error: 17_000
- .saturating_add((7_020_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64shl(r: u32) -> Weight {
- (24_212_000 as Weight)
- // Standard Error: 13_000
- .saturating_add((7_172_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64shrs(r: u32) -> Weight {
- (24_220_000 as Weight)
- // Standard Error: 27_000
- .saturating_add((7_246_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64shru(r: u32) -> Weight {
- (24_213_000 as Weight)
- // Standard Error: 14_000
- .saturating_add((7_191_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64rotl(r: u32) -> Weight {
- (24_221_000 as Weight)
- // Standard Error: 18_000
- .saturating_add((7_192_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64rotr(r: u32) -> Weight {
- (24_235_000 as Weight)
- // Standard Error: 12_000
- .saturating_add((7_106_000 as Weight).saturating_mul(r as Weight))
- }
-}
-
-// For backwards compatibility and tests
-impl WeightInfo for () {
- fn on_initialize() -> Weight {
- (3_850_000 as Weight).saturating_add(RocksDbWeight::get().reads(1 as Weight))
- }
- fn on_initialize_per_trie_key(k: u32) -> Weight {
- (52_925_000 as Weight)
- // Standard Error: 5_000
- .saturating_add((2_297_000 as Weight).saturating_mul(k as Weight))
- .saturating_add(RocksDbWeight::get().reads(1 as Weight))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
- .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight)))
- }
- fn on_initialize_per_queue_item(q: u32) -> Weight {
- (434_698_000 as Weight)
- // Standard Error: 210_000
- .saturating_add((166_559_000 as Weight).saturating_mul(q as Weight))
- .saturating_add(RocksDbWeight::get().reads(1 as Weight))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
- }
- fn instrument(c: u32) -> Weight {
- (29_918_000 as Weight)
- // Standard Error: 185_000
- .saturating_add((123_774_000 as Weight).saturating_mul(c as Weight))
- .saturating_add(RocksDbWeight::get().reads(1 as Weight))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
- }
- fn update_schedule() -> Weight {
- (29_795_000 as Weight)
- .saturating_add(RocksDbWeight::get().reads(1 as Weight))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
- }
- fn instantiate_with_code(c: u32, s: u32) -> Weight {
- (225_834_000 as Weight)
- // Standard Error: 144_000
- .saturating_add((165_632_000 as Weight).saturating_mul(c as Weight))
- // Standard Error: 9_000
- .saturating_add((2_563_000 as Weight).saturating_mul(s as Weight))
- .saturating_add(RocksDbWeight::get().reads(6 as Weight))
- .saturating_add(RocksDbWeight::get().writes(5 as Weight))
- }
- fn instantiate(c: u32, s: u32) -> Weight {
- (190_482_000 as Weight)
- // Standard Error: 12_000
- .saturating_add((8_724_000 as Weight).saturating_mul(c as Weight))
- // Standard Error: 1_000
- .saturating_add((2_512_000 as Weight).saturating_mul(s as Weight))
- .saturating_add(RocksDbWeight::get().reads(6 as Weight))
- .saturating_add(RocksDbWeight::get().writes(4 as Weight))
- }
- fn call(c: u32) -> Weight {
- (195_414_000 as Weight)
- // Standard Error: 2_000
- .saturating_add((3_920_000 as Weight).saturating_mul(c as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- .saturating_add(RocksDbWeight::get().writes(2 as Weight))
- }
- fn claim_surcharge(c: u32) -> Weight {
- (336_867_000 as Weight)
- // Standard Error: 10_000
- .saturating_add((5_262_000 as Weight).saturating_mul(c as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- .saturating_add(RocksDbWeight::get().writes(4 as Weight))
- }
- fn seal_caller(r: u32) -> Weight {
- (143_935_000 as Weight)
- // Standard Error: 128_000
- .saturating_add((266_876_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_address(r: u32) -> Weight {
- (150_342_000 as Weight)
- // Standard Error: 127_000
- .saturating_add((266_051_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_gas_left(r: u32) -> Weight {
- (144_833_000 as Weight)
- // Standard Error: 124_000
- .saturating_add((259_279_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_balance(r: u32) -> Weight {
- (152_032_000 as Weight)
- // Standard Error: 218_000
- .saturating_add((573_038_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_value_transferred(r: u32) -> Weight {
- (148_831_000 as Weight)
- // Standard Error: 147_000
- .saturating_add((260_718_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_minimum_balance(r: u32) -> Weight {
- (142_925_000 as Weight)
- // Standard Error: 130_000
- .saturating_add((260_426_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_tombstone_deposit(r: u32) -> Weight {
- (143_151_000 as Weight)
- // Standard Error: 119_000
- .saturating_add((260_964_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_rent_allowance(r: u32) -> Weight {
- (155_126_000 as Weight)
- // Standard Error: 225_000
- .saturating_add((599_056_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_block_number(r: u32) -> Weight {
- (144_566_000 as Weight)
- // Standard Error: 110_000
- .saturating_add((257_620_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_now(r: u32) -> Weight {
- (147_274_000 as Weight)
- // Standard Error: 115_000
- .saturating_add((258_627_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_rent_params(r: u32) -> Weight {
- (168_575_000 as Weight)
- // Standard Error: 394_000
- .saturating_add((397_754_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_weight_to_fee(r: u32) -> Weight {
- (148_102_000 as Weight)
- // Standard Error: 201_000
- .saturating_add((537_088_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(6 as Weight))
- }
- fn seal_gas(r: u32) -> Weight {
- (125_122_000 as Weight)
- // Standard Error: 89_000
- .saturating_add((122_350_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_input(r: u32) -> Weight {
- (137_334_000 as Weight)
- // Standard Error: 99_000
- .saturating_add((7_359_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_input_per_kb(n: u32) -> Weight {
- (145_094_000 as Weight)
- // Standard Error: 0
- .saturating_add((283_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_return(r: u32) -> Weight {
- (127_544_000 as Weight)
- // Standard Error: 138_000
- .saturating_add((4_640_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_return_per_kb(n: u32) -> Weight {
- (137_517_000 as Weight)
- // Standard Error: 0
- .saturating_add((783_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_terminate(r: u32) -> Weight {
- (138_292_000 as Weight)
- // Standard Error: 689_000
- .saturating_add((111_698_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(r as Weight)))
- .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_terminate_per_code_kb(c: u32) -> Weight {
- (263_507_000 as Weight)
- // Standard Error: 12_000
- .saturating_add((8_409_000 as Weight).saturating_mul(c as Weight))
- .saturating_add(RocksDbWeight::get().reads(7 as Weight))
- .saturating_add(RocksDbWeight::get().writes(5 as Weight))
- }
- fn seal_restore_to(r: u32) -> Weight {
- (232_291_000 as Weight)
- // Standard Error: 301_000
- .saturating_add((136_379_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight)))
- .saturating_add(RocksDbWeight::get().writes((6 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_restore_to_per_code_kb_delta(c: u32, t: u32, d: u32) -> Weight {
- (0 as Weight)
- // Standard Error: 162_000
- .saturating_add((8_619_000 as Weight).saturating_mul(c as Weight))
- // Standard Error: 162_000
- .saturating_add((4_877_000 as Weight).saturating_mul(t as Weight))
- // Standard Error: 1_433_000
- .saturating_add((3_762_810_000 as Weight).saturating_mul(d as Weight))
- .saturating_add(RocksDbWeight::get().reads(8 as Weight))
- .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(d as Weight)))
- .saturating_add(RocksDbWeight::get().writes(7 as Weight))
- .saturating_add(
- RocksDbWeight::get().writes((100 as Weight).saturating_mul(d as Weight)),
- )
- }
- fn seal_random(r: u32) -> Weight {
- (153_634_000 as Weight)
- // Standard Error: 267_000
- .saturating_add((650_160_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(6 as Weight))
- }
- fn seal_deposit_event(r: u32) -> Weight {
- (137_080_000 as Weight)
- // Standard Error: 1_009_000
- .saturating_add((949_228_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32) -> Weight {
- (1_259_129_000 as Weight)
- // Standard Error: 2_542_000
- .saturating_add((609_859_000 as Weight).saturating_mul(t as Weight))
- // Standard Error: 501_000
- .saturating_add((249_496_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight)))
- .saturating_add(
- RocksDbWeight::get().writes((100 as Weight).saturating_mul(t as Weight)),
- )
- }
- fn seal_set_rent_allowance(r: u32) -> Weight {
- (170_417_000 as Weight)
- // Standard Error: 434_000
- .saturating_add((721_511_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
- }
- fn seal_set_storage(r: u32) -> Weight {
- (1_870_542_000 as Weight)
- // Standard Error: 26_871_000
- .saturating_add((18_312_239_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight)))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
- .saturating_add(
- RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight)),
- )
- }
- fn seal_set_storage_per_kb(n: u32) -> Weight {
- (1_763_732_000 as Weight)
- // Standard Error: 258_000
- .saturating_add((74_848_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(RocksDbWeight::get().reads(6 as Weight))
- .saturating_add(RocksDbWeight::get().writes(2 as Weight))
- }
- fn seal_clear_storage(r: u32) -> Weight {
- (0 as Weight)
- // Standard Error: 2_745_000
- .saturating_add((2_316_433_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight)))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
- .saturating_add(
- RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight)),
- )
- }
- fn seal_get_storage(r: u32) -> Weight {
- (87_218_000 as Weight)
- // Standard Error: 745_000
- .saturating_add((948_121_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_get_storage_per_kb(n: u32) -> Weight {
- (719_050_000 as Weight)
- // Standard Error: 266_000
- .saturating_add((154_812_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(RocksDbWeight::get().reads(6 as Weight))
- }
- fn seal_transfer(r: u32) -> Weight {
- (19_439_000 as Weight)
- // Standard Error: 2_468_000
- .saturating_add((5_674_822_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight)))
- .saturating_add(RocksDbWeight::get().writes(1 as Weight))
- .saturating_add(
- RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight)),
- )
- }
- fn seal_call(r: u32) -> Weight {
- (0 as Weight)
- // Standard Error: 7_465_000
- .saturating_add((11_066_530_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(6 as Weight))
- .saturating_add(RocksDbWeight::get().reads((200 as Weight).saturating_mul(r as Weight)))
- }
- fn seal_call_per_code_transfer_input_output_kb(c: u32, t: u32, i: u32, o: u32) -> Weight {
- (9_916_288_000 as Weight)
- // Standard Error: 552_000
- .saturating_add((397_842_000 as Weight).saturating_mul(c as Weight))
- // Standard Error: 229_902_000
- .saturating_add((5_243_673_000 as Weight).saturating_mul(t as Weight))
- // Standard Error: 72_000
- .saturating_add((59_737_000 as Weight).saturating_mul(i as Weight))
- // Standard Error: 77_000
- .saturating_add((82_259_000 as Weight).saturating_mul(o as Weight))
- .saturating_add(RocksDbWeight::get().reads(206 as Weight))
- .saturating_add(
- RocksDbWeight::get().writes((101 as Weight).saturating_mul(t as Weight)),
- )
- }
- fn seal_instantiate(r: u32) -> Weight {
- (0 as Weight)
- // Standard Error: 32_016_000
- .saturating_add((22_206_489_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(6 as Weight))
- .saturating_add(RocksDbWeight::get().reads((300 as Weight).saturating_mul(r as Weight)))
- .saturating_add(RocksDbWeight::get().writes(2 as Weight))
- .saturating_add(
- RocksDbWeight::get().writes((300 as Weight).saturating_mul(r as Weight)),
- )
- }
- fn seal_instantiate_per_code_input_output_salt_kb(c: u32, i: u32, o: u32, s: u32) -> Weight {
- (9_991_947_000 as Weight)
- // Standard Error: 637_000
- .saturating_add((881_981_000 as Weight).saturating_mul(c as Weight))
- // Standard Error: 90_000
- .saturating_add((63_638_000 as Weight).saturating_mul(i as Weight))
- // Standard Error: 90_000
- .saturating_add((87_288_000 as Weight).saturating_mul(o as Weight))
- // Standard Error: 90_000
- .saturating_add((311_808_000 as Weight).saturating_mul(s as Weight))
- .saturating_add(RocksDbWeight::get().reads(207 as Weight))
- .saturating_add(RocksDbWeight::get().writes(203 as Weight))
- }
- fn seal_hash_sha2_256(r: u32) -> Weight {
- (132_452_000 as Weight)
- // Standard Error: 227_000
- .saturating_add((239_671_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_sha2_256_per_kb(n: u32) -> Weight {
- (756_802_000 as Weight)
- // Standard Error: 48_000
- .saturating_add((429_454_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_keccak_256(r: u32) -> Weight {
- (139_440_000 as Weight)
- // Standard Error: 128_000
- .saturating_add((249_514_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_keccak_256_per_kb(n: u32) -> Weight {
- (658_595_000 as Weight)
- // Standard Error: 35_000
- .saturating_add((343_814_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_blake2_256(r: u32) -> Weight {
- (138_124_000 as Weight)
- // Standard Error: 140_000
- .saturating_add((223_189_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_blake2_256_per_kb(n: u32) -> Weight {
- (689_667_000 as Weight)
- // Standard Error: 41_000
- .saturating_add((160_006_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_blake2_128(r: u32) -> Weight {
- (140_225_000 as Weight)
- // Standard Error: 156_000
- .saturating_add((223_696_000 as Weight).saturating_mul(r as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn seal_hash_blake2_128_per_kb(n: u32) -> Weight {
- (693_756_000 as Weight)
- // Standard Error: 40_000
- .saturating_add((159_996_000 as Weight).saturating_mul(n as Weight))
- .saturating_add(RocksDbWeight::get().reads(5 as Weight))
- }
- fn instr_i64const(r: u32) -> Weight {
- (24_250_000 as Weight)
- // Standard Error: 14_000
- .saturating_add((3_134_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64load(r: u32) -> Weight {
- (26_509_000 as Weight)
- // Standard Error: 27_000
- .saturating_add((161_556_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64store(r: u32) -> Weight {
- (26_499_000 as Weight)
- // Standard Error: 59_000
- .saturating_add((233_755_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_select(r: u32) -> Weight {
- (24_175_000 as Weight)
- // Standard Error: 16_000
- .saturating_add((12_450_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_if(r: u32) -> Weight {
- (24_219_000 as Weight)
- // Standard Error: 26_000
- .saturating_add((12_058_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_br(r: u32) -> Weight {
- (24_146_000 as Weight)
- // Standard Error: 20_000
- .saturating_add((6_017_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_br_if(r: u32) -> Weight {
- (24_229_000 as Weight)
- // Standard Error: 24_000
- .saturating_add((13_726_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_br_table(r: u32) -> Weight {
- (24_219_000 as Weight)
- // Standard Error: 27_000
- .saturating_add((15_115_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_br_table_per_entry(e: u32) -> Weight {
- (34_981_000 as Weight)
- // Standard Error: 1_000
- .saturating_add((156_000 as Weight).saturating_mul(e as Weight))
- }
- fn instr_call(r: u32) -> Weight {
- (24_599_000 as Weight)
- // Standard Error: 102_000
- .saturating_add((95_771_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_call_indirect(r: u32) -> Weight {
- (32_584_000 as Weight)
- // Standard Error: 176_000
- .saturating_add((193_216_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_call_indirect_per_param(p: u32) -> Weight {
- (240_739_000 as Weight)
- // Standard Error: 6_000
- .saturating_add((3_407_000 as Weight).saturating_mul(p as Weight))
- }
- fn instr_local_get(r: u32) -> Weight {
- (41_963_000 as Weight)
- // Standard Error: 15_000
- .saturating_add((3_110_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_local_set(r: u32) -> Weight {
- (41_956_000 as Weight)
- // Standard Error: 9_000
- .saturating_add((3_460_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_local_tee(r: u32) -> Weight {
- (42_002_000 as Weight)
- // Standard Error: 20_000
- .saturating_add((4_591_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_global_get(r: u32) -> Weight {
- (27_646_000 as Weight)
- // Standard Error: 23_000
- .saturating_add((7_821_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_global_set(r: u32) -> Weight {
- (27_615_000 as Weight)
- // Standard Error: 27_000
- .saturating_add((11_807_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_memory_current(r: u32) -> Weight {
- (27_106_000 as Weight)
- // Standard Error: 78_000
- .saturating_add((2_952_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_memory_grow(r: u32) -> Weight {
- (24_956_000 as Weight)
- // Standard Error: 3_541_000
- .saturating_add((2_332_414_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64clz(r: u32) -> Weight {
- (24_183_000 as Weight)
- // Standard Error: 18_000
- .saturating_add((5_166_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64ctz(r: u32) -> Weight {
- (24_142_000 as Weight)
- // Standard Error: 17_000
- .saturating_add((5_146_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64popcnt(r: u32) -> Weight {
- (24_161_000 as Weight)
- // Standard Error: 23_000
- .saturating_add((5_807_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64eqz(r: u32) -> Weight {
- (24_167_000 as Weight)
- // Standard Error: 24_000
- .saturating_add((5_288_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64extendsi32(r: u32) -> Weight {
- (24_252_000 as Weight)
- // Standard Error: 9_000
- .saturating_add((5_091_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64extendui32(r: u32) -> Weight {
- (24_243_000 as Weight)
- // Standard Error: 16_000
- .saturating_add((5_076_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i32wrapi64(r: u32) -> Weight {
- (24_227_000 as Weight)
- // Standard Error: 15_000
- .saturating_add((5_135_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64eq(r: u32) -> Weight {
- (24_278_000 as Weight)
- // Standard Error: 15_000
- .saturating_add((7_124_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64ne(r: u32) -> Weight {
- (24_254_000 as Weight)
- // Standard Error: 19_000
- .saturating_add((7_067_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64lts(r: u32) -> Weight {
- (24_220_000 as Weight)
- // Standard Error: 14_000
- .saturating_add((7_122_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64ltu(r: u32) -> Weight {
- (24_221_000 as Weight)
- // Standard Error: 19_000
- .saturating_add((7_221_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64gts(r: u32) -> Weight {
- (24_259_000 as Weight)
- // Standard Error: 13_000
- .saturating_add((7_135_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64gtu(r: u32) -> Weight {
- (24_245_000 as Weight)
- // Standard Error: 10_000
- .saturating_add((7_193_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64les(r: u32) -> Weight {
- (24_289_000 as Weight)
- // Standard Error: 22_000
- .saturating_add((7_023_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64leu(r: u32) -> Weight {
- (24_239_000 as Weight)
- // Standard Error: 21_000
- .saturating_add((7_065_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64ges(r: u32) -> Weight {
- (24_256_000 as Weight)
- // Standard Error: 13_000
- .saturating_add((7_119_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64geu(r: u32) -> Weight {
- (24_240_000 as Weight)
- // Standard Error: 18_000
- .saturating_add((7_225_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64add(r: u32) -> Weight {
- (24_266_000 as Weight)
- // Standard Error: 24_000
- .saturating_add((6_996_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64sub(r: u32) -> Weight {
- (24_265_000 as Weight)
- // Standard Error: 17_000
- .saturating_add((6_974_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64mul(r: u32) -> Weight {
- (24_232_000 as Weight)
- // Standard Error: 15_000
- .saturating_add((7_103_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64divs(r: u32) -> Weight {
- (24_245_000 as Weight)
- // Standard Error: 20_000
- .saturating_add((12_915_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64divu(r: u32) -> Weight {
- (24_177_000 as Weight)
- // Standard Error: 21_000
- .saturating_add((12_232_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64rems(r: u32) -> Weight {
- (24_171_000 as Weight)
- // Standard Error: 15_000
- .saturating_add((12_939_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64remu(r: u32) -> Weight {
- (24_788_000 as Weight)
- // Standard Error: 22_000
- .saturating_add((11_657_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64and(r: u32) -> Weight {
- (24_252_000 as Weight)
- // Standard Error: 19_000
- .saturating_add((7_003_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64or(r: u32) -> Weight {
- (24_263_000 as Weight)
- // Standard Error: 12_000
- .saturating_add((7_005_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64xor(r: u32) -> Weight {
- (24_239_000 as Weight)
- // Standard Error: 17_000
- .saturating_add((7_020_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64shl(r: u32) -> Weight {
- (24_212_000 as Weight)
- // Standard Error: 13_000
- .saturating_add((7_172_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64shrs(r: u32) -> Weight {
- (24_220_000 as Weight)
- // Standard Error: 27_000
- .saturating_add((7_246_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64shru(r: u32) -> Weight {
- (24_213_000 as Weight)
- // Standard Error: 14_000
- .saturating_add((7_191_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64rotl(r: u32) -> Weight {
- (24_221_000 as Weight)
- // Standard Error: 18_000
- .saturating_add((7_192_000 as Weight).saturating_mul(r as Weight))
- }
- fn instr_i64rotr(r: u32) -> Weight {
- (24_235_000 as Weight)
- // Standard Error: 12_000
- .saturating_add((7_106_000 as Weight).saturating_mul(r as Weight))
- }
-}