Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

contracts: Make chain extension state types public #12032

Merged
merged 1 commit into from
Aug 17, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 60 additions & 38 deletions frame/contracts/src/chain_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ pub use crate::{exec::Ext, Config};
pub use frame_system::Config as SysConfig;
pub use pallet_contracts_primitives::ReturnFlags;
pub use sp_core::crypto::UncheckedFrom;
pub use state::Init as InitState;

/// Result that returns a [`DispatchError`] on error.
pub type Result<T> = sp_std::result::Result<T, DispatchError>;
Expand Down Expand Up @@ -198,15 +197,15 @@ pub enum RetVal {
///
/// It uses [typestate programming](https://docs.rust-embedded.org/book/static-guarantees/typestate-programming.html)
/// to enforce the correct usage of the parameters passed to the chain extension.
pub struct Environment<'a, 'b, E: Ext, S: state::State> {
pub struct Environment<'a, 'b, E: Ext, S: State> {
/// The actual data of this type.
inner: Inner<'a, 'b, E>,
/// `S` is only used in the type system but never as value.
phantom: PhantomData<S>,
}

/// Functions that are available in every state of this type.
impl<'a, 'b, E: Ext, S: state::State> Environment<'a, 'b, E, S>
impl<'a, 'b, E: Ext, S: State> Environment<'a, 'b, E, S>
where
<E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
{
Expand Down Expand Up @@ -264,7 +263,7 @@ where
///
/// Those are the functions that determine how the arguments to the chain extensions
/// should be consumed.
impl<'a, 'b, E: Ext> Environment<'a, 'b, E, state::Init> {
impl<'a, 'b, E: Ext> Environment<'a, 'b, E, InitState> {
/// Creates a new environment for consumption by a chain extension.
///
/// It is only available to this crate because only the wasm runtime module needs to
Expand All @@ -284,23 +283,23 @@ impl<'a, 'b, E: Ext> Environment<'a, 'b, E, state::Init> {
}

/// Use all arguments as integer values.
pub fn only_in(self) -> Environment<'a, 'b, E, state::OnlyIn> {
pub fn only_in(self) -> Environment<'a, 'b, E, OnlyInState> {
Environment { inner: self.inner, phantom: PhantomData }
}

/// Use input arguments as integer and output arguments as pointer to a buffer.
pub fn prim_in_buf_out(self) -> Environment<'a, 'b, E, state::PrimInBufOut> {
pub fn prim_in_buf_out(self) -> Environment<'a, 'b, E, PrimInBufOutState> {
Environment { inner: self.inner, phantom: PhantomData }
}

/// Use input and output arguments as pointers to a buffer.
pub fn buf_in_buf_out(self) -> Environment<'a, 'b, E, state::BufInBufOut> {
pub fn buf_in_buf_out(self) -> Environment<'a, 'b, E, BufInBufOutState> {
Environment { inner: self.inner, phantom: PhantomData }
}
}

/// Functions to use the input arguments as integers.
impl<'a, 'b, E: Ext, S: state::PrimIn> Environment<'a, 'b, E, S> {
impl<'a, 'b, E: Ext, S: PrimIn> Environment<'a, 'b, E, S> {
/// The `input_ptr` argument.
pub fn val0(&self) -> u32 {
self.inner.input_ptr
Expand All @@ -313,7 +312,7 @@ impl<'a, 'b, E: Ext, S: state::PrimIn> Environment<'a, 'b, E, S> {
}

/// Functions to use the output arguments as integers.
impl<'a, 'b, E: Ext, S: state::PrimOut> Environment<'a, 'b, E, S> {
impl<'a, 'b, E: Ext, S: PrimOut> Environment<'a, 'b, E, S> {
/// The `output_ptr` argument.
pub fn val2(&self) -> u32 {
self.inner.output_ptr
Expand All @@ -326,7 +325,7 @@ impl<'a, 'b, E: Ext, S: state::PrimOut> Environment<'a, 'b, E, S> {
}

/// Functions to use the input arguments as pointer to a buffer.
impl<'a, 'b, E: Ext, S: state::BufIn> Environment<'a, 'b, E, S>
impl<'a, 'b, E: Ext, S: BufIn> Environment<'a, 'b, E, S>
where
<E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
{
Expand Down Expand Up @@ -389,7 +388,7 @@ where
}

/// Functions to use the output arguments as pointer to a buffer.
impl<'a, 'b, E: Ext, S: state::BufOut> Environment<'a, 'b, E, S>
impl<'a, 'b, E: Ext, S: BufOut> Environment<'a, 'b, E, S>
where
<E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
{
Expand Down Expand Up @@ -438,31 +437,54 @@ struct Inner<'a, 'b, E: Ext> {
output_len_ptr: u32,
}

/// Private submodule with public types to prevent other modules from naming them.
mod state {
pub trait State {}

pub trait PrimIn: State {}
pub trait PrimOut: State {}
pub trait BufIn: State {}
pub trait BufOut: State {}

/// The initial state of an [`Environment`](`super::Environment`).
/// See [typestate programming](https://docs.rust-embedded.org/book/static-guarantees/typestate-programming.html).
pub enum Init {}
pub enum OnlyIn {}
pub enum PrimInBufOut {}
pub enum BufInBufOut {}

impl State for Init {}
impl State for OnlyIn {}
impl State for PrimInBufOut {}
impl State for BufInBufOut {}

impl PrimIn for OnlyIn {}
impl PrimOut for OnlyIn {}
impl PrimIn for PrimInBufOut {}
impl BufOut for PrimInBufOut {}
impl BufIn for BufInBufOut {}
impl BufOut for BufInBufOut {}
/// Any state of an [`Environment`] implements this trait.
/// See [typestate programming](https://docs.rust-embedded.org/book/static-guarantees/typestate-programming.html).
pub trait State: sealed::Sealed {}

/// A state that uses primitive inputs.
pub trait PrimIn: State {}

/// A state that uses primitive outputs.
pub trait PrimOut: State {}

/// A state that uses a buffer as input.
pub trait BufIn: State {}

/// A state that uses a buffer as output.
pub trait BufOut: State {}

/// The initial state of an [`Environment`].
pub enum InitState {}

/// A state that uses all arguments as primitive inputs.
pub enum OnlyInState {}

/// A state that uses two arguments as primitive inputs and the other two as buffer output.
pub enum PrimInBufOutState {}

/// Uses a buffer for input and a buffer for output.
pub enum BufInBufOutState {}

mod sealed {
use super::*;

/// Trait to prevent users from implementing `State` for anything else.
pub trait Sealed {}

impl Sealed for InitState {}
impl Sealed for OnlyInState {}
impl Sealed for PrimInBufOutState {}
impl Sealed for BufInBufOutState {}

impl State for InitState {}
impl State for OnlyInState {}
impl State for PrimInBufOutState {}
impl State for BufInBufOutState {}

impl PrimIn for OnlyInState {}
impl PrimOut for OnlyInState {}
impl PrimIn for PrimInBufOutState {}
impl BufOut for PrimInBufOutState {}
impl BufIn for BufInBufOutState {}
impl BufOut for BufInBufOutState {}
}