contracts: Allow ChainExtension::call() to access &mut self (#11874)

* Give chain extensions the ability to store some temporary values

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

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Rename func_id -> id

* Replace `id` param by two functions on `env`

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
This commit is contained in:
Alexander Theißen
2022-07-25 17:48:01 +02:00
committed by GitHub
parent 626140454d
commit c470e9d11d
6 changed files with 254 additions and 56 deletions
+21 -7
View File
@@ -65,7 +65,7 @@ impl KeyType {
/// This enum can be extended in the future: New codes can be added but existing codes
/// will not be changed or removed. This means that any contract **must not** exhaustively
/// match return codes. Instead, contracts should prepare for unknown variants and deal with
/// those errors gracefuly in order to be forward compatible.
/// those errors gracefully in order to be forward compatible.
#[repr(u32)]
pub enum ReturnCode {
/// API call successful.
@@ -101,8 +101,9 @@ pub enum ReturnCode {
}
impl ConvertibleToWasm for ReturnCode {
type NativeType = Self;
const VALUE_TYPE: ValueType = ValueType::I32;
type NativeType = Self;
fn to_typed_value(self) -> sp_sandbox::Value {
sp_sandbox::Value::I32(self as i32)
}
@@ -439,6 +440,7 @@ pub struct Runtime<'a, E: Ext + 'a> {
input_data: Option<Vec<u8>>,
memory: sp_sandbox::default_executor::Memory,
trap_reason: Option<TrapReason>,
chain_extension: Option<Box<<E::T as Config>::ChainExtension>>,
}
impl<'a, E> Runtime<'a, E>
@@ -452,7 +454,13 @@ where
input_data: Vec<u8>,
memory: sp_sandbox::default_executor::Memory,
) -> Self {
Runtime { ext, input_data: Some(input_data), memory, trap_reason: None }
Runtime {
ext,
input_data: Some(input_data),
memory,
trap_reason: None,
chain_extension: Some(Box::new(Default::default())),
}
}
/// Converts the sandbox result and the runtime state into the execution outcome.
@@ -2006,7 +2014,7 @@ define_env!(Env, <E: Ext>,
// module error.
[seal0] seal_call_chain_extension(
ctx,
func_id: u32,
id: u32,
input_ptr: u32,
input_len: u32,
output_ptr: u32,
@@ -2016,14 +2024,20 @@ define_env!(Env, <E: Ext>,
if !<E::T as Config>::ChainExtension::enabled() {
return Err(Error::<E::T>::NoChainExtension.into());
}
let env = Environment::new(ctx, input_ptr, input_len, output_ptr, output_len_ptr);
match <E::T as Config>::ChainExtension::call(func_id, env)? {
let mut chain_extension = ctx.chain_extension.take().expect(
"Constructor initializes with `Some`. This is the only place where it is set to `None`.\
It is always reset to `Some` afterwards. qed"
);
let env = Environment::new(ctx, id, input_ptr, input_len, output_ptr, output_len_ptr);
let ret = match chain_extension.call(env)? {
RetVal::Converging(val) => Ok(val),
RetVal::Diverging{flags, data} => Err(TrapReason::Return(ReturnData {
flags: flags.bits(),
data,
})),
}
};
ctx.chain_extension = Some(chain_extension);
ret
},
// Emit a custom debug message.