contracts: Replace cargo feature unstable-interface with config (#12787)

* Replace cargo feature with config

* Update frame/contracts/proc-macro/src/lib.rs

Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>

Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>
This commit is contained in:
Alexander Theißen
2022-11-30 14:19:14 +00:00
committed by GitHub
parent ec064e5edf
commit edce3ead3b
10 changed files with 94 additions and 66 deletions
@@ -64,7 +64,7 @@ where
struct EmptyEnv;
impl Environment<()> for EmptyEnv {
fn define(_store: &mut Store<()>, _linker: &mut Linker<()>) -> Result<(), LinkerError> {
fn define(_: &mut Store<()>, _: &mut Linker<()>, _: bool) -> Result<(), LinkerError> {
Ok(())
}
}
+14
View File
@@ -326,10 +326,24 @@ pub mod pallet {
/// The maximum length of a contract code in bytes. This limit applies to the instrumented
/// version of the code. Therefore `instantiate_with_code` can fail even when supplying
/// a wasm binary below this maximum size.
#[pallet::constant]
type MaxCodeLen: Get<u32>;
/// The maximum allowable length in bytes for storage keys.
#[pallet::constant]
type MaxStorageKeyLen: Get<u32>;
/// Make contract callable functions marked as `#[unstable]` available.
///
/// Contracts that use `#[unstable]` functions won't be able to be uploaded unless
/// this is set to `true`. This is only meant for testnets and dev nodes in order to
/// experiment with new features.
///
/// # Warning
///
/// Do **not** set to `true` on productions chains.
#[pallet::constant]
type UnsafeUnstableInterface: Get<bool>;
}
#[pallet::hooks]
+8 -4
View File
@@ -122,6 +122,12 @@ pub mod test_utils {
}
}
impl Test {
pub fn set_unstable_interface(unstable_interface: bool) {
UNSTABLE_INTERFACE.with(|v| *v.borrow_mut() = unstable_interface);
}
}
parameter_types! {
static TestExtensionTestValue: TestExtension = Default::default();
}
@@ -385,6 +391,7 @@ impl Contains<RuntimeCall> for TestFilter {
parameter_types! {
pub const DeletionWeightLimit: Weight = Weight::from_ref_time(500_000_000_000);
pub static UnstableInterface: bool = true;
}
impl Config for Test {
@@ -407,6 +414,7 @@ impl Config for Test {
type AddressGenerator = DefaultAddressGenerator;
type MaxCodeLen = ConstU32<{ 128 * 1024 }>;
type MaxStorageKeyLen = ConstU32<128>;
type UnsafeUnstableInterface = UnstableInterface;
}
pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]);
@@ -2687,7 +2695,6 @@ fn gas_estimation_nested_call_fixed_limit() {
}
#[test]
#[cfg(feature = "unstable-interface")]
fn gas_estimation_call_runtime() {
use codec::Decode;
let (caller_code, caller_hash) = compile_module::<Test>("call_runtime").unwrap();
@@ -4411,7 +4418,6 @@ fn delegate_call_indeterministic_code() {
}
#[test]
#[cfg(feature = "unstable-interface")]
fn reentrance_count_works_with_call() {
let (wasm, code_hash) = compile_module::<Test>("reentrance_count_call").unwrap();
let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
@@ -4448,7 +4454,6 @@ fn reentrance_count_works_with_call() {
}
#[test]
#[cfg(feature = "unstable-interface")]
fn reentrance_count_works_with_delegated_call() {
let (wasm, code_hash) = compile_module::<Test>("reentrance_count_delegated_call").unwrap();
let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
@@ -4485,7 +4490,6 @@ fn reentrance_count_works_with_delegated_call() {
}
#[test]
#[cfg(feature = "unstable-interface")]
fn account_reentrance_count_works() {
let (wasm, code_hash) = compile_module::<Test>("account_reentrance_count_call").unwrap();
let (wasm_reentrance_count, code_hash_reentrance_count) =
+44 -12
View File
@@ -36,7 +36,7 @@ use crate::{
};
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::dispatch::{DispatchError, DispatchResult};
use sp_core::crypto::UncheckedFrom;
use sp_core::{crypto::UncheckedFrom, Get};
use sp_runtime::RuntimeDebug;
use sp_std::prelude::*;
#[cfg(test)]
@@ -218,7 +218,7 @@ where
let module = Module::new(&engine, code)?;
let mut store = Store::new(&engine, host_state);
let mut linker = Linker::new();
E::define(&mut store, &mut linker)?;
E::define(&mut store, &mut linker, T::UnsafeUnstableInterface::get())?;
let memory = Memory::new(&mut store, MemoryType::new(memory.0, Some(memory.1))?).expect(
"The limits defined in our `Schedule` limit the amount of memory well below u32::MAX; qed",
);
@@ -627,10 +627,17 @@ mod tests {
}
}
fn execute<E: BorrowMut<MockExt>>(wat: &str, input_data: Vec<u8>, mut ext: E) -> ExecResult {
fn execute_internal<E: BorrowMut<MockExt>>(
wat: &str,
input_data: Vec<u8>,
mut ext: E,
unstable_interface: bool,
) -> ExecResult {
type RuntimeConfig = <MockExt as Ext>::T;
RuntimeConfig::set_unstable_interface(unstable_interface);
let wasm = wat::parse_str(wat).unwrap();
let schedule = crate::Schedule::default();
let executable = PrefabWasmModule::<<MockExt as Ext>::T>::from_code(
let executable = PrefabWasmModule::<RuntimeConfig>::from_code(
wasm,
&schedule,
ALICE,
@@ -641,6 +648,19 @@ mod tests {
executable.execute(ext.borrow_mut(), &ExportedFunction::Call, input_data)
}
fn execute<E: BorrowMut<MockExt>>(wat: &str, input_data: Vec<u8>, ext: E) -> ExecResult {
execute_internal(wat, input_data, ext, false)
}
#[cfg(not(feature = "runtime-benchmarks"))]
fn execute_with_unstable<E: BorrowMut<MockExt>>(
wat: &str,
input_data: Vec<u8>,
ext: E,
) -> ExecResult {
execute_internal(wat, input_data, ext, true)
}
const CODE_TRANSFER: &str = r#"
(module
;; seal_transfer(
@@ -741,7 +761,6 @@ mod tests {
}
#[test]
#[cfg(feature = "unstable-interface")]
fn contract_delegate_call() {
const CODE: &str = r#"
(module
@@ -2274,7 +2293,6 @@ mod tests {
);
}
#[cfg(feature = "unstable-interface")]
const CODE_CALL_RUNTIME: &str = r#"
(module
(import "seal0" "call_runtime" (func $call_runtime (param i32 i32) (result i32)))
@@ -2311,7 +2329,6 @@ mod tests {
"#;
#[test]
#[cfg(feature = "unstable-interface")]
fn call_runtime_works() {
let call =
RuntimeCall::System(frame_system::Call::remark { remark: b"Hello World".to_vec() });
@@ -2323,7 +2340,6 @@ mod tests {
}
#[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);
@@ -2586,7 +2602,6 @@ mod tests {
}
#[test]
#[cfg(feature = "unstable-interface")]
fn take_storage_works() {
const CODE: &str = r#"
(module
@@ -2822,7 +2837,6 @@ mod tests {
}
#[test]
#[cfg(feature = "unstable-interface")]
fn caller_is_origin_works() {
const CODE_CALLER_IS_ORIGIN: &str = r#"
;; This runs `caller_is_origin` check on zero account address
@@ -2894,7 +2908,6 @@ mod tests {
}
#[test]
#[cfg(feature = "unstable-interface")]
fn reentrance_count_works() {
const CODE: &str = r#"
(module
@@ -2927,7 +2940,6 @@ mod tests {
}
#[test]
#[cfg(feature = "unstable-interface")]
fn account_reentrance_count_works() {
const CODE: &str = r#"
(module
@@ -2958,4 +2970,24 @@ mod tests {
let mut mock_ext = MockExt::default();
execute(CODE, vec![], &mut mock_ext).unwrap();
}
/// This test check that an unstable interface cannot be deployed. In case of runtime
/// benchmarks we always allow unstable interfaces. This is why this test does not
/// work when this feature is enabled.
#[cfg(not(feature = "runtime-benchmarks"))]
#[test]
fn cannot_deploy_unstable() {
const CANNT_DEPLOY_UNSTABLE: &str = r#"
(module
(import "seal0" "reentrance_count" (func $reentrance_count (result i32)))
(func (export "call"))
(func (export "deploy"))
)
"#;
assert_err!(
execute(CANNT_DEPLOY_UNSTABLE, vec![], MockExt::default()),
<Error<Test>>::CodeRejected,
);
assert_ok!(execute_with_unstable(CANNT_DEPLOY_UNSTABLE, vec![], MockExt::default()));
}
}
@@ -46,6 +46,7 @@ pub trait Environment<HostState> {
fn define(
store: &mut Store<HostState>,
linker: &mut Linker<HostState>,
allow_unstable: bool,
) -> Result<(), LinkerError>;
}
@@ -105,7 +106,6 @@ pub enum ReturnCode {
/// recording was disabled.
LoggingDisabled = 9,
/// The call dispatched by `seal_call_runtime` was executed but returned an error.
#[cfg(feature = "unstable-interface")]
CallRuntimeReturnedError = 10,
/// ECDSA pubkey recovery failed (most probably wrong recovery id or signature), or
/// ECDSA compressed pubkey conversion into Ethereum address failed (most probably
@@ -228,7 +228,6 @@ pub enum RuntimeCosts {
/// Weight of calling `seal_get_storage` with the specified size in storage.
GetStorage(u32),
/// Weight of calling `seal_take_storage` for the given size.
#[cfg(feature = "unstable-interface")]
TakeStorage(u32),
/// Weight of calling `seal_transfer`.
Transfer,
@@ -257,17 +256,14 @@ pub enum RuntimeCosts {
/// Weight charged by a chain extension through `seal_call_chain_extension`.
ChainExtension(u64),
/// Weight charged for calling into the runtime.
#[cfg(feature = "unstable-interface")]
CallRuntime(Weight),
/// Weight of calling `seal_set_code_hash`
SetCodeHash,
/// Weight of calling `ecdsa_to_eth_address`
EcdsaToEthAddress,
/// Weight of calling `reentrance_count`
#[cfg(feature = "unstable-interface")]
ReentrantCount,
/// Weight of calling `account_reentrance_count`
#[cfg(feature = "unstable-interface")]
AccountEntranceCount,
}
@@ -316,7 +312,6 @@ impl RuntimeCosts {
.saturating_add(s.contains_storage_per_byte.saturating_mul(len.into())),
GetStorage(len) =>
s.get_storage.saturating_add(s.get_storage_per_byte.saturating_mul(len.into())),
#[cfg(feature = "unstable-interface")]
TakeStorage(len) => s
.take_storage
.saturating_add(s.take_storage_per_byte.saturating_mul(len.into())),
@@ -344,13 +339,10 @@ impl RuntimeCosts {
.saturating_add(s.hash_blake2_128_per_byte.saturating_mul(len.into())),
EcdsaRecovery => s.ecdsa_recover,
ChainExtension(amount) => amount,
#[cfg(feature = "unstable-interface")]
CallRuntime(weight) => weight.ref_time(),
SetCodeHash => s.set_code_hash,
EcdsaToEthAddress => s.ecdsa_to_eth_address,
#[cfg(feature = "unstable-interface")]
ReentrantCount => s.reentrance_count,
#[cfg(feature = "unstable-interface")]
AccountEntranceCount => s.account_reentrance_count,
};
RuntimeToken {