mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 00:37:57 +00:00
contracts: Allow contracts to dispatch calls into the runtime (#9276)
* contracts: Allow contracts to dispatch calls into the runtime * Fix RPC tests * Fix typo * Replace () by AllowAllFilter and DenyAllFilter * Add rust doc * Fixup for `()` removal * Fix lowest gas calculation * Rename AllowAllFilter and DenyAllFilter * Updated changelog
This commit is contained in:
committed by
GitHub
parent
2f31602896
commit
e01ac8cea0
Generated
+1
@@ -4871,6 +4871,7 @@ dependencies = [
|
||||
"pallet-contracts-proc-macro",
|
||||
"pallet-randomness-collective-flip",
|
||||
"pallet-timestamp",
|
||||
"pallet-utility",
|
||||
"parity-scale-codec",
|
||||
"paste 1.0.4",
|
||||
"pretty_assertions 0.7.2",
|
||||
|
||||
@@ -27,7 +27,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -146,7 +146,7 @@ parameter_types! {
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
/// The basic call filter to use in dispatchable.
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
/// Block & extrinsics weights: base values and limits.
|
||||
type BlockWeights = BlockWeights;
|
||||
/// The maximum length of a block (in bytes).
|
||||
|
||||
@@ -33,7 +33,7 @@ use frame_support::{
|
||||
},
|
||||
traits::{
|
||||
Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, LockIdentifier,
|
||||
U128CurrencyToVote,
|
||||
U128CurrencyToVote, AllowAll, DenyAll,
|
||||
},
|
||||
};
|
||||
use frame_system::{
|
||||
@@ -193,7 +193,7 @@ parameter_types! {
|
||||
const_assert!(NORMAL_DISPATCH_RATIO.deconstruct() >= AVERAGE_ON_INITIALIZE_RATIO.deconstruct());
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = AllowAll;
|
||||
type BlockWeights = RuntimeBlockWeights;
|
||||
type BlockLength = RuntimeBlockLength;
|
||||
type DbWeight = RocksDbWeight;
|
||||
@@ -839,6 +839,14 @@ impl pallet_contracts::Config for Runtime {
|
||||
type Randomness = RandomnessCollectiveFlip;
|
||||
type Currency = Balances;
|
||||
type Event = Event;
|
||||
type Call = Call;
|
||||
/// The safest default is to allow no calls at all.
|
||||
///
|
||||
/// Runtimes should whitelist dispatchables that are allowed to be called from contracts
|
||||
/// and make sure they are stable. Dispatchables exposed to contracts are not allowed to
|
||||
/// change because that would break already deployed contracts. The `Call` structure itself
|
||||
/// is not allowed to change the indices of existing pallets, too.
|
||||
type CallFilter = DenyAll;
|
||||
type RentPayment = ();
|
||||
type SignedClaimHandicap = SignedClaimHandicap;
|
||||
type TombstoneDeposit = TombstoneDeposit;
|
||||
|
||||
@@ -143,7 +143,7 @@ And update the overall definition for weights on frame and a few related types a
|
||||
+const_assert!(NORMAL_DISPATCH_RATIO.deconstruct() >= AVERAGE_ON_INITIALIZE_RATIO.deconstruct());
|
||||
+
|
||||
+impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
+ type BlockWeights = RuntimeBlockWeights;
|
||||
+ type BlockLength = RuntimeBlockLength;
|
||||
+ type DbWeight = RocksDbWeight;
|
||||
|
||||
@@ -43,7 +43,7 @@ parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type Origin = Origin;
|
||||
|
||||
@@ -31,7 +31,7 @@ parameter_types! {
|
||||
frame_system::limits::BlockWeights::simple_max(1024);
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -48,7 +48,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -50,7 +50,7 @@ pub mod pallet {
|
||||
Vec<AuthorityId>,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn next_keys)]
|
||||
/// Keys of the next authority set.
|
||||
@@ -212,7 +212,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -440,7 +440,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -70,7 +70,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -54,7 +54,7 @@ parameter_types! {
|
||||
pub static ExistentialDeposit: u64 = 0;
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = BlockWeights;
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -56,7 +56,7 @@ parameter_types! {
|
||||
pub static ExistentialDeposit: u64 = 0;
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = BlockWeights;
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -64,7 +64,7 @@ parameter_types! {
|
||||
pub static ExistentialDeposit: u64 = 0;
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = BlockWeights;
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -82,7 +82,7 @@ frame_support::construct_runtime!(
|
||||
);
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -59,7 +59,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -986,7 +986,7 @@ mod tests {
|
||||
frame_system::limits::BlockWeights::simple_max(1024);
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -20,6 +20,9 @@ In other words: Upgrading this pallet will not break pre-existing contracts.
|
||||
|
||||
### Added
|
||||
|
||||
- Allow contracts to dispatch calls into the runtime (**unstable**)
|
||||
[#9276](https://github.com/paritytech/substrate/pull/9276)
|
||||
|
||||
- New **unstable** version of `seal_call` that offers more features.
|
||||
[#8909](https://github.com/paritytech/substrate/pull/8909)
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ wat = "1"
|
||||
pallet-balances = { version = "4.0.0-dev", path = "../balances" }
|
||||
pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" }
|
||||
pallet-randomness-collective-flip = { version = "4.0.0-dev", path = "../randomness-collective-flip" }
|
||||
pallet-utility = { version = "4.0.0-dev", path = "../utility" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
|
||||
@@ -37,6 +37,15 @@ use serde::{Serialize, Deserialize};
|
||||
pub struct ContractResult<T> {
|
||||
/// How much gas was consumed during execution.
|
||||
pub gas_consumed: u64,
|
||||
/// How much gas is required as gas limit in order to execute this call.
|
||||
///
|
||||
/// This value should be used to determine the gas limit for on-chain execution.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This can only different from [`Self::gas_consumed`] when weight pre charging
|
||||
/// is used. Currently, only `seal_call_runtime` makes use of pre charging.
|
||||
pub gas_required: u64,
|
||||
/// An optional debug message. This message is only filled when explicitly requested
|
||||
/// by the code that calls into the contract. Otherwise it is empty.
|
||||
///
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
;; This passes its input to `seal_call_runtime` and returns the return value to its caller.
|
||||
(module
|
||||
(import "__unstable__" "seal_call_runtime" (func $seal_call_runtime (param 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 1 1))
|
||||
|
||||
;; 0x1000 = 4k in little endian
|
||||
;; size of input buffer
|
||||
(data (i32.const 0) "\00\10")
|
||||
|
||||
(func (export "call")
|
||||
;; Receive the encoded call
|
||||
(call $seal_input
|
||||
(i32.const 4) ;; Pointer to the input buffer
|
||||
(i32.const 0) ;; Size of the length buffer
|
||||
)
|
||||
;; Just use the call passed as input and store result to memory
|
||||
(i32.store (i32.const 0)
|
||||
(call $seal_call_runtime
|
||||
(i32.const 4) ;; Pointer where the call is stored
|
||||
(i32.load (i32.const 0)) ;; Size of the call
|
||||
)
|
||||
)
|
||||
(call $seal_return
|
||||
(i32.const 0) ;; flags
|
||||
(i32.const 0) ;; returned value
|
||||
(i32.const 4) ;; length of returned value
|
||||
)
|
||||
)
|
||||
|
||||
(func (export "deploy"))
|
||||
)
|
||||
@@ -0,0 +1,37 @@
|
||||
;; This expects [account_id, gas_limit] as input and calls the account_id with the supplied gas_limit.
|
||||
;; It returns the result of the call as output data.
|
||||
(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))
|
||||
|
||||
;; 0x1000 = 4k in little endian
|
||||
;; size of input buffer
|
||||
(data (i32.const 0) "\00\10")
|
||||
|
||||
(func (export "deploy"))
|
||||
|
||||
(func (export "call")
|
||||
;; Receive the encoded call + gas_limit
|
||||
(call $seal_input
|
||||
(i32.const 4) ;; Pointer to the input buffer
|
||||
(i32.const 0) ;; Size of the length buffer
|
||||
)
|
||||
(i32.store
|
||||
(i32.const 0)
|
||||
(call $seal_call
|
||||
(i32.const 4) ;; Pointer to "callee" address.
|
||||
(i32.const 32) ;; Length of "callee" address.
|
||||
(i64.load (i32.const 36)) ;; How much gas to devote for the execution.
|
||||
(i32.const 0) ;; Pointer to the buffer with value to transfer
|
||||
(i32.const 0) ;; 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 0xffffffff) ;; u32 max sentinel value: do not copy output
|
||||
(i32.const 0) ;; Ptr to output buffer len
|
||||
)
|
||||
)
|
||||
(call $seal_return (i32.const 0) (i32.const 0) (i32.const 4))
|
||||
)
|
||||
)
|
||||
@@ -385,7 +385,8 @@ mod tests {
|
||||
}
|
||||
test(r#"{
|
||||
"gasConsumed": 5000,
|
||||
"debugMessage": "0x68656c704f6b",
|
||||
"gasRequired": 8000,
|
||||
"debugMessage": "HelloWorld",
|
||||
"result": {
|
||||
"Ok": {
|
||||
"flags": 5,
|
||||
@@ -395,7 +396,8 @@ mod tests {
|
||||
}"#);
|
||||
test(r#"{
|
||||
"gasConsumed": 3400,
|
||||
"debugMessage": "0x68656c70457272",
|
||||
"gasRequired": 5200,
|
||||
"debugMessage": "HelloWorld",
|
||||
"result": {
|
||||
"Err": "BadOrigin"
|
||||
}
|
||||
@@ -411,7 +413,8 @@ mod tests {
|
||||
}
|
||||
test(r#"{
|
||||
"gasConsumed": 5000,
|
||||
"debugMessage": "0x68656c704f6b",
|
||||
"gasRequired": 8000,
|
||||
"debugMessage": "HelloWorld",
|
||||
"result": {
|
||||
"Ok": {
|
||||
"result": {
|
||||
@@ -425,7 +428,8 @@ mod tests {
|
||||
}"#);
|
||||
test(r#"{
|
||||
"gasConsumed": 3400,
|
||||
"debugMessage": "0x68656c70457272",
|
||||
"gasRequired": 5200,
|
||||
"debugMessage": "HelloWorld",
|
||||
"result": {
|
||||
"Err": "BadOrigin"
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
use crate::{
|
||||
Error,
|
||||
wasm::{Runtime, RuntimeCosts},
|
||||
gas::ChargedAmount,
|
||||
};
|
||||
use codec::{Decode, MaxEncodedLen};
|
||||
use frame_support::weights::Weight;
|
||||
@@ -167,11 +168,22 @@ where
|
||||
/// `weight`. It returns `Err` otherwise. In this case the chain extension should
|
||||
/// abort the execution and pass through the error.
|
||||
///
|
||||
/// The returned value can be used to with [`Self::adjust_weight`]. Other than that
|
||||
/// it has no purpose.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// Weight is synonymous with gas in substrate.
|
||||
pub fn charge_weight(&mut self, amount: Weight) -> Result<()> {
|
||||
self.inner.runtime.charge_gas(RuntimeCosts::ChainExtension(amount)).map(|_| ())
|
||||
pub fn charge_weight(&mut self, amount: Weight) -> Result<ChargedAmount> {
|
||||
self.inner.runtime.charge_gas(RuntimeCosts::ChainExtension(amount))
|
||||
}
|
||||
|
||||
/// 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_weight(&mut self, charged: ChargedAmount, actual_weight: Weight) {
|
||||
self.inner.runtime.adjust_gas(charged, RuntimeCosts::ChainExtension(actual_weight))
|
||||
}
|
||||
|
||||
/// Grants access to the execution environment of the current contract call.
|
||||
|
||||
@@ -28,12 +28,13 @@ use sp_std::{
|
||||
};
|
||||
use sp_runtime::{Perbill, traits::{Convert, Saturating}};
|
||||
use frame_support::{
|
||||
dispatch::{DispatchResult, DispatchError},
|
||||
dispatch::{DispatchResult, DispatchError, DispatchResultWithPostInfo, Dispatchable},
|
||||
storage::{with_transaction, TransactionOutcome},
|
||||
traits::{ExistenceRequirement, Currency, Time, Randomness, Get},
|
||||
traits::{ExistenceRequirement, Currency, Time, Randomness, Get, OriginTrait, Filter},
|
||||
weights::Weight,
|
||||
ensure, DefaultNoBound,
|
||||
};
|
||||
use frame_system::RawOrigin;
|
||||
use pallet_contracts_primitives::{ExecReturnValue};
|
||||
use smallvec::{SmallVec, Array};
|
||||
|
||||
@@ -300,6 +301,9 @@ pub trait Ext: sealing::Sealed {
|
||||
///
|
||||
/// Returns `true` if debug message recording is enabled. Otherwise `false` is returned.
|
||||
fn append_debug_buffer(&mut self, msg: &str) -> bool;
|
||||
|
||||
/// Call some dispatchable and return the result.
|
||||
fn call_runtime(&self, call: <Self::T as Config>::Call) -> DispatchResultWithPostInfo;
|
||||
}
|
||||
|
||||
/// Describes the different functions that can be exported by an [`Executable`].
|
||||
@@ -1291,6 +1295,12 @@ where
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn call_runtime(&self, call: <Self::T as Config>::Call) -> DispatchResultWithPostInfo {
|
||||
let mut origin: T::Origin = RawOrigin::Signed(self.address().clone()).into();
|
||||
origin.add_filter(T::CallFilter::filter);
|
||||
call.dispatch(origin)
|
||||
}
|
||||
}
|
||||
|
||||
fn deposit_event<T: Config>(
|
||||
@@ -1326,10 +1336,10 @@ mod sealing {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
gas::GasMeter, tests::{ExtBuilder, Test, Event as MetaEvent},
|
||||
gas::GasMeter,
|
||||
storage::Storage,
|
||||
tests::{
|
||||
ALICE, BOB, CHARLIE,
|
||||
ALICE, BOB, CHARLIE, Call, TestFilter, ExtBuilder, Test, Event as MetaEvent,
|
||||
test_utils::{place_contract, set_balance, get_balance},
|
||||
},
|
||||
exec::ExportedFunction::*,
|
||||
@@ -1337,12 +1347,15 @@ mod tests {
|
||||
};
|
||||
use codec::{Encode, Decode};
|
||||
use sp_core::Bytes;
|
||||
use sp_runtime::DispatchError;
|
||||
use sp_runtime::{DispatchError, traits::{BadOrigin, Hash}};
|
||||
use assert_matches::assert_matches;
|
||||
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||
use pretty_assertions::{assert_eq, assert_ne};
|
||||
use pallet_contracts_primitives::ReturnFlags;
|
||||
use frame_support::{assert_ok, assert_err};
|
||||
use frame_system::{EventRecord, Phase};
|
||||
|
||||
type System = frame_system::Pallet<Test>;
|
||||
|
||||
type MockStack<'a> = Stack<'a, Test, MockExecutable>;
|
||||
|
||||
@@ -1353,7 +1366,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn events() -> Vec<Event<Test>> {
|
||||
<frame_system::Pallet<Test>>::events()
|
||||
System::events()
|
||||
.into_iter()
|
||||
.filter_map(|meta| match meta.event {
|
||||
MetaEvent::Contracts(contract_event) => Some(contract_event),
|
||||
@@ -2503,4 +2516,114 @@ mod tests {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_runtime_works() {
|
||||
let code_hash = MockLoader::insert(Call, |ctx, _| {
|
||||
let call = Call::System(frame_system::Call::remark_with_event(b"Hello World".to_vec()));
|
||||
ctx.ext.call_runtime(call).unwrap();
|
||||
exec_success()
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let subsistence = Contracts::<Test>::subsistence_threshold();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
set_balance(&ALICE, subsistence * 10);
|
||||
place_contract(&BOB, code_hash);
|
||||
System::reset_events();
|
||||
MockStack::run_call(
|
||||
ALICE,
|
||||
BOB,
|
||||
&mut gas_meter,
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
).unwrap();
|
||||
|
||||
let remark_hash = <Test as frame_system::Config>::Hashing::hash(b"Hello World");
|
||||
assert_eq!(System::events(), vec![
|
||||
EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: MetaEvent::System(frame_system::Event::Remarked(BOB, remark_hash)),
|
||||
topics: vec![],
|
||||
},
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_runtime_filter() {
|
||||
let code_hash = MockLoader::insert(Call, |ctx, _| {
|
||||
use frame_system::Call as SysCall;
|
||||
use pallet_balances::Call as BalanceCall;
|
||||
use pallet_utility::Call as UtilCall;
|
||||
|
||||
// remark should still be allowed
|
||||
let allowed_call = Call::System(SysCall::remark_with_event(b"Hello".to_vec()));
|
||||
|
||||
// transfers are disallowed by the `TestFiler` (see below)
|
||||
let forbidden_call = Call::Balances(BalanceCall::transfer(CHARLIE, 22));
|
||||
|
||||
// simple cases: direct call
|
||||
assert_err!(
|
||||
ctx.ext.call_runtime(forbidden_call.clone()),
|
||||
BadOrigin,
|
||||
);
|
||||
|
||||
// as part of a patch: return is OK (but it interrupted the batch)
|
||||
assert_ok!(
|
||||
ctx.ext.call_runtime(Call::Utility(UtilCall::batch(vec![
|
||||
allowed_call.clone(), forbidden_call, allowed_call
|
||||
]))),
|
||||
);
|
||||
|
||||
// the transfer wasn't performed
|
||||
assert_eq!(get_balance(&CHARLIE), 0);
|
||||
|
||||
exec_success()
|
||||
});
|
||||
|
||||
TestFilter::set_filter(|call| {
|
||||
match call {
|
||||
Call::Balances(pallet_balances::Call::transfer(_, _)) => false,
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let subsistence = Contracts::<Test>::subsistence_threshold();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
|
||||
set_balance(&ALICE, subsistence * 10);
|
||||
place_contract(&BOB, code_hash);
|
||||
System::reset_events();
|
||||
MockStack::run_call(
|
||||
ALICE,
|
||||
BOB,
|
||||
&mut gas_meter,
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
).unwrap();
|
||||
|
||||
let remark_hash = <Test as frame_system::Config>::Hashing::hash(b"Hello");
|
||||
assert_eq!(System::events(), vec![
|
||||
EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: MetaEvent::System(frame_system::Event::Remarked(BOB, remark_hash)),
|
||||
topics: vec![],
|
||||
},
|
||||
EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: MetaEvent::Utility(
|
||||
pallet_utility::Event::BatchInterrupted(1, BadOrigin.into()),
|
||||
),
|
||||
topics: vec![],
|
||||
},
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ pub struct GasMeter<T: Config> {
|
||||
gas_limit: Weight,
|
||||
/// Amount of gas left from initial gas limit. Can reach zero.
|
||||
gas_left: Weight,
|
||||
/// Due to `adjust_gas` and `nested` the `gas_left` can temporarily dip below its final value.
|
||||
gas_left_lowest: Weight,
|
||||
_phantom: PhantomData<T>,
|
||||
#[cfg(test)]
|
||||
tokens: Vec<ErasedToken>,
|
||||
@@ -92,6 +94,7 @@ where
|
||||
GasMeter {
|
||||
gas_limit,
|
||||
gas_left: gas_limit,
|
||||
gas_left_lowest: gas_limit,
|
||||
_phantom: PhantomData,
|
||||
#[cfg(test)]
|
||||
tokens: Vec::new(),
|
||||
@@ -122,6 +125,19 @@ where
|
||||
|
||||
/// Absorb the remaining gas of a nested meter after we are done using it.
|
||||
pub fn absorb_nested(&mut self, nested: Self) {
|
||||
if self.gas_left == 0 {
|
||||
// All of the remaining gas was inherited by the nested gas meter. When absorbing
|
||||
// we can therefore safely inherit the lowest gas that the nested gas meter experienced
|
||||
// as long as it is lower than the lowest gas that was experienced by the parent.
|
||||
// We cannot call `self.gas_left_lowest()` here because in the state that this
|
||||
// code is run the parent gas meter has `0` gas left.
|
||||
self.gas_left_lowest = nested.gas_left_lowest().min(self.gas_left_lowest);
|
||||
} else {
|
||||
// The nested gas meter was created with a fixed amount that did not consume all of the
|
||||
// parents (self) gas. The lowest gas that self will experience is when the nested
|
||||
// gas was pre charged with the fixed amount.
|
||||
self.gas_left_lowest = self.gas_left_lowest();
|
||||
}
|
||||
self.gas_left += nested.gas_left;
|
||||
}
|
||||
|
||||
@@ -163,12 +179,21 @@ where
|
||||
/// 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, token: Tok) {
|
||||
self.gas_left_lowest = self.gas_left_lowest();
|
||||
let adjustment = charged_amount.0.saturating_sub(token.weight());
|
||||
self.gas_left = self.gas_left.saturating_add(adjustment).min(self.gas_limit);
|
||||
}
|
||||
|
||||
/// Returns how much gas was used.
|
||||
pub fn gas_spent(&self) -> Weight {
|
||||
/// Returns the amount of gas that is required to run the same call.
|
||||
///
|
||||
/// This can be different from `gas_spent` because due to `adjust_gas` the amount of
|
||||
/// spent gas can temporarily drop and be refunded later.
|
||||
pub fn gas_required(&self) -> Weight {
|
||||
self.gas_limit - self.gas_left_lowest()
|
||||
}
|
||||
|
||||
/// Returns how much gas was spent
|
||||
pub fn gas_consumed(&self) -> Weight {
|
||||
self.gas_limit - self.gas_left
|
||||
}
|
||||
|
||||
@@ -179,14 +204,15 @@ where
|
||||
|
||||
/// Turn this GasMeter into a DispatchResult that contains the actually used gas.
|
||||
pub fn into_dispatch_result<R, E>(
|
||||
self, result: 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)),
|
||||
actual_weight: Some(self.gas_consumed().saturating_add(base_weight)),
|
||||
pays_fee: Default::default(),
|
||||
};
|
||||
|
||||
@@ -195,6 +221,10 @@ where
|
||||
.map_err(|e| DispatchErrorWithPostInfo { post_info, error: e.into().error })
|
||||
}
|
||||
|
||||
fn gas_left_lowest(&self) -> Weight {
|
||||
self.gas_left_lowest.min(self.gas_left)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn tokens(&self) -> &[ErasedToken] {
|
||||
&self.tokens
|
||||
|
||||
@@ -118,8 +118,9 @@ use sp_runtime::{
|
||||
Perbill,
|
||||
};
|
||||
use frame_support::{
|
||||
traits::{OnUnbalanced, Currency, Get, Time, Randomness},
|
||||
weights::{Weight, PostDispatchInfo, WithPostDispatchInfo},
|
||||
traits::{OnUnbalanced, Currency, Get, Time, Randomness, Filter},
|
||||
weights::{Weight, PostDispatchInfo, WithPostDispatchInfo, GetDispatchInfo},
|
||||
dispatch::Dispatchable,
|
||||
};
|
||||
use frame_system::Pallet as System;
|
||||
use pallet_contracts_primitives::{
|
||||
@@ -154,6 +155,41 @@ pub mod pallet {
|
||||
/// The overarching event type.
|
||||
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
|
||||
|
||||
/// The overarching call type.
|
||||
type Call:
|
||||
Dispatchable<Origin=Self::Origin, PostInfo=PostDispatchInfo> +
|
||||
GetDispatchInfo +
|
||||
codec::Decode +
|
||||
IsType<<Self as frame_system::Config>::Call>;
|
||||
|
||||
/// Filter that is applied to calls dispatched by contracts.
|
||||
///
|
||||
/// Use this filter to control which dispatchables are callable by contracts.
|
||||
/// This is applied in **addition** to [`frame_system::Config::BaseCallFilter`].
|
||||
/// It is recommended to treat this as a whitelist.
|
||||
///
|
||||
/// # Subsistence Threshold
|
||||
///
|
||||
/// The runtime **must** make sure that any allowed dispatchable makes sure that the
|
||||
/// `total_balance` of the contract stays above [`Pallet::subsistence_threshold()`].
|
||||
/// Otherwise contracts can clutter the storage with their tombstones without
|
||||
/// deposting the correct amount of balance.
|
||||
///
|
||||
/// # Stability
|
||||
///
|
||||
/// The runtime **must** make sure that all dispatchables that are callable by
|
||||
/// contracts remain stable. In addition [`Self::Call`] itself must remain stable.
|
||||
/// This means that no existing variants are allowed to switch their positions.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// Note that dispatchables that are called via contracts do not spawn their
|
||||
/// own wasm instance for each call (as opposed to when called via a transaction).
|
||||
/// Therefore please make sure to be restrictive about which dispatchables are allowed
|
||||
/// in order to not introduce a new DoS vector like memory allocation patterns that can
|
||||
/// be exploited to drive the runtime into a panic.
|
||||
type CallFilter: Filter<<Self as frame_system::Config>::Call>;
|
||||
|
||||
/// Handler for rent payments.
|
||||
type RentPayment: OnUnbalanced<NegativeImbalanceOf<Self>>;
|
||||
|
||||
@@ -658,7 +694,8 @@ where
|
||||
);
|
||||
ContractExecResult {
|
||||
result: result.map_err(|r| r.error),
|
||||
gas_consumed: gas_meter.gas_spent(),
|
||||
gas_consumed: gas_meter.gas_consumed(),
|
||||
gas_required: gas_meter.gas_required(),
|
||||
debug_message: debug_message.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
@@ -699,7 +736,8 @@ where
|
||||
Ok(executable) => executable,
|
||||
Err(error) => return ContractInstantiateResult {
|
||||
result: Err(error.into()),
|
||||
gas_consumed: gas_meter.gas_spent(),
|
||||
gas_consumed: gas_meter.gas_consumed(),
|
||||
gas_required: gas_meter.gas_required(),
|
||||
debug_message: Vec::new(),
|
||||
}
|
||||
};
|
||||
@@ -727,7 +765,8 @@ where
|
||||
});
|
||||
ContractInstantiateResult {
|
||||
result: result.map_err(|e| e.error),
|
||||
gas_consumed: gas_meter.gas_spent(),
|
||||
gas_consumed: gas_meter.gas_consumed(),
|
||||
gas_required: gas_meter.gas_required(),
|
||||
debug_message: debug_message.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,13 +40,14 @@ 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},
|
||||
traits::{Currency, ReservableCurrency, OnInitialize, Filter},
|
||||
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 std::cell::RefCell;
|
||||
|
||||
use crate as pallet_contracts;
|
||||
|
||||
@@ -63,6 +64,7 @@ frame_support::construct_runtime!(
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
|
||||
Randomness: pallet_randomness_collective_flip::{Pallet, Storage},
|
||||
Utility: pallet_utility::{Pallet, Call, Storage, Event},
|
||||
Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>},
|
||||
}
|
||||
);
|
||||
@@ -125,7 +127,7 @@ pub mod test_utils {
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static TEST_EXTENSION: sp_std::cell::RefCell<TestExtension> = Default::default();
|
||||
static TEST_EXTENSION: RefCell<TestExtension> = Default::default();
|
||||
}
|
||||
|
||||
pub struct TestExtension {
|
||||
@@ -211,7 +213,7 @@ parameter_types! {
|
||||
pub static ExistentialDeposit: u64 = 0;
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = BlockWeights;
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
@@ -256,6 +258,11 @@ impl pallet_timestamp::Config for Test {
|
||||
type MinimumPeriod = MinimumPeriod;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
impl pallet_utility::Config for Test {
|
||||
type Event = Event;
|
||||
type Call = Call;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
parameter_types! {
|
||||
pub const SignedClaimHandicap: u64 = 2;
|
||||
pub const TombstoneDeposit: u64 = 16;
|
||||
@@ -269,9 +276,6 @@ parameter_types! {
|
||||
pub const DeletionWeightLimit: Weight = 500_000_000_000;
|
||||
pub const MaxCodeSize: u32 = 2 * 1024;
|
||||
pub MySchedule: Schedule<Test> = <Schedule<Test>>::default();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const TransactionByteFee: u64 = 0;
|
||||
}
|
||||
|
||||
@@ -281,11 +285,32 @@ impl Convert<Weight, BalanceOf<Self>> for Test {
|
||||
}
|
||||
}
|
||||
|
||||
/// A filter whose filter function can be swapped at runtime.
|
||||
pub struct TestFilter;
|
||||
|
||||
thread_local! {
|
||||
static CALL_FILTER: RefCell<fn(&Call) -> bool> = RefCell::new(|_| true);
|
||||
}
|
||||
|
||||
impl TestFilter {
|
||||
pub fn set_filter(filter: fn(&Call) -> bool) {
|
||||
CALL_FILTER.with(|fltr| *fltr.borrow_mut() = filter);
|
||||
}
|
||||
}
|
||||
|
||||
impl Filter<Call> for TestFilter {
|
||||
fn filter(call: &Call) -> bool {
|
||||
CALL_FILTER.with(|fltr| fltr.borrow()(call))
|
||||
}
|
||||
}
|
||||
|
||||
impl Config for Test {
|
||||
type Time = Timestamp;
|
||||
type Randomness = Randomness;
|
||||
type Currency = Balances;
|
||||
type Event = Event;
|
||||
type Call = Call;
|
||||
type CallFilter = TestFilter;
|
||||
type RentPayment = ();
|
||||
type SignedClaimHandicap = SignedClaimHandicap;
|
||||
type TombstoneDeposit = TombstoneDeposit;
|
||||
@@ -2944,8 +2969,8 @@ fn debug_message_invalid_utf8() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gas_estimation_correct() {
|
||||
let (caller_code, caller_hash) = compile_module::<Test>("call_return_code").unwrap();
|
||||
fn gas_estimation_nested_call_fixed_limit() {
|
||||
let (caller_code, caller_hash) = compile_module::<Test>("call_with_limit").unwrap();
|
||||
let (callee_code, callee_hash) = compile_module::<Test>("dummy").unwrap();
|
||||
ExtBuilder::default().existential_deposit(50).build().execute_with(|| {
|
||||
let subsistence = Pallet::<Test>::subsistence_threshold();
|
||||
@@ -2976,24 +3001,93 @@ fn gas_estimation_correct() {
|
||||
);
|
||||
let addr_callee = Contracts::contract_address(&ALICE, &callee_hash, &[1]);
|
||||
|
||||
let input: Vec<u8> = AsRef::<[u8]>::as_ref(&addr_callee)
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain((GAS_LIMIT / 5).to_le_bytes())
|
||||
.collect();
|
||||
|
||||
// Call in order to determine the gas that is required for this call
|
||||
let result = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr_caller.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
AsRef::<[u8]>::as_ref(&addr_callee).to_vec(),
|
||||
input.clone(),
|
||||
false,
|
||||
);
|
||||
assert_ok!(result.result);
|
||||
assert_ok!(&result.result);
|
||||
|
||||
assert!(result.gas_required > result.gas_consumed);
|
||||
|
||||
// Make the same call using the estimated gas. Should succeed.
|
||||
assert_ok!(Contracts::bare_call(
|
||||
ALICE,
|
||||
addr_caller,
|
||||
0,
|
||||
result.gas_consumed,
|
||||
AsRef::<[u8]>::as_ref(&addr_callee).to_vec(),
|
||||
result.gas_required,
|
||||
input,
|
||||
false,
|
||||
).result);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn gas_estimation_call_runtime() {
|
||||
let (caller_code, caller_hash) = compile_module::<Test>("call_runtime").unwrap();
|
||||
let (callee_code, callee_hash) = compile_module::<Test>("dummy").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![],
|
||||
vec![0],
|
||||
),
|
||||
);
|
||||
let addr_caller = Contracts::contract_address(&ALICE, &caller_hash, &[0]);
|
||||
|
||||
assert_ok!(
|
||||
Contracts::instantiate_with_code(
|
||||
Origin::signed(ALICE),
|
||||
subsistence * 100,
|
||||
GAS_LIMIT,
|
||||
callee_code,
|
||||
vec![],
|
||||
vec![1],
|
||||
),
|
||||
);
|
||||
let addr_callee = Contracts::contract_address(&ALICE, &callee_hash, &[1]);
|
||||
|
||||
// Call something trivial with a huge gas limit so that we can observe the effects
|
||||
// of pre-charging. This should create a difference between consumed and required.
|
||||
let call = Call::Contracts(crate::Call::call(addr_callee, 0, GAS_LIMIT / 3, vec![]));
|
||||
let result = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr_caller.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
call.encode(),
|
||||
false,
|
||||
);
|
||||
assert_ok!(&result.result);
|
||||
|
||||
assert!(result.gas_required > result.gas_consumed);
|
||||
|
||||
// Make the same call using the required gas. Should succeed.
|
||||
assert_ok!(Contracts::bare_call(
|
||||
ALICE,
|
||||
addr_caller,
|
||||
0,
|
||||
result.gas_required,
|
||||
call.encode(),
|
||||
false,
|
||||
).result);
|
||||
});
|
||||
|
||||
@@ -254,18 +254,22 @@ mod tests {
|
||||
rent::RentStatus,
|
||||
tests::{Test, Call, ALICE, BOB},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::{
|
||||
borrow::BorrowMut,
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
};
|
||||
use sp_core::{Bytes, H256};
|
||||
use hex_literal::hex;
|
||||
use sp_runtime::DispatchError;
|
||||
use frame_support::{assert_ok, dispatch::DispatchResult, weights::Weight};
|
||||
use frame_support::{
|
||||
assert_ok,
|
||||
dispatch::{DispatchResult, DispatchResultWithPostInfo},
|
||||
weights::Weight,
|
||||
};
|
||||
use assert_matches::assert_matches;
|
||||
use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags};
|
||||
use pretty_assertions::assert_eq;
|
||||
use sp_std::borrow::BorrowMut;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct DispatchEntry(Call);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct RestoreEntry {
|
||||
@@ -313,6 +317,7 @@ mod tests {
|
||||
restores: Vec<RestoreEntry>,
|
||||
// (topics, data)
|
||||
events: Vec<(Vec<H256>, Vec<u8>)>,
|
||||
runtime_calls: RefCell<Vec<Call>>,
|
||||
schedule: Schedule<Test>,
|
||||
rent_params: RentParams<Test>,
|
||||
gas_meter: GasMeter<Test>,
|
||||
@@ -335,6 +340,7 @@ mod tests {
|
||||
transfers: Default::default(),
|
||||
restores: Default::default(),
|
||||
events: Default::default(),
|
||||
runtime_calls: Default::default(),
|
||||
schedule: Default::default(),
|
||||
rent_params: Default::default(),
|
||||
gas_meter: GasMeter::new(10_000_000_000),
|
||||
@@ -481,6 +487,10 @@ mod tests {
|
||||
self.debug_buffer.extend(msg.as_bytes());
|
||||
true
|
||||
}
|
||||
fn call_runtime(&self, call: <Self::T as Config>::Call) -> DispatchResultWithPostInfo {
|
||||
self.runtime_calls.borrow_mut().push(call);
|
||||
Ok(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
fn execute<E: BorrowMut<MockExt>>(
|
||||
@@ -2160,4 +2170,81 @@ mod tests {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
const CODE_CALL_RUNTIME: &str = r#"
|
||||
(module
|
||||
(import "__unstable__" "seal_call_runtime" (func $seal_call_runtime (param 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 1 1))
|
||||
|
||||
;; 0x1000 = 4k in little endian
|
||||
;; size of input buffer
|
||||
(data (i32.const 0) "\00\10")
|
||||
|
||||
(func (export "call")
|
||||
;; Receive the encoded call
|
||||
(call $seal_input
|
||||
(i32.const 4) ;; Pointer to the input buffer
|
||||
(i32.const 0) ;; Size of the length buffer
|
||||
)
|
||||
;; Just use the call passed as input and store result to memory
|
||||
(i32.store (i32.const 0)
|
||||
(call $seal_call_runtime
|
||||
(i32.const 4) ;; Pointer where the call is stored
|
||||
(i32.load (i32.const 0)) ;; Size of the call
|
||||
)
|
||||
)
|
||||
(call $seal_return
|
||||
(i32.const 0) ;; flags
|
||||
(i32.const 0) ;; returned value
|
||||
(i32.const 4) ;; length of returned value
|
||||
)
|
||||
)
|
||||
|
||||
(func (export "deploy"))
|
||||
)
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn call_runtime_works() {
|
||||
use std::convert::TryInto;
|
||||
let call = Call::System(frame_system::Call::remark(b"Hello World".to_vec()));
|
||||
let mut ext = MockExt::default();
|
||||
let result = execute(
|
||||
CODE_CALL_RUNTIME,
|
||||
call.encode(),
|
||||
&mut ext,
|
||||
).unwrap();
|
||||
assert_eq!(
|
||||
*ext.runtime_calls.borrow(),
|
||||
vec![call],
|
||||
);
|
||||
// 0 = ReturnCode::Success
|
||||
assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn call_runtime_panics_on_invalid_call() {
|
||||
let mut ext = MockExt::default();
|
||||
let result = execute(
|
||||
CODE_CALL_RUNTIME,
|
||||
vec![0x42],
|
||||
&mut ext,
|
||||
);
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(ExecError {
|
||||
error: Error::<Test>::DecodingFailed.into(),
|
||||
origin: ErrorOrigin::Caller,
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
*ext.runtime_calls.borrow(),
|
||||
vec![],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,9 @@ pub enum ReturnCode {
|
||||
/// recording was disabled.
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
LoggingDisabled = 9,
|
||||
/// The call dispatched by `seal_call_runtime` was executed but returned an error.
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CallRuntimeReturnedError = 10,
|
||||
}
|
||||
|
||||
impl ConvertibleToWasm for ReturnCode {
|
||||
@@ -213,6 +216,12 @@ pub enum RuntimeCosts {
|
||||
HashBlake128(u32),
|
||||
/// Weight charged by a chain extension through `seal_call_chain_extension`.
|
||||
ChainExtension(u64),
|
||||
/// Weight charged for copying data from the sandbox.
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CopyIn(u32),
|
||||
/// Weight charged for calling into the runtime.
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CallRuntime(Weight),
|
||||
}
|
||||
|
||||
impl RuntimeCosts {
|
||||
@@ -273,6 +282,10 @@ impl RuntimeCosts {
|
||||
HashBlake128(len) => s.hash_blake2_128
|
||||
.saturating_add(s.hash_blake2_128_per_byte.saturating_mul(len.into())),
|
||||
ChainExtension(amount) => amount,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CopyIn(len) => s.return_per_byte.saturating_mul(len.into()),
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CallRuntime(weight) => weight,
|
||||
};
|
||||
RuntimeToken {
|
||||
#[cfg(test)]
|
||||
@@ -457,6 +470,15 @@ where
|
||||
self.ext.gas_meter().charge(token)
|
||||
}
|
||||
|
||||
/// 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(&mut self, charged: ChargedAmount, actual_costs: RuntimeCosts) {
|
||||
let token = actual_costs.token(&self.ext.schedule().host_fn_weights);
|
||||
self.ext.gas_meter().adjust_gas(charged, token);
|
||||
}
|
||||
|
||||
/// Read designated chunk from the sandbox memory.
|
||||
///
|
||||
/// Returns `Err` if one of the following conditions occurs:
|
||||
@@ -797,7 +819,6 @@ where
|
||||
// data passed to the supervisor will lead to a trap. This is not documented explicitly
|
||||
// for every function.
|
||||
define_env!(Env, <E: Ext>,
|
||||
|
||||
// Account for used gas. Traps if gas used is greater than gas limit.
|
||||
//
|
||||
// NOTE: This is a implementation defined call and is NOT a part of the public API.
|
||||
@@ -1808,4 +1829,58 @@ define_env!(Env, <E: Ext>,
|
||||
out_ptr, out_len_ptr, &rent_status, false, already_charged
|
||||
)?)
|
||||
},
|
||||
|
||||
// Call some dispatchable of the runtime.
|
||||
//
|
||||
// This function decodes the passed in data as the overarching `Call` type of the
|
||||
// runtime and dispatches it. The weight as specified in the runtime is charged
|
||||
// from the gas meter. Any weight refunds made by the dispatchable are considered.
|
||||
//
|
||||
// The filter specified by `Config::CallFilter` is attached to the origin of
|
||||
// the dispatched call.
|
||||
//
|
||||
// # Parameters
|
||||
//
|
||||
// - `input_ptr`: the pointer into the linear memory where the input data is placed.
|
||||
// - `input_len`: the length of the input data in bytes.
|
||||
//
|
||||
// # Return Value
|
||||
//
|
||||
// Returns `ReturnCode::Success` when the dispatchable was succesfully executed and
|
||||
// returned `Ok`. When the dispatchable was exeuted but returned an error
|
||||
// `ReturnCode::CallRuntimeReturnedError` is returned. The full error is not
|
||||
// provided because it is not guaranteed to be stable.
|
||||
//
|
||||
// # Comparison with `ChainExtension`
|
||||
//
|
||||
// Just as a chain extension this API allows the runtime to extend the functionality
|
||||
// of contracts. While making use of this function is generelly easier it cannot be
|
||||
// used in call cases. Consider writing a chain extension if you need to do perform
|
||||
// one of the following tasks:
|
||||
//
|
||||
// - Return data.
|
||||
// - Provide functionality **exclusively** to contracts.
|
||||
// - Provide custom weights.
|
||||
// - Avoid the need to keep the `Call` data structure stable.
|
||||
//
|
||||
// # Unstable
|
||||
//
|
||||
// This function is unstable and subject to change (or removal) in the future. Do not
|
||||
// deploy a contract using it to a production chain.
|
||||
[__unstable__] seal_call_runtime(ctx, call_ptr: u32, call_len: u32) -> ReturnCode => {
|
||||
use frame_support::{dispatch::GetDispatchInfo, weights::extract_actual_weight};
|
||||
ctx.charge_gas(RuntimeCosts::CopyIn(call_len))?;
|
||||
let call: <E::T as Config>::Call = ctx.read_sandbox_memory_as_unbounded(
|
||||
call_ptr, call_len
|
||||
)?;
|
||||
let dispatch_info = call.get_dispatch_info();
|
||||
let charged = ctx.charge_gas(RuntimeCosts::CallRuntime(dispatch_info.weight))?;
|
||||
let result = ctx.ext.call_runtime(call);
|
||||
let actual_weight = extract_actual_weight(&result, &dispatch_info);
|
||||
ctx.adjust_gas(charged, RuntimeCosts::CallRuntime(actual_weight));
|
||||
match result {
|
||||
Ok(_) => Ok(ReturnCode::Success),
|
||||
Err(_) => Ok(ReturnCode::CallRuntimeReturnedError),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -199,7 +199,7 @@ pub fn witness() -> SolutionOrSnapshotSize {
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type SS58Prefix = ();
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = u64;
|
||||
|
||||
@@ -1123,7 +1123,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = BlockWeights;
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -36,7 +36,7 @@ parameter_types! {
|
||||
frame_system::limits::BlockWeights::simple_max(1024);
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -60,7 +60,7 @@ parameter_types! {
|
||||
frame_system::limits::BlockWeights::simple_max(1024);
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -44,7 +44,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Origin = Origin;
|
||||
type Call = Call;
|
||||
type PalletInfo = PalletInfo;
|
||||
|
||||
@@ -54,7 +54,7 @@ parameter_types! {
|
||||
frame_system::limits::BlockWeights::simple_max(1024);
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -694,7 +694,7 @@ mod tests {
|
||||
};
|
||||
}
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = BlockWeights;
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -48,7 +48,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type Origin = Origin;
|
||||
|
||||
@@ -75,7 +75,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -50,7 +50,7 @@ parameter_types! {
|
||||
frame_system::limits::BlockWeights::simple_max(1024);
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type Origin = Origin;
|
||||
|
||||
@@ -118,7 +118,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -46,7 +46,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -56,7 +56,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -491,7 +491,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -49,7 +49,7 @@ parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Origin = Origin;
|
||||
type Call = Call;
|
||||
type Index = u64;
|
||||
|
||||
@@ -275,7 +275,7 @@ mod tests {
|
||||
frame_system::limits::BlockWeights::simple_max(1024);
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -48,7 +48,7 @@ parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type DbWeight = ();
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
|
||||
@@ -43,7 +43,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -85,7 +85,7 @@ parameter_types! {
|
||||
frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND);
|
||||
}
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = RocksDbWeight;
|
||||
|
||||
@@ -195,7 +195,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = BlockLength;
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -48,7 +48,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -57,7 +57,7 @@ ord_parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -45,7 +45,7 @@ frame_support::construct_runtime!(
|
||||
);
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -228,7 +228,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -69,7 +69,7 @@ ord_parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -42,7 +42,7 @@ frame_support::construct_runtime!(
|
||||
);
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -128,7 +128,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = RocksDbWeight;
|
||||
|
||||
@@ -2684,7 +2684,7 @@ mod tests {
|
||||
type Origin = OuterOrigin;
|
||||
type AccountId = u32;
|
||||
type Call = ();
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockNumber = u32;
|
||||
type PalletInfo = Self;
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -45,6 +45,7 @@ pub use validation::{
|
||||
mod filter;
|
||||
pub use filter::{
|
||||
Filter, FilterStack, FilterStackGuard, ClearFilterGuard, InstanceFilter, IntegrityTest,
|
||||
AllowAll, DenyAll,
|
||||
};
|
||||
|
||||
mod misc;
|
||||
|
||||
@@ -25,10 +25,20 @@ pub trait Filter<T> {
|
||||
fn filter(_: &T) -> bool;
|
||||
}
|
||||
|
||||
impl<T> Filter<T> for () {
|
||||
/// A [`Filter`] that allows any value.
|
||||
pub enum AllowAll {}
|
||||
|
||||
/// A [`Filter`] that denies any value.
|
||||
pub enum DenyAll {}
|
||||
|
||||
impl<T> Filter<T> for AllowAll {
|
||||
fn filter(_: &T) -> bool { true }
|
||||
}
|
||||
|
||||
impl<T> Filter<T> for DenyAll {
|
||||
fn filter(_: &T) -> bool { false }
|
||||
}
|
||||
|
||||
/// Trait to add a constraint onto the filter.
|
||||
pub trait FilterStack<T>: Filter<T> {
|
||||
/// The type used to archive the stack.
|
||||
|
||||
@@ -225,7 +225,7 @@ pub type BlockNumber = u64;
|
||||
pub type Index = u64;
|
||||
|
||||
impl system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Hash = H256;
|
||||
type Origin = Origin;
|
||||
type BlockNumber = BlockNumber;
|
||||
|
||||
@@ -255,7 +255,7 @@ pub type BlockNumber = u64;
|
||||
pub type Index = u64;
|
||||
|
||||
impl system::Config for Runtime {
|
||||
type BaseCallFilter= ();
|
||||
type BaseCallFilter= frame_support::traits::AllowAll;
|
||||
type Hash = H256;
|
||||
type Origin = Origin;
|
||||
type BlockNumber = BlockNumber;
|
||||
|
||||
@@ -158,7 +158,7 @@ pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
|
||||
|
||||
impl system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Hash = H256;
|
||||
type Origin = Origin;
|
||||
type BlockNumber = BlockNumber;
|
||||
|
||||
@@ -448,7 +448,7 @@ frame_support::parameter_types!(
|
||||
);
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = u32;
|
||||
|
||||
@@ -203,7 +203,7 @@ frame_support::parameter_types!(
|
||||
);
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = u32;
|
||||
|
||||
@@ -198,7 +198,7 @@ impl frame_system::Config for Runtime {
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = u32;
|
||||
|
||||
@@ -250,7 +250,7 @@ frame_support::parameter_types!(
|
||||
);
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = u32;
|
||||
|
||||
@@ -144,7 +144,7 @@ frame_support::parameter_types!(
|
||||
);
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = BlockNumber;
|
||||
|
||||
@@ -126,7 +126,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = u64;
|
||||
|
||||
@@ -67,7 +67,7 @@ frame_support::parameter_types! {
|
||||
);
|
||||
}
|
||||
impl system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = BlockLength;
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -39,7 +39,7 @@ frame_support::construct_runtime!(
|
||||
);
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -85,7 +85,7 @@ impl OnKilledAccount<u64> for RecordKilled {
|
||||
}
|
||||
|
||||
impl Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = RuntimeBlockWeights;
|
||||
type BlockLength = RuntimeBlockLength;
|
||||
type Origin = Origin;
|
||||
|
||||
@@ -326,7 +326,7 @@ mod tests {
|
||||
frame_system::limits::BlockWeights::simple_max(1024);
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -58,7 +58,7 @@ parameter_types! {
|
||||
pub const AvailableBlockRatio: Perbill = Perbill::one();
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -715,7 +715,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = BlockWeights;
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -51,7 +51,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type Origin = Origin;
|
||||
|
||||
@@ -54,7 +54,7 @@ parameter_types! {
|
||||
frame_system::limits::BlockWeights::simple_max(1024);
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
|
||||
@@ -43,7 +43,7 @@ parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type Origin = Origin;
|
||||
|
||||
@@ -48,7 +48,7 @@ parameter_types! {
|
||||
impl frame_system::Config for Test {
|
||||
type AccountData = pallet_balances::AccountData<u64>;
|
||||
type AccountId = u64;
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockHashCount = BlockHashCount;
|
||||
type BlockLength = ();
|
||||
type BlockNumber = u64;
|
||||
|
||||
@@ -541,7 +541,7 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type BaseCallFilter = ();
|
||||
type BaseCallFilter = frame_support::traits::AllowAll;
|
||||
type BlockWeights = RuntimeBlockWeights;
|
||||
type BlockLength = RuntimeBlockLength;
|
||||
type Origin = Origin;
|
||||
|
||||
Reference in New Issue
Block a user