Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
contracts: Allow contracts to dispatch calls into the runtime (#9276)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
athei authored Jul 12, 2021
1 parent 00de218 commit 2543f6f
Show file tree
Hide file tree
Showing 80 changed files with 674 additions and 107 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bin/node-template/pallets/template/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();
Expand Down
2 changes: 1 addition & 1 deletion bin/node-template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
12 changes: 10 additions & 2 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use frame_support::{
},
traits::{
Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, LockIdentifier,
U128CurrencyToVote,
U128CurrencyToVote, AllowAll, DenyAll,
},
};
use frame_system::{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion docs/Upgrading-2.0-to-3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion frame/assets/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion frame/atomic-swap/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/aura/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();
Expand Down
4 changes: 2 additions & 2 deletions frame/authority-discovery/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub mod pallet {
Vec<AuthorityId>,
ValueQuery,
>;

#[pallet::storage]
#[pallet::getter(fn next_keys)]
/// Keys of the next authority set.
Expand Down Expand Up @@ -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 = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/authorship/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/babe/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/balances/src/tests_composite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/balances/src/tests_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/balances/src/tests_reentrancy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/benchmarking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/bounties/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/collective/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ();
Expand Down
3 changes: 3 additions & 0 deletions frame/contracts/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
1 change: 1 addition & 0 deletions frame/contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
9 changes: 9 additions & 0 deletions frame/contracts/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
33 changes: 33 additions & 0 deletions frame/contracts/fixtures/call_runtime.wat
Original file line number Diff line number Diff line change
@@ -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"))
)
37 changes: 37 additions & 0 deletions frame/contracts/fixtures/call_with_limit.wat
Original file line number Diff line number Diff line change
@@ -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))
)
)
12 changes: 8 additions & 4 deletions frame/contracts/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,8 @@ mod tests {
}
test(r#"{
"gasConsumed": 5000,
"debugMessage": "0x68656c704f6b",
"gasRequired": 8000,
"debugMessage": "HelloWorld",
"result": {
"Ok": {
"flags": 5,
Expand All @@ -395,7 +396,8 @@ mod tests {
}"#);
test(r#"{
"gasConsumed": 3400,
"debugMessage": "0x68656c70457272",
"gasRequired": 5200,
"debugMessage": "HelloWorld",
"result": {
"Err": "BadOrigin"
}
Expand All @@ -411,7 +413,8 @@ mod tests {
}
test(r#"{
"gasConsumed": 5000,
"debugMessage": "0x68656c704f6b",
"gasRequired": 8000,
"debugMessage": "HelloWorld",
"result": {
"Ok": {
"result": {
Expand All @@ -425,7 +428,8 @@ mod tests {
}"#);
test(r#"{
"gasConsumed": 3400,
"debugMessage": "0x68656c70457272",
"gasRequired": 5200,
"debugMessage": "HelloWorld",
"result": {
"Err": "BadOrigin"
}
Expand Down
16 changes: 14 additions & 2 deletions frame/contracts/src/chain_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
use crate::{
Error,
wasm::{Runtime, RuntimeCosts},
gas::ChargedAmount,
};
use codec::{Decode, MaxEncodedLen};
use frame_support::weights::Weight;
Expand Down Expand Up @@ -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.
Expand Down
Loading

0 comments on commit 2543f6f

Please sign in to comment.