contracts: Refactor instantiate with code (#14503)

* wip

* fixes

* rm comment

* join fns

* clippy

* Fix limits

* reduce diff

* fix

* fix

* fix typo

* refactor store to  use self

* refactor run to take self by value

* pass tests

* rm comment

* fixes

* fix typo

* rm

* fix fmt

* clippy

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts

* Update frame/contracts/src/lib.rs

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

* Update frame/contracts/src/wasm/mod.rs

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

* Update frame/contracts/src/wasm/mod.rs

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

* PR review, rm duplicate increment_refcount

* PR review

* Update frame/contracts/src/wasm/prepare.rs

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

* Add test for failing storage_deposit

* fix lint

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts

---------

Co-authored-by: command-bot <>
Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>
This commit is contained in:
PG Herveou
2023-07-07 15:46:16 +02:00
committed by GitHub
parent 9510ad7310
commit d3ef2badcb
7 changed files with 780 additions and 809 deletions
+17 -36
View File
@@ -41,21 +41,6 @@ use wasmi::{
/// compiler toolchains might not support specifying other modules than "env" for memory imports.
pub const IMPORT_MODULE_MEMORY: &str = "env";
/// Determines whether a module should be instantiated during preparation.
pub enum TryInstantiate {
/// Do the instantiation to make sure that the module is valid.
///
/// This should be used if a module is only uploaded but not executed. We need
/// to make sure that it can be actually instantiated.
Instantiate,
/// Skip the instantiation during preparation.
///
/// This makes sense when the preparation takes place as part of an instantiation. Then
/// this instantiation would fail the whole transaction and an extra check is not
/// necessary.
Skip,
}
/// The inner deserialized module is valid and contains only allowed WebAssembly features.
/// This is checked by loading it into wasmi interpreter `engine`.
pub struct LoadedModule {
@@ -237,7 +222,6 @@ fn validate<E, T>(
code: &[u8],
schedule: &Schedule<T>,
determinism: Determinism,
try_instantiate: TryInstantiate,
) -> Result<(), (DispatchError, &'static str)>
where
E: Environment<()>,
@@ -261,23 +245,22 @@ where
//
// - It doesn't use any unknown imports.
// - It doesn't explode the wasmi bytecode generation.
if matches!(try_instantiate, TryInstantiate::Instantiate) {
// We don't actually ever run any code so we can get away with a minimal stack which
// reduces the amount of memory that needs to be zeroed.
let stack_limits = StackLimits::new(1, 1, 0).expect("initial <= max; qed");
WasmBlob::<T>::instantiate::<E, _>(
&code,
(),
schedule,
determinism,
stack_limits,
AllowDeprecatedInterface::No,
)
.map_err(|err| {
log::debug!(target: LOG_TARGET, "{}", err);
(Error::<T>::CodeRejected.into(), "New code rejected on wasmi instantiation!")
})?;
}
//
// We don't actually ever execute this instance so we can get away with a minimal stack which
// reduces the amount of memory that needs to be zeroed.
let stack_limits = StackLimits::new(1, 1, 0).expect("initial <= max; qed");
WasmBlob::<T>::instantiate::<E, _>(
&code,
(),
schedule,
determinism,
stack_limits,
AllowDeprecatedInterface::No,
)
.map_err(|err| {
log::debug!(target: LOG_TARGET, "{}", err);
(Error::<T>::CodeRejected.into(), "New code rejected on wasmi instantiation!")
})?;
Ok(())
}
@@ -295,13 +278,12 @@ pub fn prepare<E, T>(
schedule: &Schedule<T>,
owner: AccountIdOf<T>,
determinism: Determinism,
try_instantiate: TryInstantiate,
) -> Result<WasmBlob<T>, (DispatchError, &'static str)>
where
E: Environment<()>,
T: Config,
{
validate::<E, T>(code.as_ref(), schedule, determinism, try_instantiate)?;
validate::<E, T>(code.as_ref(), schedule, determinism)?;
// Calculate deposit for storing contract code and `code_info` in two different storage items.
let bytes_added = code.len().saturating_add(<CodeInfo<T>>::max_encoded_len()) as u32;
@@ -416,7 +398,6 @@ mod tests {
&schedule,
ALICE,
Determinism::Enforced,
TryInstantiate::Instantiate,
);
assert_matches::assert_matches!(r.map_err(|(_, msg)| msg), $($expected)*);
}