Unverified Commit ba5aed19 authored by Hero Bird's avatar Hero Bird Committed by GitHub
Browse files

Sync with Substrate RC6 (#478)



* [core] remove get_runtime_storage and invoke_runtime

* [core] invalidate all implementations and usages of ext functions

* [core] adjust ext_ functions in ext.rs

* [core] add ReturnFlags to public API

* [core] remove off-chain impls for get_runtime_storage and invoke_runtime

* [core] rename ext::ext_input -> ext::input

* [core] change return type of get_contract_storage

Previously returned Option<Result<R>> and now returns Result<Option<R>>.
This change is more pragmatic.

* [core] add conversion from ext::Error to EnvError

* [core] on-chain: add new utilities for static buffer modifications

- EncodeScope: for efficiently appending encoded values
- ScopedBuffer: for efficiently chunking buffers

* [core] add impls for on-chain property getters

* [core] remove no longer needed utiltiy function

* [core] on-chain: new impl for invoke_contract and eval_contract

* [core] on-chain: new impl for get_contract_storage

* [core] on-chain: new impl for decode_input

We should also rename this to simply "input" later.

* [core] on-chain: new impl for output

Now also uses the new ReturnFlags abstraction.

* [core] on-chain: new impl for instantiate_contract

* [core] on-chain: remove unused API

* [core] on-chain: move EncodeScope and ScopedBuffer to buffer.rs

* [core] on-chain: implement rest of the on-chain API

* [core] add ScopedBuffer::take_bytes

* [core] Add Env::call_chain_extension trait method

* [core] remove unused helper methods

* [core] on-chain: simplify static buffer

- No more length
- No more encodable
- Only full range access

* [core] add env::call_chain_extension public API

* [core] rename Env::output -> return_value

* [core] off-chain: adjust a bunch of off-chain methods to new interfaces

* [core] off-chain: adjust get_contract_storage return type

* [core] off-chain: remove RuntimeCallHandler and RuntimeStorage facilities

* [core] off-chain: adjust some tests

* [core] off-chain: remove OffCall utility type

* [core] off-chain: implement chain extension handler

* [core] adjust panic message

* [core] apply rustfmt

* [core] apply clippy suggestion

* [core] off-chain: re-export ChainExtension and ChainSpec types from test API

* [core] on-chain: retain panic messages

* [core] rename ext_ to seal_ for all on-chain functions

* [alloc] fix some warnings and add some minor comments

* [core] add wasm_import_module = "seal0"

* [core] introduce new Seal error codes

* [core] directly return ReturnCode from C-FII

* [core] make transfer return Result

* [core] improve some doc comments

* rename some old errors to their new names

* [core] remove unused env errors and rename some off-chain errors

* [core] fix bug in ReturnFlags::set_reverted (formerly known as set_trapped)

* [core] avoid From impl for () for OffChainError

* [lang] adjust lang layer for changes in core

- Remove invoke_runtime
- Remove get_runtime_storage
- Rename gas_price -> weight_to_fee
- Add ReturnFlags to return_value call

* [core] turn redundant asserts into debug_assert

* [core] be more strict when handling ext::get_storage error

* [core] implement clippy suggestion

* [examples] remove no longer useful runtime-storage contract

We no longer support the get_runtime_storage host function.
It will eventually be reintroduced at a later point through chain extensions.

* [core] disable chain extensions by default

Can be enabled by experimental crate feature:
- unstable_chain_extensions

* [lang] apply clippy suggestion to use matches! macro

* [core] fix docs for ext_return
Co-authored-by: Alexander Theißen's avatarAlexander Theißen <alex.theissen@me.com>

* [core] fix return type of api::return_value

Not sure why the compiler didn't mention this return type failure ...
Co-authored-by: Alexander Theißen's avatarAlexander Theißen <alex.theissen@me.com>

* [core] fix doc comment of Env::return_value

* [core] introduce RawReturnCode as a layer between Seal error codes and ink!

* [alloc] make #[alloc_error_handler] private

* [alloc, core] move alloc_handler from ink_alloc to ink_core

* [core] replace useless intermediate ReturnCode type

* [core] rename RawReturnCode -> ReturnCode

* [core] apply rustfmt

* [core] apply rustfmt

* [core] off-chain: rename invoke -> eval for chain extension calling

* [core] use Ptr32 and Ptr32Mut to encapsulate pointer -> u32 conversions

* [core] make new Ptr32 and Ptr32Mut abstractions more type safe
Co-authored-by: Alexander Theißen's avatarAlexander Theißen <alex.theissen@me.com>
parent eeb6bc0f
Pipeline #104772 canceled with stages
in 5 minutes and 42 seconds
// Copyright 2018-2019 Parity Technologies (UK) Ltd. // Copyright 2018-2020 Parity Technologies (UK) Ltd.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
...@@ -12,14 +12,7 @@ ...@@ -12,14 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#[panic_handler]
pub fn panic(_info: &core::panic::PanicInfo) -> ! {
core::intrinsics::abort()
}
// `extern` fn uses type `core::alloc::Layout`, which is not FFI-safe
#[allow(improper_ctypes)]
#[alloc_error_handler] #[alloc_error_handler]
pub extern "C" fn oom(_: core::alloc::Layout) -> ! { fn oom(_: core::alloc::Layout) -> ! {
core::intrinsics::abort() core::intrinsics::abort()
} }
// Copyright 2018-2019 Parity Technologies (UK) Ltd. // Copyright 2018-2020 Parity Technologies (UK) Ltd.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc_error_handler, core_intrinsics))] #![cfg_attr(not(feature = "std"), feature(alloc_error_handler, core_intrinsics))]
// Use `wee_alloc` as the global allocator. // We use `wee_alloc` as the global allocator since it is optimized for binary file size
// so that contracts compiled with it as allocator do not grow too much in size.
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
#[global_allocator] #[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
......
...@@ -73,6 +73,7 @@ std = [ ...@@ -73,6 +73,7 @@ std = [
"blake2", "blake2",
] ]
ink-fuzz-tests = ["std"] ink-fuzz-tests = ["std"]
ink-unstable-chain-extensions = []
[[bench]] [[bench]]
name = "bench_lazy" name = "bench_lazy"
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
use crate::env::{ use crate::env::{
backend::{ backend::{
Env, Env,
ReturnFlags,
TypedEnv, TypedEnv,
}, },
call::{ call::{
...@@ -65,12 +66,12 @@ where ...@@ -65,12 +66,12 @@ where
/// # Errors /// # Errors
/// ///
/// If the returned value cannot be properly decoded. /// If the returned value cannot be properly decoded.
pub fn gas_price<T>(gas: u64) -> Result<T::Balance> pub fn weight_to_fee<T>(gas: u64) -> Result<T::Balance>
where where
T: EnvTypes, T: EnvTypes,
{ {
<EnvInstance as OnInstance>::on_instance(|instance| { <EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnv::gas_price::<T>(instance, gas) TypedEnv::weight_to_fee::<T>(instance, gas)
}) })
} }
...@@ -208,6 +209,10 @@ where ...@@ -208,6 +209,10 @@ where
} }
/// Writes the value to the contract storage under the given key. /// Writes the value to the contract storage under the given key.
///
/// # Panics
///
/// - If the encode length of value exceeds the configured maximum value length of a storage entry.
pub fn set_contract_storage<V>(key: &Key, value: &V) pub fn set_contract_storage<V>(key: &Key, value: &V)
where where
V: scale::Encode, V: scale::Encode,
...@@ -221,8 +226,8 @@ where ...@@ -221,8 +226,8 @@ where
/// ///
/// # Errors /// # Errors
/// ///
/// - If the decoding of the typed value failed /// - If the decoding of the typed value failed (`KeyNotFound`)
pub fn get_contract_storage<R>(key: &Key) -> Option<Result<R>> pub fn get_contract_storage<R>(key: &Key) -> Result<Option<R>>
where where
R: scale::Decode, R: scale::Decode,
{ {
...@@ -238,25 +243,6 @@ pub fn clear_contract_storage(key: &Key) { ...@@ -238,25 +243,6 @@ pub fn clear_contract_storage(key: &Key) {
}) })
} }
/// Invokes a call to the runtime.
///
/// # Note
///
/// The call is not guaranteed to execute immediately but might be deferred
/// to the end of the contract execution.
///
/// # Errors
///
/// - If the called runtime function does not exist.
pub fn invoke_runtime<T>(params: &T::Call) -> Result<()>
where
T: EnvTypes,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnv::invoke_runtime::<T>(instance, params)
})
}
/// Invokes a contract message. /// Invokes a contract message.
/// ///
/// # Note /// # Note
...@@ -268,7 +254,8 @@ where ...@@ -268,7 +254,8 @@ where
/// ///
/// # Errors /// # Errors
/// ///
/// - If the called contract does not exist. /// - If the called account does not exist.
/// - If the called account is not a contract.
/// - If the called contract is a tombstone. /// - If the called contract is a tombstone.
/// - If arguments passed to the called contract message are invalid. /// - If arguments passed to the called contract message are invalid.
/// - If the called contract execution has trapped. /// - If the called contract execution has trapped.
...@@ -292,7 +279,8 @@ where ...@@ -292,7 +279,8 @@ where
/// ///
/// # Errors /// # Errors
/// ///
/// - If the called contract does not exist. /// - If the called account does not exist.
/// - If the called account is not a contract.
/// - If the called contract is a tombstone. /// - If the called contract is a tombstone.
/// - If arguments passed to the called contract message are invalid. /// - If arguments passed to the called contract message are invalid.
/// - If the called contract execution has trapped. /// - If the called contract execution has trapped.
...@@ -424,7 +412,7 @@ where ...@@ -424,7 +412,7 @@ where
/// contract call or invoke a runtime function that performs the /// contract call or invoke a runtime function that performs the
/// transaction. /// transaction.
/// ///
/// # Errors /// # Panics
/// ///
/// If the contract doesn't have sufficient funds. /// If the contract doesn't have sufficient funds.
pub fn transfer<T>(destination: T::AccountId, value: T::Balance) -> Result<()> pub fn transfer<T>(destination: T::AccountId, value: T::Balance) -> Result<()>
...@@ -436,6 +424,27 @@ where ...@@ -436,6 +424,27 @@ where
}) })
} }
/// Calls the chain extension with the given ID and inputs.
///
/// Returns the given output type.
///
/// # Errors
///
/// - If the given function ID does not exist in the runtime.
/// - If the given inputs cannot be properly decoded by the runtime.
/// - If the given output type cannot be properly decoded by the contract.
/// - If some chain extension specific conditions are not met.
#[cfg(feature = "ink-unstable-chain-extensions")]
pub fn call_chain_extension<I, O>(func_id: u32, input: &I) -> Result<O>
where
I: scale::Codec + 'static,
O: scale::Codec + 'static,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
Env::call_chain_extension(instance, func_id, input)
})
}
/// Returns the execution input to the executed contract and decodes it as `T`. /// Returns the execution input to the executed contract and decodes it as `T`.
/// ///
/// # Note /// # Note
...@@ -470,14 +479,13 @@ where ...@@ -470,14 +479,13 @@ where
/// ///
/// # Note /// # Note
/// ///
/// This call must be the last call to the contract /// This function stops the execution of the contract immediately.
/// environment for every contract execution. pub fn return_value<R>(return_flags: ReturnFlags, return_value: &R) -> !
pub fn output<R>(return_value: &R)
where where
R: scale::Encode, R: scale::Encode,
{ {
<EnvInstance as OnInstance>::on_instance(|instance| { <EnvInstance as OnInstance>::on_instance(|instance| {
Env::output::<R>(instance, return_value) Env::return_value::<R>(instance, return_flags, return_value)
}) })
} }
...@@ -505,20 +513,6 @@ pub fn println(content: &str) { ...@@ -505,20 +513,6 @@ pub fn println(content: &str) {
<EnvInstance as OnInstance>::on_instance(|instance| Env::println(instance, content)) <EnvInstance as OnInstance>::on_instance(|instance| Env::println(instance, content))
} }
/// Returns the value from the *runtime* storage at the position of the key if any.
///
/// # Errors
///
/// - If the decoding of the typed value failed
pub fn get_runtime_storage<R>(runtime_key: &[u8]) -> Option<Result<R>>
where
R: scale::Decode,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
Env::get_runtime_storage::<R>(instance, runtime_key)
})
}
/// Built-in efficient cryptographic hash functions. /// Built-in efficient cryptographic hash functions.
pub mod hash { pub mod hash {
use super::*; use super::*;
......
...@@ -24,6 +24,33 @@ use crate::env::{ ...@@ -24,6 +24,33 @@ use crate::env::{
}; };
use ink_primitives::Key; use ink_primitives::Key;
/// The flags to indicate further information about the end of a contract execution.
pub struct ReturnFlags {
value: u32,
}
impl Default for ReturnFlags {
fn default() -> Self {
Self { value: 0 }
}
}
impl ReturnFlags {
/// Sets the bit to indicate that the execution is going to be reverted.
pub fn set_reverted(mut self, has_reverted: bool) -> Self {
match has_reverted {
true => self.value |= has_reverted as u32,
false => self.value &= !has_reverted as u32,
}
self
}
/// Returns the underlying `u32` representation.
pub(crate) fn into_u32(self) -> u32 {
self.value
}
}
/// Environmental contract functionality that does not require `EnvTypes`. /// Environmental contract functionality that does not require `EnvTypes`.
pub trait Env { pub trait Env {
/// Writes the value to the contract storage under the given key. /// Writes the value to the contract storage under the given key.
...@@ -36,22 +63,13 @@ pub trait Env { ...@@ -36,22 +63,13 @@ pub trait Env {
/// # Errors /// # Errors
/// ///
/// - If the decoding of the typed value failed /// - If the decoding of the typed value failed
fn get_contract_storage<R>(&mut self, key: &Key) -> Option<Result<R>> fn get_contract_storage<R>(&mut self, key: &Key) -> Result<Option<R>>
where where
R: scale::Decode; R: scale::Decode;
/// Clears the contract's storage key entry. /// Clears the contract's storage key entry.
fn clear_contract_storage(&mut self, key: &Key); fn clear_contract_storage(&mut self, key: &Key);
/// Returns the value from the *runtime* storage at the position of the key if any.
///
/// # Errors
///
/// - If the decoding of the typed value failed
fn get_runtime_storage<R>(&mut self, runtime_key: &[u8]) -> Option<Result<R>>
where
R: scale::Decode;
/// Returns the execution input to the executed contract and decodes it as `T`. /// Returns the execution input to the executed contract and decodes it as `T`.
/// ///
/// # Note /// # Note
...@@ -83,10 +101,12 @@ pub trait Env { ...@@ -83,10 +101,12 @@ pub trait Env {
/// ///
/// # Note /// # Note
/// ///
/// The setting of this property must be the last interaction between /// Calling this method will end contract execution immediately.
/// the executed contract and its environment. /// It will return the given return value back to its caller.
/// The environment access asserts this guarantee. ///
fn output<R>(&mut self, return_value: &R) /// The `flags` parameter can be used to revert the state changes of the
/// entire execution if necessary.
fn return_value<R>(&mut self, flags: ReturnFlags, return_value: &R) -> !
where where
R: scale::Encode; R: scale::Encode;
...@@ -108,6 +128,22 @@ pub trait Env { ...@@ -108,6 +128,22 @@ pub trait Env {
/// Conducts the BLAKE2 128-bit hash of the input /// Conducts the BLAKE2 128-bit hash of the input
/// puts the result into the output buffer. /// puts the result into the output buffer.
fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]); fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]);
/// Calls the chain extension with the given ID and inputs.
///
/// Returns the output of the chain extension of the specified type.
///
/// # Errors
///
/// - If the chain extension with the given ID does not exist.
/// - If the inputs had an unexpected encoding.
/// - If the output could not be properly decoded.
/// - If some extension specific condition has not been met.
#[cfg(feature = "ink-unstable-chain-extensions")]
fn call_chain_extension<I, O>(&mut self, func_id: u32, input: &I) -> Result<O>
where
I: scale::Codec + 'static,
O: scale::Codec + 'static;
} }
/// Environmental contract functionality. /// Environmental contract functionality.
...@@ -131,7 +167,7 @@ pub trait TypedEnv: Env { ...@@ -131,7 +167,7 @@ pub trait TypedEnv: Env {
/// # Note /// # Note
/// ///
/// For more details visit: [`ink_core::env::gas_price`] /// For more details visit: [`ink_core::env::gas_price`]
fn gas_price<T: EnvTypes>(&mut self, gas: u64) -> Result<T::Balance>; fn weight_to_fee<T: EnvTypes>(&mut self, gas: u64) -> Result<T::Balance>;
/// Returns the amount of gas left for the contract execution. /// Returns the amount of gas left for the contract execution.
/// ///
...@@ -208,15 +244,6 @@ pub trait TypedEnv: Env { ...@@ -208,15 +244,6 @@ pub trait TypedEnv: Env {
where where
T: EnvTypes; T: EnvTypes;
/// Invokes a call of the runtime.
///
/// # Note
///
/// For more details visit: [`ink_core::env::invoke_runtime`]
fn invoke_runtime<T>(&mut self, call: &T::Call) -> Result<()>
where
T: EnvTypes;
/// Invokes a contract message. /// Invokes a contract message.
/// ///
/// # Note /// # Note
......
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
//
// 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 super::OffChainError;
use crate::env::Result;
use std::collections::HashMap;
type FuncId = u32;
/// Types implementing this trait can be used as chain extensions.
///
/// This trait is only useful for testing contract via the off-chain environment.
pub trait ChainExtension {
/// The expected input type.
///
/// # Note
///
/// This can be a tuple to expect multiple input types.
type Input: scale::Codec;
/// The expected output type.
type Output: scale::Codec;
/// The static function ID of the chain extension.
///
/// # Note
///
/// This is expected to return a constant value.
fn func_id(&self) -> u32;
/// Calls the chain extension with the given input.
fn call(&mut self, input: &Self::Input) -> Result<Self::Output>;
}
/// A raw chain extension function.
///
/// This is mostly a wrapper closure around the real chain extension function
/// that handles marshalling of types between their encoded and decoded
/// representations.
type ChainExtensionFn = Box<dyn FnMut(Vec<u8>) -> Result<Vec<u8>>>;
/// Runtime call handler.
///
/// More generically a mapping from bytes to bytes.
pub struct ChainExtensionHandler {
/// The currently registered runtime call handler.
registered: HashMap<FuncId, ChainExtensionFn>,
}
impl ChainExtensionHandler {
/// Creates a new chain extension handler.
///
/// Initialized with an empty set of chain extensions.
pub fn new() -> Self {
Self {
registered: HashMap::new(),
}
}
/// Resets the chain extension handler to uninitialized state.
pub fn reset(&mut self) {
self.registered.clear()
}
/// Register a new chain extension.
pub fn register<I, O>(
&mut self,
mut extension: Box<dyn ChainExtension<Input = I, Output = O>>,
) where
I: scale::Codec + 'static,
O: scale::Codec + 'static,
{
let func_id = extension.func_id();
self.registered.insert(
func_id,
Box::new(move |encoded_input: Vec<u8>| {
let decoded_input = scale::Decode::decode(&mut &encoded_input[..])?;
let decoded_output = extension.call(&decoded_input)?;
Ok(scale::Encode::encode(&decoded_output))
}),
);
}
/// Evaluates the chain extension with the given parameters.
///
/// Upon success returns the values returned by the evaluated chain extension.
pub fn eval<I, O>(&mut self, func_id: FuncId, input: &I) -> Result<O>
where
I: scale::Codec + 'static,
O: scale::Codec + 'static,
{
use std::collections::hash_map::Entry;
match self.registered.entry(func_id) {
Entry::Occupied(mut occupied) => {
let encoded_input = scale::Encode::encode(input);
let encoded_output = occupied.get_mut()(encoded_input)?;
scale::Decode::decode(&mut &encoded_output[..]).map_err(Into::into)
}
Entry::Vacant(_vacant) => {
Err(OffChainError::UnregisteredChainExtension.into())
}
}
}
}
...@@ -247,13 +247,12 @@ impl Account { ...@@ -247,13 +247,12 @@ impl Account {
} }
/// Returns the value stored in the contract storage at the given key. /// Returns the value stored in the contract storage at the given key.
pub fn get_storage<T>(&self, at: Key) -> Option<Result<T>> pub fn get_storage<T>(&self, at: Key) -> Result<Option<T>>
where where
T: scale::Decode, T: scale::Decode,
{ {
self.contract_or_err() self.contract_or_err()
.and_then(|contract| contract.storage.get_storage::<T>(at)) .and_then(|contract| contract.storage.get_storage::<T>(at))
.transpose()
} }
/// Returns the total number of reads and write from and to the contract's storage. /// Returns the total number of reads and write from and to the contract's storage.
......
...@@ -27,11 +27,12 @@ use crate::env::{ ...@@ -27,11 +27,12 @@ use crate::env::{
EnvError, EnvError,
EnvTypes, EnvTypes,
Result, Result,
ReturnFlags,
Topics, Topics,
TypedEnv, TypedEnv,
}; };
use ink_primitives::Key;
use core::convert::TryInto; use core::convert::TryInto;
use ink_primitives::Key;
use num_traits::Bounded; use num_traits::Bounded;
impl EnvInstance { impl EnvInstance {
...@@ -70,13 +71,13 @@ impl Env for EnvInstance { ...@@ -70,13 +71,13 @@ impl Env for EnvInstance {
.expect("callee account is not a smart contract"); .expect("callee account is not a smart contract");
} }
fn get_contract_storage<R>(&mut self, key: &Key) -> Option<Result<R>> fn get_contract_storage<R>(&mut self, key: &Key) -> Result<Option<R>>
where where
R: scale::Decode, R: scale::Decode,
{ {
self.callee_account() self.callee_account()
.get_storage::<R>(*key)