feat: Rebrand Polkadot/Substrate references to PezkuwiChain

This commit systematically rebrands various references from Parity Technologies'
Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk.

Key changes include:
- Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks.
- Modified internal documentation and code comments to reflect PezkuwiChain naming and structure.
- Replaced direct references to  with  or specific paths within the  for XCM, Pezkuwi, and other modules.
- Cleaned up deprecated  issue and PR references in various  and  files, particularly in  and  modules.
- Adjusted image and logo URLs in documentation to point to PezkuwiChain assets.
- Removed or rephrased comments related to external Polkadot/Substrate PRs and issues.

This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
2025-12-14 00:04:10 +03:00
parent 286de54384
commit 1c0e57d984
9084 changed files with 997839 additions and 997557 deletions
@@ -0,0 +1,62 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Traits required by the runtime interface from the host side.
use crate::RIType;
use pezsp_wasm_interface::{FunctionContext, Result};
/// A type used as a return value in a host function. Can be turned into an FFI value.
pub trait IntoFFIValue: RIType {
/// Convert `Self::Inner` into an FFI value.
fn into_ffi_value(
value: Self::Inner,
context: &mut dyn FunctionContext,
) -> Result<Self::FFIType>;
}
/// A type used as a parameter in a host function. Can be created from an FFI value.
///
/// Implementations are safe to assume that the `arg` given to `from_ffi_value`
/// is only generated by the corresponding [`wasm::IntoFFIValue`](crate::wasm::IntoFFIValue)
/// implementation.
pub trait FromFFIValue<'a>: RIType {
/// The owned inner type.
type Owned;
/// Creates `Self::Owned` from the given `arg` received through the FFI boundary from the
/// runtime.
fn from_ffi_value(context: &mut dyn FunctionContext, arg: Self::FFIType)
-> Result<Self::Owned>;
/// Creates `Self::Inner` from an owned value.
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner;
/// Write back a modified `value` back into the runtime's memory.
///
/// Only makes sense for parameters like e.g. `&mut [u8]`.
#[inline]
fn write_back_into_runtime(
_value: Self::Owned,
_context: &mut dyn FunctionContext,
_arg: Self::FFIType,
) -> Result<()> {
// Default dummy implementation, because the vast majority of impls won't need this.
Ok(())
}
}
@@ -0,0 +1,193 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Provides implementations for the runtime interface types which can be
//! passed directly without any serialization strategy wrappers.
#[cfg(not(bizinikiwi_runtime))]
use crate::host::*;
#[cfg(bizinikiwi_runtime)]
use crate::wasm::*;
use crate::{Pointer, RIType};
#[cfg(not(bizinikiwi_runtime))]
use pezsp_wasm_interface::{FunctionContext, Result};
// Make sure that our assumptions for storing a pointer + its size in `u64` is valid.
#[cfg(all(bizinikiwi_runtime, not(feature = "disable_target_static_assertions")))]
const _: () = {
assert!(core::mem::size_of::<usize>() == core::mem::size_of::<u32>());
assert!(core::mem::size_of::<*const u8>() == core::mem::size_of::<u32>());
};
/// Implement the traits for the given primitive traits.
macro_rules! impl_traits_for_primitives {
(
$(
$rty:ty, $fty:ty,
)*
) => {
$(
/// The type is passed directly.
impl RIType for $rty {
type FFIType = $fty;
type Inner = Self;
}
#[cfg(bizinikiwi_runtime)]
impl IntoFFIValue for $rty {
type Destructor = ();
fn into_ffi_value(value: &mut $rty) -> (Self::FFIType, Self::Destructor) {
(*value as $fty, ())
}
}
#[cfg(bizinikiwi_runtime)]
impl FromFFIValue for $rty {
fn from_ffi_value(arg: $fty) -> $rty {
arg as $rty
}
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a> FromFFIValue<'a> for $rty {
type Owned = Self;
fn from_ffi_value(_: &mut dyn FunctionContext, arg: $fty) -> Result<$rty> {
Ok(arg as $rty)
}
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
*owned
}
}
#[cfg(not(bizinikiwi_runtime))]
impl IntoFFIValue for $rty {
fn into_ffi_value(value: Self::Inner, _: &mut dyn FunctionContext) -> Result<$fty> {
Ok(value as $fty)
}
}
)*
}
}
impl_traits_for_primitives! {
u8, u32,
u16, u32,
u32, u32,
u64, u64,
i8, i32,
i16, i32,
i32, i32,
i64, i64,
}
/// `bool` is passed as `u32`.
///
/// - `1`: true
/// - `0`: false
impl RIType for bool {
type FFIType = u32;
type Inner = Self;
}
#[cfg(bizinikiwi_runtime)]
impl IntoFFIValue for bool {
type Destructor = ();
fn into_ffi_value(value: &mut bool) -> (Self::FFIType, Self::Destructor) {
(if *value { 1 } else { 0 }, ())
}
}
#[cfg(bizinikiwi_runtime)]
impl FromFFIValue for bool {
fn from_ffi_value(arg: u32) -> bool {
arg == 1
}
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a> FromFFIValue<'a> for bool {
type Owned = Self;
fn from_ffi_value(_: &mut dyn FunctionContext, arg: u32) -> Result<bool> {
Ok(arg == 1)
}
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
*owned
}
}
#[cfg(not(bizinikiwi_runtime))]
impl IntoFFIValue for bool {
fn into_ffi_value(value: Self, _: &mut dyn FunctionContext) -> Result<u32> {
Ok(if value { 1 } else { 0 })
}
}
#[cfg(not(bizinikiwi_runtime))]
impl<T: pezsp_wasm_interface::PointerType> RIType for Pointer<T> {
type FFIType = u32;
type Inner = Self;
}
/// The type is passed as `u32`.
#[cfg(bizinikiwi_runtime)]
impl<T> RIType for Pointer<T> {
type FFIType = u32;
type Inner = Self;
}
#[cfg(bizinikiwi_runtime)]
impl<T> IntoFFIValue for Pointer<T> {
type Destructor = ();
fn into_ffi_value(value: &mut Pointer<T>) -> (Self::FFIType, Self::Destructor) {
(*value as u32, ())
}
}
#[cfg(bizinikiwi_runtime)]
impl<T> FromFFIValue for Pointer<T> {
fn from_ffi_value(arg: u32) -> Self {
arg as _
}
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a, T: pezsp_wasm_interface::PointerType> FromFFIValue<'a> for Pointer<T> {
type Owned = Self;
fn from_ffi_value(_: &mut dyn FunctionContext, arg: u32) -> Result<Self> {
Ok(Pointer::new(arg))
}
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
*owned
}
}
#[cfg(not(bizinikiwi_runtime))]
impl<T: pezsp_wasm_interface::PointerType> IntoFFIValue for Pointer<T> {
fn into_ffi_value(value: Self, _: &mut dyn FunctionContext) -> Result<u32> {
Ok(value.into())
}
}
@@ -0,0 +1,395 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Bizinikiwi runtime interface
//!
//! This crate provides types, traits and macros around runtime interfaces. A runtime interface is
//! a fixed interface between a Bizinikiwi runtime (also called the "guest") and a Bizinikiwi node
//! (also called the "host"). For a native runtime the interface maps to direct function calls of
//! the implementation. For a non-native runtime the interface maps to an external function call.
//! These external functions are exported by the runtime and they map to the same implementation
//! as the native calls, just with some extra code to marshal them through the FFI boundary.
//!
//! # Using a type in a runtime interface
//!
//! Every argument type and return type must be wrapped in a marker newtype specifying the
//! marshalling strategy used to pass the value through the FFI boundary between the host
//! and the runtime. The only exceptions to this rule are a couple of basic, primitive types
//! which can be passed directly through the FFI boundary and which don't require any special
//! handling besides a straightforward, direct conversion.
//!
//! You can find the strategy wrapper types in the [`crate::pass_by`] module.
//!
//! The newtype wrappers are automatically stripped away when the function is called
//! and applied when the function returns by the `runtime_interface` macro.
//!
//! # Declaring a runtime interface
//!
//! Declaring a runtime interface is similar to declaring a trait in Rust:
//!
//! ```
//! # mod wrapper {
//! # use pezsp_runtime_interface::pass_by::PassFatPointerAndRead;
//!
//! #[pezsp_runtime_interface::runtime_interface]
//! trait RuntimeInterface {
//! fn some_function(value: PassFatPointerAndRead<&[u8]>) -> bool {
//! value.iter().all(|v| *v > 125)
//! }
//! }
//! # }
//! ```
//!
//! For more information on declaring a runtime interface, see
//! [`#[runtime_interface]`](./attr.runtime_interface.html).
#![no_std]
pub extern crate alloc;
extern crate self as pezsp_runtime_interface;
#[doc(hidden)]
#[cfg(not(bizinikiwi_runtime))]
pub use pezsp_wasm_interface;
#[doc(hidden)]
pub use pezsp_tracing;
#[doc(hidden)]
pub use pezsp_std;
/// Attribute macro for transforming a trait declaration into a runtime interface.
///
/// A runtime interface is a fixed interface between a Bizinikiwi compatible runtime and the
/// native node. This interface is callable from a native and a wasm runtime. The macro will
/// generate the corresponding code for the native implementation and the code for calling from
/// the wasm side to the native implementation.
///
/// The macro expects the runtime interface declaration as trait declaration:
///
/// ```
/// # mod wrapper {
/// # use pezsp_runtime_interface::runtime_interface;
/// # use pezsp_runtime_interface::pass_by::{PassFatPointerAndDecode, PassFatPointerAndRead, AllocateAndReturnFatPointer};
///
/// #[runtime_interface]
/// trait Interface {
/// /// A function that can be called from native/wasm.
/// ///
/// /// The implementation given to this function is only compiled on native.
/// fn call(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnFatPointer<Vec<u8>> {
/// // Here you could call some rather complex code that only compiles on native or
/// // is way faster in native than executing it in wasm.
/// Vec::new()
/// }
/// /// Call function, but different version.
/// ///
/// /// For new runtimes, only function with latest version is reachable.
/// /// But old version (above) is still accessible for old runtimes.
/// /// Default version is 1.
/// #[version(2)]
/// fn call(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnFatPointer<Vec<u8>> {
/// // Here you could call some rather complex code that only compiles on native or
/// // is way faster in native than executing it in wasm.
/// [17].to_vec()
/// }
///
/// /// Call function, different version and only being registered.
/// ///
/// /// This `register_only` version is only being registered, aka exposed to the runtime,
/// /// but the runtime will still use the version 2 of this function. This is useful for when
/// /// new host functions should be introduced. Adding new host functions requires that all
/// /// nodes have the host functions available, because otherwise they fail at instantiation
/// /// of the runtime. With `register_only` the function will not be used when compiling the
/// /// runtime, but it will already be there for a future version of the runtime that will
/// /// switch to using these host function.
/// #[version(3, register_only)]
/// fn call(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnFatPointer<Vec<u8>> {
/// // Here you could call some rather complex code that only compiles on native or
/// // is way faster in native than executing it in wasm.
/// [18].to_vec()
/// }
///
/// /// A function can take a `&self` or `&mut self` argument to get access to the
/// /// `Externalities`. (The generated method does not require
/// /// this argument, so the function can be called just with the `optional` argument)
/// fn set_or_clear(&mut self, optional: PassFatPointerAndDecode<Option<Vec<u8>>>) {
/// match optional {
/// Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value),
/// None => self.clear_storage(&[1, 2, 3, 4]),
/// }
/// }
///
/// /// A function can be gated behind a configuration (`cfg`) attribute.
/// /// To prevent ambiguity and confusion about what will be the final exposed host
/// /// functions list, conditionally compiled functions can't be versioned.
/// /// That is, conditionally compiled functions with `version`s greater than 1
/// /// are not allowed.
/// #[cfg(feature = "experimental-function")]
/// fn gated_call(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnFatPointer<Vec<u8>> {
/// [42].to_vec()
/// }
/// }
/// # }
/// ```
///
/// The given example will generate roughly the following code for native:
///
/// ```
/// // The name of the trait is converted to snake case and used as mod name.
/// //
/// // Be aware that this module is not `public`, the visibility of the module is determined based
/// // on the visibility of the trait declaration.
/// mod interface {
/// trait Interface {
/// fn call_version_1(data: &[u8]) -> Vec<u8>;
/// fn call_version_2(data: &[u8]) -> Vec<u8>;
/// fn call_version_3(data: &[u8]) -> Vec<u8>;
/// fn set_or_clear_version_1(&mut self, optional: Option<Vec<u8>>);
/// #[cfg(feature = "experimental-function")]
/// fn gated_call_version_1(data: &[u8]) -> Vec<u8>;
/// }
///
/// impl Interface for &mut dyn pezsp_externalities::Externalities {
/// fn call_version_1(data: &[u8]) -> Vec<u8> { Vec::new() }
/// fn call_version_2(data: &[u8]) -> Vec<u8> { [17].to_vec() }
/// fn call_version_3(data: &[u8]) -> Vec<u8> { [18].to_vec() }
/// fn set_or_clear_version_1(&mut self, optional: Option<Vec<u8>>) {
/// match optional {
/// Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value),
/// None => self.clear_storage(&[1, 2, 3, 4]),
/// }
/// }
/// #[cfg(feature = "experimental-function")]
/// fn gated_call_version_1(data: &[u8]) -> Vec<u8> { [42].to_vec() }
/// }
///
/// pub fn call(data: &[u8]) -> Vec<u8> {
/// // only latest version is exposed
/// call_version_2(data)
/// }
///
/// fn call_version_1(data: &[u8]) -> Vec<u8> {
/// <&mut dyn pezsp_externalities::Externalities as Interface>::call_version_1(data)
/// }
///
/// fn call_version_2(data: &[u8]) -> Vec<u8> {
/// <&mut dyn pezsp_externalities::Externalities as Interface>::call_version_2(data)
/// }
///
/// fn call_version_3(data: &[u8]) -> Vec<u8> {
/// <&mut dyn pezsp_externalities::Externalities as Interface>::call_version_3(data)
/// }
///
/// pub fn set_or_clear(optional: Option<Vec<u8>>) {
/// set_or_clear_version_1(optional)
/// }
///
/// fn set_or_clear_version_1(optional: Option<Vec<u8>>) {
/// pezsp_externalities::with_externalities(|mut ext| Interface::set_or_clear_version_1(&mut ext, optional))
/// .expect("`set_or_clear` called outside of an Externalities-provided environment.")
/// }
///
/// #[cfg(feature = "experimental-function")]
/// pub fn gated_call(data: &[u8]) -> Vec<u8> {
/// gated_call_version_1(data)
/// }
///
/// #[cfg(feature = "experimental-function")]
/// fn gated_call_version_1(data: &[u8]) -> Vec<u8> {
/// <&mut dyn pezsp_externalities::Externalities as Interface>::gated_call_version_1(data)
/// }
///
/// /// This type implements the `HostFunctions` trait (from `sp-wasm-interface`) and
/// /// provides the host implementation for the wasm side. The host implementation converts the
/// /// arguments from wasm to native and calls the corresponding native function.
/// ///
/// /// This type needs to be passed to the wasm executor, so that the host functions will be
/// /// registered in the executor.
/// pub struct HostFunctions;
/// }
/// ```
///
/// The given example will generate roughly the following code for wasm:
///
/// ```
/// mod interface {
/// mod extern_host_functions_impls {
/// /// Every function is exported by the native code as `ext_FUNCTION_NAME_version_VERSION`.
/// ///
/// /// The type for each argument of the exported function depends on
/// /// `<ARGUMENT_TYPE as RIType>::FFIType`.
/// ///
/// /// `key` holds the pointer and the length to the `data` slice.
/// pub fn call(data: &[u8]) -> Vec<u8> {
/// extern "C" { pub fn ext_call_version_2(key: u64); }
/// // Should call into external `ext_call_version_2(<[u8] as IntoFFIValue>::into_ffi_value(key))`
/// // But this is too much to replicate in a doc test so here we just return a dummy vector.
/// // Note that we jump into the latest version not marked as `register_only` (i.e. version 2).
/// Vec::new()
/// }
///
/// /// `key` holds the pointer and the length of the `option` value.
/// pub fn set_or_clear(option: Option<Vec<u8>>) {
/// extern "C" { pub fn ext_set_or_clear_version_1(key: u64); }
/// // Same as above
/// }
///
/// /// `key` holds the pointer and the length to the `data` slice.
/// #[cfg(feature = "experimental-function")]
/// pub fn gated_call(data: &[u8]) -> Vec<u8> {
/// extern "C" { pub fn ext_gated_call_version_1(key: u64); }
/// /// Same as above
/// Vec::new()
/// }
/// }
///
/// /// The type is actually `ExchangeableFunction` (from `sp-runtime-interface`) and
/// /// by default this is initialized to jump into the corresponding function in
/// /// `extern_host_functions_impls`.
/// ///
/// /// This can be used to replace the implementation of the `call` function.
/// /// Instead of calling into the host, the callee will automatically call the other
/// /// implementation.
/// ///
/// /// To replace the implementation:
/// ///
/// /// `host_call.replace_implementation(some_other_impl)`
/// pub static host_call: () = ();
/// pub static host_set_or_clear: () = ();
/// #[cfg(feature = "experimental-feature")]
/// pub static gated_call: () = ();
///
/// pub fn call(data: &[u8]) -> Vec<u8> {
/// // This is the actual call: `host_call.get()(data)`
/// //
/// // But that does not work for several reasons in this example, so we just return an
/// // empty vector.
/// Vec::new()
/// }
///
/// pub fn set_or_clear(optional: Option<Vec<u8>>) {
/// // Same as above
/// }
///
/// #[cfg(feature = "experimental-feature")]
/// pub fn gated_call(data: &[u8]) -> Vec<u8> {
/// // Same as above
/// Vec::new()
/// }
/// }
/// ```
///
/// # Argument and return types
///
/// Every argument type and return type must be wrapped in a marker newtype specifying the
/// marshalling strategy used to pass the value through the FFI boundary between the host
/// and the runtime. The only exceptions to this rule are a couple of basic, primitive types
/// which can be passed directly through the FFI boundary and which don't require any special
/// handling besides a straightforward, direct conversion.
///
/// The following table documents those types which can be passed between the host and the
/// runtime without a marshalling strategy wrapper:
///
/// | Type | FFI type | Conversion |
/// |----|----|----|
/// | `u8` | `u32` | zero-extended to 32-bits |
/// | `u16` | `u32` | zero-extended to 32-bits |
/// | `u32` | `u32` | `Identity` |
/// | `u64` | `u64` | `Identity` |
/// | `i8` | `i32` | sign-extended to 32-bits |
/// | `i16` | `i32` | sign-extended to 32-bits |
/// | `i32` | `i32` | `Identity` |
/// | `i64` | `i64` | `Identity` |
/// | `bool` | `u32` | `if v { 1 } else { 0 }` |
/// | `*const T` | `u32` | `Identity` |
///
/// `Identity` means that the value is passed as-is directly in a bit-exact fashion.
///
/// You can find the strategy wrapper types in the [`crate::pass_by`] module.
///
/// The newtype wrappers are automatically stripped away when the function is called
/// and applied when the function returns by the `runtime_interface` macro.
///
/// # Wasm only interfaces
///
/// Some interfaces are only required from within the wasm runtime e.g. the allocator
/// interface. To support this, the macro can be called like `#[runtime_interface(wasm_only)]`.
/// This instructs the macro to make two significant changes to the generated code:
///
/// 1. The generated functions are not callable from the native side.
/// 2. The trait as shown above is not implemented for [`Externalities`] and is instead
/// implemented for `FunctionContext` (from `sp-wasm-interface`).
///
/// # Disable tracing
/// By adding `no_tracing` to the list of options you can prevent the wasm-side interface from
/// generating the default `sp-tracing`-calls. Note that this is rarely needed but only meant
/// for the case when that would create a circular dependency. You usually _do not_ want to add
/// this flag, as tracing doesn't cost you anything by default anyways (it is added as a no-op)
/// but is super useful for debugging later.
pub use pezsp_runtime_interface_proc_macro::runtime_interface;
#[doc(hidden)]
#[cfg(not(bizinikiwi_runtime))]
pub use pezsp_externalities::{
set_and_run_with_externalities, with_externalities, ExtensionStore, Externalities,
ExternalitiesExt,
};
#[doc(hidden)]
pub use codec;
#[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), bizinikiwi_runtime))]
pub mod polkavm;
#[cfg(not(bizinikiwi_runtime))]
pub mod host;
pub(crate) mod impls;
pub mod pass_by;
#[cfg(any(bizinikiwi_runtime, doc))]
pub mod wasm;
mod util;
pub use util::{pack_ptr_and_len, unpack_ptr_and_len};
/// Something that can be used by the runtime interface as type to communicate between the runtime
/// and the host.
///
/// Every type that should be used in a runtime interface function signature needs to implement
/// this trait.
pub trait RIType: Sized {
/// The raw FFI type that is used to pass `Self` through the host <-> runtime boundary.
#[cfg(not(bizinikiwi_runtime))]
type FFIType: pezsp_wasm_interface::IntoValue
+ pezsp_wasm_interface::TryFromValue
+ pezsp_wasm_interface::WasmTy;
#[cfg(bizinikiwi_runtime)]
type FFIType;
/// The inner type without any serialization strategy wrapper.
type Inner;
}
/// A raw pointer that can be used in a runtime interface function signature.
#[cfg(bizinikiwi_runtime)]
pub type Pointer<T> = *mut T;
/// A raw pointer that can be used in a runtime interface function signature.
#[cfg(not(bizinikiwi_runtime))]
pub type Pointer<T> = pezsp_wasm_interface::Pointer<T>;
@@ -0,0 +1,712 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Provides host <-> runtime FFI marshalling strategy newtype wrappers
//! for defining runtime interfaces.
use crate::{
util::{pack_ptr_and_len, unpack_ptr_and_len},
RIType,
};
#[cfg(not(bizinikiwi_runtime))]
use crate::host::*;
#[cfg(bizinikiwi_runtime)]
use crate::wasm::*;
#[cfg(not(bizinikiwi_runtime))]
use pezsp_wasm_interface::{FunctionContext, Pointer, Result};
#[cfg(not(bizinikiwi_runtime))]
use alloc::{format, string::String};
use alloc::vec::Vec;
use core::{any::type_name, marker::PhantomData};
/// Pass a value into the host by a thin pointer.
///
/// This casts the value into a `&[u8]` using `AsRef<[u8]>` and passes a pointer to that byte blob
/// to the host. Then the host reads `N` bytes from that address into an `[u8; N]`, converts it
/// into target type using `From<[u8; N]>` and passes it into the host function by a copy.
///
/// Use [`PassPointerAndRead`] if you want to have the host function accept a reference type
/// on the host side or if you'd like to avoid the extra copy.
///
/// Raw FFI type: `u32` (a pointer)
pub struct PassPointerAndReadCopy<T, const N: usize>(PhantomData<(T, [u8; N])>);
impl<T, const N: usize> RIType for PassPointerAndReadCopy<T, N> {
type FFIType = u32;
type Inner = T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a, T, const N: usize> FromFFIValue<'a> for PassPointerAndReadCopy<T, N>
where
T: From<[u8; N]> + Copy,
{
type Owned = T;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<Self::Owned> {
let mut out = [0; N];
context.read_memory_into(Pointer::new(arg), &mut out)?;
Ok(T::from(out))
}
#[inline]
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
*owned
}
}
#[cfg(bizinikiwi_runtime)]
impl<T, const N: usize> IntoFFIValue for PassPointerAndReadCopy<T, N>
where
T: AsRef<[u8]>,
{
type Destructor = ();
fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
// Using an 'assert' instead of a 'T: AsRef<[u8; N]>` bound since a '[u8; N]' *doesn't*
// implement it.
assert_eq!(value.as_ref().len(), N);
(value.as_ref().as_ptr() as u32, ())
}
}
/// Pass a value into the host by a thin pointer.
///
/// This casts the value into a `&[u8]` using `AsRef<[u8]>` and passes a pointer to that byte blob
/// to the host. Then the host reads `N` bytes from that address into an `[u8; N]`, converts it
/// into target type using `From<[u8; N]>` and passes it into the host function by a reference.
///
/// This can only be used with reference types (e.g. `&[u8; 32]`). Use [`PassPointerAndReadCopy`]
/// if you want to have the host function accept a non-reference type on the host side.
///
/// Raw FFI type: `u32` (a pointer)
pub struct PassPointerAndRead<T, const N: usize>(PhantomData<(T, [u8; N])>);
impl<'a, T, const N: usize> RIType for PassPointerAndRead<&'a T, N> {
type FFIType = u32;
type Inner = &'a T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a, T, const N: usize> FromFFIValue<'a> for PassPointerAndRead<&'a T, N>
where
T: From<[u8; N]>,
{
type Owned = T;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<Self::Owned> {
let mut out = [0; N];
context.read_memory_into(Pointer::new(arg), &mut out)?;
Ok(T::from(out))
}
#[inline]
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
&*owned
}
}
#[cfg(bizinikiwi_runtime)]
impl<'a, T, const N: usize> IntoFFIValue for PassPointerAndRead<&'a T, N>
where
T: AsRef<[u8]>,
{
type Destructor = ();
fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
assert_eq!(value.as_ref().len(), N);
(value.as_ref().as_ptr() as u32, ())
}
}
/// Pass a value into the host by a fat pointer.
///
/// This casts the value into a `&[u8]` and passes a pointer to that byte blob and its length
/// to the host. Then the host reads that blob and converts it into an owned type and passes it
/// (either as an owned type or as a reference) to the host function.
///
/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
pub struct PassFatPointerAndRead<T>(PhantomData<T>);
impl<T> RIType for PassFatPointerAndRead<T> {
type FFIType = u64;
type Inner = T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a> FromFFIValue<'a> for PassFatPointerAndRead<&'a [u8]> {
type Owned = Vec<u8>;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<Self::Owned> {
let (ptr, len) = unpack_ptr_and_len(arg);
context.read_memory(Pointer::new(ptr), len)
}
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
&*owned
}
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a> FromFFIValue<'a> for PassFatPointerAndRead<&'a str> {
type Owned = String;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<Self::Owned> {
let (ptr, len) = unpack_ptr_and_len(arg);
let vec = context.read_memory(Pointer::new(ptr), len)?;
String::from_utf8(vec).map_err(|_| "could not parse '&str' when marshalling hostcall's arguments through the FFI boundary: the string is not valid UTF-8".into())
}
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
&*owned
}
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a> FromFFIValue<'a> for PassFatPointerAndRead<Vec<u8>> {
type Owned = Vec<u8>;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<Self::Owned> {
<PassFatPointerAndRead<&[u8]> as FromFFIValue>::from_ffi_value(context, arg)
}
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
core::mem::take(owned)
}
}
#[cfg(bizinikiwi_runtime)]
impl<T> IntoFFIValue for PassFatPointerAndRead<T>
where
T: AsRef<[u8]>,
{
type Destructor = ();
fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
let value = value.as_ref();
(pack_ptr_and_len(value.as_ptr() as u32, value.len() as u32), ())
}
}
/// Pass a value into the host by a fat pointer, writing it back after the host call ends.
///
/// This casts the value into a `&mut [u8]` and passes a pointer to that byte blob and its length
/// to the host. Then the host reads that blob and converts it into an owned type and passes it
/// as a mutable reference to the host function. After the host function finishes the byte blob
/// is written back into the guest memory.
///
/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
pub struct PassFatPointerAndReadWrite<T>(PhantomData<T>);
impl<T> RIType for PassFatPointerAndReadWrite<T> {
type FFIType = u64;
type Inner = T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a> FromFFIValue<'a> for PassFatPointerAndReadWrite<&'a mut [u8]> {
type Owned = Vec<u8>;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<Self::Owned> {
let (ptr, len) = unpack_ptr_and_len(arg);
context.read_memory(Pointer::new(ptr), len)
}
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
&mut *owned
}
fn write_back_into_runtime(
value: Self::Owned,
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<()> {
let (ptr, len) = unpack_ptr_and_len(arg);
assert_eq!(len as usize, value.len());
context.write_memory(Pointer::new(ptr), &value)
}
}
#[cfg(bizinikiwi_runtime)]
impl<'a> IntoFFIValue for PassFatPointerAndReadWrite<&'a mut [u8]> {
type Destructor = ();
fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
(pack_ptr_and_len(value.as_ptr() as u32, value.len() as u32), ())
}
}
/// Pass a pointer into the host and write to it after the host call ends.
///
/// This casts a given type into `&mut [u8]` using `AsMut<[u8]>` and passes a pointer to
/// that byte slice into the host. The host *doesn't* read from this and instead creates
/// a default instance of type `T` and passes it as a `&mut T` into the host function
/// implementation. After the host function finishes this value is then cast into a `&[u8]` using
/// `AsRef<[u8]>` and written back into the guest memory.
///
/// Raw FFI type: `u32` (a pointer)
pub struct PassPointerAndWrite<T, const N: usize>(PhantomData<(T, [u8; N])>);
impl<T, const N: usize> RIType for PassPointerAndWrite<T, N> {
type FFIType = u32;
type Inner = T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a, T, const N: usize> FromFFIValue<'a> for PassPointerAndWrite<&'a mut T, N>
where
T: Default + AsRef<[u8]>,
{
type Owned = T;
fn from_ffi_value(
_context: &mut dyn FunctionContext,
_arg: Self::FFIType,
) -> Result<Self::Owned> {
Ok(T::default())
}
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
&mut *owned
}
fn write_back_into_runtime(
value: Self::Owned,
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<()> {
let value = value.as_ref();
assert_eq!(value.len(), N);
context.write_memory(Pointer::new(arg), value)
}
}
#[cfg(bizinikiwi_runtime)]
impl<'a, T, const N: usize> IntoFFIValue for PassPointerAndWrite<&'a mut T, N>
where
T: AsMut<[u8]>,
{
type Destructor = ();
fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
let value = value.as_mut();
assert_eq!(value.len(), N);
(value.as_ptr() as u32, ())
}
}
/// Pass a `T` into the host using the SCALE codec.
///
/// This encodes a `T` into a `Vec<u8>` using the SCALE codec and then
/// passes a pointer to that byte blob and its length to the host,
/// which then reads it and decodes back into `T`.
///
/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
pub struct PassFatPointerAndDecode<T>(PhantomData<T>);
impl<T> RIType for PassFatPointerAndDecode<T> {
type FFIType = u64;
type Inner = T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecode<T> {
type Owned = Option<T>;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<Self::Owned> {
let (ptr, len) = unpack_ptr_and_len(arg);
let vec = context.read_memory(Pointer::new(ptr), len)?;
T::decode(&mut &vec[..]).map_err(|error| format!(
"could not SCALE-decode '{}' when marshalling hostcall's arguments through the FFI boundary: {error}",
type_name::<T>())
).map(Some)
}
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
owned.take().expect("this is called only once and is never 'None'")
}
}
#[cfg(bizinikiwi_runtime)]
impl<T: codec::Encode> IntoFFIValue for PassFatPointerAndDecode<T> {
type Destructor = Vec<u8>;
fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
let data = value.encode();
(pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32), data)
}
}
/// Pass a `&[T]` into the host using the SCALE codec.
///
/// This encodes a `&[T]` into a `Vec<u8>` using the SCALE codec and then
/// passes a pointer to that byte blob and its length to the host,
/// which then reads it and decodes back into `Vec<T>` and passes
/// a reference to that (as `&[T]`) into the host function.
///
/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
pub struct PassFatPointerAndDecodeSlice<T>(PhantomData<T>);
impl<T> RIType for PassFatPointerAndDecodeSlice<T> {
type FFIType = u64;
type Inner = T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecodeSlice<&'a [T]> {
type Owned = Vec<T>;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<Self::Owned> {
let (ptr, len) = unpack_ptr_and_len(arg);
let vec = context.read_memory(Pointer::new(ptr), len)?;
<Vec::<T> as codec::Decode>::decode(&mut &vec[..]).map_err(|error| format!(
"could not SCALE-decode '{}' when marshalling hostcall's arguments through the FFI boundary: {error}",
type_name::<Vec<T>>()
))
}
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
&*owned
}
}
#[cfg(bizinikiwi_runtime)]
impl<'a, T: codec::Encode> IntoFFIValue for PassFatPointerAndDecodeSlice<&'a [T]> {
type Destructor = Vec<u8>;
fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
let data = codec::Encode::encode(value);
(pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32), data)
}
}
/// A trait signifying a primitive type.
trait Primitive: Copy {}
impl Primitive for u8 {}
impl Primitive for u16 {}
impl Primitive for u32 {}
impl Primitive for u64 {}
impl Primitive for i8 {}
impl Primitive for i16 {}
impl Primitive for i32 {}
impl Primitive for i64 {}
/// Pass `T` through the FFI boundary by first converting it to `U` in the runtime, and then
/// converting it back to `T` on the host's side.
///
/// Raw FFI type: same as `U`'s FFI type
pub struct PassAs<T, U>(PhantomData<(T, U)>);
impl<T, U> RIType for PassAs<T, U>
where
U: RIType,
{
type FFIType = <U as RIType>::FFIType;
type Inner = T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<'a, T, U> FromFFIValue<'a> for PassAs<T, U>
where
U: RIType + FromFFIValue<'a> + Primitive,
T: TryFrom<<U as FromFFIValue<'a>>::Owned> + Copy,
{
type Owned = T;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<Self::Owned> {
<U as FromFFIValue>::from_ffi_value(context, arg).and_then(|value| value.try_into()
.map_err(|_| format!(
"failed to convert '{}' (passed as '{}') into '{}' when marshalling hostcall's arguments through the FFI boundary",
type_name::<U>(),
type_name::<Self::FFIType>(),
type_name::<Self::Owned>()
)))
}
fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
*owned
}
}
#[cfg(bizinikiwi_runtime)]
impl<T, U> IntoFFIValue for PassAs<T, U>
where
U: RIType + IntoFFIValue + Primitive,
U::Inner: From<T>,
T: Copy,
{
type Destructor = <U as IntoFFIValue>::Destructor;
fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
let mut value = U::Inner::from(*value);
<U as IntoFFIValue>::into_ffi_value(&mut value)
}
}
/// Return `T` through the FFI boundary by first converting it to `U` on the host's side, and then
/// converting it back to `T` in the runtime.
///
/// Raw FFI type: same as `U`'s FFI type
pub struct ReturnAs<T, U>(PhantomData<(T, U)>);
impl<T, U> RIType for ReturnAs<T, U>
where
U: RIType,
{
type FFIType = <U as RIType>::FFIType;
type Inner = T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<T, U> IntoFFIValue for ReturnAs<T, U>
where
U: RIType + IntoFFIValue + Primitive,
<U as RIType>::Inner: From<Self::Inner>,
{
fn into_ffi_value(
value: Self::Inner,
context: &mut dyn FunctionContext,
) -> Result<Self::FFIType> {
let value: <U as RIType>::Inner = value.into();
<U as IntoFFIValue>::into_ffi_value(value, context)
}
}
#[cfg(bizinikiwi_runtime)]
impl<T, U> FromFFIValue for ReturnAs<T, U>
where
U: RIType + FromFFIValue + Primitive,
Self::Inner: TryFrom<U::Inner>,
{
fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
let value = <U as FromFFIValue>::from_ffi_value(arg);
match Self::Inner::try_from(value) {
Ok(value) => value,
Err(_) => {
panic!(
"failed to convert '{}' (passed as '{}') into a '{}' when marshalling a hostcall's return value through the FFI boundary",
type_name::<U::Inner>(),
type_name::<Self::FFIType>(),
type_name::<Self::Inner>()
);
},
}
}
}
/// (DEPRECATED) Return `T` as a blob of bytes into the runtime.
///
/// Uses `T::AsRef<[u8]>` to cast `T` into a `&[u8]`, allocates runtime memory
/// using the legacy allocator, copies the slice into the runtime memory, and
/// returns a pointer to it.
///
/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS!
///
/// Ideally use a mutable slice to return data to the guest, for example using
/// the [`PassPointerAndWrite`] strategy.
///
/// Raw FFI type: `u32` (a pointer to the byte blob)
pub struct AllocateAndReturnPointer<T, const N: usize>(PhantomData<(T, [u8; N])>);
impl<T, const N: usize> RIType for AllocateAndReturnPointer<T, N> {
type FFIType = u32;
type Inner = T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<T, const N: usize> IntoFFIValue for AllocateAndReturnPointer<T, N>
where
T: AsRef<[u8]>,
{
fn into_ffi_value(
value: Self::Inner,
context: &mut dyn FunctionContext,
) -> Result<Self::FFIType> {
let value = value.as_ref();
assert_eq!(
value.len(),
N,
"expected the byte blob to be {N} bytes long, is {} bytes when returning '{}' from a host function",
value.len(),
type_name::<T>()
);
let addr = context.allocate_memory(value.len() as u32)?;
context.write_memory(addr, value)?;
Ok(addr.into())
}
}
#[cfg(bizinikiwi_runtime)]
impl<T: codec::Decode, const N: usize> FromFFIValue for AllocateAndReturnPointer<T, N>
where
T: From<[u8; N]>,
{
fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
// SAFETY: This memory was allocated by the host allocator with the exact
// capacity needed, so it's safe to make a `Vec` out of it.
let value = unsafe { Vec::from_raw_parts(arg as *mut u8, N, N) };
// SAFETY: Reading a `[u8; N]` from a `&[u8]` which is at least `N` elements long is safe.
let array = unsafe { *(value.as_ptr() as *const [u8; N]) };
T::from(array)
}
}
/// (DEPRECATED) Return `T` as a blob of bytes into the runtime.
///
/// Uses `T::AsRef<[u8]>` to cast `T` into a `&[u8]`, allocates runtime memory
/// using the legacy allocator, copies the slice into the runtime memory, and
/// returns a pointer to it.
///
/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS!
///
/// Ideally use a mutable slice to return data to the guest, for example using
/// the [`PassPointerAndWrite`] strategy.
///
/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
pub struct AllocateAndReturnFatPointer<T>(PhantomData<T>);
impl<T> RIType for AllocateAndReturnFatPointer<T> {
type FFIType = u64;
type Inner = T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<T> IntoFFIValue for AllocateAndReturnFatPointer<T>
where
T: AsRef<[u8]>,
{
fn into_ffi_value(
value: Self::Inner,
context: &mut dyn FunctionContext,
) -> Result<Self::FFIType> {
let value = value.as_ref();
let ptr = context.allocate_memory(value.len() as u32)?;
context.write_memory(ptr, &value)?;
Ok(pack_ptr_and_len(ptr.into(), value.len() as u32))
}
}
#[cfg(bizinikiwi_runtime)]
impl<T> FromFFIValue for AllocateAndReturnFatPointer<T>
where
T: From<Vec<u8>>,
{
fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
let (ptr, len) = unpack_ptr_and_len(arg);
let len = len as usize;
let vec = if len == 0 {
Vec::new()
} else {
// SAFETY: This memory was allocated by the host allocator with the exact
// capacity needed, so it's safe to make a `Vec` out of it.
unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) }
};
T::from(vec)
}
}
/// (DEPRECATED) Return `T` into the runtime using the SCALE codec.
///
/// Encodes `T` using the SCALE codec, allocates runtime memory using the legacy
/// allocator, copies the encoded payload into the runtime memory, and returns
/// a fat pointer to it.
///
/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS!
///
/// Ideally use a mutable slice to return data to the guest, for example using
/// the [`PassPointerAndWrite`] strategy.
///
/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
pub struct AllocateAndReturnByCodec<T>(PhantomData<T>);
impl<T> RIType for AllocateAndReturnByCodec<T> {
type FFIType = u64;
type Inner = T;
}
#[cfg(not(bizinikiwi_runtime))]
impl<T: codec::Encode> IntoFFIValue for AllocateAndReturnByCodec<T> {
fn into_ffi_value(value: T, context: &mut dyn FunctionContext) -> Result<Self::FFIType> {
let vec = value.encode();
let ptr = context.allocate_memory(vec.len() as u32)?;
context.write_memory(ptr, &vec)?;
Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32))
}
}
#[cfg(bizinikiwi_runtime)]
impl<T: codec::Decode> FromFFIValue for AllocateAndReturnByCodec<T> {
fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
let (ptr, len) = unpack_ptr_and_len(arg);
let len = len as usize;
let encoded = if len == 0 {
bytes::Bytes::new()
} else {
// SAFETY: This memory was allocated by the host allocator with the exact
// capacity needed, so it's safe to make a `Vec` out of it.
bytes::Bytes::from(unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) })
};
match codec::decode_from_bytes(encoded) {
Ok(value) => value,
Err(error) => {
panic!(
"failed to decode '{}' when marshalling a hostcall's return value through the FFI boundary: {error}",
type_name::<T>(),
);
},
}
}
}
@@ -0,0 +1,30 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub use polkavm_derive::{polkavm_export, polkavm_import};
#[polkavm_derive::polkavm_define_abi(allow_extra_input_registers)]
pub mod polkavm_abi {}
impl self::polkavm_abi::FromHost for *mut u8 {
type Regs = (u32,);
#[inline]
fn from_host((value,): Self::Regs) -> Self {
value as *mut u8
}
}
@@ -0,0 +1,60 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Various utilities that help interfacing with wasm runtime code.
/// Pack a pointer and length into an `u64`.
pub fn pack_ptr_and_len(ptr: u32, len: u32) -> u64 {
// The static assertions from above are changed into a runtime check.
#[cfg(all(bizinikiwi_runtime, feature = "disable_target_static_assertions"))]
assert_eq!(4, core::mem::size_of::<usize>());
(u64::from(len) << 32) | u64::from(ptr)
}
/// Unpacks an `u64` into the pointer and length.
///
/// Runtime API functions return a 64-bit value which encodes a pointer in the least-significant
/// 32-bits and a length in the most-significant 32 bits. This interprets the returned value as a
/// pointer, length tuple.
pub fn unpack_ptr_and_len(val: u64) -> (u32, u32) {
// The static assertions from above are changed into a runtime check.
#[cfg(all(bizinikiwi_runtime, feature = "disable_target_static_assertions"))]
assert_eq!(4, core::mem::size_of::<usize>());
let ptr = (val & (!0u32 as u64)) as u32;
let len = (val >> 32) as u32;
(ptr, len)
}
#[cfg(test)]
mod tests {
use super::{pack_ptr_and_len, unpack_ptr_and_len};
#[test]
fn ptr_len_packing_unpacking() {
const PTR: u32 = 0x1337;
const LEN: u32 = 0x7f000000;
let packed = pack_ptr_and_len(PTR, LEN);
let (ptr, len) = unpack_ptr_and_len(packed);
assert_eq!(PTR, ptr);
assert_eq!(LEN, len);
}
}
@@ -0,0 +1,108 @@
// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Traits required by the runtime interface from the wasm side.
use crate::RIType;
use core::cell::Cell;
/// A type used as a return value in a host function. Can be created from an FFI value.
///
/// Implementations are safe to assume that the `arg` given to `from_ffi_value`
/// is only generated by the corresponding [`host::IntoFFIValue`](crate::host::IntoFFIValue)
/// implementation.
pub trait FromFFIValue: Sized + RIType {
/// Create `Self::Inner` from the given FFI value.
fn from_ffi_value(arg: Self::FFIType) -> Self::Inner;
}
/// A type used as a parameter in a host function. Can be turned into an FFI value.
pub trait IntoFFIValue: RIType {
/// Destructor for the value passed into `into_ffi_value`.
type Destructor;
/// Convert `Self::Inner` into an FFI type, with an optional destructor.
fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor);
}
/// The state of an exchangeable function.
#[derive(Clone, Copy)]
enum ExchangeableFunctionState {
/// Original function is present
Original,
/// The function has been replaced.
Replaced,
}
/// A function which implementation can be exchanged.
///
/// Internally this works by swapping function pointers.
pub struct ExchangeableFunction<T>(Cell<(T, ExchangeableFunctionState)>);
impl<T> ExchangeableFunction<T> {
/// Create a new instance of `ExchangeableFunction`.
pub const fn new(impl_: T) -> Self {
Self(Cell::new((impl_, ExchangeableFunctionState::Original)))
}
}
impl<T: Copy> ExchangeableFunction<T> {
/// Replace the implementation with `new_impl`.
///
/// # Panics
///
/// Panics when trying to replace an already replaced implementation.
///
/// # Returns
///
/// Returns the original implementation wrapped in [`RestoreImplementation`].
pub fn replace_implementation(&'static self, new_impl: T) -> RestoreImplementation<T> {
if let ExchangeableFunctionState::Replaced = self.0.get().1 {
panic!("Trying to replace an already replaced implementation!")
}
let old = self.0.replace((new_impl, ExchangeableFunctionState::Replaced));
RestoreImplementation(self, Some(old.0))
}
/// Restore the original implementation.
fn restore_orig_implementation(&self, orig: T) {
self.0.set((orig, ExchangeableFunctionState::Original));
}
/// Returns the internal function pointer.
pub fn get(&self) -> T {
self.0.get().0
}
}
// Wasm does not support threads, so this is safe; qed.
unsafe impl<T> Sync for ExchangeableFunction<T> {}
/// Restores a function implementation on drop.
///
/// Stores a static reference to the function object and the original implementation.
pub struct RestoreImplementation<T: 'static + Copy>(&'static ExchangeableFunction<T>, Option<T>);
impl<T: Copy> Drop for RestoreImplementation<T> {
fn drop(&mut self) {
self.0
.restore_orig_implementation(self.1.take().expect("Value is only taken on drop; qed"));
}
}