contracts: Refactor the runtime API in order to simplify node integration (#7409)

* contracts: Make use of existing type aliases for runtime API types

* contracts: Refactor the contracts call runtime API

* review: Fix comment typo

Co-authored-by: Andrew Jones <ascjones@gmail.com>

* Update frame/contracts/common/src/lib.rs

Co-authored-by: Nikolay Volf <nikvolf@gmail.com>

* Update frame/contracts/common/src/lib.rs

Co-authored-by: Nikolay Volf <nikvolf@gmail.com>

* Update frame/contracts/common/src/lib.rs

Co-authored-by: Nikolay Volf <nikvolf@gmail.com>

* Update frame/contracts/common/src/lib.rs

Co-authored-by: Nikolay Volf <nikvolf@gmail.com>

* Update frame/contracts/common/src/lib.rs

Co-authored-by: Nikolay Volf <nikvolf@gmail.com>

* Update lib.rs

* review: Group crate imports

Co-authored-by: Andrew Jones <ascjones@gmail.com>
Co-authored-by: Addie Wagenknecht <addie@nortd.com>
Co-authored-by: Nikolay Volf <nikvolf@gmail.com>
This commit is contained in:
Alexander Theißen
2020-10-29 15:57:56 +01:00
committed by GitHub
parent bd450c24ff
commit a5ec7e5c4e
14 changed files with 143 additions and 161 deletions
@@ -34,6 +34,7 @@ use frame_system::{Module as System, RawOrigin};
use parity_wasm::elements::{Instruction, ValueType, BlockType};
use sp_runtime::traits::{Hash, Bounded};
use sp_std::{default::Default, convert::{TryInto}};
use pallet_contracts_primitives::RentProjection;
/// How many batches we do per API benchmark.
const API_BENCHMARK_BATCHES: u32 = 20;
+1 -59
View File
@@ -19,7 +19,6 @@ use crate::{
TrieId, BalanceOf, ContractInfo, TrieIdGenerator,
gas::GasMeter, rent, storage, Error, ContractInfoOf
};
use bitflags::bitflags;
use sp_std::prelude::*;
use sp_runtime::traits::{Bounded, Zero, Convert, Saturating};
use frame_support::{
@@ -28,6 +27,7 @@ use frame_support::{
weights::Weight,
ensure, StorageMap,
};
use pallet_contracts_primitives::{ErrorOrigin, ExecError, ExecReturnValue, ExecResult, ReturnFlags};
pub type AccountIdOf<T> = <T as frame_system::Trait>::AccountId;
pub type MomentOf<T> = <<T as Trait>::Time as Time>::Moment;
@@ -38,14 +38,6 @@ pub type StorageKey = [u8; 32];
/// A type that represents a topic of an event. At the moment a hash is used.
pub type TopicOf<T> = <T as frame_system::Trait>::Hash;
bitflags! {
/// Flags used by a contract to customize exit behaviour.
pub struct ReturnFlags: u32 {
/// If this bit is set all changes made by the contract exection are rolled back.
const REVERT = 0x0000_0001;
}
}
/// Describes whether we deal with a contract or a plain account.
pub enum TransactorKind {
/// Transaction was initiated from a plain account. That can be either be through a
@@ -55,56 +47,6 @@ pub enum TransactorKind {
Contract,
}
/// Output of a contract call or instantiation which ran to completion.
#[cfg_attr(test, derive(PartialEq, Eq, Debug))]
pub struct ExecReturnValue {
/// Flags passed along by `seal_return`. Empty when `seal_return` was never called.
pub flags: ReturnFlags,
/// Buffer passed along by `seal_return`. Empty when `seal_return` was never called.
pub data: Vec<u8>,
}
impl ExecReturnValue {
/// We understand the absense of a revert flag as success.
pub fn is_success(&self) -> bool {
!self.flags.contains(ReturnFlags::REVERT)
}
}
/// Call or instantiate both call into other contracts and pass through errors happening
/// in those to the caller. This enum is for the caller to distinguish whether the error
/// happened during the execution of the callee or in the current execution context.
#[cfg_attr(test, derive(PartialEq, Eq, Debug))]
pub enum ErrorOrigin {
/// The error happened in the current exeuction context rather than in the one
/// of the contract that is called into.
Caller,
/// The error happened during execution of the called contract.
Callee,
}
/// Error returned by contract exection.
#[cfg_attr(test, derive(PartialEq, Eq, Debug))]
pub struct ExecError {
/// The reason why the execution failed.
pub error: DispatchError,
/// Origin of the error.
pub origin: ErrorOrigin,
}
impl<T: Into<DispatchError>> From<T> for ExecError {
fn from(error: T) -> Self {
Self {
error: error.into(),
origin: ErrorOrigin::Caller,
}
}
}
/// The result that is returned from contract execution. It either contains the output
/// buffer or an error describing the reason for failure.
pub type ExecResult = Result<ExecReturnValue, ExecError>;
/// An interface that provides access to the external environment in which the
/// smart-contract is executed.
///
+2 -1
View File
@@ -14,12 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::{Trait, exec::ExecError};
use crate::Trait;
use sp_std::marker::PhantomData;
use sp_runtime::traits::Zero;
use frame_support::dispatch::{
DispatchResultWithPostInfo, PostDispatchInfo, DispatchErrorWithPostInfo,
};
use pallet_contracts_primitives::ExecError;
#[cfg(test)]
use std::{any::Any, fmt::Debug};
+14 -16
View File
@@ -97,7 +97,6 @@ use crate::exec::ExecutionContext;
use crate::wasm::{WasmLoader, WasmVm};
pub use crate::gas::{Gas, GasMeter};
pub use crate::exec::{ExecResult, ExecReturnValue};
pub use crate::wasm::ReturnCode as RuntimeReturnCode;
pub use crate::weight_info::WeightInfo;
pub use crate::schedule::{Schedule, HostFnWeights, InstructionWeights};
@@ -118,7 +117,9 @@ use frame_support::{
traits::{OnUnbalanced, Currency, Get, Time, Randomness},
};
use frame_system::{ensure_signed, ensure_root};
use pallet_contracts_primitives::{RentProjection, ContractAccessError};
use pallet_contracts_primitives::{
RentProjectionResult, GetStorageResult, ContractAccessError, ContractExecResult, ExecResult,
};
use frame_support::weights::Weight;
pub type CodeHash<T> = <T as frame_system::Trait>::Hash;
@@ -639,21 +640,20 @@ impl<T: Trait> Module<T> {
value: BalanceOf<T>,
gas_limit: Gas,
input_data: Vec<u8>,
) -> (ExecResult, Gas) {
) -> ContractExecResult {
let mut gas_meter = GasMeter::new(gas_limit);
(
Self::execute_wasm(origin, &mut gas_meter, |ctx, gas_meter| {
ctx.call(dest, value, gas_meter, input_data)
}),
gas_meter.gas_spent(),
)
let exec_result = Self::execute_wasm(origin, &mut gas_meter, |ctx, gas_meter| {
ctx.call(dest, value, gas_meter, input_data)
});
let gas_consumed = gas_meter.gas_spent();
ContractExecResult {
exec_result,
gas_consumed,
}
}
/// Query storage of a specified contract under a specified key.
pub fn get_storage(
address: T::AccountId,
key: [u8; 32],
) -> sp_std::result::Result<Option<Vec<u8>>, ContractAccessError> {
pub fn get_storage(address: T::AccountId, key: [u8; 32]) -> GetStorageResult {
let contract_info = ContractInfoOf::<T>::get(&address)
.ok_or(ContractAccessError::DoesntExist)?
.get_alive()
@@ -663,9 +663,7 @@ impl<T: Trait> Module<T> {
Ok(maybe_value)
}
pub fn rent_projection(
address: T::AccountId,
) -> sp_std::result::Result<RentProjection<T::BlockNumber>, ContractAccessError> {
pub fn rent_projection(address: T::AccountId) -> RentProjectionResult<T::BlockNumber> {
rent::compute_rent_projection::<T>(&address)
}
+13 -13
View File
@@ -1655,7 +1655,7 @@ fn crypto_hashes() {
0,
GAS_LIMIT,
params,
).0.unwrap();
).exec_result.unwrap();
assert!(result.is_success());
let expected = hash_fn(input.as_ref());
assert_eq!(&result.data[..*expected_size], &*expected);
@@ -1688,7 +1688,7 @@ fn transfer_return_code() {
0,
GAS_LIMIT,
vec![],
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold);
// Contract has enough total balance in order to not go below the subsistence
@@ -1702,7 +1702,7 @@ fn transfer_return_code() {
0,
GAS_LIMIT,
vec![],
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::TransferFailed);
});
}
@@ -1735,7 +1735,7 @@ fn call_return_code() {
0,
GAS_LIMIT,
vec![0],
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::NotCallable);
assert_ok!(
@@ -1755,7 +1755,7 @@ fn call_return_code() {
0,
GAS_LIMIT,
vec![0],
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold);
// Contract has enough total balance in order to not go below the subsistence
@@ -1769,7 +1769,7 @@ fn call_return_code() {
0,
GAS_LIMIT,
vec![0],
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::TransferFailed);
// Contract has enough balance but callee reverts because "1" is passed.
@@ -1780,7 +1780,7 @@ fn call_return_code() {
0,
GAS_LIMIT,
vec![1],
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::CalleeReverted);
// Contract has enough balance but callee traps because "2" is passed.
@@ -1790,7 +1790,7 @@ fn call_return_code() {
0,
GAS_LIMIT,
vec![2],
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::CalleeTrapped);
});
@@ -1825,7 +1825,7 @@ fn instantiate_return_code() {
0,
GAS_LIMIT,
vec![0; 33],
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold);
// Contract has enough total balance in order to not go below the subsistence
@@ -1839,7 +1839,7 @@ fn instantiate_return_code() {
0,
GAS_LIMIT,
vec![0; 33],
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::TransferFailed);
// Contract has enough balance but the passed code hash is invalid
@@ -1850,7 +1850,7 @@ fn instantiate_return_code() {
0,
GAS_LIMIT,
vec![0; 33],
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::CodeNotFound);
// Contract has enough balance but callee reverts because "1" is passed.
@@ -1860,7 +1860,7 @@ fn instantiate_return_code() {
0,
GAS_LIMIT,
callee_hash.iter().cloned().chain(sp_std::iter::once(1)).collect(),
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::CalleeReverted);
// Contract has enough balance but callee traps because "2" is passed.
@@ -1870,7 +1870,7 @@ fn instantiate_return_code() {
0,
GAS_LIMIT,
callee_hash.iter().cloned().chain(sp_std::iter::once(2)).collect(),
).0.unwrap();
).exec_result.unwrap();
assert_return_code!(result, RuntimeReturnCode::CalleeTrapped);
});
+5 -3
View File
@@ -19,7 +19,7 @@
use crate::{CodeHash, Schedule, Trait};
use crate::wasm::env_def::FunctionImplProvider;
use crate::exec::{Ext, ExecResult};
use crate::exec::Ext;
use crate::gas::GasMeter;
use sp_std::prelude::*;
@@ -34,6 +34,7 @@ mod runtime;
use self::runtime::{to_execution_result, Runtime};
use self::code_cache::load as load_code;
use pallet_contracts_primitives::ExecResult;
pub use self::code_cache::save as save_code;
#[cfg(feature = "runtime-benchmarks")]
@@ -155,7 +156,7 @@ mod tests {
use super::*;
use std::collections::HashMap;
use sp_core::H256;
use crate::exec::{Ext, StorageKey, ExecReturnValue, ReturnFlags, ExecError, ErrorOrigin};
use crate::exec::{Ext, StorageKey};
use crate::gas::{Gas, GasMeter};
use crate::tests::{Test, Call};
use crate::wasm::prepare::prepare_contract;
@@ -163,6 +164,7 @@ mod tests {
use hex_literal::hex;
use sp_runtime::DispatchError;
use frame_support::weights::Weight;
use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags, ExecError, ErrorOrigin};
const GAS_LIMIT: Gas = 10_000_000_000;
@@ -1361,7 +1363,7 @@ mod tests {
;; size of our buffer is 128 bytes
(data (i32.const 160) "\80")
(func $assert (param i32)
(block $ok
(br_if $ok
@@ -16,12 +16,12 @@
//! Environment definition of the wasm smart-contract runtime.
use crate::{HostFnWeights, Schedule, Trait, CodeHash, BalanceOf, Error};
use crate::exec::{
Ext, ExecResult, ExecReturnValue, StorageKey, TopicOf, ReturnFlags, ExecError
use crate::{
HostFnWeights, Schedule, Trait, CodeHash, BalanceOf, Error,
exec::{Ext, StorageKey, TopicOf},
gas::{Gas, GasMeter, Token, GasMeterResult},
wasm::env_def::ConvertibleToWasm,
};
use crate::gas::{Gas, GasMeter, Token, GasMeterResult};
use crate::wasm::env_def::ConvertibleToWasm;
use sp_sandbox;
use parity_wasm::elements::ValueType;
use frame_system;
@@ -35,6 +35,7 @@ use sp_io::hashing::{
blake2_128,
sha2_256,
};
use pallet_contracts_primitives::{ExecResult, ExecReturnValue, ReturnFlags, ExecError};
/// Every error that can be returned to a contract when it calls any of the host functions.
#[repr(u32)]
@@ -499,7 +500,7 @@ fn err_into_return_code<T: Trait>(from: DispatchError) -> Result<ReturnCode, Dis
/// Fallible conversion of a `ExecResult` to `ReturnCode`.
fn exec_into_return_code<T: Trait>(from: ExecResult) -> Result<ReturnCode, DispatchError> {
use crate::exec::ErrorOrigin::Callee;
use pallet_contracts_primitives::ErrorOrigin::Callee;
let ExecError { error, origin } = match from {
Ok(retval) => return Ok(retval.into()),