diff --git a/.github/workflows/tests-misc.yml b/.github/workflows/tests-misc.yml index 3293b35f6637b..757d88ff69cfb 100644 --- a/.github/workflows/tests-misc.yml +++ b/.github/workflows/tests-misc.yml @@ -64,9 +64,9 @@ jobs: - name: script run: | cd substrate/frame/examples/offchain-worker/ - forklift cargo build --locked --target=wasm32-unknown-unknown --no-default-features + RUSTFLAGS="--cfg substrate_runtime" forklift cargo build --locked --target=wasm32-unknown-unknown --no-default-features cd ../basic - forklift cargo build --locked --target=wasm32-unknown-unknown --no-default-features + RUSTFLAGS="--cfg substrate_runtime" forklift cargo build --locked --target=wasm32-unknown-unknown --no-default-features test-frame-ui: timeout-minutes: 60 diff --git a/Cargo.lock b/Cargo.lock index bcb7e8cb7ac16..95723c40ca595 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5612,9 +5612,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "easy-cast" @@ -22142,6 +22142,7 @@ dependencies = [ "bs58", "criterion", "dyn-clonable", + "dyn-clone", "ed25519-zebra 4.0.3", "futures", "hash-db", diff --git a/polkadot/runtime/metrics/src/with_runtime_metrics.rs b/polkadot/runtime/metrics/src/with_runtime_metrics.rs index 979d5eda9afc6..8fe35b4cb6afd 100644 --- a/polkadot/runtime/metrics/src/with_runtime_metrics.rs +++ b/polkadot/runtime/metrics/src/with_runtime_metrics.rs @@ -142,5 +142,5 @@ impl Histogram { /// Returns current time in ns pub fn get_current_time() -> u128 { - frame_benchmarking::benchmarking::current_time() + frame_benchmarking::current_time() } diff --git a/prdoc/pr_7375.prdoc b/prdoc/pr_7375.prdoc new file mode 100644 index 0000000000000..158b19349dd86 --- /dev/null +++ b/prdoc/pr_7375.prdoc @@ -0,0 +1,87 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# yaml-language-server: $schema=https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Refactor the host <-> runtime interface machinery (the `#[runtime_interface]` macro) and the way host functions are defined + +doc: + - audience: Node Dev + description: | + This PR refactors the way the host functions are defined. + + Previously the way a given type was marshalled through the host <-> runtime boundary was + hardcoded for every type by the virtue of it implementing the relevant conversion traits. + + This had two major consequences: + * It was not obvious how a given type is going to be passed just by looking at its type alone, + masking potentially expensive marshalling strategies. (For example, returning `Option` + was done through the SCALE codec and involved extra memory allocations!) + * It was not possible to use multiple marshalling strategies for a single type, making some + of the future improvements we'd like to do (e.g. move the runtime memory allocator into the runtime) + very hard to do. + + So this PR disentangles this mess and makes the marshalling strategies explicit. This makes it + much more clear how a given type in a given host function is marshalled, and also makes it possible + to use different marshalling strategies for the same type in different host functions. + + Before this PR you'd define a host function like this: + + ```rust + #[runtime_interface] + trait MyInterface { + fn say_hello_world(name: &str) { + println!("Hello {name}!"); + } + } + ``` + + and after this PR you'll define it like this: + + ```rust + #[runtime_interface] + trait MyInterface { + fn say_hello_world(name: PassFatPointerAndRead<&str>) { + println!("Hello {name}!", name); + } + } + ``` + + In this case the strategy for passing the `&str` is now explicitly specified (`PassFatPointerAndRead`). + Note that the *actual* API generated by this macro and the way arguments are accessed is completely unchanged! + The `#[runtime_interface]` machinery automatically "strips" away the marshalling strategy wrappers, + so neither the body of the `say_hello_world` function here nor its callers need to be changed. + + Furthermore, to explicitly distinguish between the runtime compilation mode and native mode, + `#[cfg(substrate_runtime)]` is now used instead of `#[cfg(not(feature = "std"))]`. That allows for fine-tuning + the compilation behavior without relying solely on the `std` feature. + +crates: + - name: sp-runtime-interface + bump: major + note: Rework of the `#[runtime_interface]` macro and associated types/trait. + - name: sp-runtime-interface-proc-macro + bump: major + note: Rework of the `#[runtime_interface]` macro. + - name: sp-wasm-interface + bump: major + note: The `Pointer` type now implements `Copy` and `Clone` unconditionally. The `Result` now always returns a `String`. + - name: sp-core + bump: major + note: Some types don't implement the traits related to the old `#[runtime_interface]` anymore. A few extra conversion impls. + - name: sp-io + bump: major + note: Requires the new `#[runtime_interface]` macro and associated machinery. Some types don't implement the traits related to the old `#[runtime_interface]` anymore. + - name: sp-statement-store + bump: major + note: Requires the new `#[runtime_interface]` macro and associated machinery. Some types don't implement the traits related to the old `#[runtime_interface]` anymore. + - name: sp-crypto-ec-utils + bump: minor + note: Requires the new `#[runtime_interface]` macro and associated machinery. + - name: frame-benchmarking + bump: major + note: Requires the new `#[runtime_interface]` macro and associated machinery. `Benchmarking::current_time` host call was changed. + - name: frame-support-procedural + bump: minor + note: Needs new `frame-benchmarking` due to the change to `current_time`. + - name: polkadot-runtime-metrics + bump: minor + note: Needs new `frame-benchmarking` due to the change to `current_time`. diff --git a/substrate/client/executor/src/executor.rs b/substrate/client/executor/src/executor.rs index 913bcdfcfe591..198a2a31ab8db 100644 --- a/substrate/client/executor/src/executor.rs +++ b/substrate/client/executor/src/executor.rs @@ -758,11 +758,11 @@ impl sp_core::traits::ReadRuntimeVersion for NativeE #[cfg(test)] mod tests { use super::*; - use sp_runtime_interface::runtime_interface; + use sp_runtime_interface::{pass_by::PassFatPointerAndRead, runtime_interface}; #[runtime_interface] trait MyInterface { - fn say_hello_world(data: &str) { + fn say_hello_world(data: PassFatPointerAndRead<&str>) { println!("Hello world from: {}", data); } } diff --git a/substrate/frame/benchmarking/src/utils.rs b/substrate/frame/benchmarking/src/utils.rs index 3a10e43d83b8c..8df070f65fb17 100644 --- a/substrate/frame/benchmarking/src/utils.rs +++ b/substrate/frame/benchmarking/src/utils.rs @@ -24,6 +24,9 @@ use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_io::hashing::blake2_256; use sp_runtime::{traits::TrailingZeroInput, DispatchError}; +use sp_runtime_interface::pass_by::{ + AllocateAndReturnByCodec, PassFatPointerAndDecode, PassFatPointerAndRead, PassPointerAndWrite, +}; use sp_storage::TrackedStorageKey; /// An alphabet of possible parameters to use for benchmarking. @@ -245,18 +248,31 @@ sp_api::decl_runtime_apis! { } } +/// Get the number of nanoseconds passed since the UNIX epoch +/// +/// WARNING! This is a non-deterministic call. Do not use this within +/// consensus critical logic. +pub fn current_time() -> u128 { + let mut out = [0; 16]; + self::benchmarking::current_time(&mut out); + u128::from_le_bytes(out) +} + /// Interface that provides functions for benchmarking the runtime. #[sp_runtime_interface::runtime_interface] pub trait Benchmarking { - /// Get the number of nanoseconds passed since the UNIX epoch + /// Get the number of nanoseconds passed since the UNIX epoch, as u128 le-bytes. + /// + /// You may want to use the standalone function [`current_time`]. /// /// WARNING! This is a non-deterministic call. Do not use this within /// consensus critical logic. - fn current_time() -> u128 { - std::time::SystemTime::now() + fn current_time(out: PassPointerAndWrite<&mut [u8; 16], 16>) { + *out = std::time::SystemTime::now() .duration_since(std::time::SystemTime::UNIX_EPOCH) .expect("Unix time doesn't go backwards; qed") .as_nanos() + .to_le_bytes(); } /// Reset the trie database to the genesis state. @@ -270,7 +286,7 @@ pub trait Benchmarking { } /// Get the read/write count. - fn read_write_count(&self) -> (u32, u32, u32, u32) { + fn read_write_count(&self) -> AllocateAndReturnByCodec<(u32, u32, u32, u32)> { self.read_write_count() } @@ -280,17 +296,17 @@ pub trait Benchmarking { } /// Get the DB whitelist. - fn get_whitelist(&self) -> Vec { + fn get_whitelist(&self) -> AllocateAndReturnByCodec> { self.get_whitelist() } /// Set the DB whitelist. - fn set_whitelist(&mut self, new: Vec) { + fn set_whitelist(&mut self, new: PassFatPointerAndDecode>) { self.set_whitelist(new) } // Add a new item to the DB whitelist. - fn add_to_whitelist(&mut self, add: TrackedStorageKey) { + fn add_to_whitelist(&mut self, add: PassFatPointerAndDecode) { let mut whitelist = self.get_whitelist(); match whitelist.iter_mut().find(|x| x.key == add.key) { // If we already have this key in the whitelist, update to be the most constrained @@ -309,18 +325,20 @@ pub trait Benchmarking { } // Remove an item from the DB whitelist. - fn remove_from_whitelist(&mut self, remove: Vec) { + fn remove_from_whitelist(&mut self, remove: PassFatPointerAndRead>) { let mut whitelist = self.get_whitelist(); whitelist.retain(|x| x.key != remove); self.set_whitelist(whitelist); } - fn get_read_and_written_keys(&self) -> Vec<(Vec, u32, u32, bool)> { + fn get_read_and_written_keys( + &self, + ) -> AllocateAndReturnByCodec, u32, u32, bool)>> { self.get_read_and_written_keys() } /// Get current estimated proof size. - fn proof_size(&self) -> Option { + fn proof_size(&self) -> AllocateAndReturnByCodec> { self.proof_size() } } @@ -400,11 +418,11 @@ impl<'a> Recording for BenchmarkRecording<'a> { fn start(&mut self) { (self.on_before_start.take().expect("start called more than once"))(); self.start_pov = crate::benchmarking::proof_size(); - self.start_extrinsic = Some(crate::benchmarking::current_time()); + self.start_extrinsic = Some(current_time()); } fn stop(&mut self) { - self.finish_extrinsic = Some(crate::benchmarking::current_time()); + self.finish_extrinsic = Some(current_time()); self.end_pov = crate::benchmarking::proof_size(); } } diff --git a/substrate/frame/benchmarking/src/v1.rs b/substrate/frame/benchmarking/src/v1.rs index 994b52bb9fd07..b7461f7cb4783 100644 --- a/substrate/frame/benchmarking/src/v1.rs +++ b/substrate/frame/benchmarking/src/v1.rs @@ -1132,9 +1132,9 @@ macro_rules! impl_benchmark { ); // Time the storage root recalculation. - let start_storage_root = $crate::benchmarking::current_time(); + let start_storage_root = $crate::current_time(); $crate::__private::storage_root($crate::__private::StateVersion::V1); - let finish_storage_root = $crate::benchmarking::current_time(); + let finish_storage_root = $crate::current_time(); let elapsed_storage_root = finish_storage_root - start_storage_root; let skip_meta = [ $( stringify!($name_skip_meta).as_ref() ),* ]; diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index 72ca4174c5321..8c788b426ce17 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -292,9 +292,12 @@ pub mod benchmarking { } pub mod prelude { - pub use super::shared::*; pub use crate::prelude::*; - pub use frame_benchmarking::v2::*; + pub use frame_benchmarking::{ + add_benchmark, benchmarking::add_to_whitelist, v1::account, v2::*, whitelist, + whitelisted_caller, + }; + pub use frame_system::{Pallet as System, RawOrigin}; } } diff --git a/substrate/frame/support/procedural/src/benchmark.rs b/substrate/frame/support/procedural/src/benchmark.rs index 87a2fc17a7c0f..c2f615ef54d93 100644 --- a/substrate/frame/support/procedural/src/benchmark.rs +++ b/substrate/frame/support/procedural/src/benchmark.rs @@ -820,9 +820,9 @@ pub fn benchmarks( ); // Time the storage root recalculation. - let start_storage_root = #krate::benchmarking::current_time(); + let start_storage_root = #krate::current_time(); #krate::__private::storage_root(#krate::__private::StateVersion::V1); - let finish_storage_root = #krate::benchmarking::current_time(); + let finish_storage_root = #krate::current_time(); let elapsed_storage_root = finish_storage_root - start_storage_root; let skip_meta = [ #(#skip_meta_benchmark_names_str),* ]; diff --git a/substrate/primitives/application-crypto/check-features-variants.sh b/substrate/primitives/application-crypto/check-features-variants.sh index dd45a212bae09..811f124d926bc 100755 --- a/substrate/primitives/application-crypto/check-features-variants.sh +++ b/substrate/primitives/application-crypto/check-features-variants.sh @@ -1,8 +1,10 @@ #!/usr/bin/env -S bash -eux export RUSTFLAGS="-Cdebug-assertions=y -Dwarnings" +cargo check --release + +export RUSTFLAGS="$RUSTFLAGS --cfg substrate_runtime" T=wasm32-unknown-unknown -cargo check --release cargo check --release --target=$T --no-default-features cargo check --release --target=$T --no-default-features --features="full_crypto" cargo check --release --target=$T --no-default-features --features="serde" diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 562562a55b024..b68e45ed574a3 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -71,6 +71,11 @@ w3f-bls = { optional = true, workspace = true } # bandersnatch crypto ark-vrf = { optional = true, workspace = true, features = ["bandersnatch", "ring"] } +[target.'cfg(not(substrate_runtime))'.dependencies] +sp-externalities = { workspace = true, default-features = false } +futures = { version = "0.3.30", default-features = false, features = ["alloc"] } +dyn-clone = "1.0.17" + [dev-dependencies] criterion = { workspace = true, default-features = true } regex = { workspace = true } @@ -86,10 +91,9 @@ std = [ "bounded-collections/std", "bs58/std", "codec/std", - "dyn-clonable", "ed25519-zebra/std", "full_crypto", - "futures", + "futures/std", "futures/thread-pool", "hash-db/std", "hash256-std-hasher/std", diff --git a/substrate/primitives/core/check-features-variants.sh b/substrate/primitives/core/check-features-variants.sh index 6d28212065a62..860d8365be386 100755 --- a/substrate/primitives/core/check-features-variants.sh +++ b/substrate/primitives/core/check-features-variants.sh @@ -1,6 +1,6 @@ #!/usr/bin/env -S bash -eux -export RUSTFLAGS="-Cdebug-assertions=y -Dwarnings" +export RUSTFLAGS="-Cdebug-assertions=y -Dwarnings --cfg substrate_runtime" T=wasm32-unknown-unknown cargo check --target=$T --release --no-default-features --features="bls-experimental" diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index 4ef1d4c6122a7..ca7fb076e7e3f 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -19,7 +19,7 @@ use crate::{ed25519, sr25519, U256}; use alloc::{format, str, vec::Vec}; -#[cfg(all(not(feature = "std"), feature = "serde"))] +#[cfg(feature = "serde")] use alloc::{string::String, vec}; use bip39::{Language, Mnemonic}; use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen}; @@ -32,7 +32,6 @@ use itertools::Itertools; use rand::{rngs::OsRng, RngCore}; use scale_info::TypeInfo; pub use secrecy::{ExposeSecret, SecretString}; -use sp_runtime_interface::pass_by::PassByInner; pub use ss58_registry::{from_known_address_format, Ss58AddressFormat, Ss58AddressFormatRegistry}; /// Trait to zeroize a memory buffer. pub use zeroize::Zeroize; @@ -1052,11 +1051,11 @@ pub trait CryptoType { Hash, Encode, Decode, - PassByInner, crate::RuntimeDebug, TypeInfo, )] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[repr(transparent)] pub struct KeyTypeId(pub [u8; 4]); impl From for KeyTypeId { @@ -1071,6 +1070,18 @@ impl From for u32 { } } +impl From<[u8; 4]> for KeyTypeId { + fn from(value: [u8; 4]) -> Self { + Self(value) + } +} + +impl AsRef<[u8]> for KeyTypeId { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + impl<'a> TryFrom<&'a str> for KeyTypeId { type Error = (); @@ -1208,6 +1219,7 @@ impl_from_entropy_base!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, U256); mod tests { use super::*; use crate::DeriveJunction; + use alloc::{string::String, vec}; struct TestCryptoTag; diff --git a/substrate/primitives/core/src/crypto_bytes.rs b/substrate/primitives/core/src/crypto_bytes.rs index 1964109cfac82..1ebb7e853a524 100644 --- a/substrate/primitives/core/src/crypto_bytes.rs +++ b/substrate/primitives/core/src/crypto_bytes.rs @@ -26,8 +26,6 @@ use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen}; use core::marker::PhantomData; use scale_info::TypeInfo; -use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; - #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; #[cfg(feature = "serde")] @@ -99,26 +97,6 @@ impl Default for CryptoBytes { } } -impl PassByInner for CryptoBytes { - type Inner = [u8; N]; - - fn into_inner(self) -> Self::Inner { - self.0 - } - - fn inner(&self) -> &Self::Inner { - &self.0 - } - - fn from_inner(inner: Self::Inner) -> Self { - Self(inner, PhantomData) - } -} - -impl PassBy for CryptoBytes { - type PassBy = pass_by::Inner; -} - impl AsRef<[u8]> for CryptoBytes { fn as_ref(&self) -> &[u8] { &self.0[..] diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index b24eb400e6459..17409095f8758 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -20,6 +20,8 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + /// Initialize a key-value collection from array. /// /// Creates a vector of given pairs and calls `collect` on the iterator from it. @@ -31,8 +33,6 @@ macro_rules! map { ); } -extern crate alloc; - use alloc::vec::Vec; #[doc(hidden)] pub use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen}; @@ -42,7 +42,6 @@ use scale_info::TypeInfo; pub use serde; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use sp_runtime_interface::pass_by::{PassByEnum, PassByInner}; pub use sp_debug_derive::RuntimeDebug; @@ -62,11 +61,11 @@ pub use paste; mod address_uri; pub mod defer; pub mod hash; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] mod hasher; pub mod offchain; pub mod testing; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub mod traits; pub mod uint; @@ -91,9 +90,9 @@ pub use self::{ }; pub use crypto::{ByteArray, DeriveJunction, Pair, Public}; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub use self::hasher::blake2::Blake2Hasher; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub use self::hasher::keccak::KeccakHasher; pub use hash_db::Hasher; @@ -180,7 +179,6 @@ impl Deref for OpaqueMetadata { Decode, DecodeWithMemTracking, RuntimeDebug, - PassByInner, TypeInfo, )] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -202,7 +200,7 @@ pub trait TypeId { /// A log level matching the one from `log` crate. /// /// Used internally by `sp_io::logging::log` method. -#[derive(Encode, Decode, PassByEnum, Copy, Clone)] +#[derive(Encode, Decode, Copy, Clone)] pub enum LogLevel { /// `Error` log level. Error = 1_isize, @@ -216,6 +214,26 @@ pub enum LogLevel { Trace = 5_isize, } +impl TryFrom for LogLevel { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + 1 => Ok(Self::Error), + 2 => Ok(Self::Warn), + 3 => Ok(Self::Info), + 4 => Ok(Self::Debug), + 5 => Ok(Self::Trace), + _ => Err(()), + } + } +} + +impl From for u8 { + fn from(value: LogLevel) -> Self { + value as Self + } +} + impl From for LogLevel { fn from(val: u32) -> Self { match val { @@ -257,7 +275,7 @@ impl From for log::Level { /// Log level filter that expresses which log levels should be filtered. /// /// This enum matches the [`log::LevelFilter`] enum. -#[derive(Encode, Decode, PassByEnum, Copy, Clone)] +#[derive(Encode, Decode, Copy, Clone)] pub enum LogLevelFilter { /// `Off` log level filter. Off = 0_isize, @@ -273,6 +291,27 @@ pub enum LogLevelFilter { Trace = 5_isize, } +impl TryFrom for LogLevelFilter { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::Off), + 1 => Ok(Self::Error), + 2 => Ok(Self::Warn), + 3 => Ok(Self::Info), + 4 => Ok(Self::Debug), + 5 => Ok(Self::Trace), + _ => Err(()), + } + } +} + +impl From for u8 { + fn from(value: LogLevelFilter) -> Self { + value as Self + } +} + impl From for log::LevelFilter { fn from(l: LogLevelFilter) -> Self { use self::LogLevelFilter::*; diff --git a/substrate/primitives/core/src/offchain/mod.rs b/substrate/primitives/core/src/offchain/mod.rs index 9be86e85d5878..b98644b7e01eb 100644 --- a/substrate/primitives/core/src/offchain/mod.rs +++ b/substrate/primitives/core/src/offchain/mod.rs @@ -21,7 +21,6 @@ use crate::{OpaquePeerId, RuntimeDebug}; use alloc::{boxed::Box, vec::Vec}; use codec::{Decode, Encode}; use scale_info::TypeInfo; -use sp_runtime_interface::pass_by::{PassByCodec, PassByEnum, PassByInner}; pub use crate::crypto::KeyTypeId; @@ -57,7 +56,7 @@ pub trait OffchainStorage: Clone + Send + Sync { } /// A type of supported crypto. -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, RuntimeDebug, PassByEnum)] +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, RuntimeDebug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(C)] pub enum StorageKind { @@ -89,17 +88,27 @@ impl TryFrom for StorageKind { impl From for u32 { fn from(c: StorageKind) -> Self { - c as u8 as u32 + c as u32 } } /// Opaque type for offchain http requests. -#[derive( - Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, Encode, Decode, PassByInner, -)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, Encode, Decode)] #[cfg_attr(feature = "std", derive(Hash))] pub struct HttpRequestId(pub u16); +impl From for HttpRequestId { + fn from(value: u16) -> Self { + Self(value) + } +} + +impl From for u16 { + fn from(c: HttpRequestId) -> Self { + c.0 + } +} + impl From for u32 { fn from(c: HttpRequestId) -> Self { c.0 as u32 @@ -107,7 +116,7 @@ impl From for u32 { } /// An error enum returned by some http methods. -#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode, PassByEnum)] +#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode)] #[repr(C)] pub enum HttpError { /// The requested action couldn't been completed within a deadline. @@ -138,7 +147,7 @@ impl From for u32 { } /// Status of the HTTP request -#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode, PassByCodec)] +#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode)] pub enum HttpRequestStatus { /// Deadline was reached while we waited for this request to finish. /// @@ -184,7 +193,7 @@ impl TryFrom for HttpRequestStatus { /// A blob to hold information about the local node's network state /// without committing to its format. -#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByCodec, TypeInfo)] +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(Default))] pub struct OpaqueNetworkState { /// PeerId of the local node in SCALE encoded. @@ -194,7 +203,7 @@ pub struct OpaqueNetworkState { } /// Simple blob to hold a `Multiaddr` without committing to its format. -#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByInner, TypeInfo)] +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct OpaqueMultiaddr(pub Vec); impl OpaqueMultiaddr { @@ -205,16 +214,24 @@ impl OpaqueMultiaddr { } /// Opaque timestamp type -#[derive( - Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode, -)] +#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, Encode, Decode)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Timestamp(u64); +impl From for Timestamp { + fn from(value: u64) -> Self { + Self(value) + } +} + +impl From for u64 { + fn from(value: Timestamp) -> u64 { + value.0 + } +} + /// Duration type -#[derive( - Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode, -)] +#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, Encode, Decode)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Duration(u64); @@ -604,13 +621,13 @@ impl Externalities for LimitedExternalities { } } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] sp_externalities::decl_extension! { /// The offchain worker extension that will be registered at the Substrate externalities. pub struct OffchainWorkerExt(Box); } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] impl OffchainWorkerExt { /// Create a new instance of `Self`. pub fn new(offchain: O) -> Self { @@ -710,13 +727,13 @@ impl DbExternalities for LimitedExternalities { } } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] sp_externalities::decl_extension! { /// The offchain database extension that will be registered at the Substrate externalities. pub struct OffchainDbExt(Box); } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] impl OffchainDbExt { /// Create a new instance of `OffchainDbExt`. pub fn new(offchain: O) -> Self { @@ -729,7 +746,7 @@ impl OffchainDbExt { /// This trait is currently used within the `ExternalitiesExtension` /// to provide offchain calls with access to the transaction pool without /// tight coupling with any pool implementation. -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub trait TransactionPool { /// Submit transaction. /// @@ -737,13 +754,13 @@ pub trait TransactionPool { fn submit_transaction(&mut self, extrinsic: Vec) -> Result<(), ()>; } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] sp_externalities::decl_extension! { /// An externalities extension to submit transactions to the pool. pub struct TransactionPoolExt(Box); } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] impl TransactionPoolExt { /// Create a new instance of `TransactionPoolExt`. pub fn new(pool: O) -> Self { diff --git a/substrate/primitives/core/src/sr25519.rs b/substrate/primitives/core/src/sr25519.rs index 48780f2ccff93..5541b0d0e8281 100644 --- a/substrate/primitives/core/src/sr25519.rs +++ b/substrate/primitives/core/src/sr25519.rs @@ -42,8 +42,6 @@ use alloc::{format, string::String}; use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH}; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(feature = "std")] -use sp_runtime_interface::pass_by::PassByInner; // signing context const SIGNING_CTX: &[u8] = b"substrate"; @@ -104,7 +102,7 @@ impl core::fmt::Debug for Public { #[cfg(feature = "std")] fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { let s = self.to_ss58check(); - write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(self.inner()), &s[0..8]) + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) } #[cfg(not(feature = "std"))] @@ -269,7 +267,7 @@ impl TraitPair for Pair { } } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] impl Pair { /// Verify a signature on a message. Returns `true` if the signature is good. /// Supports old 0.1.1 deprecated signatures and should be used only for backward diff --git a/substrate/primitives/core/src/traits.rs b/substrate/primitives/core/src/traits.rs index 851d89103914e..f9b29c41a9eeb 100644 --- a/substrate/primitives/core/src/traits.rs +++ b/substrate/primitives/core/src/traits.rs @@ -17,10 +17,8 @@ //! Shareable Substrate traits. -use std::{ - borrow::Cow, - fmt::{Debug, Display}, -}; +use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec}; +use core::fmt::{Debug, Display}; pub use sp_externalities::{Externalities, ExternalitiesExt}; @@ -64,7 +62,7 @@ pub trait FetchRuntimeCode { } /// Wrapper to use a `u8` slice or `Vec` as [`FetchRuntimeCode`]. -pub struct WrappedRuntimeCode<'a>(pub std::borrow::Cow<'a, [u8]>); +pub struct WrappedRuntimeCode<'a>(pub Cow<'a, [u8]>); impl<'a> FetchRuntimeCode for WrappedRuntimeCode<'a> { fn fetch_runtime_code(&self) -> Option> { @@ -122,8 +120,8 @@ impl<'a> FetchRuntimeCode for RuntimeCode<'a> { #[derive(Debug)] pub struct CodeNotFound; -impl std::fmt::Display for CodeNotFound { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { +impl core::fmt::Display for CodeNotFound { + fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { write!(f, "the storage entry `:code` doesn't have any code") } } @@ -156,7 +154,7 @@ pub trait ReadRuntimeVersion: Send + Sync { ) -> Result, String>; } -impl ReadRuntimeVersion for std::sync::Arc { +impl ReadRuntimeVersion for alloc::sync::Arc { fn read_runtime_version( &self, wasm_code: &[u8], @@ -180,8 +178,7 @@ impl ReadRuntimeVersionExt { /// Something that can spawn tasks (blocking and non-blocking) with an assigned name /// and optional group. -#[dyn_clonable::clonable] -pub trait SpawnNamed: Clone + Send + Sync { +pub trait SpawnNamed: dyn_clone::DynClone + Send + Sync { /// Spawn the given blocking future. /// /// The given `group` and `name` is used to identify the future in tracing. @@ -202,6 +199,8 @@ pub trait SpawnNamed: Clone + Send + Sync { ); } +dyn_clone::clone_trait_object!(SpawnNamed); + impl SpawnNamed for Box { fn spawn_blocking( &self, @@ -225,8 +224,7 @@ impl SpawnNamed for Box { /// and optional group. /// /// Essential tasks are special tasks that should take down the node when they end. -#[dyn_clonable::clonable] -pub trait SpawnEssentialNamed: Clone + Send + Sync { +pub trait SpawnEssentialNamed: dyn_clone::DynClone + Send + Sync { /// Spawn the given blocking future. /// /// The given `group` and `name` is used to identify the future in tracing. @@ -247,6 +245,8 @@ pub trait SpawnEssentialNamed: Clone + Send + Sync { ); } +dyn_clone::clone_trait_object!(SpawnEssentialNamed); + impl SpawnEssentialNamed for Box { fn spawn_essential_blocking( &self, diff --git a/substrate/primitives/crypto/ec-utils/src/bls12_377.rs b/substrate/primitives/crypto/ec-utils/src/bls12_377.rs index a1ea5dbbf935a..0413ae7ff96cf 100644 --- a/substrate/primitives/crypto/ec-utils/src/bls12_377.rs +++ b/substrate/primitives/crypto/ec-utils/src/bls12_377.rs @@ -21,7 +21,10 @@ use crate::utils; use alloc::vec::Vec; use ark_bls12_377_ext::CurveHooks; use ark_ec::{pairing::Pairing, CurveConfig}; -use sp_runtime_interface::runtime_interface; +use sp_runtime_interface::{ + pass_by::{AllocateAndReturnByCodec, PassFatPointerAndRead}, + runtime_interface, +}; /// First pairing group definitions. pub mod g1 { @@ -151,7 +154,10 @@ pub trait HostCalls { /// - `a`: `ArkScale>`. /// - `b`: `ArkScale>`. /// - Returns encoded: `ArkScale`. - fn bls12_377_multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { + fn bls12_377_multi_miller_loop( + a: PassFatPointerAndRead>, + b: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::multi_miller_loop::(a, b) } @@ -159,7 +165,9 @@ pub trait HostCalls { /// /// - Receives encoded: `ArkScale`. /// - Returns encoded: `ArkScale`. - fn bls12_377_final_exponentiation(f: Vec) -> Result, ()> { + fn bls12_377_final_exponentiation( + f: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::final_exponentiation::(f) } @@ -169,7 +177,10 @@ pub trait HostCalls { /// - `bases`: `ArkScale>`. /// - `scalars`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn bls12_377_msm_g1(bases: Vec, scalars: Vec) -> Result, ()> { + fn bls12_377_msm_g1( + bases: PassFatPointerAndRead>, + scalars: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::msm_sw::(bases, scalars) } @@ -179,7 +190,10 @@ pub trait HostCalls { /// - `bases`: `ArkScale>`. /// - `scalars`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn bls12_377_msm_g2(bases: Vec, scalars: Vec) -> Result, ()> { + fn bls12_377_msm_g2( + bases: PassFatPointerAndRead>, + scalars: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::msm_sw::(bases, scalars) } @@ -189,7 +203,10 @@ pub trait HostCalls { /// - `base`: `ArkScaleProjective`. /// - `scalar`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn bls12_377_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { + fn bls12_377_mul_projective_g1( + base: PassFatPointerAndRead>, + scalar: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::mul_projective_sw::(base, scalar) } @@ -199,7 +216,10 @@ pub trait HostCalls { /// - `base`: `ArkScaleProjective`. /// - `scalar`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn bls12_377_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { + fn bls12_377_mul_projective_g2( + base: PassFatPointerAndRead>, + scalar: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::mul_projective_sw::(base, scalar) } } diff --git a/substrate/primitives/crypto/ec-utils/src/bls12_381.rs b/substrate/primitives/crypto/ec-utils/src/bls12_381.rs index 5e02862ed7ba5..573322d6ce8c9 100644 --- a/substrate/primitives/crypto/ec-utils/src/bls12_381.rs +++ b/substrate/primitives/crypto/ec-utils/src/bls12_381.rs @@ -21,7 +21,10 @@ use crate::utils; use alloc::vec::Vec; use ark_bls12_381_ext::CurveHooks; use ark_ec::{pairing::Pairing, CurveConfig}; -use sp_runtime_interface::runtime_interface; +use sp_runtime_interface::{ + pass_by::{AllocateAndReturnByCodec, PassFatPointerAndRead}, + runtime_interface, +}; /// First pairing group definitions. pub mod g1 { @@ -141,7 +144,10 @@ pub trait HostCalls { /// - `a`: `ArkScale>`. /// - `b`: `ArkScale>`. /// - Returns encoded: `ArkScale`. - fn bls12_381_multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { + fn bls12_381_multi_miller_loop( + a: PassFatPointerAndRead>, + b: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::multi_miller_loop::(a, b) } @@ -149,7 +155,9 @@ pub trait HostCalls { /// /// - Receives encoded: `ArkScale<`. /// - Returns encoded: `ArkScale<` - fn bls12_381_final_exponentiation(f: Vec) -> Result, ()> { + fn bls12_381_final_exponentiation( + f: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::final_exponentiation::(f) } @@ -159,7 +167,10 @@ pub trait HostCalls { /// - `bases`: `ArkScale>`. /// - `scalars`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn bls12_381_msm_g1(bases: Vec, scalars: Vec) -> Result, ()> { + fn bls12_381_msm_g1( + bases: PassFatPointerAndRead>, + scalars: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::msm_sw::(bases, scalars) } @@ -169,7 +180,10 @@ pub trait HostCalls { /// - `bases`: `ArkScale>`. /// - `scalars`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn bls12_381_msm_g2(bases: Vec, scalars: Vec) -> Result, ()> { + fn bls12_381_msm_g2( + bases: PassFatPointerAndRead>, + scalars: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::msm_sw::(bases, scalars) } @@ -179,7 +193,10 @@ pub trait HostCalls { /// - `base`: `ArkScaleProjective`. /// - `scalar`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn bls12_381_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { + fn bls12_381_mul_projective_g1( + base: PassFatPointerAndRead>, + scalar: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::mul_projective_sw::(base, scalar) } @@ -189,7 +206,10 @@ pub trait HostCalls { /// - `base`: `ArkScaleProjective`. /// - `scalar`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn bls12_381_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { + fn bls12_381_mul_projective_g2( + base: PassFatPointerAndRead>, + scalar: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::mul_projective_sw::(base, scalar) } } diff --git a/substrate/primitives/crypto/ec-utils/src/bw6_761.rs b/substrate/primitives/crypto/ec-utils/src/bw6_761.rs index 4ee1035f670f8..399ededbedf66 100644 --- a/substrate/primitives/crypto/ec-utils/src/bw6_761.rs +++ b/substrate/primitives/crypto/ec-utils/src/bw6_761.rs @@ -21,7 +21,10 @@ use crate::utils; use alloc::vec::Vec; use ark_bw6_761_ext::CurveHooks; use ark_ec::{pairing::Pairing, CurveConfig}; -use sp_runtime_interface::runtime_interface; +use sp_runtime_interface::{ + pass_by::{AllocateAndReturnByCodec, PassFatPointerAndRead}, + runtime_interface, +}; /// First pairing group definitions. pub mod g1 { @@ -132,7 +135,10 @@ pub trait HostCalls { /// - `a: ArkScale>`. /// - `b: ArkScale>`. /// - Returns encoded: `ArkScale`. - fn bw6_761_multi_miller_loop(a: Vec, b: Vec) -> Result, ()> { + fn bw6_761_multi_miller_loop( + a: PassFatPointerAndRead>, + b: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::multi_miller_loop::(a, b) } @@ -140,7 +146,9 @@ pub trait HostCalls { /// /// - Receives encoded: `ArkScale`. /// - Returns encoded: `ArkScale`. - fn bw6_761_final_exponentiation(f: Vec) -> Result, ()> { + fn bw6_761_final_exponentiation( + f: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::final_exponentiation::(f) } @@ -150,7 +158,10 @@ pub trait HostCalls { /// - `bases`: `ArkScale>`. /// - `scalars`: `ArkScale`. /// - Returns encoded: `ArkScaleProjective`. - fn bw6_761_msm_g1(bases: Vec, scalars: Vec) -> Result, ()> { + fn bw6_761_msm_g1( + bases: PassFatPointerAndRead>, + scalars: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::msm_sw::(bases, scalars) } @@ -160,7 +171,10 @@ pub trait HostCalls { /// - `bases`: `ArkScale>`. /// - `scalars`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn bw6_761_msm_g2(bases: Vec, scalars: Vec) -> Result, ()> { + fn bw6_761_msm_g2( + bases: PassFatPointerAndRead>, + scalars: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::msm_sw::(bases, scalars) } @@ -170,7 +184,10 @@ pub trait HostCalls { /// - `base`: `ArkScaleProjective`. /// - `scalar`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn bw6_761_mul_projective_g1(base: Vec, scalar: Vec) -> Result, ()> { + fn bw6_761_mul_projective_g1( + base: PassFatPointerAndRead>, + scalar: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::mul_projective_sw::(base, scalar) } @@ -180,7 +197,10 @@ pub trait HostCalls { /// - `base`: `ArkScaleProjective`. /// - `scalar`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn bw6_761_mul_projective_g2(base: Vec, scalar: Vec) -> Result, ()> { + fn bw6_761_mul_projective_g2( + base: PassFatPointerAndRead>, + scalar: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::mul_projective_sw::(base, scalar) } } diff --git a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs index e068507b3473e..11ddfcdb9b2e3 100644 --- a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs +++ b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_377.rs @@ -21,7 +21,10 @@ use crate::utils; use alloc::vec::Vec; use ark_ec::CurveConfig; use ark_ed_on_bls12_377_ext::CurveHooks; -use sp_runtime_interface::runtime_interface; +use sp_runtime_interface::{ + pass_by::{AllocateAndReturnByCodec, PassFatPointerAndRead}, + runtime_interface, +}; /// Curve hooks jumping into [`host_calls`] host functions. #[derive(Copy, Clone)] @@ -72,7 +75,10 @@ pub trait HostCalls { /// - `base`: `ArkScaleProjective`. /// - `scalars`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn ed_on_bls12_377_te_msm(bases: Vec, scalars: Vec) -> Result, ()> { + fn ed_on_bls12_377_te_msm( + bases: PassFatPointerAndRead>, + scalars: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::msm_te::(bases, scalars) } @@ -82,7 +88,10 @@ pub trait HostCalls { /// - `base`: `ArkScaleProjective`. /// - `scalar`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. - fn ed_on_bls12_377_te_mul_projective(base: Vec, scalar: Vec) -> Result, ()> { + fn ed_on_bls12_377_te_mul_projective( + base: PassFatPointerAndRead>, + scalar: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::mul_projective_te::(base, scalar) } } diff --git a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs index 487ad98dac657..7b25d1fbecf56 100644 --- a/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs +++ b/substrate/primitives/crypto/ec-utils/src/ed_on_bls12_381_bandersnatch.rs @@ -22,7 +22,10 @@ use crate::utils; use alloc::vec::Vec; use ark_ec::CurveConfig; use ark_ed_on_bls12_381_bandersnatch_ext::CurveHooks; -use sp_runtime_interface::runtime_interface; +use sp_runtime_interface::{ + pass_by::{AllocateAndReturnByCodec, PassFatPointerAndRead}, + runtime_interface, +}; /// Curve hooks jumping into [`host_calls`] host functions. #[derive(Copy, Clone)] @@ -106,9 +109,9 @@ pub trait HostCalls { /// - `scalars`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. fn ed_on_bls12_381_bandersnatch_te_msm( - bases: Vec, - scalars: Vec, - ) -> Result, ()> { + bases: PassFatPointerAndRead>, + scalars: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::msm_te::(bases, scalars) } @@ -119,9 +122,9 @@ pub trait HostCalls { /// - `scalar`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. fn ed_on_bls12_381_bandersnatch_te_mul_projective( - base: Vec, - scalar: Vec, - ) -> Result, ()> { + base: PassFatPointerAndRead>, + scalar: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::mul_projective_te::(base, scalar) } @@ -132,9 +135,9 @@ pub trait HostCalls { /// - `scalars`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. fn ed_on_bls12_381_bandersnatch_sw_msm( - bases: Vec, - scalars: Vec, - ) -> Result, ()> { + bases: PassFatPointerAndRead>, + scalars: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::msm_sw::(bases, scalars) } @@ -145,9 +148,9 @@ pub trait HostCalls { /// - `scalar`: `ArkScale>`. /// - Returns encoded: `ArkScaleProjective`. fn ed_on_bls12_381_bandersnatch_sw_mul_projective( - base: Vec, - scalar: Vec, - ) -> Result, ()> { + base: PassFatPointerAndRead>, + scalar: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec, ()>> { utils::mul_projective_sw::(base, scalar) } } diff --git a/substrate/primitives/externalities/src/extensions.rs b/substrate/primitives/externalities/src/extensions.rs index a4aa847a1aa84..6e7e369a676cf 100644 --- a/substrate/primitives/externalities/src/extensions.rs +++ b/substrate/primitives/externalities/src/extensions.rs @@ -160,9 +160,8 @@ pub struct Extensions { extensions: BTreeMap>, } -#[cfg(feature = "std")] -impl std::fmt::Debug for Extensions { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl core::fmt::Debug for Extensions { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Extensions: ({})", self.extensions.len()) } } diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index b7cc7e91ce82c..38ff09e0cdf09 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -20,8 +20,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytes = { workspace = true } codec = { features = ["bytes"], workspace = true } -libsecp256k1 = { optional = true, workspace = true, default-features = true } -log = { optional = true, workspace = true, default-features = true } secp256k1 = { features = ["global-context", "recovery"], optional = true, workspace = true, default-features = true } sp-core = { workspace = true } sp-crypto-hashing = { workspace = true } @@ -34,8 +32,16 @@ sp-trie = { optional = true, workspace = true } tracing = { workspace = true } tracing-core = { workspace = true } +[target.'cfg(not(substrate_runtime))'.dependencies] +sp-keystore = { workspace = true, default-features = false } +sp-trie = { workspace = true, default-features = false } +sp-state-machine = { workspace = true, default-features = false } +log = { workspace = true, default-features = true } +libsecp256k1 = { workspace = true, default-features = false, features = ["static-context"] } +secp256k1 = { workspace = true, default-features = false, features = ["alloc", "recovery"] } + # Required for backwards compatibility reason, but only used for verifying when `UseDalekExt` is set. -ed25519-dalek = { optional = true, workspace = true } +ed25519-dalek = { workspace = true } docify = { workspace = true } @@ -50,11 +56,11 @@ default = ["std"] std = [ "bytes/std", "codec/std", - "ed25519-dalek", - "ed25519-dalek?/std", - "libsecp256k1", + "ed25519-dalek/std", + "libsecp256k1/std", "log/std", - "secp256k1", + "secp256k1/global-context", + "secp256k1/std", "sp-core/std", "sp-crypto-hashing/std", "sp-externalities/std", @@ -99,7 +105,7 @@ improved_panic_error_reporting = [] # This feature adds BLS crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bls-experimental = ["sp-keystore/bls-experimental"] +bls-experimental = ["sp-core/bls-experimental", "sp-keystore/bls-experimental"] # This feature adds Bandersnatch crypto primitives. # It should not be used in production since the implementation and interface may still diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index bea79ec23f7b0..825b8db7ab67a 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -81,17 +81,17 @@ extern crate alloc; use alloc::vec::Vec; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use tracing; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use sp_core::{ crypto::Pair, hexdisplay::HexDisplay, offchain::{OffchainDbExt, OffchainWorkerExt, TransactionPoolExt}, storage::ChildInfo, }; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use sp_keystore::KeystoreExt; #[cfg(feature = "bandersnatch-experimental")] @@ -110,23 +110,27 @@ use sp_core::{ #[cfg(feature = "bls-experimental")] use sp_core::{bls381, ecdsa_bls381}; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; use sp_runtime_interface::{ - pass_by::{PassBy, PassByCodec}, + pass_by::{ + AllocateAndReturnByCodec, AllocateAndReturnFatPointer, AllocateAndReturnPointer, PassAs, + PassFatPointerAndDecode, PassFatPointerAndDecodeSlice, PassFatPointerAndRead, + PassFatPointerAndReadWrite, PassPointerAndRead, PassPointerAndReadCopy, ReturnAs, + }, runtime_interface, Pointer, }; use codec::{Decode, Encode}; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, - Message, SECP256K1, + Message, }; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use sp_externalities::{Externalities, ExternalitiesExt}; pub use sp_externalities::MultiRemovalResults; @@ -141,7 +145,7 @@ mod global_alloc_wasm; ))] mod global_alloc_riscv; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] const LOG_TARGET: &str = "runtime::io"; /// Error verifying ECDSA signature @@ -157,7 +161,7 @@ pub enum EcdsaVerifyError { /// The outcome of calling `storage_kill`. Returned value is the number of storage items /// removed from the backend from making the `storage_kill` call. -#[derive(PassByCodec, Encode, Decode)] +#[derive(Encode, Decode)] pub enum KillStorageResult { /// All keys to remove were removed, return number of iterations performed during the /// operation. @@ -183,8 +187,11 @@ impl From for KillStorageResult { #[runtime_interface] pub trait Storage { /// Returns the data for `key` in the storage or `None` if the key can not be found. - fn get(&mut self, key: &[u8]) -> Option { - self.storage(key).map(bytes::Bytes::from) + fn get( + &mut self, + key: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec> { + self.storage(key).map(|s| bytes::Bytes::from(s.to_vec())) } /// Get `key` from storage, placing the value into `value_out` and return the number of @@ -192,33 +199,38 @@ pub trait Storage { /// doesn't exist at all. /// If `value_out` length is smaller than the returned length, only `value_out` length bytes /// are copied into `value_out`. - fn read(&mut self, key: &[u8], value_out: &mut [u8], value_offset: u32) -> Option { + fn read( + &mut self, + key: PassFatPointerAndRead<&[u8]>, + value_out: PassFatPointerAndReadWrite<&mut [u8]>, + value_offset: u32, + ) -> AllocateAndReturnByCodec> { self.storage(key).map(|value| { let value_offset = value_offset as usize; let data = &value[value_offset.min(value.len())..]; - let written = std::cmp::min(data.len(), value_out.len()); + let written = core::cmp::min(data.len(), value_out.len()); value_out[..written].copy_from_slice(&data[..written]); data.len() as u32 }) } /// Set `key` to `value` in the storage. - fn set(&mut self, key: &[u8], value: &[u8]) { + fn set(&mut self, key: PassFatPointerAndRead<&[u8]>, value: PassFatPointerAndRead<&[u8]>) { self.set_storage(key.to_vec(), value.to_vec()); } /// Clear the storage of the given `key` and its value. - fn clear(&mut self, key: &[u8]) { + fn clear(&mut self, key: PassFatPointerAndRead<&[u8]>) { self.clear_storage(key) } /// Check whether the given `key` exists in storage. - fn exists(&mut self, key: &[u8]) -> bool { + fn exists(&mut self, key: PassFatPointerAndRead<&[u8]>) -> bool { self.exists_storage(key) } /// Clear the storage of each key-value pair where the key starts with the given `prefix`. - fn clear_prefix(&mut self, prefix: &[u8]) { + fn clear_prefix(&mut self, prefix: PassFatPointerAndRead<&[u8]>) { let _ = Externalities::clear_prefix(*self, prefix, None, None); } @@ -248,7 +260,11 @@ pub trait Storage { /// because the keys in the overlay are not taken into account when deleting keys in the /// backend. #[version(2)] - fn clear_prefix(&mut self, prefix: &[u8], limit: Option) -> KillStorageResult { + fn clear_prefix( + &mut self, + prefix: PassFatPointerAndRead<&[u8]>, + limit: PassFatPointerAndDecode>, + ) -> AllocateAndReturnByCodec { Externalities::clear_prefix(*self, prefix, limit, None).into() } @@ -286,10 +302,11 @@ pub trait Storage { #[version(3, register_only)] fn clear_prefix( &mut self, - maybe_prefix: &[u8], - maybe_limit: Option, - maybe_cursor: Option>, //< TODO Make work or just Option>? - ) -> MultiRemovalResults { + maybe_prefix: PassFatPointerAndRead<&[u8]>, + maybe_limit: PassFatPointerAndDecode>, + maybe_cursor: PassFatPointerAndDecode>>, /* TODO Make work or just + * Option>? */ + ) -> AllocateAndReturnByCodec { Externalities::clear_prefix( *self, maybe_prefix, @@ -307,7 +324,7 @@ pub trait Storage { /// /// If the storage item does not support [`EncodeAppend`](codec::EncodeAppend) or /// something else fails at appending, the storage item will be set to `[value]`. - fn append(&mut self, key: &[u8], value: Vec) { + fn append(&mut self, key: PassFatPointerAndRead<&[u8]>, value: PassFatPointerAndRead>) { self.storage_append(key.to_vec(), value); } @@ -316,7 +333,7 @@ pub trait Storage { /// The hashing algorithm is defined by the `Block`. /// /// Returns a `Vec` that holds the SCALE encoded hash. - fn root(&mut self) -> Vec { + fn root(&mut self) -> AllocateAndReturnFatPointer> { self.storage_root(StateVersion::V0) } @@ -326,17 +343,23 @@ pub trait Storage { /// /// Returns a `Vec` that holds the SCALE encoded hash. #[version(2)] - fn root(&mut self, version: StateVersion) -> Vec { + fn root(&mut self, version: PassAs) -> AllocateAndReturnFatPointer> { self.storage_root(version) } /// Always returns `None`. This function exists for compatibility reasons. - fn changes_root(&mut self, _parent_hash: &[u8]) -> Option> { + fn changes_root( + &mut self, + _parent_hash: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec>> { None } /// Get the next key in storage after the given one in lexicographic order. - fn next_key(&mut self, key: &[u8]) -> Option> { + fn next_key( + &mut self, + key: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec>> { self.next_storage_key(key) } @@ -389,7 +412,11 @@ pub trait DefaultChildStorage { /// /// Parameter `storage_key` is the unprefixed location of the root of the child trie in the /// parent trie. Result is `None` if the value for `key` in the child storage can not be found. - fn get(&mut self, storage_key: &[u8], key: &[u8]) -> Option> { + fn get( + &mut self, + storage_key: PassFatPointerAndRead<&[u8]>, + key: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec>> { let child_info = ChildInfo::new_default(storage_key); self.child_storage(&child_info, key).map(|s| s.to_vec()) } @@ -403,16 +430,16 @@ pub trait DefaultChildStorage { /// are copied into `value_out`. fn read( &mut self, - storage_key: &[u8], - key: &[u8], - value_out: &mut [u8], + storage_key: PassFatPointerAndRead<&[u8]>, + key: PassFatPointerAndRead<&[u8]>, + value_out: PassFatPointerAndReadWrite<&mut [u8]>, value_offset: u32, - ) -> Option { + ) -> AllocateAndReturnByCodec> { let child_info = ChildInfo::new_default(storage_key); self.child_storage(&child_info, key).map(|value| { let value_offset = value_offset as usize; let data = &value[value_offset.min(value.len())..]; - let written = std::cmp::min(data.len(), value_out.len()); + let written = core::cmp::min(data.len(), value_out.len()); value_out[..written].copy_from_slice(&data[..written]); data.len() as u32 }) @@ -421,7 +448,12 @@ pub trait DefaultChildStorage { /// Set a child storage value. /// /// Set `key` to `value` in the child storage denoted by `storage_key`. - fn set(&mut self, storage_key: &[u8], key: &[u8], value: &[u8]) { + fn set( + &mut self, + storage_key: PassFatPointerAndRead<&[u8]>, + key: PassFatPointerAndRead<&[u8]>, + value: PassFatPointerAndRead<&[u8]>, + ) { let child_info = ChildInfo::new_default(storage_key); self.set_child_storage(&child_info, key.to_vec(), value.to_vec()); } @@ -429,7 +461,11 @@ pub trait DefaultChildStorage { /// Clear a child storage key. /// /// For the default child storage at `storage_key`, clear value at `key`. - fn clear(&mut self, storage_key: &[u8], key: &[u8]) { + fn clear( + &mut self, + storage_key: PassFatPointerAndRead<&[u8]>, + key: PassFatPointerAndRead<&[u8]>, + ) { let child_info = ChildInfo::new_default(storage_key); self.clear_child_storage(&child_info, key); } @@ -438,7 +474,7 @@ pub trait DefaultChildStorage { /// /// If it exists, the child storage for `storage_key` /// is removed. - fn storage_kill(&mut self, storage_key: &[u8]) { + fn storage_kill(&mut self, storage_key: PassFatPointerAndRead<&[u8]>) { let child_info = ChildInfo::new_default(storage_key); let _ = self.kill_child_storage(&child_info, None, None); } @@ -447,7 +483,11 @@ pub trait DefaultChildStorage { /// /// See `Storage` module `clear_prefix` documentation for `limit` usage. #[version(2)] - fn storage_kill(&mut self, storage_key: &[u8], limit: Option) -> bool { + fn storage_kill( + &mut self, + storage_key: PassFatPointerAndRead<&[u8]>, + limit: PassFatPointerAndDecode>, + ) -> bool { let child_info = ChildInfo::new_default(storage_key); let r = self.kill_child_storage(&child_info, limit, None); r.maybe_cursor.is_none() @@ -457,7 +497,11 @@ pub trait DefaultChildStorage { /// /// See `Storage` module `clear_prefix` documentation for `limit` usage. #[version(3)] - fn storage_kill(&mut self, storage_key: &[u8], limit: Option) -> KillStorageResult { + fn storage_kill( + &mut self, + storage_key: PassFatPointerAndRead<&[u8]>, + limit: PassFatPointerAndDecode>, + ) -> AllocateAndReturnByCodec { let child_info = ChildInfo::new_default(storage_key); self.kill_child_storage(&child_info, limit, None).into() } @@ -468,10 +512,10 @@ pub trait DefaultChildStorage { #[version(4, register_only)] fn storage_kill( &mut self, - storage_key: &[u8], - maybe_limit: Option, - maybe_cursor: Option>, - ) -> MultiRemovalResults { + storage_key: PassFatPointerAndRead<&[u8]>, + maybe_limit: PassFatPointerAndDecode>, + maybe_cursor: PassFatPointerAndDecode>>, + ) -> AllocateAndReturnByCodec { let child_info = ChildInfo::new_default(storage_key); self.kill_child_storage(&child_info, maybe_limit, maybe_cursor.as_ref().map(|x| &x[..])) .into() @@ -480,7 +524,11 @@ pub trait DefaultChildStorage { /// Check a child storage key. /// /// Check whether the given `key` exists in default child defined at `storage_key`. - fn exists(&mut self, storage_key: &[u8], key: &[u8]) -> bool { + fn exists( + &mut self, + storage_key: PassFatPointerAndRead<&[u8]>, + key: PassFatPointerAndRead<&[u8]>, + ) -> bool { let child_info = ChildInfo::new_default(storage_key); self.exists_child_storage(&child_info, key) } @@ -488,7 +536,11 @@ pub trait DefaultChildStorage { /// Clear child default key by prefix. /// /// Clear the child storage of each key-value pair where the key starts with the given `prefix`. - fn clear_prefix(&mut self, storage_key: &[u8], prefix: &[u8]) { + fn clear_prefix( + &mut self, + storage_key: PassFatPointerAndRead<&[u8]>, + prefix: PassFatPointerAndRead<&[u8]>, + ) { let child_info = ChildInfo::new_default(storage_key); let _ = self.clear_child_prefix(&child_info, prefix, None, None); } @@ -499,10 +551,10 @@ pub trait DefaultChildStorage { #[version(2)] fn clear_prefix( &mut self, - storage_key: &[u8], - prefix: &[u8], - limit: Option, - ) -> KillStorageResult { + storage_key: PassFatPointerAndRead<&[u8]>, + prefix: PassFatPointerAndRead<&[u8]>, + limit: PassFatPointerAndDecode>, + ) -> AllocateAndReturnByCodec { let child_info = ChildInfo::new_default(storage_key); self.clear_child_prefix(&child_info, prefix, limit, None).into() } @@ -513,11 +565,11 @@ pub trait DefaultChildStorage { #[version(3, register_only)] fn clear_prefix( &mut self, - storage_key: &[u8], - prefix: &[u8], - maybe_limit: Option, - maybe_cursor: Option>, - ) -> MultiRemovalResults { + storage_key: PassFatPointerAndRead<&[u8]>, + prefix: PassFatPointerAndRead<&[u8]>, + maybe_limit: PassFatPointerAndDecode>, + maybe_cursor: PassFatPointerAndDecode>>, + ) -> AllocateAndReturnByCodec { let child_info = ChildInfo::new_default(storage_key); self.clear_child_prefix( &child_info, @@ -534,7 +586,10 @@ pub trait DefaultChildStorage { /// The hashing algorithm is defined by the `Block`. /// /// Returns a `Vec` that holds the SCALE encoded hash. - fn root(&mut self, storage_key: &[u8]) -> Vec { + fn root( + &mut self, + storage_key: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnFatPointer> { let child_info = ChildInfo::new_default(storage_key); self.child_storage_root(&child_info, StateVersion::V0) } @@ -546,7 +601,11 @@ pub trait DefaultChildStorage { /// /// Returns a `Vec` that holds the SCALE encoded hash. #[version(2)] - fn root(&mut self, storage_key: &[u8], version: StateVersion) -> Vec { + fn root( + &mut self, + storage_key: PassFatPointerAndRead<&[u8]>, + version: PassAs, + ) -> AllocateAndReturnFatPointer> { let child_info = ChildInfo::new_default(storage_key); self.child_storage_root(&child_info, version) } @@ -554,7 +613,11 @@ pub trait DefaultChildStorage { /// Child storage key iteration. /// /// Get the next key in storage after the given one in lexicographic order in child storage. - fn next_key(&mut self, storage_key: &[u8], key: &[u8]) -> Option> { + fn next_key( + &mut self, + storage_key: PassFatPointerAndRead<&[u8]>, + key: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec>> { let child_info = ChildInfo::new_default(storage_key); self.next_child_storage_key(&child_info, key) } @@ -564,13 +627,18 @@ pub trait DefaultChildStorage { #[runtime_interface] pub trait Trie { /// A trie root formed from the iterated items. - fn blake2_256_root(input: Vec<(Vec, Vec)>) -> H256 { + fn blake2_256_root( + input: PassFatPointerAndDecode, Vec)>>, + ) -> AllocateAndReturnPointer { LayoutV0::::trie_root(input) } /// A trie root formed from the iterated items. #[version(2)] - fn blake2_256_root(input: Vec<(Vec, Vec)>, version: StateVersion) -> H256 { + fn blake2_256_root( + input: PassFatPointerAndDecode, Vec)>>, + version: PassAs, + ) -> AllocateAndReturnPointer { match version { StateVersion::V0 => LayoutV0::::trie_root(input), StateVersion::V1 => LayoutV1::::trie_root(input), @@ -578,13 +646,18 @@ pub trait Trie { } /// A trie root formed from the enumerated items. - fn blake2_256_ordered_root(input: Vec>) -> H256 { + fn blake2_256_ordered_root( + input: PassFatPointerAndDecode>>, + ) -> AllocateAndReturnPointer { LayoutV0::::ordered_trie_root(input) } /// A trie root formed from the enumerated items. #[version(2)] - fn blake2_256_ordered_root(input: Vec>, version: StateVersion) -> H256 { + fn blake2_256_ordered_root( + input: PassFatPointerAndDecode>>, + version: PassAs, + ) -> AllocateAndReturnPointer { match version { StateVersion::V0 => LayoutV0::::ordered_trie_root(input), StateVersion::V1 => LayoutV1::::ordered_trie_root(input), @@ -592,13 +665,18 @@ pub trait Trie { } /// A trie root formed from the iterated items. - fn keccak_256_root(input: Vec<(Vec, Vec)>) -> H256 { + fn keccak_256_root( + input: PassFatPointerAndDecode, Vec)>>, + ) -> AllocateAndReturnPointer { LayoutV0::::trie_root(input) } /// A trie root formed from the iterated items. #[version(2)] - fn keccak_256_root(input: Vec<(Vec, Vec)>, version: StateVersion) -> H256 { + fn keccak_256_root( + input: PassFatPointerAndDecode, Vec)>>, + version: PassAs, + ) -> AllocateAndReturnPointer { match version { StateVersion::V0 => LayoutV0::::trie_root(input), StateVersion::V1 => LayoutV1::::trie_root(input), @@ -606,13 +684,18 @@ pub trait Trie { } /// A trie root formed from the enumerated items. - fn keccak_256_ordered_root(input: Vec>) -> H256 { + fn keccak_256_ordered_root( + input: PassFatPointerAndDecode>>, + ) -> AllocateAndReturnPointer { LayoutV0::::ordered_trie_root(input) } /// A trie root formed from the enumerated items. #[version(2)] - fn keccak_256_ordered_root(input: Vec>, version: StateVersion) -> H256 { + fn keccak_256_ordered_root( + input: PassFatPointerAndDecode>>, + version: PassAs, + ) -> AllocateAndReturnPointer { match version { StateVersion::V0 => LayoutV0::::ordered_trie_root(input), StateVersion::V1 => LayoutV1::::ordered_trie_root(input), @@ -620,7 +703,12 @@ pub trait Trie { } /// Verify trie proof - fn blake2_256_verify_proof(root: H256, proof: &[Vec], key: &[u8], value: &[u8]) -> bool { + fn blake2_256_verify_proof( + root: PassPointerAndReadCopy, + proof: PassFatPointerAndDecodeSlice<&[Vec]>, + key: PassFatPointerAndRead<&[u8]>, + value: PassFatPointerAndRead<&[u8]>, + ) -> bool { sp_trie::verify_trie_proof::, _, _, _>( &root, proof, @@ -632,11 +720,11 @@ pub trait Trie { /// Verify trie proof #[version(2)] fn blake2_256_verify_proof( - root: H256, - proof: &[Vec], - key: &[u8], - value: &[u8], - version: StateVersion, + root: PassPointerAndReadCopy, + proof: PassFatPointerAndDecodeSlice<&[Vec]>, + key: PassFatPointerAndRead<&[u8]>, + value: PassFatPointerAndRead<&[u8]>, + version: PassAs, ) -> bool { match version { StateVersion::V0 => sp_trie::verify_trie_proof::< @@ -657,7 +745,12 @@ pub trait Trie { } /// Verify trie proof - fn keccak_256_verify_proof(root: H256, proof: &[Vec], key: &[u8], value: &[u8]) -> bool { + fn keccak_256_verify_proof( + root: PassPointerAndReadCopy, + proof: PassFatPointerAndDecodeSlice<&[Vec]>, + key: PassFatPointerAndRead<&[u8]>, + value: PassFatPointerAndRead<&[u8]>, + ) -> bool { sp_trie::verify_trie_proof::, _, _, _>( &root, proof, @@ -669,11 +762,11 @@ pub trait Trie { /// Verify trie proof #[version(2)] fn keccak_256_verify_proof( - root: H256, - proof: &[Vec], - key: &[u8], - value: &[u8], - version: StateVersion, + root: PassPointerAndReadCopy, + proof: PassFatPointerAndDecodeSlice<&[Vec]>, + key: PassFatPointerAndRead<&[u8]>, + value: PassFatPointerAndRead<&[u8]>, + version: PassAs, ) -> bool { match version { StateVersion::V0 => sp_trie::verify_trie_proof::< @@ -707,14 +800,14 @@ pub trait Misc { } /// Print any valid `utf8` buffer. - fn print_utf8(utf8: &[u8]) { - if let Ok(data) = std::str::from_utf8(utf8) { + fn print_utf8(utf8: PassFatPointerAndRead<&[u8]>) { + if let Ok(data) = core::str::from_utf8(utf8) { log::debug!(target: "runtime", "{}", data) } } /// Print any `u8` slice as hex. - fn print_hex(data: &[u8]) { + fn print_hex(data: PassFatPointerAndRead<&[u8]>) { log::debug!(target: "runtime", "{}", HexDisplay::from(&data)); } @@ -733,7 +826,10 @@ pub trait Misc { /// may be involved. This means that a runtime call will be performed to query the version. /// /// Calling into the runtime may be incredible expensive and should be approached with care. - fn runtime_version(&mut self, wasm: &[u8]) -> Option> { + fn runtime_version( + &mut self, + wasm: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec>> { use sp_core::traits::ReadRuntimeVersionExt; let mut ext = sp_state_machine::BasicExternalities::default(); @@ -756,7 +852,7 @@ pub trait Misc { } } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] sp_externalities::decl_extension! { /// Extension to signal to [`crypt::ed25519_verify`] to use the dalek crate. /// @@ -777,7 +873,7 @@ sp_externalities::decl_extension! { pub struct UseDalekExt; } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] impl Default for UseDalekExt { fn default() -> Self { Self @@ -788,7 +884,10 @@ impl Default for UseDalekExt { #[runtime_interface] pub trait Crypto { /// Returns all `ed25519` public keys for the given key id from the keystore. - fn ed25519_public_keys(&mut self, id: KeyTypeId) -> Vec { + fn ed25519_public_keys( + &mut self, + id: PassPointerAndReadCopy, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("No `keystore` associated for the current context!") .ed25519_public_keys(id) @@ -800,8 +899,12 @@ pub trait Crypto { /// The `seed` needs to be a valid utf8. /// /// Returns the public key. - fn ed25519_generate(&mut self, id: KeyTypeId, seed: Option>) -> ed25519::Public { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + fn ed25519_generate( + &mut self, + id: PassPointerAndReadCopy, + seed: PassFatPointerAndDecode>>, + ) -> AllocateAndReturnPointer { + let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") .ed25519_generate_new(id, seed) @@ -814,10 +917,10 @@ pub trait Crypto { /// Returns the signature. fn ed25519_sign( &mut self, - id: KeyTypeId, - pub_key: &ed25519::Public, - msg: &[u8], - ) -> Option { + id: PassPointerAndReadCopy, + pub_key: PassPointerAndRead<&ed25519::Public, 32>, + msg: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("No `keystore` associated for the current context!") .ed25519_sign(id, pub_key, msg) @@ -828,7 +931,11 @@ pub trait Crypto { /// Verify `ed25519` signature. /// /// Returns `true` when the verification was successful. - fn ed25519_verify(sig: &ed25519::Signature, msg: &[u8], pub_key: &ed25519::Public) -> bool { + fn ed25519_verify( + sig: PassPointerAndRead<&ed25519::Signature, 64>, + msg: PassFatPointerAndRead<&[u8]>, + pub_key: PassPointerAndRead<&ed25519::Public, 32>, + ) -> bool { // We don't want to force everyone needing to call the function in an externalities context. // So, we assume that we should not use dalek when we are not in externalities context. // Otherwise, we check if the extension is present. @@ -865,9 +972,9 @@ pub trait Crypto { #[version(1, register_only)] fn ed25519_batch_verify( &mut self, - sig: &ed25519::Signature, - msg: &[u8], - pub_key: &ed25519::Public, + sig: PassPointerAndRead<&ed25519::Signature, 64>, + msg: PassFatPointerAndRead<&[u8]>, + pub_key: PassPointerAndRead<&ed25519::Public, 32>, ) -> bool { let res = ed25519_verify(sig, msg, pub_key); @@ -882,7 +989,11 @@ pub trait Crypto { /// /// Returns `true` when the verification was successful. #[version(2)] - fn sr25519_verify(sig: &sr25519::Signature, msg: &[u8], pub_key: &sr25519::Public) -> bool { + fn sr25519_verify( + sig: PassPointerAndRead<&sr25519::Signature, 64>, + msg: PassFatPointerAndRead<&[u8]>, + pub_key: PassPointerAndRead<&sr25519::Public, 32>, + ) -> bool { sr25519::Pair::verify(sig, msg, pub_key) } @@ -902,9 +1013,9 @@ pub trait Crypto { #[version(1, register_only)] fn sr25519_batch_verify( &mut self, - sig: &sr25519::Signature, - msg: &[u8], - pub_key: &sr25519::Public, + sig: PassPointerAndRead<&sr25519::Signature, 64>, + msg: PassFatPointerAndRead<&[u8]>, + pub_key: PassPointerAndRead<&sr25519::Public, 32>, ) -> bool { let res = sr25519_verify(sig, msg, pub_key); @@ -952,7 +1063,10 @@ pub trait Crypto { } /// Returns all `sr25519` public keys for the given key id from the keystore. - fn sr25519_public_keys(&mut self, id: KeyTypeId) -> Vec { + fn sr25519_public_keys( + &mut self, + id: PassPointerAndReadCopy, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("No `keystore` associated for the current context!") .sr25519_public_keys(id) @@ -964,8 +1078,12 @@ pub trait Crypto { /// The `seed` needs to be a valid utf8. /// /// Returns the public key. - fn sr25519_generate(&mut self, id: KeyTypeId, seed: Option>) -> sr25519::Public { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + fn sr25519_generate( + &mut self, + id: PassPointerAndReadCopy, + seed: PassFatPointerAndDecode>>, + ) -> AllocateAndReturnPointer { + let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") .sr25519_generate_new(id, seed) @@ -978,10 +1096,10 @@ pub trait Crypto { /// Returns the signature. fn sr25519_sign( &mut self, - id: KeyTypeId, - pub_key: &sr25519::Public, - msg: &[u8], - ) -> Option { + id: PassPointerAndReadCopy, + pub_key: PassPointerAndRead<&sr25519::Public, 32>, + msg: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("No `keystore` associated for the current context!") .sr25519_sign(id, pub_key, msg) @@ -993,12 +1111,19 @@ pub trait Crypto { /// /// Returns `true` when the verification in successful regardless of /// signature version. - fn sr25519_verify(sig: &sr25519::Signature, msg: &[u8], pubkey: &sr25519::Public) -> bool { + fn sr25519_verify( + sig: PassPointerAndRead<&sr25519::Signature, 64>, + msg: PassFatPointerAndRead<&[u8]>, + pubkey: PassPointerAndRead<&sr25519::Public, 32>, + ) -> bool { sr25519::Pair::verify_deprecated(sig, msg, pubkey) } /// Returns all `ecdsa` public keys for the given key id from the keystore. - fn ecdsa_public_keys(&mut self, id: KeyTypeId) -> Vec { + fn ecdsa_public_keys( + &mut self, + id: PassPointerAndReadCopy, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("No `keystore` associated for the current context!") .ecdsa_public_keys(id) @@ -1010,8 +1135,12 @@ pub trait Crypto { /// The `seed` needs to be a valid utf8. /// /// Returns the public key. - fn ecdsa_generate(&mut self, id: KeyTypeId, seed: Option>) -> ecdsa::Public { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + fn ecdsa_generate( + &mut self, + id: PassPointerAndReadCopy, + seed: PassFatPointerAndDecode>>, + ) -> AllocateAndReturnPointer { + let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") .ecdsa_generate_new(id, seed) @@ -1024,10 +1153,10 @@ pub trait Crypto { /// Returns the signature. fn ecdsa_sign( &mut self, - id: KeyTypeId, - pub_key: &ecdsa::Public, - msg: &[u8], - ) -> Option { + id: PassPointerAndReadCopy, + pub_key: PassPointerAndRead<&ecdsa::Public, 33>, + msg: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("No `keystore` associated for the current context!") .ecdsa_sign(id, pub_key, msg) @@ -1041,10 +1170,10 @@ pub trait Crypto { /// Returns the signature. fn ecdsa_sign_prehashed( &mut self, - id: KeyTypeId, - pub_key: &ecdsa::Public, - msg: &[u8; 32], - ) -> Option { + id: PassPointerAndReadCopy, + pub_key: PassPointerAndRead<&ecdsa::Public, 33>, + msg: PassPointerAndRead<&[u8; 32], 32>, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("No `keystore` associated for the current context!") .ecdsa_sign_prehashed(id, pub_key, msg) @@ -1056,7 +1185,11 @@ pub trait Crypto { /// /// Returns `true` when the verification was successful. /// This version is able to handle, non-standard, overflowing signatures. - fn ecdsa_verify(sig: &ecdsa::Signature, msg: &[u8], pub_key: &ecdsa::Public) -> bool { + fn ecdsa_verify( + sig: PassPointerAndRead<&ecdsa::Signature, 65>, + msg: PassFatPointerAndRead<&[u8]>, + pub_key: PassPointerAndRead<&ecdsa::Public, 33>, + ) -> bool { #[allow(deprecated)] ecdsa::Pair::verify_deprecated(sig, msg, pub_key) } @@ -1065,7 +1198,11 @@ pub trait Crypto { /// /// Returns `true` when the verification was successful. #[version(2)] - fn ecdsa_verify(sig: &ecdsa::Signature, msg: &[u8], pub_key: &ecdsa::Public) -> bool { + fn ecdsa_verify( + sig: PassPointerAndRead<&ecdsa::Signature, 65>, + msg: PassFatPointerAndRead<&[u8]>, + pub_key: PassPointerAndRead<&ecdsa::Public, 33>, + ) -> bool { ecdsa::Pair::verify(sig, msg, pub_key) } @@ -1073,9 +1210,9 @@ pub trait Crypto { /// /// Returns `true` when the verification was successful. fn ecdsa_verify_prehashed( - sig: &ecdsa::Signature, - msg: &[u8; 32], - pub_key: &ecdsa::Public, + sig: PassPointerAndRead<&ecdsa::Signature, 65>, + msg: PassPointerAndRead<&[u8; 32], 32>, + pub_key: PassPointerAndRead<&ecdsa::Public, 33>, ) -> bool { ecdsa::Pair::verify_prehashed(sig, msg, pub_key) } @@ -1096,9 +1233,9 @@ pub trait Crypto { #[version(1, register_only)] fn ecdsa_batch_verify( &mut self, - sig: &ecdsa::Signature, - msg: &[u8], - pub_key: &ecdsa::Public, + sig: PassPointerAndRead<&ecdsa::Signature, 65>, + msg: PassFatPointerAndRead<&[u8]>, + pub_key: PassPointerAndRead<&ecdsa::Public, 33>, ) -> bool { let res = ecdsa_verify(sig, msg, pub_key); @@ -1118,9 +1255,9 @@ pub trait Crypto { /// (doesn't include the 0x04 prefix). /// This version is able to handle, non-standard, overflowing signatures. fn secp256k1_ecdsa_recover( - sig: &[u8; 65], - msg: &[u8; 32], - ) -> Result<[u8; 64], EcdsaVerifyError> { + sig: PassPointerAndRead<&[u8; 65], 65>, + msg: PassPointerAndRead<&[u8; 32], 32>, + ) -> AllocateAndReturnByCodec> { let rid = libsecp256k1::RecoveryId::parse( if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8, ) @@ -1144,17 +1281,19 @@ pub trait Crypto { /// (doesn't include the 0x04 prefix). #[version(2)] fn secp256k1_ecdsa_recover( - sig: &[u8; 65], - msg: &[u8; 32], - ) -> Result<[u8; 64], EcdsaVerifyError> { + sig: PassPointerAndRead<&[u8; 65], 65>, + msg: PassPointerAndRead<&[u8; 32], 32>, + ) -> AllocateAndReturnByCodec> { let rid = RecoveryId::from_i32(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as i32) .map_err(|_| EcdsaVerifyError::BadV)?; let sig = RecoverableSignature::from_compact(&sig[..64], rid) .map_err(|_| EcdsaVerifyError::BadRS)?; let msg = Message::from_digest_slice(msg).expect("Message is 32 bytes; qed"); - let pubkey = SECP256K1 - .recover_ecdsa(&msg, &sig) - .map_err(|_| EcdsaVerifyError::BadSignature)?; + #[cfg(feature = "std")] + let ctx = secp256k1::SECP256K1; + #[cfg(not(feature = "std"))] + let ctx = secp256k1::Secp256k1::::gen_new(); + let pubkey = ctx.recover_ecdsa(&msg, &sig).map_err(|_| EcdsaVerifyError::BadSignature)?; let mut res = [0u8; 64]; res.copy_from_slice(&pubkey.serialize_uncompressed()[1..]); Ok(res) @@ -1167,9 +1306,9 @@ pub trait Crypto { /// /// Returns `Err` if the signature is bad, otherwise the 33-byte compressed pubkey. fn secp256k1_ecdsa_recover_compressed( - sig: &[u8; 65], - msg: &[u8; 32], - ) -> Result<[u8; 33], EcdsaVerifyError> { + sig: PassPointerAndRead<&[u8; 65], 65>, + msg: PassPointerAndRead<&[u8; 32], 32>, + ) -> AllocateAndReturnByCodec> { let rid = libsecp256k1::RecoveryId::parse( if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8, ) @@ -1190,17 +1329,19 @@ pub trait Crypto { /// Returns `Err` if the signature is bad, otherwise the 33-byte compressed pubkey. #[version(2)] fn secp256k1_ecdsa_recover_compressed( - sig: &[u8; 65], - msg: &[u8; 32], - ) -> Result<[u8; 33], EcdsaVerifyError> { + sig: PassPointerAndRead<&[u8; 65], 65>, + msg: PassPointerAndRead<&[u8; 32], 32>, + ) -> AllocateAndReturnByCodec> { let rid = RecoveryId::from_i32(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as i32) .map_err(|_| EcdsaVerifyError::BadV)?; let sig = RecoverableSignature::from_compact(&sig[..64], rid) .map_err(|_| EcdsaVerifyError::BadRS)?; let msg = Message::from_digest_slice(msg).expect("Message is 32 bytes; qed"); - let pubkey = SECP256K1 - .recover_ecdsa(&msg, &sig) - .map_err(|_| EcdsaVerifyError::BadSignature)?; + #[cfg(feature = "std")] + let ctx = secp256k1::SECP256K1; + #[cfg(not(feature = "std"))] + let ctx = secp256k1::Secp256k1::::gen_new(); + let pubkey = ctx.recover_ecdsa(&msg, &sig).map_err(|_| EcdsaVerifyError::BadSignature)?; Ok(pubkey.serialize()) } @@ -1211,8 +1352,12 @@ pub trait Crypto { /// /// Returns the public key. #[cfg(feature = "bls-experimental")] - fn bls381_generate(&mut self, id: KeyTypeId, seed: Option>) -> bls381::Public { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + fn bls381_generate( + &mut self, + id: PassPointerAndReadCopy, + seed: PassFatPointerAndDecode>>, + ) -> AllocateAndReturnPointer { + let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") .bls381_generate_new(id, seed) @@ -1228,10 +1373,10 @@ pub trait Crypto { #[cfg(feature = "bls-experimental")] fn ecdsa_bls381_generate( &mut self, - id: KeyTypeId, - seed: Option>, - ) -> ecdsa_bls381::Public { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + id: PassPointerAndReadCopy, + seed: PassFatPointerAndDecode>>, + ) -> AllocateAndReturnPointer { + let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") .ecdsa_bls381_generate_new(id, seed) @@ -1247,10 +1392,10 @@ pub trait Crypto { #[cfg(feature = "bandersnatch-experimental")] fn bandersnatch_generate( &mut self, - id: KeyTypeId, - seed: Option>, - ) -> bandersnatch::Public { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + id: PassPointerAndReadCopy, + seed: PassFatPointerAndDecode>>, + ) -> AllocateAndReturnPointer { + let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") .bandersnatch_generate_new(id, seed) @@ -1262,42 +1407,42 @@ pub trait Crypto { #[runtime_interface] pub trait Hashing { /// Conduct a 256-bit Keccak hash. - fn keccak_256(data: &[u8]) -> [u8; 32] { + fn keccak_256(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 32], 32> { sp_crypto_hashing::keccak_256(data) } /// Conduct a 512-bit Keccak hash. - fn keccak_512(data: &[u8]) -> [u8; 64] { + fn keccak_512(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 64], 64> { sp_crypto_hashing::keccak_512(data) } /// Conduct a 256-bit Sha2 hash. - fn sha2_256(data: &[u8]) -> [u8; 32] { + fn sha2_256(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 32], 32> { sp_crypto_hashing::sha2_256(data) } /// Conduct a 128-bit Blake2 hash. - fn blake2_128(data: &[u8]) -> [u8; 16] { + fn blake2_128(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 16], 16> { sp_crypto_hashing::blake2_128(data) } /// Conduct a 256-bit Blake2 hash. - fn blake2_256(data: &[u8]) -> [u8; 32] { + fn blake2_256(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 32], 32> { sp_crypto_hashing::blake2_256(data) } /// Conduct four XX hashes to give a 256-bit result. - fn twox_256(data: &[u8]) -> [u8; 32] { + fn twox_256(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 32], 32> { sp_crypto_hashing::twox_256(data) } /// Conduct two XX hashes to give a 128-bit result. - fn twox_128(data: &[u8]) -> [u8; 16] { + fn twox_128(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 16], 16> { sp_crypto_hashing::twox_128(data) } /// Conduct two XX hashes to give a 64-bit result. - fn twox_64(data: &[u8]) -> [u8; 8] { + fn twox_64(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnPointer<[u8; 8], 8> { sp_crypto_hashing::twox_64(data) } } @@ -1306,12 +1451,17 @@ pub trait Hashing { #[runtime_interface] pub trait TransactionIndex { /// Add transaction index. Returns indexed content hash. - fn index(&mut self, extrinsic: u32, size: u32, context_hash: [u8; 32]) { + fn index( + &mut self, + extrinsic: u32, + size: u32, + context_hash: PassPointerAndReadCopy<[u8; 32], 32>, + ) { self.storage_index_transaction(extrinsic, &context_hash, size); } /// Conduct a 512-bit Keccak hash. - fn renew(&mut self, extrinsic: u32, context_hash: [u8; 32]) { + fn renew(&mut self, extrinsic: u32, context_hash: PassPointerAndReadCopy<[u8; 32], 32>) { self.storage_renew_transaction_index(extrinsic, &context_hash); } } @@ -1320,17 +1470,17 @@ pub trait TransactionIndex { #[runtime_interface] pub trait OffchainIndex { /// Write a key value pair to the Offchain DB database in a buffered fashion. - fn set(&mut self, key: &[u8], value: &[u8]) { + fn set(&mut self, key: PassFatPointerAndRead<&[u8]>, value: PassFatPointerAndRead<&[u8]>) { self.set_offchain_storage(key, Some(value)); } /// Remove a key and its associated value from the Offchain DB. - fn clear(&mut self, key: &[u8]) { + fn clear(&mut self, key: PassFatPointerAndRead<&[u8]>) { self.set_offchain_storage(key, None); } } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] sp_externalities::decl_extension! { /// Deprecated verification context. /// @@ -1356,7 +1506,10 @@ pub trait Offchain { /// Submit an encoded transaction to the pool. /// /// The transaction will end up in the pool. - fn submit_transaction(&mut self, data: Vec) -> Result<(), ()> { + fn submit_transaction( + &mut self, + data: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect( "submit_transaction can be called only in the offchain call context with @@ -1366,21 +1519,21 @@ pub trait Offchain { } /// Returns information about the local node's network state. - fn network_state(&mut self) -> Result { + fn network_state(&mut self) -> AllocateAndReturnByCodec> { self.extension::() .expect("network_state can be called only in the offchain worker context") .network_state() } /// Returns current UNIX timestamp (in millis) - fn timestamp(&mut self) -> Timestamp { + fn timestamp(&mut self) -> ReturnAs { self.extension::() .expect("timestamp can be called only in the offchain worker context") .timestamp() } /// Pause the execution until `deadline` is reached. - fn sleep_until(&mut self, deadline: Timestamp) { + fn sleep_until(&mut self, deadline: PassAs) { self.extension::() .expect("sleep_until can be called only in the offchain worker context") .sleep_until(deadline) @@ -1390,7 +1543,7 @@ pub trait Offchain { /// /// This is a truly random, non-deterministic seed generated by host environment. /// Obviously fine in the off-chain worker context. - fn random_seed(&mut self) -> [u8; 32] { + fn random_seed(&mut self) -> AllocateAndReturnPointer<[u8; 32], 32> { self.extension::() .expect("random_seed can be called only in the offchain worker context") .random_seed() @@ -1400,7 +1553,12 @@ pub trait Offchain { /// /// Note this storage is not part of the consensus, it's only accessible by /// offchain worker tasks running on the same machine. It IS persisted between runs. - fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) { + fn local_storage_set( + &mut self, + kind: PassAs, + key: PassFatPointerAndRead<&[u8]>, + value: PassFatPointerAndRead<&[u8]>, + ) { self.extension::() .expect( "local_storage_set can be called only in the offchain call context with @@ -1413,7 +1571,11 @@ pub trait Offchain { /// /// Note this storage is not part of the consensus, it's only accessible by /// offchain worker tasks running on the same machine. It IS persisted between runs. - fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]) { + fn local_storage_clear( + &mut self, + kind: PassAs, + key: PassFatPointerAndRead<&[u8]>, + ) { self.extension::() .expect( "local_storage_clear can be called only in the offchain call context with @@ -1433,10 +1595,10 @@ pub trait Offchain { /// offchain worker tasks running on the same machine. It IS persisted between runs. fn local_storage_compare_and_set( &mut self, - kind: StorageKind, - key: &[u8], - old_value: Option>, - new_value: &[u8], + kind: PassAs, + key: PassFatPointerAndRead<&[u8]>, + old_value: PassFatPointerAndDecode>>, + new_value: PassFatPointerAndRead<&[u8]>, ) -> bool { self.extension::() .expect( @@ -1451,7 +1613,11 @@ pub trait Offchain { /// If the value does not exist in the storage `None` will be returned. /// Note this storage is not part of the consensus, it's only accessible by /// offchain worker tasks running on the same machine. It IS persisted between runs. - fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option> { + fn local_storage_get( + &mut self, + kind: PassAs, + key: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec>> { self.extension::() .expect( "local_storage_get can be called only in the offchain call context with @@ -1466,10 +1632,10 @@ pub trait Offchain { /// parameters. Returns the id of newly started request. fn http_request_start( &mut self, - method: &str, - uri: &str, - meta: &[u8], - ) -> Result { + method: PassFatPointerAndRead<&str>, + uri: PassFatPointerAndRead<&str>, + meta: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("http_request_start can be called only in the offchain worker context") .http_request_start(method, uri, meta) @@ -1478,10 +1644,10 @@ pub trait Offchain { /// Append header to the request. fn http_request_add_header( &mut self, - request_id: HttpRequestId, - name: &str, - value: &str, - ) -> Result<(), ()> { + request_id: PassAs, + name: PassFatPointerAndRead<&str>, + value: PassFatPointerAndRead<&str>, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("http_request_add_header can be called only in the offchain worker context") .http_request_add_header(request_id, name, value) @@ -1495,10 +1661,10 @@ pub trait Offchain { /// Returns an error in case deadline is reached or the chunk couldn't be written. fn http_request_write_body( &mut self, - request_id: HttpRequestId, - chunk: &[u8], - deadline: Option, - ) -> Result<(), HttpError> { + request_id: PassAs, + chunk: PassFatPointerAndRead<&[u8]>, + deadline: PassFatPointerAndDecode>, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("http_request_write_body can be called only in the offchain worker context") .http_request_write_body(request_id, chunk, deadline) @@ -1513,9 +1679,9 @@ pub trait Offchain { /// Passing `None` as deadline blocks forever. fn http_response_wait( &mut self, - ids: &[HttpRequestId], - deadline: Option, - ) -> Vec { + ids: PassFatPointerAndDecodeSlice<&[HttpRequestId]>, + deadline: PassFatPointerAndDecode>, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("http_response_wait can be called only in the offchain worker context") .http_response_wait(ids, deadline) @@ -1525,7 +1691,10 @@ pub trait Offchain { /// /// Returns a vector of pairs `(HeaderKey, HeaderValue)`. /// NOTE: response headers have to be read before response body. - fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec, Vec)> { + fn http_response_headers( + &mut self, + request_id: PassAs, + ) -> AllocateAndReturnByCodec, Vec)>> { self.extension::() .expect("http_response_headers can be called only in the offchain worker context") .http_response_headers(request_id) @@ -1541,10 +1710,10 @@ pub trait Offchain { /// Passing `None` as a deadline blocks forever. fn http_response_read_body( &mut self, - request_id: HttpRequestId, - buffer: &mut [u8], - deadline: Option, - ) -> Result { + request_id: PassAs, + buffer: PassFatPointerAndReadWrite<&mut [u8]>, + deadline: PassFatPointerAndDecode>, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("http_response_read_body can be called only in the offchain worker context") .http_response_read_body(request_id, buffer, deadline) @@ -1552,7 +1721,11 @@ pub trait Offchain { } /// Set the authorized nodes and authorized_only flag. - fn set_authorized_nodes(&mut self, nodes: Vec, authorized_only: bool) { + fn set_authorized_nodes( + &mut self, + nodes: PassFatPointerAndDecode>, + authorized_only: bool, + ) { self.extension::() .expect("set_authorized_nodes can be called only in the offchain worker context") .set_authorized_nodes(nodes, authorized_only) @@ -1579,7 +1752,7 @@ pub trait Allocator { pub trait PanicHandler { /// Aborts the current execution with the given error message. #[trap_on_return] - fn abort_on_panic(&mut self, message: &str) { + fn abort_on_panic(&mut self, message: PassFatPointerAndRead<&str>) { self.register_panic_error_message(message); } } @@ -1593,44 +1766,22 @@ pub trait Logging { /// given level and target. /// /// Instead of using directly, prefer setting up `RuntimeLogger` and using `log` macros. - fn log(level: LogLevel, target: &str, message: &[u8]) { - if let Ok(message) = std::str::from_utf8(message) { + fn log( + level: PassAs, + target: PassFatPointerAndRead<&str>, + message: PassFatPointerAndRead<&[u8]>, + ) { + if let Ok(message) = core::str::from_utf8(message) { log::log!(target: target, log::Level::from(level), "{}", message) } } /// Returns the max log level used by the host. - fn max_level() -> LogLevelFilter { + fn max_level() -> ReturnAs { log::max_level().into() } } -#[derive(Encode, Decode)] -/// Crossing is a helper wrapping any Encode-Decodeable type -/// for transferring over the wasm barrier. -pub struct Crossing(T); - -impl PassBy for Crossing { - type PassBy = sp_runtime_interface::pass_by::Codec; -} - -impl Crossing { - /// Convert into the inner type - pub fn into_inner(self) -> T { - self.0 - } -} - -// useful for testing -impl core::default::Default for Crossing -where - T: core::default::Default + Encode + Decode, -{ - fn default() -> Self { - Self(Default::default()) - } -} - /// Interface to provide tracing facilities for wasm. Modelled after tokios `tracing`-crate /// interfaces. See `sp-tracing` for more information. #[runtime_interface(wasm_only, no_tracing)] @@ -1644,8 +1795,8 @@ pub trait WasmTracing { /// checked more than once per metadata. This exists for optimisation purposes but is still not /// cheap as it will jump the wasm-native-barrier every time it is called. So an implementation /// might chose to cache the result for the execution of the entire block. - fn enabled(&mut self, metadata: Crossing) -> bool { - let metadata: &tracing_core::metadata::Metadata<'static> = (&metadata.into_inner()).into(); + fn enabled(&mut self, metadata: PassFatPointerAndDecode) -> bool { + let metadata: &tracing_core::metadata::Metadata<'static> = (&metadata).into(); tracing::dispatcher::get_default(|d| d.enabled(metadata)) } @@ -1655,8 +1806,11 @@ pub trait WasmTracing { /// and then calls `clone_span` with the ID to signal that we are keeping it around on the wasm- /// side even after the local span is dropped. The resulting ID is then handed over to the wasm- /// side. - fn enter_span(&mut self, span: Crossing) -> u64 { - let span: tracing::Span = span.into_inner().into(); + fn enter_span( + &mut self, + span: PassFatPointerAndDecode, + ) -> u64 { + let span: tracing::Span = span.into(); match span.id() { Some(id) => tracing::dispatcher::get_default(|d| { // inform dispatch that we'll keep the ID around @@ -1670,8 +1824,8 @@ pub trait WasmTracing { } /// Emit the given event to the global tracer on the native side - fn event(&mut self, event: Crossing) { - event.into_inner().emit(); + fn event(&mut self, event: PassFatPointerAndDecode) { + event.emit(); } /// Signal that a given span-id has been exited. On native, this directly @@ -1684,9 +1838,9 @@ pub trait WasmTracing { } } -#[cfg(all(not(feature = "std"), feature = "with-tracing"))] +#[cfg(all(substrate_runtime, feature = "with-tracing"))] mod tracing_setup { - use super::{wasm_tracing, Crossing}; + use super::wasm_tracing; use core::sync::atomic::{AtomicBool, Ordering}; use tracing_core::{ dispatcher::{set_global_default, Dispatch}, @@ -1702,10 +1856,10 @@ mod tracing_setup { impl tracing_core::Subscriber for PassingTracingSubscriber { fn enabled(&self, metadata: &Metadata<'_>) -> bool { - wasm_tracing::enabled(Crossing(metadata.into())) + wasm_tracing::enabled(metadata.into()) } fn new_span(&self, attrs: &Attributes<'_>) -> Id { - Id::from_u64(wasm_tracing::enter_span(Crossing(attrs.into()))) + Id::from_u64(wasm_tracing::enter_span(attrs.into())) } fn enter(&self, _: &Id) { // Do nothing, we already entered the span previously @@ -1721,7 +1875,7 @@ mod tracing_setup { unimplemented! {} // this usage is not supported } fn event(&self, event: &Event<'_>) { - wasm_tracing::event(Crossing(event.into())) + wasm_tracing::event(event.into()) } fn exit(&self, span: &Id) { wasm_tracing::exit(span.into_u64()) @@ -1740,10 +1894,10 @@ mod tracing_setup { } } -#[cfg(not(all(not(feature = "std"), feature = "with-tracing")))] +#[cfg(not(all(substrate_runtime, feature = "with-tracing")))] mod tracing_setup { /// Initialize tracing of sp_tracing not necessary – noop. To enable build - /// without std and with the `with-tracing`-feature. + /// when not both `substrate_runtime` and `with-tracing`-feature. pub fn init_tracing() {} } @@ -1800,14 +1954,14 @@ pub fn oom(_: core::alloc::Layout) -> ! { } /// Type alias for Externalities implementation used in tests. -#[cfg(feature = "std")] +#[cfg(feature = "std")] // NOTE: Deliberately isn't `not(substrate_runtime)`. pub type TestExternalities = sp_state_machine::TestExternalities; /// The host functions Substrate provides for the Wasm runtime environment. /// /// All these host functions will be callable from inside the Wasm environment. #[docify::export] -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub type SubstrateHostFunctions = ( storage::HostFunctions, default_child_storage::HostFunctions, diff --git a/substrate/primitives/keyring/check-features-variants.sh b/substrate/primitives/keyring/check-features-variants.sh index 9c28d83589465..ce7634f60abb0 100755 --- a/substrate/primitives/keyring/check-features-variants.sh +++ b/substrate/primitives/keyring/check-features-variants.sh @@ -1,8 +1,9 @@ #!/usr/bin/env -S bash -eux export RUSTFLAGS="-Cdebug-assertions=y -Dwarnings" -T=wasm32-unknown-unknown - cargo check --release -cargo check --release --features="bandersnatch-experimental" +cargo check --release --features="bandersnatch-experimental" + +export RUSTFLAGS="$RUSTFLAGS --cfg substrate_runtime" +T=wasm32-unknown-unknown cargo check --release --target=$T --no-default-features diff --git a/substrate/primitives/runtime-interface/proc-macro/src/lib.rs b/substrate/primitives/runtime-interface/proc-macro/src/lib.rs index e6f060c219e01..6ca7827acae58 100644 --- a/substrate/primitives/runtime-interface/proc-macro/src/lib.rs +++ b/substrate/primitives/runtime-interface/proc-macro/src/lib.rs @@ -18,21 +18,14 @@ //! This crate provides procedural macros for usage within the context of the Substrate runtime //! interface. //! -//! The following macros are provided: -//! -//! 1. The [`#[runtime_interface]`](attr.runtime_interface.html) attribute macro for generating the -//! runtime interfaces. -//! 2. The [`PassByCodec`](derive.PassByCodec.html) derive macro for implementing `PassBy` with -//! `Codec`. 3. The [`PassByEnum`](derive.PassByInner.html) derive macro for implementing `PassBy` -//! with `Enum`. 4. The [`PassByInner`](derive.PassByInner.html) derive macro for implementing -//! `PassBy` with `Inner`. +//! It provides the [`#[runtime_interface]`](attr.runtime_interface.html) attribute macro +//! for generating the runtime interfaces. use syn::{ parse::{Parse, ParseStream}, - parse_macro_input, DeriveInput, ItemTrait, Result, Token, + parse_macro_input, ItemTrait, Result, Token, }; -mod pass_by; mod runtime_interface; mod utils; @@ -85,25 +78,3 @@ pub fn runtime_interface( .unwrap_or_else(|e| e.to_compile_error()) .into() } - -#[proc_macro_derive(PassByCodec)] -pub fn pass_by_codec(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input = parse_macro_input!(input as DeriveInput); - pass_by::codec_derive_impl(input) - .unwrap_or_else(|e| e.to_compile_error()) - .into() -} - -#[proc_macro_derive(PassByInner)] -pub fn pass_by_inner(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input = parse_macro_input!(input as DeriveInput); - pass_by::inner_derive_impl(input) - .unwrap_or_else(|e| e.to_compile_error()) - .into() -} - -#[proc_macro_derive(PassByEnum)] -pub fn pass_by_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input = parse_macro_input!(input as DeriveInput); - pass_by::enum_derive_impl(input).unwrap_or_else(|e| e.to_compile_error()).into() -} diff --git a/substrate/primitives/runtime-interface/proc-macro/src/pass_by/codec.rs b/substrate/primitives/runtime-interface/proc-macro/src/pass_by/codec.rs deleted file mode 100644 index a1b7bccd3acc0..0000000000000 --- a/substrate/primitives/runtime-interface/proc-macro/src/pass_by/codec.rs +++ /dev/null @@ -1,59 +0,0 @@ -// This file is part of Substrate. - -// 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. - -//! Derive macro implementation of `PassBy` with the associated type set to `Codec`. -//! -//! It is required that the type implements `Encode` and `Decode` from the `parity-scale-codec` -//! crate. - -use crate::utils::{generate_crate_access, generate_runtime_interface_include}; - -use syn::{parse_quote, DeriveInput, Generics, Result}; - -use quote::quote; - -use proc_macro2::TokenStream; - -/// The derive implementation for `PassBy` with `Codec`. -pub fn derive_impl(mut input: DeriveInput) -> Result { - add_trait_bounds(&mut input.generics); - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let crate_include = generate_runtime_interface_include(); - let crate_ = generate_crate_access(); - let ident = input.ident; - - let res = quote! { - const _: () = { - #crate_include - - impl #impl_generics #crate_::pass_by::PassBy for #ident #ty_generics #where_clause { - type PassBy = #crate_::pass_by::Codec<#ident>; - } - }; - }; - - Ok(res) -} - -/// Add the `codec::Codec` trait bound to every type parameter. -fn add_trait_bounds(generics: &mut Generics) { - let crate_ = generate_crate_access(); - - generics - .type_params_mut() - .for_each(|type_param| type_param.bounds.push(parse_quote!(#crate_::codec::Codec))); -} diff --git a/substrate/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs b/substrate/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs deleted file mode 100644 index d0eb382cdc566..0000000000000 --- a/substrate/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs +++ /dev/null @@ -1,101 +0,0 @@ -// This file is part of Substrate. - -// 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. - -//! Derive macro implementation of `PassBy` with the associated type set to `Enum`. -//! -//! Besides `PassBy`, `TryFrom` and `From for u8` are implemented for the type. - -use crate::utils::{generate_crate_access, generate_runtime_interface_include}; - -use syn::{Data, DeriveInput, Error, Fields, Ident, Result}; - -use quote::quote; - -use proc_macro2::{Span, TokenStream}; - -/// The derive implementation for `PassBy` with `Enum`. -pub fn derive_impl(input: DeriveInput) -> Result { - let crate_include = generate_runtime_interface_include(); - let crate_ = generate_crate_access(); - let ident = input.ident; - let enum_fields = get_enum_field_idents(&input.data)? - .enumerate() - .map(|(i, v)| { - let i = i as u8; - - v.map(|v| (quote!(#i => Ok(#ident::#v)), quote!(#ident::#v => #i))) - }) - .collect::>>()?; - let try_from_variants = enum_fields.iter().map(|i| &i.0); - let into_variants = enum_fields.iter().map(|i| &i.1); - - let res = quote! { - const _: () = { - #crate_include - - impl #crate_::pass_by::PassBy for #ident { - type PassBy = #crate_::pass_by::Enum<#ident>; - } - - impl TryFrom for #ident { - type Error = (); - - fn try_from(inner: u8) -> core::result::Result { - match inner { - #( #try_from_variants, )* - _ => Err(()), - } - } - } - - impl From<#ident> for u8 { - fn from(var: #ident) -> u8 { - match var { - #( #into_variants ),* - } - } - } - }; - }; - - Ok(res) -} - -/// Get the enum fields idents of the given `data` object as iterator. -/// -/// Returns an error if the number of variants is greater than `256`, the given `data` is not an -/// enum or a variant is not an unit. -fn get_enum_field_idents(data: &Data) -> Result>> { - match data { - Data::Enum(d) => - if d.variants.len() <= 256 { - Ok(d.variants.iter().map(|v| { - if let Fields::Unit = v.fields { - Ok(&v.ident) - } else { - Err(Error::new( - Span::call_site(), - "`PassByEnum` only supports unit variants.", - )) - } - })) - } else { - Err(Error::new(Span::call_site(), "`PassByEnum` only supports `256` variants.")) - }, - _ => Err(Error::new(Span::call_site(), "`PassByEnum` only supports enums as input type.")), - } -} diff --git a/substrate/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs b/substrate/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs deleted file mode 100644 index cc51fe44f912f..0000000000000 --- a/substrate/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs +++ /dev/null @@ -1,110 +0,0 @@ -// This file is part of Substrate. - -// 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. - -//! Derive macro implementation of `PassBy` with the associated type set to `Inner` and of the -//! helper trait `PassByInner`. -//! -//! It is required that the type is a newtype struct, otherwise an error is generated. - -use crate::utils::{generate_crate_access, generate_runtime_interface_include}; - -use syn::{parse_quote, Data, DeriveInput, Error, Fields, Generics, Ident, Result, Type}; - -use quote::quote; - -use proc_macro2::{Span, TokenStream}; - -/// The derive implementation for `PassBy` with `Inner` and `PassByInner`. -pub fn derive_impl(mut input: DeriveInput) -> Result { - add_trait_bounds(&mut input.generics); - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let crate_include = generate_runtime_interface_include(); - let crate_ = generate_crate_access(); - let ident = input.ident; - let (inner_ty, inner_name) = extract_inner_ty_and_name(&input.data)?; - - let access_inner = match inner_name { - Some(ref name) => quote!(self.#name), - None => quote!(self.0), - }; - - let from_inner = match inner_name { - Some(name) => quote!(Self { #name: inner }), - None => quote!(Self(inner)), - }; - - let res = quote! { - const _: () = { - #crate_include - - impl #impl_generics #crate_::pass_by::PassBy for #ident #ty_generics #where_clause { - type PassBy = #crate_::pass_by::Inner; - } - - impl #impl_generics #crate_::pass_by::PassByInner for #ident #ty_generics #where_clause { - type Inner = #inner_ty; - - fn into_inner(self) -> Self::Inner { - #access_inner - } - - fn inner(&self) -> &Self::Inner { - &#access_inner - } - - fn from_inner(inner: Self::Inner) -> Self { - #from_inner - } - } - }; - }; - - Ok(res) -} - -/// Add the `RIType` trait bound to every type parameter. -fn add_trait_bounds(generics: &mut Generics) { - let crate_ = generate_crate_access(); - - generics - .type_params_mut() - .for_each(|type_param| type_param.bounds.push(parse_quote!(#crate_::RIType))); -} - -/// Extract the inner type and optional name from given input data. -/// -/// It also checks that the input data is a newtype struct. -fn extract_inner_ty_and_name(data: &Data) -> Result<(Type, Option)> { - if let Data::Struct(ref struct_data) = data { - match struct_data.fields { - Fields::Named(ref named) if named.named.len() == 1 => { - let field = &named.named[0]; - return Ok((field.ty.clone(), field.ident.clone())) - }, - Fields::Unnamed(ref unnamed) if unnamed.unnamed.len() == 1 => { - let field = &unnamed.unnamed[0]; - return Ok((field.ty.clone(), field.ident.clone())) - }, - _ => {}, - } - } - - Err(Error::new( - Span::call_site(), - "Only newtype/one field structs are supported by `PassByInner`!", - )) -} diff --git a/substrate/primitives/runtime-interface/proc-macro/src/pass_by/mod.rs b/substrate/primitives/runtime-interface/proc-macro/src/pass_by/mod.rs deleted file mode 100644 index f3d51d36248dd..0000000000000 --- a/substrate/primitives/runtime-interface/proc-macro/src/pass_by/mod.rs +++ /dev/null @@ -1,26 +0,0 @@ -// This file is part of Substrate. - -// 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. - -//! All the `PassBy*` derive implementations. - -mod codec; -mod enum_; -mod inner; - -pub use self::codec::derive_impl as codec_derive_impl; -pub use enum_::derive_impl as enum_derive_impl; -pub use inner::derive_impl as inner_derive_impl; diff --git a/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs b/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs index 32455b39eed6f..551c63358c59d 100644 --- a/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs +++ b/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/bare_function_interface.rs @@ -32,7 +32,7 @@ use crate::utils::{ create_exchangeable_host_function_ident, create_function_ident_with_version, generate_crate_access, get_function_argument_names, get_function_arguments, - get_runtime_interface, RuntimeInterfaceFunction, + get_runtime_interface, host_inner_return_ty, pat_ty_to_host_inner, RuntimeInterfaceFunction, }; use syn::{ @@ -90,16 +90,20 @@ fn function_for_method( }) } -/// Generates the bare function implementation for `cfg(not(feature = "std"))`. +/// Generates the bare function implementation for `cfg(substrate_runtime)`. fn function_no_std_impl( method: &RuntimeInterfaceFunction, is_wasm_only: bool, ) -> Result { + let should_trap_on_return = method.should_trap_on_return(); + let mut method = (*method).clone(); + crate::utils::unpack_inner_types_in_signature(&mut method.sig); + let function_name = &method.sig.ident; let host_function_name = create_exchangeable_host_function_ident(&method.sig.ident); let args = get_function_arguments(&method.sig); let arg_names = get_function_argument_names(&method.sig); - let return_value = if method.should_trap_on_return() { + let return_value = if should_trap_on_return { syn::ReturnType::Type( ]>::default(), Box::new(syn::TypeNever { bang_token: ::default() }.into()), @@ -107,7 +111,7 @@ fn function_no_std_impl( } else { method.sig.output.clone() }; - let maybe_unreachable = if method.should_trap_on_return() { + let maybe_unreachable = if should_trap_on_return { quote! { ; #[cfg(target_family = "wasm")] @@ -130,7 +134,7 @@ fn function_no_std_impl( Ok(quote! { #cfg_wasm_only - #[cfg(not(feature = "std"))] + #[cfg(substrate_runtime)] #( #attrs )* pub fn #function_name( #( #args, )* ) #return_value { // Call the host function @@ -140,20 +144,20 @@ fn function_no_std_impl( }) } -/// Generate call to latest function version for `cfg((feature = "std")` +/// Generate call to latest function version for `cfg(not(substrate_runtime))` /// /// This should generate simple `fn func(..) { func_version_(..) }`. fn function_std_latest_impl(method: &TraitItemFn, latest_version: u32) -> Result { let function_name = &method.sig.ident; - let args = get_function_arguments(&method.sig).map(FnArg::Typed); + let args = get_function_arguments(&method.sig).map(pat_ty_to_host_inner).map(FnArg::Typed); let arg_names = get_function_argument_names(&method.sig).collect::>(); - let return_value = &method.sig.output; + let return_value = host_inner_return_ty(&method.sig.output); let attrs = method.attrs.iter().filter(|a| !a.path().is_ident("version")); let latest_function_name = create_function_ident_with_version(&method.sig.ident, latest_version); Ok(quote_spanned! { method.span() => - #[cfg(feature = "std")] + #[cfg(not(substrate_runtime))] #( #attrs )* pub fn #function_name( #( #args, )* ) #return_value { #latest_function_name( @@ -163,7 +167,7 @@ fn function_std_latest_impl(method: &TraitItemFn, latest_version: u32) -> Result }) } -/// Generates the bare function implementation for `cfg(feature = "std")`. +/// Generates the bare function implementation for `cfg(not(substrate_runtime))`. fn function_std_impl( trait_name: &Ident, method: &TraitItemFn, @@ -175,20 +179,23 @@ fn function_std_impl( let function_name_str = function_name.to_string(); let crate_ = generate_crate_access(); - let args = get_function_arguments(&method.sig).map(FnArg::Typed).chain( - // Add the function context as last parameter when this is a wasm only interface. - iter::from_fn(|| { - if is_wasm_only { - Some(parse_quote!( - mut __function_context__: &mut dyn #crate_::sp_wasm_interface::FunctionContext - )) - } else { - None - } - }) - .take(1), - ); - let return_value = &method.sig.output; + let args = get_function_arguments(&method.sig) + .map(pat_ty_to_host_inner) + .map(FnArg::Typed) + .chain( + // Add the function context as last parameter when this is a wasm only interface. + iter::from_fn(|| { + if is_wasm_only { + Some(parse_quote!( + mut __function_context__: &mut dyn #crate_::sp_wasm_interface::FunctionContext + )) + } else { + None + } + }) + .take(1), + ); + let return_value = host_inner_return_ty(&method.sig.output); let attrs = method.attrs.iter().filter(|a| !a.path().is_ident("version")); // Don't make the function public accessible when this is a wasm only interface. let call_to_trait = generate_call_to_trait(trait_name, method, version, is_wasm_only); @@ -203,7 +210,7 @@ fn function_std_impl( }; Ok(quote_spanned! { method.span() => - #[cfg(feature = "std")] + #[cfg(not(substrate_runtime))] #( #attrs )* fn #function_name( #( #args, )* ) #return_value { #call_to_trait diff --git a/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs b/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs index fc985157cdb7f..d68d6c0a2bdae 100644 --- a/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs +++ b/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/host_function_interface.rs @@ -24,9 +24,8 @@ use crate::utils::{ create_exchangeable_host_function_ident, create_function_ident_with_version, create_host_function_ident, generate_crate_access, get_function_argument_names, - get_function_argument_names_and_types_without_ref, get_function_argument_types, - get_function_argument_types_ref_and_mut, get_function_argument_types_without_ref, - get_function_arguments, get_runtime_interface, RuntimeInterfaceFunction, + get_function_argument_names_and_types, get_function_argument_types, get_function_arguments, + get_runtime_interface, RuntimeInterfaceFunction, }; use syn::{ @@ -63,7 +62,7 @@ pub fn generate(trait_def: &ItemTrait, is_wasm_only: bool) -> Result ret` to make the function implementations exchangeable. - #[cfg(not(feature = "std"))] + #[cfg(substrate_runtime)] mod extern_host_function_impls { use super::*; @@ -83,12 +82,14 @@ fn generate_extern_host_function( trait_name: &Ident, ) -> Result { let crate_ = generate_crate_access(); - let args = get_function_arguments(&method.sig); - let arg_types = get_function_argument_types_without_ref(&method.sig); - let arg_types2 = get_function_argument_types_without_ref(&method.sig); + + let mut unpacked_sig = method.sig.clone(); + crate::utils::unpack_inner_types_in_signature(&mut unpacked_sig); + let unpacked_args = get_function_arguments(&unpacked_sig); + let unpacked_return_value = &unpacked_sig.output; + + let arg_types = get_function_argument_types(&method.sig); let arg_names = get_function_argument_names(&method.sig); - let arg_names2 = get_function_argument_names(&method.sig); - let arg_names3 = get_function_argument_names(&method.sig); let function = &method.sig.ident; let ext_function = create_host_function_ident(&method.sig.ident, version, trait_name); let doc_string = format!( @@ -106,16 +107,43 @@ fn generate_extern_host_function( }; let convert_return_value = match return_value { - ReturnType::Default => quote!(), + ReturnType::Default => quote! { __runtime_interface_result_ }, ReturnType::Type(_, ref ty) => quote! { - <#ty as #crate_::wasm::FromFFIValue>::from_ffi_value(result) + <#ty as #crate_::wasm::FromFFIValue>::from_ffi_value(__runtime_interface_result_) }, }; + let mut call_into_ffi_value = Vec::new(); + let mut drop_args = Vec::new(); + let mut ffi_names = Vec::new(); + for (nth, arg) in get_function_arguments(&method.sig).enumerate() { + let arg_name = &arg.pat; + let arg_ty = &arg.ty; + let ffi_name = + Ident::new(&format!("__runtime_interface_ffi_value_{}_", nth), arg.pat.span()); + let destructor_name = + Ident::new(&format!("__runtime_interface_arg_destructor_{}_", nth), arg.pat.span()); + + ffi_names.push(ffi_name.clone()); + + call_into_ffi_value.push(quote! { + let mut #arg_name = #arg_name; + let (#ffi_name, #destructor_name) = <#arg_ty as #crate_::wasm::IntoFFIValue>::into_ffi_value(&mut #arg_name); + }); + + drop_args.push(quote! { + #[allow(dropping_copy_types)] + ::core::mem::drop(#destructor_name); + }); + } + + // Drop in the reverse order to construction. + drop_args.reverse(); + Ok(quote! { #(#cfg_attrs)* #[doc = #doc_string] - pub fn #function ( #( #args ),* ) #return_value { + pub fn #function ( #( #unpacked_args ),* ) #unpacked_return_value { #[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), #crate_::polkavm::polkavm_import(abi = #crate_::polkavm::polkavm_abi))] extern "C" { pub fn #ext_function ( @@ -123,15 +151,9 @@ fn generate_extern_host_function( ) #ffi_return_value; } - // Generate all wrapped ffi values. - #( - let #arg_names2 = <#arg_types2 as #crate_::wasm::IntoFFIValue>::into_ffi_value( - &#arg_names2, - ); - )* - - let result = unsafe { #ext_function( #( #arg_names3.get() ),* ) }; - + #(#call_into_ffi_value)* + let __runtime_interface_result_ = unsafe { #ext_function( #( #ffi_names ),* ) }; + #(#drop_args)* #convert_return_value } }) @@ -139,6 +161,9 @@ fn generate_extern_host_function( /// Generate the host exchangeable function for the given method. fn generate_exchangeable_host_function(method: &TraitItemFn) -> Result { + let mut method = method.clone(); + crate::utils::unpack_inner_types_in_signature(&mut method.sig); + let crate_ = generate_crate_access(); let arg_types = get_function_argument_types(&method.sig); let function = &method.sig.ident; @@ -149,7 +174,7 @@ fn generate_exchangeable_host_function(method: &TraitItemFn) -> Result Vec<&'static dyn #crate_::sp_wasm_interface::Function> { let mut host_functions_list = Vec::new(); @@ -222,7 +247,6 @@ fn generate_host_function_implementation( let signature = generate_wasm_interface_signature_for_host_function(&method.sig)?; let fn_name = create_function_ident_with_version(&method.sig.ident, version); - let ref_and_mut = get_function_argument_types_ref_and_mut(&method.sig); // List of variable names containing WASM FFI-compatible arguments. let mut ffi_names = Vec::new(); @@ -246,9 +270,7 @@ fn generate_host_function_implementation( // List of code snippets to convert static FFI args (`u32`, etc.) into native Rust types. let mut convert_args_static_ffi_to_host = Vec::new(); - for ((host_name, host_ty), ref_and_mut) in - get_function_argument_names_and_types_without_ref(&method.sig).zip(ref_and_mut) - { + for (host_name, host_ty) in get_function_argument_names_and_types(&method.sig) { let ffi_name = generate_ffi_value_var_name(&host_name)?; let host_name_ident = match *host_name { Pat::Ident(ref pat_ident) => pat_ident.ident.clone(), @@ -267,23 +289,15 @@ fn generate_host_function_implementation( ); convert_args_static_ffi_to_host.push(quote! { let mut #host_name = <#host_ty as #crate_::host::FromFFIValue>::from_ffi_value(__function_context__, #ffi_name) - .map_err(|err| format!("{}: {}", err, #convert_arg_error))?; + .map_err(|err| #crate_::alloc::format!("{}: {}", err, #convert_arg_error))?; }); - let ref_and_mut_tokens = - ref_and_mut.map(|(token_ref, token_mut)| quote!(#token_ref #token_mut)); - - host_names_with_ref.push(quote! { #ref_and_mut_tokens #host_name }); - - if ref_and_mut.map(|(_, token_mut)| token_mut.is_some()).unwrap_or(false) { - copy_data_into_ref_mut_args.push(quote! { - <#host_ty as #crate_::host::IntoPreallocatedFFIValue>::into_preallocated_ffi_value( - #host_name, - __function_context__, - #ffi_name, - )?; - }); - } + host_names_with_ref.push( + quote! { <#host_ty as #crate_::host::FromFFIValue>::take_from_owned(&mut #host_name) }, + ); + copy_data_into_ref_mut_args.push(quote! { + <#host_ty as #crate_::host::FromFFIValue>::write_back_into_runtime(#host_name, __function_context__, #ffi_name)?; + }); let arg_count_mismatch_error = format!( "missing argument '{}': number of arguments given to '{}' from interface '{}' does not match the expected number of arguments", @@ -292,9 +306,9 @@ fn generate_host_function_implementation( trait_name ); convert_args_dynamic_ffi_to_static_ffi.push(quote! { - let #ffi_name = args.next().ok_or_else(|| #arg_count_mismatch_error.to_owned())?; + let #ffi_name = args.next().ok_or_else(|| #crate_::alloc::borrow::ToOwned::to_owned(#arg_count_mismatch_error))?; let #ffi_name: #ffi_ty = #crate_::sp_wasm_interface::TryFromValue::try_from_value(#ffi_name) - .ok_or_else(|| #convert_arg_error.to_owned())?; + .ok_or_else(|| #crate_::alloc::borrow::ToOwned::to_owned(#convert_arg_error))?; }); } @@ -341,16 +355,16 @@ fn generate_host_function_implementation( let implementation = quote! { #(#cfg_attrs)* - #[cfg(feature = "std")] + #[cfg(not(substrate_runtime))] struct #struct_name; #(#cfg_attrs)* - #[cfg(feature = "std")] + #[cfg(not(substrate_runtime))] impl #struct_name { fn call( __function_context__: &mut dyn #crate_::sp_wasm_interface::FunctionContext, #(#ffi_args_prototype),* - ) -> std::result::Result<#ffi_return_ty, String> { + ) -> ::core::result::Result<#ffi_return_ty, #crate_::alloc::string::String> { #(#convert_args_static_ffi_to_host)* let __result__ = #fn_name(#(#host_names_with_ref),*); #(#copy_data_into_ref_mut_args)* @@ -360,7 +374,7 @@ fn generate_host_function_implementation( } #(#cfg_attrs)* - #[cfg(feature = "std")] + #[cfg(not(substrate_runtime))] impl #crate_::sp_wasm_interface::Function for #struct_name { fn name(&self) -> &str { #name @@ -374,7 +388,7 @@ fn generate_host_function_implementation( &self, __function_context__: &mut dyn #crate_::sp_wasm_interface::FunctionContext, args: &mut dyn Iterator, - ) -> std::result::Result, String> { + ) -> ::core::result::Result, #crate_::alloc::string::String> { #(#convert_args_dynamic_ffi_to_static_ffi)* let __result__ = Self::call( __function_context__, @@ -391,7 +405,7 @@ fn generate_host_function_implementation( registry.register_static( #crate_::sp_wasm_interface::Function::name(&#struct_name), |mut caller: #crate_::sp_wasm_interface::wasmtime::Caller, #(#ffi_args_prototype),*| - -> std::result::Result<#ffi_return_ty, #crate_::sp_wasm_interface::anyhow::Error> + -> ::core::result::Result<#ffi_return_ty, #crate_::sp_wasm_interface::anyhow::Error> { T::with_function_context(caller, move |__function_context__| { let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { @@ -404,12 +418,12 @@ fn generate_host_function_implementation( Ok(result) => result, Err(panic) => { let message = - if let Some(message) = panic.downcast_ref::() { - format!("host code panicked while being called by the runtime: {}", message) + if let Some(message) = panic.downcast_ref::<#crate_::alloc::string::String>() { + #crate_::alloc::format!("host code panicked while being called by the runtime: {}", message) } else if let Some(message) = panic.downcast_ref::<&'static str>() { - format!("host code panicked while being called by the runtime: {}", message) + #crate_::alloc::format!("host code panicked while being called by the runtime: {}", message) } else { - "host code panicked while being called by the runtime".to_owned() + #crate_::alloc::borrow::ToOwned::to_owned("host code panicked while being called by the runtime") }; return Err(#crate_::sp_wasm_interface::anyhow::Error::msg(message)); } @@ -436,7 +450,7 @@ fn generate_wasm_interface_signature_for_host_function(sig: &Signature) -> Resul }, ReturnType::Default => quote!(None), }; - let arg_types = get_function_argument_types_without_ref(sig).map(|ty| { + let arg_types = get_function_argument_types(sig).map(|ty| { quote! { <<#ty as #crate_::RIType>::FFIType as #crate_::sp_wasm_interface::IntoValue>::VALUE_TYPE } @@ -444,7 +458,7 @@ fn generate_wasm_interface_signature_for_host_function(sig: &Signature) -> Resul Ok(quote! { #crate_::sp_wasm_interface::Signature { - args: std::borrow::Cow::Borrowed(&[ #( #arg_types ),* ][..]), + args: #crate_::alloc::borrow::Cow::Borrowed(&[ #( #arg_types ),* ][..]), return_value: #return_value, } }) diff --git a/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs b/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs index 540e930b0c14b..cf605f6797c24 100644 --- a/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs +++ b/substrate/primitives/runtime-interface/proc-macro/src/runtime_interface/trait_decl_impl.rs @@ -19,8 +19,8 @@ //! default implementations and implements the trait for `&mut dyn Externalities`. use crate::utils::{ - create_function_ident_with_version, generate_crate_access, - get_function_argument_types_without_ref, get_runtime_interface, + create_function_ident_with_version, generate_crate_access, get_function_argument_types, + get_runtime_interface, }; use syn::{ @@ -75,6 +75,7 @@ impl ToEssentialTraitDef { fn process(&mut self, method: &TraitItemFn, version: u32) { let mut folded = self.fold_trait_item_fn(method.clone()); folded.sig.ident = create_function_ident_with_version(&folded.sig.ident, version); + crate::utils::unpack_inner_types_in_signature(&mut folded.sig); self.methods.push(folded); } @@ -95,7 +96,7 @@ impl Fold for ToEssentialTraitDef { self.push_error(&method, "Methods need to have an implementation."); } - let arg_types = get_function_argument_types_without_ref(&method.sig); + let arg_types = get_function_argument_types(&method.sig); arg_types .filter_map(|ty| match *ty { Type::ImplTrait(impl_trait) => Some(impl_trait), @@ -156,6 +157,7 @@ fn impl_trait_for_externalities(trait_def: &ItemTrait, is_wasm_only: bool) -> Re let mut cloned = (*method).clone(); cloned.attrs.retain(|a| !a.path().is_ident("version")); cloned.sig.ident = create_function_ident_with_version(&cloned.sig.ident, version); + crate::utils::unpack_inner_types_in_signature(&mut cloned.sig); cloned }); @@ -166,7 +168,7 @@ fn impl_trait_for_externalities(trait_def: &ItemTrait, is_wasm_only: bool) -> Re }; Ok(quote! { - #[cfg(feature = "std")] + #[cfg(not(substrate_runtime))] impl #trait_ for #impl_type { #( #methods )* } diff --git a/substrate/primitives/runtime-interface/proc-macro/src/utils.rs b/substrate/primitives/runtime-interface/proc-macro/src/utils.rs index 7d97f9f3e1ca0..d271a56c1dab5 100644 --- a/substrate/primitives/runtime-interface/proc-macro/src/utils.rs +++ b/substrate/primitives/runtime-interface/proc-macro/src/utils.rs @@ -237,37 +237,11 @@ pub fn get_function_argument_types(sig: &Signature) -> impl Iterator impl Iterator> + '_ { - get_function_arguments(sig).map(|pt| pt.ty).map(|ty| match *ty { - Type::Reference(type_ref) => type_ref.elem, - _ => ty, - }) -} - -/// Returns the function argument names and types, minus any `self`. If any of the arguments -/// is a reference, the underlying type without the ref is returned. -pub fn get_function_argument_names_and_types_without_ref( +/// Returns the function argument names and types, minus any `self`. +pub fn get_function_argument_names_and_types( sig: &Signature, ) -> impl Iterator, Box)> + '_ { - get_function_arguments(sig).map(|pt| match *pt.ty { - Type::Reference(type_ref) => (pt.pat, type_ref.elem), - _ => (pt.pat, pt.ty), - }) -} - -/// Returns the `&`/`&mut` for all function argument types, minus the `self` arg. If a function -/// argument is not a reference, `None` is returned. -pub fn get_function_argument_types_ref_and_mut( - sig: &Signature, -) -> impl Iterator)>> + '_ { - get_function_arguments(sig).map(|pt| pt.ty).map(|ty| match *ty { - Type::Reference(type_ref) => Some((type_ref.and_token, type_ref.mutability)), - _ => None, - }) + get_function_arguments(sig).map(|pt| (pt.pat, pt.ty)) } /// Returns an iterator over all trait methods for the given trait definition. @@ -370,3 +344,36 @@ pub fn get_runtime_interface(trait_def: &ItemTrait) -> Result Ok(RuntimeInterface { items: functions }) } + +pub fn host_inner_arg_ty(ty: &syn::Type) -> syn::Type { + let crate_ = generate_crate_access(); + syn::parse2::(quote! { <#ty as #crate_::RIType>::Inner }) + .expect("parsing doesn't fail") +} + +pub fn pat_ty_to_host_inner(mut pat: syn::PatType) -> syn::PatType { + pat.ty = Box::new(host_inner_arg_ty(&pat.ty)); + pat +} + +pub fn host_inner_return_ty(ty: &syn::ReturnType) -> syn::ReturnType { + let crate_ = generate_crate_access(); + match ty { + syn::ReturnType::Default => syn::ReturnType::Default, + syn::ReturnType::Type(ref arrow, ref ty) => + syn::parse2::(quote! { #arrow <#ty as #crate_::RIType>::Inner }) + .expect("parsing doesn't fail"), + } +} + +pub fn unpack_inner_types_in_signature(sig: &mut syn::Signature) { + sig.output = crate::utils::host_inner_return_ty(&sig.output); + for arg in sig.inputs.iter_mut() { + match arg { + syn::FnArg::Typed(ref mut pat_ty) => { + *pat_ty = crate::utils::pat_ty_to_host_inner(pat_ty.clone()); + }, + syn::FnArg::Receiver(..) => {}, + } + } +} diff --git a/substrate/primitives/runtime-interface/src/host.rs b/substrate/primitives/runtime-interface/src/host.rs index 914e575539d2f..096bbeb75a072 100644 --- a/substrate/primitives/runtime-interface/src/host.rs +++ b/substrate/primitives/runtime-interface/src/host.rs @@ -21,46 +21,42 @@ use crate::RIType; use sp_wasm_interface::{FunctionContext, Result}; -/// Something that can be converted into a ffi value. +/// A type used as a return value in a host function. Can be turned into an FFI value. pub trait IntoFFIValue: RIType { - /// Convert `self` into a ffi value. - fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result; -} - -/// Something that can be converted into a preallocated ffi value. -/// -/// Every type parameter that should be given as `&mut` into a runtime interface function, needs -/// to implement this trait. After executing the host implementation of the runtime interface -/// function, the value is copied into the preallocated wasm memory. -/// -/// This should only be used for types which have a fixed size, like slices. Other types like a vec -/// do not work with this interface, as we can not call into wasm to reallocate memory. So, this -/// trait should be implemented carefully. -pub trait IntoPreallocatedFFIValue: RIType { - /// As `Self` can be an unsized type, it needs to be represented by a sized type at the host. - /// This `SelfInstance` is the sized type. - type SelfInstance; - - /// Convert `self_instance` into the given preallocated ffi value. - fn into_preallocated_ffi_value( - self_instance: Self::SelfInstance, + /// Convert `Self::Inner` into an FFI value. + fn into_ffi_value( + value: Self::Inner, context: &mut dyn FunctionContext, - allocated: Self::FFIType, - ) -> Result<()>; + ) -> Result; } -/// Something that can be created from a ffi value. +/// 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: RIType { - /// As `Self` can be an unsized type, it needs to be represented by a sized type at the host. - /// This `SelfInstance` is the sized type. - type SelfInstance; - - /// Create `SelfInstance` from the given - fn from_ffi_value( - context: &mut dyn FunctionContext, - arg: Self::FFIType, - ) -> Result; +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; + + /// 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(()) + } } diff --git a/substrate/primitives/runtime-interface/src/impls.rs b/substrate/primitives/runtime-interface/src/impls.rs index daf5725e7f511..f7c5f25fcc90a 100644 --- a/substrate/primitives/runtime-interface/src/impls.rs +++ b/substrate/primitives/runtime-interface/src/impls.rs @@ -15,38 +15,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Provides implementations for the runtime interface traits. +//! Provides implementations for the runtime interface types which can be +//! passed directly without any serialization strategy wrappers. -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use crate::host::*; -#[cfg(not(feature = "std"))] +#[cfg(substrate_runtime)] use crate::wasm::*; -use crate::{ - pass_by::{Codec, Enum, Inner, PassBy, PassByInner}, - util::{pack_ptr_and_len, unpack_ptr_and_len}, - Pointer, RIType, -}; - -#[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))] -use static_assertions::assert_eq_size; +use crate::{Pointer, RIType}; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use sp_wasm_interface::{FunctionContext, Result}; -use codec::{Decode, Encode}; - -use core::{any::TypeId, mem}; - -use alloc::vec::Vec; - -#[cfg(feature = "std")] -use alloc::borrow::Cow; - // Make sure that our assumptions for storing a pointer + its size in `u64` is valid. -#[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))] -assert_eq_size!(usize, u32); -#[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))] -assert_eq_size!(*const u8, u32); +#[cfg(all(substrate_runtime, not(feature = "disable_target_static_assertions")))] +const _: () = { + assert!(core::mem::size_of::() == core::mem::size_of::()); + assert!(core::mem::size_of::<*const u8>() == core::mem::size_of::()); +}; /// Implement the traits for the given primitive traits. macro_rules! impl_traits_for_primitives { @@ -59,37 +45,42 @@ macro_rules! impl_traits_for_primitives { /// The type is passed directly. impl RIType for $rty { type FFIType = $fty; + type Inner = Self; } - #[cfg(not(feature = "std"))] + #[cfg(substrate_runtime)] impl IntoFFIValue for $rty { - type Owned = (); + type Destructor = (); - fn into_ffi_value(&self) -> WrappedFFIValue<$fty> { - (*self as $fty).into() + fn into_ffi_value(value: &mut $rty) -> (Self::FFIType, Self::Destructor) { + (*value as $fty, ()) } } - #[cfg(not(feature = "std"))] + #[cfg(substrate_runtime)] impl FromFFIValue for $rty { fn from_ffi_value(arg: $fty) -> $rty { arg as $rty } } - #[cfg(feature = "std")] - impl FromFFIValue for $rty { - type SelfInstance = $rty; + #[cfg(not(substrate_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(feature = "std")] + #[cfg(not(substrate_runtime))] impl IntoFFIValue for $rty { - fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result<$fty> { - Ok(self as $fty) + fn into_ffi_value(value: Self::Inner, _: &mut dyn FunctionContext) -> Result<$fty> { + Ok(value as $fty) } } )* @@ -113,425 +104,90 @@ impl_traits_for_primitives! { /// - `0`: false impl RIType for bool { type FFIType = u32; + type Inner = Self; } -#[cfg(not(feature = "std"))] +#[cfg(substrate_runtime)] impl IntoFFIValue for bool { - type Owned = (); + type Destructor = (); - fn into_ffi_value(&self) -> WrappedFFIValue { - if *self { 1 } else { 0 }.into() + fn into_ffi_value(value: &mut bool) -> (Self::FFIType, Self::Destructor) { + (if *value { 1 } else { 0 }, ()) } } -#[cfg(not(feature = "std"))] +#[cfg(substrate_runtime)] impl FromFFIValue for bool { fn from_ffi_value(arg: u32) -> bool { arg == 1 } } -#[cfg(feature = "std")] -impl FromFFIValue for bool { - type SelfInstance = bool; +#[cfg(not(substrate_runtime))] +impl<'a> FromFFIValue<'a> for bool { + type Owned = Self; fn from_ffi_value(_: &mut dyn FunctionContext, arg: u32) -> Result { Ok(arg == 1) } -} - -#[cfg(feature = "std")] -impl IntoFFIValue for bool { - fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result { - Ok(if self { 1 } else { 0 }) - } -} - -/// The type is passed as `u64`. -/// -/// The `u64` value is build by `length 32bit << 32 | pointer 32bit` -/// -/// If `T == u8` the length and the pointer are taken directly from `Self`. -/// Otherwise `Self` is encoded and the length and the pointer are taken from the encoded vector. -impl RIType for Vec { - type FFIType = u64; -} - -#[cfg(feature = "std")] -impl IntoFFIValue for Vec { - fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result { - let vec: Cow<'_, [u8]> = if TypeId::of::() == TypeId::of::() { - unsafe { Cow::Borrowed(mem::transmute(&self[..])) } - } else { - Cow::Owned(self.encode()) - }; - - let ptr = context.allocate_memory(vec.as_ref().len() as u32)?; - context.write_memory(ptr, &vec)?; - - Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32)) - } -} - -#[cfg(feature = "std")] -impl FromFFIValue for Vec { - type SelfInstance = Vec; - fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result> { - <[T] as FromFFIValue>::from_ffi_value(context, arg) + fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner { + *owned } } -#[cfg(not(feature = "std"))] -impl IntoFFIValue for Vec { - type Owned = Vec; - - fn into_ffi_value(&self) -> WrappedFFIValue> { - self[..].into_ffi_value() - } -} - -#[cfg(not(feature = "std"))] -impl FromFFIValue for Vec { - fn from_ffi_value(arg: u64) -> Vec { - let (ptr, len) = unpack_ptr_and_len(arg); - let len = len as usize; - - if len == 0 { - return Vec::new() - } - - let data = unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) }; - - if TypeId::of::() == TypeId::of::() { - unsafe { mem::transmute(data) } - } else { - Self::decode(&mut &data[..]).expect("Host to wasm values are encoded correctly; qed") - } - } -} - -/// The type is passed as `u64`. -/// -/// The `u64` value is build by `length 32bit << 32 | pointer 32bit` -/// -/// If `T == u8` the length and the pointer are taken directly from `Self`. -/// Otherwise `Self` is encoded and the length and the pointer are taken from the encoded vector. -impl RIType for [T] { - type FFIType = u64; -} - -#[cfg(feature = "std")] -impl FromFFIValue for [T] { - type SelfInstance = Vec; - - fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result> { - let (ptr, len) = unpack_ptr_and_len(arg); - - let vec = context.read_memory(Pointer::new(ptr), len)?; - - if TypeId::of::() == TypeId::of::() { - Ok(unsafe { mem::transmute(vec) }) - } else { - Ok(Vec::::decode(&mut &vec[..]) - .expect("Wasm to host values are encoded correctly; qed")) - } - } -} - -#[cfg(feature = "std")] -impl IntoPreallocatedFFIValue for [u8] { - type SelfInstance = Vec; - - fn into_preallocated_ffi_value( - self_instance: Self::SelfInstance, - context: &mut dyn FunctionContext, - allocated: u64, - ) -> Result<()> { - let (ptr, len) = unpack_ptr_and_len(allocated); - - if (len as usize) < self_instance.len() { - Err(format!( - "Preallocated buffer is not big enough (given {} vs needed {})!", - len, - self_instance.len() - )) - } else { - context.write_memory(Pointer::new(ptr), &self_instance) - } - } -} - -#[cfg(not(feature = "std"))] -impl IntoFFIValue for [T] { - type Owned = Vec; - - fn into_ffi_value(&self) -> WrappedFFIValue> { - if TypeId::of::() == TypeId::of::() { - let slice = unsafe { mem::transmute::<&[T], &[u8]>(self) }; - pack_ptr_and_len(slice.as_ptr() as u32, slice.len() as u32).into() - } else { - let data = self.encode(); - let ffi_value = pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32); - (ffi_value, data).into() - } - } -} - -/// The type is passed as `u32`. -/// -/// The `u32` is the pointer to the array. -impl RIType for [u8; N] { - type FFIType = u32; -} - -#[cfg(not(feature = "std"))] -impl IntoFFIValue for [u8; N] { - type Owned = (); - - fn into_ffi_value(&self) -> WrappedFFIValue { - (self.as_ptr() as u32).into() - } -} - -#[cfg(not(feature = "std"))] -impl FromFFIValue for [u8; N] { - fn from_ffi_value(arg: u32) -> [u8; N] { - let mut res = [0u8; N]; - let data = unsafe { Vec::from_raw_parts(arg as *mut u8, N, N) }; - - res.copy_from_slice(&data); - - res - } -} - -#[cfg(feature = "std")] -impl FromFFIValue for [u8; N] { - type SelfInstance = [u8; N]; - - fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<[u8; N]> { - let mut res = [0u8; N]; - context.read_memory_into(Pointer::new(arg), &mut res)?; - Ok(res) - } -} - -#[cfg(feature = "std")] -impl IntoFFIValue for [u8; N] { - fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result { - let addr = context.allocate_memory(N as u32)?; - context.write_memory(addr, &self)?; - Ok(addr.into()) - } -} - -#[cfg(feature = "std")] -impl IntoPreallocatedFFIValue for [u8; N] { - type SelfInstance = [u8; N]; - - fn into_preallocated_ffi_value( - self_instance: Self::SelfInstance, - context: &mut dyn FunctionContext, - allocated: u32, - ) -> Result<()> { - context.write_memory(Pointer::new(allocated), &self_instance) - } -} - -impl PassBy for core::result::Result { - type PassBy = Codec; -} - -impl PassBy for Option { - type PassBy = Codec; -} - -#[impl_trait_for_tuples::impl_for_tuples(30)] -#[tuple_types_no_default_trait_bound] -impl PassBy for Tuple -where - Self: codec::Codec, -{ - type PassBy = Codec; -} - -/// Implement `PassBy` with `Inner` for the given fixed sized hash types. -macro_rules! for_primitive_types { - { $( $hash:ident $n:expr ),* $(,)? } => { - $( - impl PassBy for primitive_types::$hash { - type PassBy = Inner; - } - - impl PassByInner for primitive_types::$hash { - type Inner = [u8; $n]; - - fn inner(&self) -> &Self::Inner { - &self.0 - } - - fn into_inner(self) -> Self::Inner { - self.0 - } - - fn from_inner(inner: Self::Inner) -> Self { - Self(inner) - } - } - )* - } -} - -for_primitive_types! { - H160 20, - H256 32, - H512 64, -} - -/// The type is passed as `u64`. -/// -/// The `u64` value is build by `length 32bit << 32 | pointer 32bit` -/// -/// The length and the pointer are taken directly from `Self`. -impl RIType for str { - type FFIType = u64; -} - -#[cfg(feature = "std")] -impl FromFFIValue for str { - type SelfInstance = String; - - fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result { - let (ptr, len) = unpack_ptr_and_len(arg); - - let vec = context.read_memory(Pointer::new(ptr), len)?; - - // The data is valid utf8, as it is stored as `&str` in wasm. - String::from_utf8(vec).map_err(|_| "Invalid utf8 data provided".into()) - } -} - -#[cfg(not(feature = "std"))] -impl IntoFFIValue for str { - type Owned = (); - - fn into_ffi_value(&self) -> WrappedFFIValue { - let bytes = self.as_bytes(); - pack_ptr_and_len(bytes.as_ptr() as u32, bytes.len() as u32).into() +#[cfg(not(substrate_runtime))] +impl IntoFFIValue for bool { + fn into_ffi_value(value: Self, _: &mut dyn FunctionContext) -> Result { + Ok(if value { 1 } else { 0 }) } } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] impl RIType for Pointer { type FFIType = u32; + type Inner = Self; } /// The type is passed as `u32`. -#[cfg(not(feature = "std"))] +#[cfg(substrate_runtime)] impl RIType for Pointer { type FFIType = u32; + type Inner = Self; } -#[cfg(not(feature = "std"))] +#[cfg(substrate_runtime)] impl IntoFFIValue for Pointer { - type Owned = (); + type Destructor = (); - fn into_ffi_value(&self) -> WrappedFFIValue { - (*self as u32).into() + fn into_ffi_value(value: &mut Pointer) -> (Self::FFIType, Self::Destructor) { + (*value as u32, ()) } } -#[cfg(not(feature = "std"))] +#[cfg(substrate_runtime)] impl FromFFIValue for Pointer { fn from_ffi_value(arg: u32) -> Self { arg as _ } } -#[cfg(feature = "std")] -impl FromFFIValue for Pointer { - type SelfInstance = Self; +#[cfg(not(substrate_runtime))] +impl<'a, T: sp_wasm_interface::PointerType> FromFFIValue<'a> for Pointer { + type Owned = Self; fn from_ffi_value(_: &mut dyn FunctionContext, arg: u32) -> Result { Ok(Pointer::new(arg)) } -} -#[cfg(feature = "std")] -impl IntoFFIValue for Pointer { - fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result { - Ok(self.into()) + fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner { + *owned } } -/// Implement the traits for `u128`/`i128` -macro_rules! for_u128_i128 { - ($type:ty) => { - /// `u128`/`i128` is passed as `u32`. - /// - /// The `u32` is a pointer to an `[u8; 16]` array. - impl RIType for $type { - type FFIType = u32; - } - - #[cfg(not(feature = "std"))] - impl IntoFFIValue for $type { - type Owned = (); - - fn into_ffi_value(&self) -> WrappedFFIValue { - unsafe { (mem::transmute::<&Self, *const u8>(self) as u32).into() } - } - } - - #[cfg(not(feature = "std"))] - impl FromFFIValue for $type { - fn from_ffi_value(arg: u32) -> $type { - <$type>::from_le_bytes(<[u8; mem::size_of::<$type>()]>::from_ffi_value(arg)) - } - } - - #[cfg(feature = "std")] - impl FromFFIValue for $type { - type SelfInstance = $type; - - fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<$type> { - let mut res = [0u8; mem::size_of::<$type>()]; - context.read_memory_into(Pointer::new(arg), &mut res)?; - Ok(<$type>::from_le_bytes(res)) - } - } - - #[cfg(feature = "std")] - impl IntoFFIValue for $type { - fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result { - let addr = context.allocate_memory(mem::size_of::<$type>() as u32)?; - context.write_memory(addr, &self.to_le_bytes())?; - Ok(addr.into()) - } - } - }; -} - -for_u128_i128!(u128); -for_u128_i128!(i128); - -impl PassBy for sp_wasm_interface::ValueType { - type PassBy = Enum; -} - -impl PassBy for sp_wasm_interface::Value { - type PassBy = Codec; -} - -impl PassBy for sp_storage::TrackedStorageKey { - type PassBy = Codec; -} - -impl PassBy for sp_storage::StateVersion { - type PassBy = Enum; -} - -impl PassBy for sp_externalities::MultiRemovalResults { - type PassBy = Codec; +#[cfg(not(substrate_runtime))] +impl IntoFFIValue for Pointer { + fn into_ffi_value(value: Self, _: &mut dyn FunctionContext) -> Result { + Ok(value.into()) + } } diff --git a/substrate/primitives/runtime-interface/src/lib.rs b/substrate/primitives/runtime-interface/src/lib.rs index 1de8543c461d5..21d512cddc435 100644 --- a/substrate/primitives/runtime-interface/src/lib.rs +++ b/substrate/primitives/runtime-interface/src/lib.rs @@ -18,100 +18,52 @@ //! Substrate runtime interface //! //! This crate provides types, traits and macros around runtime interfaces. A runtime interface is -//! a fixed interface between a Substrate runtime and a Substrate node. For a native runtime the -//! interface maps to a direct function call of the implementation. For a wasm runtime the interface -//! maps to an external function call. These external functions are exported by the wasm executor -//! and they map to the same implementation as the native calls. +//! a fixed interface between a Substrate runtime (also called the "guest") and a Substrate 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 //! -//! Any type that should be used in a runtime interface as argument or return value needs to -//! implement [`RIType`]. The associated type -//! [`FFIType`](./trait.RIType.html#associatedtype.FFIType) is the type that is used in the FFI -//! function to represent the actual type. For example `[T]` is represented by an `u64`. The slice -//! pointer and the length will be mapped to an `u64` value. For more information see this -//! [table](#ffi-type-and-conversion). The FFI function definition is used when calling from the -//! wasm runtime into the node. +//! 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. //! -//! Traits are used to convert from a type to the corresponding -//! [`RIType::FFIType`](./trait.RIType.html#associatedtype.FFIType). -//! Depending on where and how a type should be used in a function signature, a combination of the -//! following traits need to be implemented: -//! -//! 1. Pass as function argument: [`wasm::IntoFFIValue`] and [`host::FromFFIValue`] -//! 2. As function return value: [`wasm::FromFFIValue`] and [`host::IntoFFIValue`] -//! 3. Pass as mutable function argument: [`host::IntoPreallocatedFFIValue`] +//! You can find the strategy wrapper types in the [`crate::pass_by`] module. //! -//! The traits are implemented for most of the common types like `[T]`, `Vec`, arrays and -//! primitive types. -//! -//! For custom types, we provide the [`PassBy`](./pass_by#PassBy) trait and strategies that define -//! how a type is passed between the wasm runtime and the node. Each strategy also provides a derive -//! macro to simplify the implementation. -//! -//! # Performance -//! -//! To not waste any more performance when calling into the node, not all types are SCALE encoded -//! when being passed as arguments between the wasm runtime and the node. For most types that -//! are raw bytes like `Vec`, `[u8]` or `[u8; N]` we pass them directly, without SCALE encoding -//! them in front of. The implementation of [`RIType`] each type provides more information on how -//! the data is passed. +//! 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 sp_runtime_interface::pass_by::PassFatPointerAndRead; +//! //! #[sp_runtime_interface::runtime_interface] //! trait RuntimeInterface { -//! fn some_function(value: &[u8]) -> bool { +//! 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). -//! -//! # FFI type and conversion -//! -//! The following table documents how values of types are passed between the wasm and -//! the host side and how they are converted into the corresponding type. -//! -//! | Type | FFI type | Conversion | -//! |----|----|----| -//! | `u8` | `u32` | zero-extended to 32-bits | -//! | `u16` | `u32` | zero-extended to 32-bits | -//! | `u32` | `u32` | `Identity` | -//! | `u64` | `u64` | `Identity` | -//! | `i128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) | -//! | `i8` | `i32` | sign-extended to 32-bits | -//! | `i16` | `i32` | sign-extended to 32-bits | -//! | `i32` | `i32` | `Identity` | -//! | `i64` | `i64` | `Identity` | -//! | `u128` | `u32` | `v.as_ptr()` (pointer to a 16 byte array) | -//! | `bool` | `u32` | `if v { 1 } else { 0 }` | -//! | `&str` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | -//! | `&[u8]` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | -//! | `Vec` | `u64` | v.len() 32bit << 32 | v.as_ptr() 32bit | -//! | `Vec where T: Encode` | `u64` | `let e = v.encode();`

e.len() 32bit << 32 | e.as_ptr() 32bit | -//! | `&[T] where T: Encode` | `u64` | `let e = v.encode();`

e.len() 32bit << 32 | e.as_ptr() 32bit | -//! | `[u8; N]` | `u32` | `v.as_ptr()` | -//! | `*const T` | `u32` | `Identity` | -//! | `Option` | `u64` | `let e = v.encode();`

e.len() 32bit << 32 | e.as_ptr() 32bit | -//! | [`T where T: PassBy`](./pass_by#Inner) | Depends on inner | Depends on inner | -//! | [`T where T: PassBy`](./pass_by#Codec)|`u64`|v.len() 32bit << 32 |v.as_ptr() 32bit| -//! -//! `Identity` means that the value is converted directly into the corresponding FFI type. -#![cfg_attr(not(feature = "std"), no_std)] +#![no_std] +pub extern crate alloc; extern crate self as sp_runtime_interface; -extern crate alloc; - #[doc(hidden)] -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub use sp_wasm_interface; #[doc(hidden)] @@ -130,14 +82,16 @@ pub use sp_std; /// The macro expects the runtime interface declaration as trait declaration: /// /// ``` +/// # mod wrapper { /// # use sp_runtime_interface::runtime_interface; +/// # use sp_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: &[u8]) -> Vec { +/// fn call(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnFatPointer> { /// // 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() @@ -148,7 +102,7 @@ pub use sp_std; /// /// But old version (above) is still accessible for old runtimes. /// /// Default version is 1. /// #[version(2)] -/// fn call(data: &[u8]) -> Vec { +/// fn call(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnFatPointer> { /// // 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() @@ -164,7 +118,7 @@ pub use sp_std; /// /// 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: &[u8]) -> Vec { +/// fn call(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnFatPointer> { /// // 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() @@ -173,7 +127,7 @@ pub use sp_std; /// /// 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: Option>) { +/// fn set_or_clear(&mut self, optional: PassFatPointerAndDecode>>) { /// match optional { /// Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value), /// None => self.clear_storage(&[1, 2, 3, 4]), @@ -186,10 +140,11 @@ pub use sp_std; /// /// That is, conditionally compiled functions with `version`s greater than 1 /// /// are not allowed. /// #[cfg(feature = "experimental-function")] -/// fn gated_call(data: &[u8]) -> Vec { +/// fn gated_call(data: PassFatPointerAndRead<&[u8]>) -> AllocateAndReturnFatPointer> { /// [42].to_vec() /// } /// } +/// # } /// ``` /// /// The given example will generate roughly the following code for native: @@ -339,13 +294,36 @@ pub use sp_std; /// } /// ``` /// -/// # Argument types +/// # 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` | /// -/// The macro supports any kind of argument type, as long as it implements [`RIType`] and the -/// required `FromFFIValue`/`IntoFFIValue`. The macro will convert each -/// argument to the corresponding FFI representation and will call into the host using this FFI -/// representation. On the host each argument is converted back to the native representation -/// and the native implementation is called. Any return value is handled in the same way. +/// `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 /// @@ -366,7 +344,7 @@ pub use sp_std; pub use sp_runtime_interface_proc_macro::runtime_interface; #[doc(hidden)] -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub use sp_externalities::{ set_and_run_with_externalities, with_externalities, ExtensionStore, Externalities, ExternalitiesExt, @@ -378,36 +356,40 @@ pub use codec; #[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), substrate_runtime))] pub mod polkavm; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub mod host; pub(crate) mod impls; pub mod pass_by; -#[cfg(any(not(feature = "std"), doc))] +#[cfg(any(substrate_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 wasm and the -/// host. +/// 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 { - /// The ffi type that is used to represent `Self`. - #[cfg(feature = "std")] +pub trait RIType: Sized { + /// The raw FFI type that is used to pass `Self` through the host <-> runtime boundary. + #[cfg(not(substrate_runtime))] type FFIType: sp_wasm_interface::IntoValue + sp_wasm_interface::TryFromValue + sp_wasm_interface::WasmTy; - #[cfg(not(feature = "std"))] + + #[cfg(substrate_runtime)] type FFIType; + + /// The inner type without any serialization strategy wrapper. + type Inner; } -/// A pointer that can be used in a runtime interface function signature. -#[cfg(not(feature = "std"))] +/// A raw pointer that can be used in a runtime interface function signature. +#[cfg(substrate_runtime)] pub type Pointer = *mut T; -/// A pointer that can be used in a runtime interface function signature. -#[cfg(feature = "std")] +/// A raw pointer that can be used in a runtime interface function signature. +#[cfg(not(substrate_runtime))] pub type Pointer = sp_wasm_interface::Pointer; diff --git a/substrate/primitives/runtime-interface/src/pass_by.rs b/substrate/primitives/runtime-interface/src/pass_by.rs index dce0b8e4bddb7..796bab10ba234 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -15,419 +15,698 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Provides the [`PassBy`] trait to simplify the implementation of the -//! runtime interface traits for custom types. -//! -//! [`Codec`], [`Inner`] and [`Enum`] are the provided strategy implementations. +//! 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(feature = "std")] +#[cfg(not(substrate_runtime))] use crate::host::*; -#[cfg(not(feature = "std"))] + +#[cfg(substrate_runtime)] use crate::wasm::*; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use sp_wasm_interface::{FunctionContext, Pointer, Result}; -use core::marker::PhantomData; +#[cfg(not(substrate_runtime))] +use alloc::{format, string::String}; -#[cfg(not(feature = "std"))] use alloc::vec::Vec; +use core::{any::type_name, marker::PhantomData}; -/// Derive macro for implementing [`PassBy`] with the [`Codec`] strategy. -/// -/// This requires that the type implements [`Encode`](codec::Encode) and -/// [`Decode`](codec::Decode) from `parity-scale-codec`. -/// -/// # Example -/// -/// ``` -/// # use sp_runtime_interface::pass_by::PassByCodec; -/// # use codec::{Encode, Decode}; -/// #[derive(PassByCodec, Encode, Decode)] -/// struct EncodableType { -/// name: Vec, -/// param: u32, -/// } -/// ``` -pub use sp_runtime_interface_proc_macro::PassByCodec; - -/// Derive macro for implementing [`PassBy`] with the [`Inner`] strategy. -/// -/// Besides implementing [`PassBy`], this derive also implements the helper trait -/// [`PassByInner`]. -/// -/// The type is required to be a struct with just one field. The field type needs to implement -/// the required traits to pass it between the wasm and the native side. (See the runtime -/// interface crate for more information about these traits.) -/// -/// # Example +/// Pass a value into the host by a thin pointer. /// -/// ``` -/// # use sp_runtime_interface::pass_by::PassByInner; -/// #[derive(PassByInner)] -/// struct Data([u8; 32]); -/// ``` +/// 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 sp_runtime_interface::pass_by::PassByInner; -/// #[derive(PassByInner)] -/// struct Data { -/// data: [u8; 32], -/// } -/// ``` -pub use sp_runtime_interface_proc_macro::PassByInner; - -/// Derive macro for implementing [`PassBy`] with the [`Enum`] strategy. +/// 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. /// -/// Besides implementing [`PassBy`], this derive also implements `TryFrom` and -/// `From for u8` for the type. -/// -/// The type is required to be an enum with only unit variants and at maximum `256` variants. -/// Also it is required that the type implements `Copy`. +/// Raw FFI type: `u32` (a pointer) +pub struct PassPointerAndReadCopy(PhantomData<(T, [u8; N])>); + +impl RIType for PassPointerAndReadCopy { + type FFIType = u32; + type Inner = T; +} + +#[cfg(not(substrate_runtime))] +impl<'a, T, const N: usize> FromFFIValue<'a> for PassPointerAndReadCopy +where + T: From<[u8; N]> + Copy, +{ + type Owned = T; + + fn from_ffi_value( + context: &mut dyn FunctionContext, + arg: Self::FFIType, + ) -> Result { + 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(substrate_runtime)] +impl IntoFFIValue for PassPointerAndReadCopy +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. /// -/// # Example +/// 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. /// -/// ``` -/// # use sp_runtime_interface::pass_by::PassByEnum; -/// #[derive(PassByEnum, Copy, Clone)] -/// enum Data { -/// Okay, -/// NotOkay, -/// // This will not work with the derive. -/// //Why(u32), -/// } -/// ``` -pub use sp_runtime_interface_proc_macro::PassByEnum; - -/// Something that should be passed between wasm and the host using the given strategy. +/// 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. /// -/// See [`Codec`], [`Inner`] or [`Enum`] for more information about the provided strategies. -pub trait PassBy: Sized { - /// The strategy that should be used to pass the type. - type PassBy: PassByImpl; +/// Raw FFI type: `u32` (a pointer) +pub struct PassPointerAndRead(PhantomData<(T, [u8; N])>); + +impl<'a, T, const N: usize> RIType for PassPointerAndRead<&'a T, N> { + type FFIType = u32; + type Inner = &'a T; } -/// Something that provides a strategy for passing a type between wasm and the host. -/// -/// This trait exposes the same functionality as [`crate::host::IntoFFIValue`] and -/// [`crate::host::FromFFIValue`] to delegate the implementation for a type to a different type. -/// -/// This trait is used for the host implementation. -#[cfg(feature = "std")] -pub trait PassByImpl: RIType { - /// Convert the given instance to the ffi value. - /// - /// For more information see: [`crate::host::IntoFFIValue::into_ffi_value`] - fn into_ffi_value(instance: T, context: &mut dyn FunctionContext) -> Result; +#[cfg(not(substrate_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 { + 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(substrate_runtime)] +impl<'a, T, const N: usize> IntoFFIValue for PassPointerAndRead<&'a T, N> +where + T: AsRef<[u8]>, +{ + type Destructor = (); - /// Create `T` from the given ffi value. - /// - /// For more information see: [`crate::host::FromFFIValue::from_ffi_value`] - fn from_ffi_value(context: &mut dyn FunctionContext, arg: Self::FFIType) -> Result; + 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, ()) + } } -/// Something that provides a strategy for passing a type between wasm and the host. +/// Pass a value into the host by a fat pointer. /// -/// This trait exposes the same functionality as [`crate::wasm::IntoFFIValue`] and -/// [`crate::wasm::FromFFIValue`] to delegate the implementation for a type to a different type. +/// 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. /// -/// This trait is used for the wasm implementation. -#[cfg(not(feature = "std"))] -pub trait PassByImpl: RIType { - /// The owned rust type that is stored with the ffi value in [`crate::wasm::WrappedFFIValue`]. - type Owned; - - /// Convert the given `instance` into [`crate::wasm::WrappedFFIValue`]. - /// - /// For more information see: [`crate::wasm::IntoFFIValue::into_ffi_value`] - fn into_ffi_value(instance: &T) -> WrappedFFIValue; +/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer) +pub struct PassFatPointerAndRead(PhantomData); - /// Create `T` from the given ffi value. - /// - /// For more information see: [`crate::wasm::FromFFIValue::from_ffi_value`] - fn from_ffi_value(arg: Self::FFIType) -> T; +impl RIType for PassFatPointerAndRead { + type FFIType = u64; + type Inner = T; } -impl RIType for T { - type FFIType = ::FFIType; -} +#[cfg(not(substrate_runtime))] +impl<'a> FromFFIValue<'a> for PassFatPointerAndRead<&'a [u8]> { + type Owned = Vec; -#[cfg(feature = "std")] -impl IntoFFIValue for T { - fn into_ffi_value( - self, + fn from_ffi_value( context: &mut dyn FunctionContext, - ) -> Result<::FFIType> { - T::PassBy::into_ffi_value(self, context) + arg: Self::FFIType, + ) -> Result { + 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(feature = "std")] -impl FromFFIValue for T { - type SelfInstance = Self; +#[cfg(not(substrate_runtime))] +impl<'a> FromFFIValue<'a> for PassFatPointerAndRead<&'a str> { + type Owned = String; fn from_ffi_value( context: &mut dyn FunctionContext, - arg: ::FFIType, - ) -> Result { - T::PassBy::from_ffi_value(context, arg) + arg: Self::FFIType, + ) -> Result { + 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(feature = "std"))] -impl IntoFFIValue for T { - type Owned = >::Owned; +#[cfg(not(substrate_runtime))] +impl<'a> FromFFIValue<'a> for PassFatPointerAndRead> { + type Owned = Vec; + + fn from_ffi_value( + context: &mut dyn FunctionContext, + arg: Self::FFIType, + ) -> Result { + as FromFFIValue>::from_ffi_value(context, arg) + } - fn into_ffi_value(&self) -> WrappedFFIValue<::FFIType, Self::Owned> { - T::PassBy::into_ffi_value(self) + fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner { + core::mem::take(owned) } } -#[cfg(not(feature = "std"))] -impl FromFFIValue for T { - fn from_ffi_value(arg: ::FFIType) -> Self { - T::PassBy::from_ffi_value(arg) +#[cfg(substrate_runtime)] +impl IntoFFIValue for PassFatPointerAndRead +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), ()) } } -/// The implementation of the pass by codec strategy. This strategy uses a SCALE encoded -/// representation of the type between wasm and the host. -/// -/// Use this type as associated type for [`PassBy`] to implement this strategy for a type. +/// Pass a value into the host by a fat pointer, writing it back after the host call ends. /// -/// This type expects the type that wants to implement this strategy as generic parameter. +/// 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. /// -/// [`PassByCodec`](derive.PassByCodec.html) is a derive macro to implement this strategy. -/// -/// # Example -/// ``` -/// # use sp_runtime_interface::pass_by::{PassBy, Codec}; -/// #[derive(codec::Encode, codec::Decode)] -/// struct Test; -/// -/// impl PassBy for Test { -/// type PassBy = Codec; -/// } -/// ``` -pub struct Codec(PhantomData); - -#[cfg(feature = "std")] -impl PassByImpl for Codec { - fn into_ffi_value(instance: T, context: &mut dyn FunctionContext) -> Result { - let vec = instance.encode(); - let ptr = context.allocate_memory(vec.len() as u32)?; - context.write_memory(ptr, &vec)?; +/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer) +pub struct PassFatPointerAndReadWrite(PhantomData); - Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32)) +impl RIType for PassFatPointerAndReadWrite { + type FFIType = u64; + type Inner = T; +} + +#[cfg(not(substrate_runtime))] +impl<'a> FromFFIValue<'a> for PassFatPointerAndReadWrite<&'a mut [u8]> { + type Owned = Vec; + + fn from_ffi_value( + context: &mut dyn FunctionContext, + arg: Self::FFIType, + ) -> Result { + let (ptr, len) = unpack_ptr_and_len(arg); + context.read_memory(Pointer::new(ptr), len) } - fn from_ffi_value(context: &mut dyn FunctionContext, arg: Self::FFIType) -> Result { + 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); - let vec = context.read_memory(Pointer::new(ptr), len)?; - T::decode(&mut &vec[..]).map_err(|e| format!("Could not decode value from wasm: {}", e)) + assert_eq!(len as usize, value.len()); + context.write_memory(Pointer::new(ptr), &value) } } -#[cfg(not(feature = "std"))] -impl PassByImpl for Codec { - type Owned = Vec; +#[cfg(substrate_runtime)] +impl<'a> IntoFFIValue for PassFatPointerAndReadWrite<&'a mut [u8]> { + type Destructor = (); - fn into_ffi_value(instance: &T) -> WrappedFFIValue { - let data = instance.encode(); - let ffi_value = pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32); - (ffi_value, data).into() + 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), ()) } +} - fn from_ffi_value(arg: Self::FFIType) -> T { - let (ptr, len) = unpack_ptr_and_len(arg); - let len = len as usize; +/// 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(PhantomData<(T, [u8; N])>); - let encoded = if len == 0 { - bytes::Bytes::new() - } else { - bytes::Bytes::from(unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) }) - }; +impl RIType for PassPointerAndWrite { + type FFIType = u32; + type Inner = T; +} + +#[cfg(not(substrate_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 { + 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(substrate_runtime)] +impl<'a, T, const N: usize> IntoFFIValue for PassPointerAndWrite<&'a mut T, N> +where + T: AsMut<[u8]>, +{ + type Destructor = (); - codec::decode_from_bytes(encoded).expect("Host to wasm values are encoded correctly; qed") + 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, ()) } } -/// The type is passed as `u64`. +/// Pass a `T` into the host using the SCALE codec. /// -/// The `u64` value is build by `length 32bit << 32 | pointer 32bit` +/// This encodes a `T` into a `Vec` 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`. /// -/// `Self` is encoded and the length and the pointer are taken from the encoded vector. -impl RIType for Codec { +/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer) +pub struct PassFatPointerAndDecode(PhantomData); + +impl RIType for PassFatPointerAndDecode { type FFIType = u64; + type Inner = T; } -/// Trait that needs to be implemented by a type that should be passed between wasm and the host, -/// by using the inner type. See [`Inner`] for more information. -pub trait PassByInner: Sized { - /// The inner type that is wrapped by `Self`. - type Inner: RIType; +#[cfg(not(substrate_runtime))] +impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecode { + type Owned = Option; + + fn from_ffi_value( + context: &mut dyn FunctionContext, + arg: Self::FFIType, + ) -> Result { + 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::()) + ).map(Some) + } - /// Consumes `self` and returns the inner type. - fn into_inner(self) -> Self::Inner; + fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner { + owned.take().expect("this is called only once and is never 'None'") + } +} - /// Returns the reference to the inner type. - fn inner(&self) -> &Self::Inner; +#[cfg(substrate_runtime)] +impl IntoFFIValue for PassFatPointerAndDecode { + type Destructor = Vec; - /// Construct `Self` from the given `inner`. - fn from_inner(inner: Self::Inner) -> Self; + 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) + } } -/// The implementation of the pass by inner type strategy. The type that uses this strategy will be -/// passed between wasm and the host by using the wrapped inner type. So, this strategy is only -/// usable by newtype structs. -/// -/// Use this type as associated type for [`PassBy`] to implement this strategy for a type. Besides -/// that the `PassByInner` trait need to be implemented as well. -/// -/// This type expects the type that wants to use this strategy as generic parameter `T` and the -/// inner type as generic parameter `I`. -/// -/// [`PassByInner`](derive.PassByInner.html) is a derive macro to implement this strategy. +/// Pass a `&[T]` into the host using the SCALE codec. /// -/// # Example -/// ``` -/// # use sp_runtime_interface::pass_by::{PassBy, Inner, PassByInner}; -/// struct Test([u8; 32]); +/// This encodes a `&[T]` into a `Vec` 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` and passes +/// a reference to that (as `&[T]`) into the host function. /// -/// impl PassBy for Test { -/// type PassBy = Inner; -/// } -/// -/// impl PassByInner for Test { -/// type Inner = [u8; 32]; +/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer) +pub struct PassFatPointerAndDecodeSlice(PhantomData); + +impl RIType for PassFatPointerAndDecodeSlice { + type FFIType = u64; + type Inner = T; +} + +#[cfg(not(substrate_runtime))] +impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecodeSlice<&'a [T]> { + type Owned = Vec; + + fn from_ffi_value( + context: &mut dyn FunctionContext, + arg: Self::FFIType, + ) -> Result { + let (ptr, len) = unpack_ptr_and_len(arg); + let vec = context.read_memory(Pointer::new(ptr), len)?; + 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::>() + )) + } + + fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner { + &*owned + } +} + +#[cfg(substrate_runtime)] +impl<'a, T: codec::Encode> IntoFFIValue for PassFatPointerAndDecodeSlice<&'a [T]> { + type Destructor = Vec; + + 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. /// -/// fn into_inner(self) -> [u8; 32] { -/// self.0 -/// } -/// fn inner(&self) -> &[u8; 32] { -/// &self.0 -/// } -/// fn from_inner(inner: [u8; 32]) -> Self { -/// Self(inner) -/// } -/// } -/// ``` -pub struct Inner, I: RIType>(PhantomData<(T, I)>); - -#[cfg(feature = "std")] -impl, I: RIType> PassByImpl for Inner +/// Raw FFI type: same as `U`'s FFI type +pub struct PassAs(PhantomData<(T, U)>); + +impl RIType for PassAs where - I: IntoFFIValue + FromFFIValue, + U: RIType, { - fn into_ffi_value(instance: T, context: &mut dyn FunctionContext) -> Result { - instance.into_inner().into_ffi_value(context) + type FFIType = ::FFIType; + type Inner = T; +} + +#[cfg(not(substrate_runtime))] +impl<'a, T, U> FromFFIValue<'a> for PassAs +where + U: RIType + FromFFIValue<'a> + Primitive, + T: TryFrom<>::Owned> + Copy, +{ + type Owned = T; + + fn from_ffi_value( + context: &mut dyn FunctionContext, + arg: Self::FFIType, + ) -> Result { + ::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::(), + type_name::(), + type_name::() + ))) } - fn from_ffi_value(context: &mut dyn FunctionContext, arg: Self::FFIType) -> Result { - I::from_ffi_value(context, arg).map(T::from_inner) + fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner { + *owned } } -#[cfg(not(feature = "std"))] -impl, I: RIType> PassByImpl for Inner +#[cfg(substrate_runtime)] +impl IntoFFIValue for PassAs where - I: IntoFFIValue + FromFFIValue, + U: RIType + IntoFFIValue + Primitive, + U::Inner: From, + T: Copy, { - type Owned = I::Owned; + type Destructor = ::Destructor; - fn into_ffi_value(instance: &T) -> WrappedFFIValue { - instance.inner().into_ffi_value() + fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) { + let mut value = U::Inner::from(*value); + ::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(PhantomData<(T, U)>); + +impl RIType for ReturnAs +where + U: RIType, +{ + type FFIType = ::FFIType; + type Inner = T; +} - fn from_ffi_value(arg: Self::FFIType) -> T { - T::from_inner(I::from_ffi_value(arg)) +#[cfg(not(substrate_runtime))] +impl IntoFFIValue for ReturnAs +where + U: RIType + IntoFFIValue + Primitive, + ::Inner: From, +{ + fn into_ffi_value( + value: Self::Inner, + context: &mut dyn FunctionContext, + ) -> Result { + let value: ::Inner = value.into(); + ::into_ffi_value(value, context) } } -/// The type is passed as the inner type. -impl, I: RIType> RIType for Inner { - type FFIType = I::FFIType; +#[cfg(substrate_runtime)] +impl FromFFIValue for ReturnAs +where + U: RIType + FromFFIValue + Primitive, + Self::Inner: TryFrom, +{ + fn from_ffi_value(arg: Self::FFIType) -> Self::Inner { + let value = ::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::(), + type_name::(), + type_name::() + ); + }, + } + } } -/// The implementation of the pass by enum strategy. This strategy uses an `u8` internally to pass -/// the enum between wasm and the host. So, this strategy only supports enums with unit variants. +/// (DEPRECATED) Return `T` as a blob of bytes into the runtime. /// -/// Use this type as associated type for [`PassBy`] to implement this strategy for a type. +/// 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 type expects the type that wants to implement this strategy as generic parameter. Besides -/// that the type needs to implement `TryFrom` and `From for u8`. +/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS! /// -/// [`PassByEnum`](derive.PassByEnum.html) is a derive macro to implement this strategy. +/// Ideally use a mutable slice to return data to the guest, for example using +/// the [`PassPointerAndWrite`] strategy. /// -/// # Example -/// ``` -/// # use sp_runtime_interface::pass_by::{PassBy, Enum}; -/// #[derive(Clone, Copy)] -/// enum Test { -/// Test1, -/// Test2, -/// } +/// Raw FFI type: `u32` (a pointer to the byte blob) +pub struct AllocateAndReturnPointer(PhantomData<(T, [u8; N])>); + +impl RIType for AllocateAndReturnPointer { + type FFIType = u32; + type Inner = T; +} + +#[cfg(not(substrate_runtime))] +impl IntoFFIValue for AllocateAndReturnPointer +where + T: AsRef<[u8]>, +{ + fn into_ffi_value( + value: Self::Inner, + context: &mut dyn FunctionContext, + ) -> Result { + 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::() + ); + + let addr = context.allocate_memory(value.len() as u32)?; + context.write_memory(addr, value)?; + Ok(addr.into()) + } +} + +#[cfg(substrate_runtime)] +impl FromFFIValue for AllocateAndReturnPointer +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. /// -/// impl From for u8 { -/// fn from(val: Test) -> u8 { -/// match val { -/// Test::Test1 => 0, -/// Test::Test2 => 1, -/// } -/// } -/// } +/// 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. /// -/// impl TryFrom for Test { -/// type Error = (); +/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS! /// -/// fn try_from(val: u8) -> Result { -/// match val { -/// 0 => Ok(Test::Test1), -/// 1 => Ok(Test::Test2), -/// _ => Err(()), -/// } -/// } -/// } +/// Ideally use a mutable slice to return data to the guest, for example using +/// the [`PassPointerAndWrite`] strategy. /// -/// impl PassBy for Test { -/// type PassBy = Enum; -/// } -/// ``` -pub struct Enum + TryFrom>(PhantomData); +/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer) +pub struct AllocateAndReturnFatPointer(PhantomData); -#[cfg(feature = "std")] -impl + TryFrom> PassByImpl for Enum { - fn into_ffi_value(instance: T, _: &mut dyn FunctionContext) -> Result { - Ok(instance.into() as u32) - } +impl RIType for AllocateAndReturnFatPointer { + type FFIType = u64; + type Inner = T; +} - fn from_ffi_value(_: &mut dyn FunctionContext, arg: Self::FFIType) -> Result { - T::try_from(arg as u8).map_err(|_| format!("Invalid enum discriminant: {}", arg)) +#[cfg(not(substrate_runtime))] +impl IntoFFIValue for AllocateAndReturnFatPointer +where + T: AsRef<[u8]>, +{ + fn into_ffi_value( + value: Self::Inner, + context: &mut dyn FunctionContext, + ) -> Result { + 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(not(feature = "std"))] -impl + TryFrom> PassByImpl for Enum { - type Owned = (); +#[cfg(substrate_runtime)] +impl FromFFIValue for AllocateAndReturnFatPointer +where + T: From>, +{ + 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) } + }; - fn into_ffi_value(instance: &T) -> WrappedFFIValue { - let value: u8 = (*instance).into(); - (value as u32).into() + 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(PhantomData); - fn from_ffi_value(arg: Self::FFIType) -> T { - T::try_from(arg as u8).expect("Host to wasm provides a valid enum discriminant; qed") +impl RIType for AllocateAndReturnByCodec { + type FFIType = u64; + type Inner = T; +} + +#[cfg(not(substrate_runtime))] +impl IntoFFIValue for AllocateAndReturnByCodec { + fn into_ffi_value(value: T, context: &mut dyn FunctionContext) -> Result { + 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)) } } -/// The type is passed as `u32`. -/// -/// The value is corresponds to the discriminant of the variant. -impl + TryFrom> RIType for Enum { - type FFIType = u32; +#[cfg(substrate_runtime)] +impl FromFFIValue for AllocateAndReturnByCodec { + 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::(), + ); + }, + } + } } diff --git a/substrate/primitives/runtime-interface/src/util.rs b/substrate/primitives/runtime-interface/src/util.rs index 86c8e4b50e293..b40ef91296fd5 100644 --- a/substrate/primitives/runtime-interface/src/util.rs +++ b/substrate/primitives/runtime-interface/src/util.rs @@ -20,7 +20,7 @@ /// 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(not(feature = "std"), feature = "disable_target_static_assertions"))] + #[cfg(all(substrate_runtime, feature = "disable_target_static_assertions"))] assert_eq!(4, core::mem::size_of::()); (u64::from(len) << 32) | u64::from(ptr) @@ -33,7 +33,7 @@ pub fn pack_ptr_and_len(ptr: u32, len: u32) -> u64 { /// 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(not(feature = "std"), feature = "disable_target_static_assertions"))] + #[cfg(all(substrate_runtime, feature = "disable_target_static_assertions"))] assert_eq!(4, core::mem::size_of::()); let ptr = (val & (!0u32 as u64)) as u32; diff --git a/substrate/primitives/runtime-interface/src/wasm.rs b/substrate/primitives/runtime-interface/src/wasm.rs index 10bb50c640398..749064e6092f9 100644 --- a/substrate/primitives/runtime-interface/src/wasm.rs +++ b/substrate/primitives/runtime-interface/src/wasm.rs @@ -21,60 +21,23 @@ use crate::RIType; use core::cell::Cell; -/// Something that can be created from a ffi value. +/// A type used as a return value in a host function. Can be created from an FFI value. /// -/// # Safety -/// -/// It is unsafe behavior to call `Something::into_ffi_value().get()` and take this as input for -/// `from_ffi_value`. Implementations are safe to assume that the `arg` given to `from_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` from the given ffi value. - fn from_ffi_value(arg: Self::FFIType) -> Self; + /// Create `Self::Inner` from the given FFI value. + fn from_ffi_value(arg: Self::FFIType) -> Self::Inner; } -/// Something that can be converted into a ffi value. +/// A type used as a parameter in a host function. Can be turned into an FFI value. pub trait IntoFFIValue: RIType { - /// The owned rust type that is stored with the ffi value in [`WrappedFFIValue`]. - /// - /// If no owned value is required, `()` can be used as a type. - type Owned; - - /// Convert `self` into a [`WrappedFFIValue`]. - fn into_ffi_value(&self) -> WrappedFFIValue; -} - -/// Represents a wrapped ffi value. -/// -/// It is either the ffi value itself or the ffi value plus some other owned value. By providing -/// support for storing another owned value besides the actual ffi value certain performance -/// optimizations can be applied. For example using the pointer to a `Vec`, while using the -/// pointer to a SCALE encoded `Vec` that is stored in this wrapper for any other `Vec`. -pub enum WrappedFFIValue { - Wrapped(T), - WrappedAndOwned(T, O), -} - -impl WrappedFFIValue { - /// Returns the wrapped ffi value. - pub fn get(&self) -> T { - match self { - Self::Wrapped(data) | Self::WrappedAndOwned(data, _) => *data, - } - } -} + /// Destructor for the value passed into `into_ffi_value`. + type Destructor; -impl From for WrappedFFIValue { - fn from(val: T) -> Self { - WrappedFFIValue::Wrapped(val) - } -} - -impl From<(T, O)> for WrappedFFIValue { - fn from(val: (T, O)) -> Self { - WrappedFFIValue::WrappedAndOwned(val.0, val.1) - } + /// 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. diff --git a/substrate/primitives/runtime-interface/test-wasm/src/lib.rs b/substrate/primitives/runtime-interface/test-wasm/src/lib.rs index f0b9d6839d412..74e96674f7043 100644 --- a/substrate/primitives/runtime-interface/test-wasm/src/lib.rs +++ b/substrate/primitives/runtime-interface/test-wasm/src/lib.rs @@ -21,7 +21,15 @@ extern crate alloc; -use sp_runtime_interface::runtime_interface; +use sp_runtime_interface::{ + pass_by::{ + AllocateAndReturnByCodec, AllocateAndReturnFatPointer, AllocateAndReturnPointer, PassAs, + PassFatPointerAndDecode, PassFatPointerAndDecodeSlice, PassFatPointerAndRead, + PassFatPointerAndReadWrite, PassPointerAndRead, PassPointerAndReadCopy, + PassPointerAndWrite, ReturnAs, + }, + runtime_interface, +}; #[cfg(not(feature = "std"))] use core::mem; @@ -48,7 +56,7 @@ const TEST_ARRAY: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, #[runtime_interface] pub trait TestApi { /// Returns the input data as result. - fn return_input(data: Vec) -> Vec { + fn return_input(data: PassFatPointerAndRead>) -> AllocateAndReturnFatPointer> { data } @@ -59,59 +67,69 @@ pub trait TestApi { /// We return a `Vec` because this will use the code path that uses SCALE /// to pass the data between native/wasm. (`Vec` is passed without encoding the /// data) - fn return_16kb() -> Vec { + fn return_16kb() -> AllocateAndReturnByCodec> { vec![0; 4 * 1024] } - fn return_option_vec() -> Option> { + fn return_option_vec() -> AllocateAndReturnByCodec>> { let mut vec = Vec::new(); vec.resize(16 * 1024, 0xAA); Some(vec) } - fn return_option_bytes() -> Option { + fn return_option_bytes() -> AllocateAndReturnByCodec> { let mut vec = Vec::new(); vec.resize(16 * 1024, 0xAA); Some(vec.into()) } /// Set the storage at key with value. - fn set_storage(&mut self, key: &[u8], data: &[u8]) { + fn set_storage( + &mut self, + key: PassFatPointerAndRead<&[u8]>, + data: PassFatPointerAndRead<&[u8]>, + ) { self.place_storage(key.to_vec(), Some(data.to_vec())); } /// Copy `hello` into the given mutable reference - fn return_value_into_mutable_reference(&self, data: &mut [u8]) { + fn return_value_into_mutable_reference(&self, data: PassFatPointerAndReadWrite<&mut [u8]>) { let res = "hello"; data[..res.len()].copy_from_slice(res.as_bytes()); } /// Returns the input data wrapped in an `Option` as result. - fn return_option_input(data: Vec) -> Option> { + fn return_option_input( + data: PassFatPointerAndRead>, + ) -> AllocateAndReturnByCodec>> { Some(data) } /// Get an array as input and returns a subset of this array. - fn get_and_return_array(data: [u8; 34]) -> [u8; 16] { + fn get_and_return_array( + data: PassPointerAndReadCopy<[u8; 34], 34>, + ) -> AllocateAndReturnPointer<[u8; 16], 16> { let mut res = [0u8; 16]; res.copy_from_slice(&data[..16]); res } /// Take and fill mutable array. - fn array_as_mutable_reference(data: &mut [u8; 16]) { + fn array_as_mutable_reference(data: PassPointerAndWrite<&mut [u8; 16], 16>) { data.copy_from_slice(&TEST_ARRAY); } /// Returns the given public key as result. - fn return_input_public_key(key: Public) -> Public { + fn return_input_public_key( + key: PassPointerAndReadCopy, + ) -> AllocateAndReturnPointer { key } /// A function that is called with invalid utf8 data from the runtime. /// /// This also checks that we accept `_` (wild card) argument names. - fn invalid_utf8_data(_: &str) {} + fn invalid_utf8_data(_: PassFatPointerAndRead<&str>) {} /// Overwrite the native implementation in wasm. The native implementation always returns /// `false` and the replacement function will return always `true`. @@ -119,16 +137,6 @@ pub trait TestApi { false } - /// Gets an `u128` and returns this value - fn get_and_return_u128(val: u128) -> u128 { - val - } - - /// Gets an `i128` and returns this value - fn get_and_return_i128(val: i128) -> i128 { - val - } - fn test_versioning(&self, data: u32) -> bool { data == 42 || data == 50 } @@ -149,13 +157,81 @@ pub trait TestApi { /// Returns the input values as tuple. fn return_input_as_tuple( - a: Vec, + a: PassFatPointerAndRead>, b: u32, - c: Option>, + c: PassFatPointerAndDecode>>, d: u8, - ) -> (Vec, u32, Option>, u8) { + ) -> AllocateAndReturnByCodec<(Vec, u32, Option>, u8)> { (a, b, c, d) } + + // Host functions for testing every marshaling strategy: + + fn pass_pointer_and_read_copy(value: PassPointerAndReadCopy<[u8; 3], 3>) { + assert_eq!(value, [1, 2, 3]); + } + + fn pass_pointer_and_read(value: PassPointerAndRead<&[u8; 3], 3>) { + assert_eq!(value, &[1, 2, 3]); + } + + fn pass_fat_pointer_and_read(value: PassFatPointerAndRead<&[u8]>) { + assert_eq!(value, [1, 2, 3]); + } + + fn pass_fat_pointer_and_read_write(value: PassFatPointerAndReadWrite<&mut [u8]>) { + assert_eq!(value, [1, 2, 3]); + value.copy_from_slice(&[4, 5, 6]); + } + + fn pass_pointer_and_write(value: PassPointerAndWrite<&mut [u8; 3], 3>) { + assert_eq!(*value, [0, 0, 0]); + *value = [1, 2, 3]; + } + + fn pass_by_codec(value: PassFatPointerAndDecode>) { + assert_eq!(value, [1, 2, 3]); + } + + fn pass_slice_ref_by_codec(value: PassFatPointerAndDecodeSlice<&[u16]>) { + assert_eq!(value, [1, 2, 3]); + } + + fn pass_as(value: PassAs) { + assert_eq!(value.0, 123); + } + + fn return_as() -> ReturnAs { + Opaque(123) + } + + fn allocate_and_return_pointer() -> AllocateAndReturnPointer<[u8; 3], 3> { + [1, 2, 3] + } + + fn allocate_and_return_fat_pointer() -> AllocateAndReturnFatPointer> { + vec![1, 2, 3] + } + + fn allocate_and_return_by_codec() -> AllocateAndReturnByCodec> { + vec![1, 2, 3] + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Opaque(u32); + +impl From for u32 { + fn from(value: Opaque) -> Self { + value.0 + } +} + +impl TryFrom for Opaque { + type Error = (); + fn try_from(value: u32) -> Result { + Ok(Opaque(value)) + } } /// This function is not used, but we require it for the compiler to include `sp-io`. @@ -251,16 +327,6 @@ wasm_export_functions! { assert!(test_api::overwrite_native_function_implementation()); } - fn test_u128_i128_as_parameter_and_return_value() { - for val in &[u128::MAX, 1u128, 5000u128, u64::MAX as u128] { - assert_eq!(*val, test_api::get_and_return_u128(*val)); - } - - for val in &[i128::MAX, i128::MIN, 1i128, 5000i128, u64::MAX as i128] { - assert_eq!(*val, test_api::get_and_return_i128(*val)); - } - } - fn test_vec_return_value_memory_is_freed() { let mut len = 0; for _ in 0..1024 { @@ -323,4 +389,27 @@ wasm_export_functions! { fn test_return_option_bytes() { test_api::return_option_bytes(); } + + fn test_marshalling_strategies() { + test_api::pass_pointer_and_read_copy([1_u8, 2, 3]); + test_api::pass_pointer_and_read(&[1_u8, 2, 3]); + test_api::pass_fat_pointer_and_read(&[1_u8, 2, 3][..]); + { + let mut slice = [1_u8, 2, 3]; + test_api::pass_fat_pointer_and_read_write(&mut slice); + assert_eq!(slice, [4_u8, 5, 6]); + } + { + let mut slice = [9_u8, 9, 9]; + test_api::pass_pointer_and_write(&mut slice); + assert_eq!(slice, [1_u8, 2, 3]); + } + test_api::pass_by_codec(vec![1_u16, 2, 3]); + test_api::pass_slice_ref_by_codec(&[1_u16, 2, 3][..]); + test_api::pass_as(Opaque(123)); + assert_eq!(test_api::return_as(), Opaque(123)); + assert_eq!(test_api::allocate_and_return_pointer(), [1_u8, 2, 3]); + assert_eq!(test_api::allocate_and_return_fat_pointer(), vec![1_u8, 2, 3]); + assert_eq!(test_api::allocate_and_return_by_codec(), vec![1_u16, 2, 3]); + } } diff --git a/substrate/primitives/runtime-interface/test/src/lib.rs b/substrate/primitives/runtime-interface/test/src/lib.rs index 05a955fbe3f86..cccc7f4af67d6 100644 --- a/substrate/primitives/runtime-interface/test/src/lib.rs +++ b/substrate/primitives/runtime-interface/test/src/lib.rs @@ -114,12 +114,13 @@ fn host_function_not_found() { } #[test] -#[should_panic(expected = "Invalid utf8 data provided")] fn test_invalid_utf8_data_should_return_an_error() { - call_wasm_method::( + call_wasm_method_with_result::( wasm_binary_unwrap(), "test_invalid_utf8_data_should_return_an_error", - ); + ) + .0 + .unwrap_err(); } #[test] @@ -130,14 +131,6 @@ fn test_overwrite_native_function_implementation() { ); } -#[test] -fn test_u128_i128_as_parameter_and_return_value() { - call_wasm_method::( - wasm_binary_unwrap(), - "test_u128_i128_as_parameter_and_return_value", - ); -} - #[test] fn test_vec_return_value_memory_is_freed() { call_wasm_method::( @@ -302,3 +295,8 @@ fn test_returning_option_bytes_from_a_host_function_is_efficient() { // deserializing `Option>`. assert_eq!(stats_bytes.bytes_allocated_sum + 16 * 1024 + 8, stats_vec.bytes_allocated_sum); } + +#[test] +fn test_marshalling_strategies() { + call_wasm_method::(wasm_binary_unwrap(), "test_marshalling_strategies"); +} diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.rs b/substrate/primitives/runtime-interface/tests/ui/improperly_wrapped_ri_type.rs similarity index 78% rename from substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.rs rename to substrate/primitives/runtime-interface/tests/ui/improperly_wrapped_ri_type.rs index b6faa46605bf7..f0910e4d5fa10 100644 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.rs +++ b/substrate/primitives/runtime-interface/tests/ui/improperly_wrapped_ri_type.rs @@ -15,11 +15,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use sp_runtime_interface::pass_by::PassByEnum; +mod test { + #![allow(unexpected_cfgs)] -#[derive(PassByEnum)] -enum Test { - Var0(u32), + use sp_runtime_interface::runtime_interface; + + #[runtime_interface] + trait Test { + fn test(&self, a: Option) -> Option {} + } } fn main() {} diff --git a/substrate/primitives/runtime-interface/tests/ui/improperly_wrapped_ri_type.stderr b/substrate/primitives/runtime-interface/tests/ui/improperly_wrapped_ri_type.stderr new file mode 100644 index 0000000000000..d13fdb3ba2338 --- /dev/null +++ b/substrate/primitives/runtime-interface/tests/ui/improperly_wrapped_ri_type.stderr @@ -0,0 +1,188 @@ +error[E0277]: the trait bound `Option: RIType` is not satisfied + --> tests/ui/improperly_wrapped_ri_type.rs:23:2 + | +23 | #[runtime_interface] + | ^^^^^^^^^^^^^^^^^^^^ the trait `RIType` is not implemented for `Option` + | + = help: the following other types implement trait `RIType`: + AllocateAndReturnByCodec + AllocateAndReturnFatPointer + AllocateAndReturnPointer + PassAs + PassFatPointerAndDecode + PassFatPointerAndDecodeSlice + PassFatPointerAndRead + PassFatPointerAndReadWrite + and $N others + = note: this error originates in the attribute macro `runtime_interface` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Option: RIType` is not satisfied + --> tests/ui/improperly_wrapped_ri_type.rs:23:2 + | +23 | #[runtime_interface] + | ^^^^^^^^^^^^^^^^^^^^ the trait `RIType` is not implemented for `Option` + | + = help: the following other types implement trait `RIType`: + AllocateAndReturnByCodec + AllocateAndReturnFatPointer + AllocateAndReturnPointer + PassAs + PassFatPointerAndDecode + PassFatPointerAndDecodeSlice + PassFatPointerAndRead + PassFatPointerAndReadWrite + and $N others + +error[E0277]: the trait bound `Option: RIType` is not satisfied + --> tests/ui/improperly_wrapped_ri_type.rs:25:9 + | +25 | fn test(&self, a: Option) -> Option {} + | ^^ the trait `RIType` is not implemented for `Option` + | + = help: the following other types implement trait `RIType`: + AllocateAndReturnByCodec + AllocateAndReturnFatPointer + AllocateAndReturnPointer + PassAs + PassFatPointerAndDecode + PassFatPointerAndDecodeSlice + PassFatPointerAndRead + PassFatPointerAndReadWrite + and $N others + +error[E0277]: the trait bound `Option: RIType` is not satisfied + --> tests/ui/improperly_wrapped_ri_type.rs:25:24 + | +25 | fn test(&self, a: Option) -> Option {} + | ^ the trait `RIType` is not implemented for `Option` + | + = help: the following other types implement trait `RIType`: + AllocateAndReturnByCodec + AllocateAndReturnFatPointer + AllocateAndReturnPointer + PassAs + PassFatPointerAndDecode + PassFatPointerAndDecodeSlice + PassFatPointerAndRead + PassFatPointerAndReadWrite + and $N others + +error[E0277]: the trait bound `Option: RIType` is not satisfied + --> tests/ui/improperly_wrapped_ri_type.rs:25:53 + | +25 | fn test(&self, a: Option) -> Option {} + | ^^ the trait `RIType` is not implemented for `Option` + | + = help: the following other types implement trait `RIType`: + AllocateAndReturnByCodec + AllocateAndReturnFatPointer + AllocateAndReturnPointer + PassAs + PassFatPointerAndDecode + PassFatPointerAndDecodeSlice + PassFatPointerAndRead + PassFatPointerAndReadWrite + and $N others + +error[E0277]: the trait bound `Option: FromFFIValue<'_>` is not satisfied + --> tests/ui/improperly_wrapped_ri_type.rs:25:27 + | +25 | fn test(&self, a: Option) -> Option {} + | ^^^^^^^^^^ the trait `FromFFIValue<'_>` is not implemented for `Option` + | + = help: the following other types implement trait `FromFFIValue<'a>`: + PassAs + PassFatPointerAndDecode + PassFatPointerAndDecodeSlice<&'a [T]> + PassFatPointerAndRead<&'a [u8]> + PassFatPointerAndRead<&'a str> + PassFatPointerAndRead> + PassFatPointerAndReadWrite<&'a mut [u8]> + PassPointerAndRead<&'a T, N> + and $N others + +error[E0277]: the trait bound `Option: IntoFFIValue` is not satisfied + --> tests/ui/improperly_wrapped_ri_type.rs:25:42 + | +25 | fn test(&self, a: Option) -> Option {} + | ^^^^^^^^^^ the trait `IntoFFIValue` is not implemented for `Option` + | + = help: the following other types implement trait `IntoFFIValue`: + AllocateAndReturnByCodec + AllocateAndReturnFatPointer + AllocateAndReturnPointer + ReturnAs + bool + i16 + i32 + i64 + and $N others + +error[E0277]: the trait bound `Option: FromFFIValue<'_>` is not satisfied + --> tests/ui/improperly_wrapped_ri_type.rs:25:24 + | +25 | fn test(&self, a: Option) -> Option {} + | ^ the trait `FromFFIValue<'_>` is not implemented for `Option` + | + = help: the following other types implement trait `FromFFIValue<'a>`: + PassAs + PassFatPointerAndDecode + PassFatPointerAndDecodeSlice<&'a [T]> + PassFatPointerAndRead<&'a [u8]> + PassFatPointerAndRead<&'a str> + PassFatPointerAndRead> + PassFatPointerAndReadWrite<&'a mut [u8]> + PassPointerAndRead<&'a T, N> + and $N others + +error[E0277]: the trait bound `Option: FromFFIValue<'_>` is not satisfied + --> tests/ui/improperly_wrapped_ri_type.rs:23:2 + | +23 | #[runtime_interface] + | ^^^^^^^^^^^^^^^^^^^^ the trait `FromFFIValue<'_>` is not implemented for `Option` + | + = help: the following other types implement trait `FromFFIValue<'a>`: + PassAs + PassFatPointerAndDecode + PassFatPointerAndDecodeSlice<&'a [T]> + PassFatPointerAndRead<&'a [u8]> + PassFatPointerAndRead<&'a str> + PassFatPointerAndRead> + PassFatPointerAndReadWrite<&'a mut [u8]> + PassPointerAndRead<&'a T, N> + and $N others + = note: this error originates in the attribute macro `runtime_interface` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Option: RIType` is not satisfied + --> tests/ui/improperly_wrapped_ri_type.rs:25:27 + | +25 | fn test(&self, a: Option) -> Option {} + | ^^^^^^^^^^ the trait `RIType` is not implemented for `Option` + | + = help: the following other types implement trait `RIType`: + AllocateAndReturnByCodec + AllocateAndReturnFatPointer + AllocateAndReturnPointer + PassAs + PassFatPointerAndDecode + PassFatPointerAndDecodeSlice + PassFatPointerAndRead + PassFatPointerAndReadWrite + and $N others + +error[E0277]: the trait bound `Option: RIType` is not satisfied + --> tests/ui/improperly_wrapped_ri_type.rs:25:42 + | +25 | fn test(&self, a: Option) -> Option {} + | ^^^^^^^^^^ the trait `RIType` is not implemented for `Option` + | + = help: the following other types implement trait `RIType`: + AllocateAndReturnByCodec + AllocateAndReturnFatPointer + AllocateAndReturnPointer + PassAs + PassFatPointerAndDecode + PassFatPointerAndDecodeSlice + PassFatPointerAndRead + PassFatPointerAndReadWrite + and $N others diff --git a/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.rs b/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.rs index 836c5866459fa..46152fa55ffd3 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.rs +++ b/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.rs @@ -15,6 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Due to https://github.com/dtolnay/trybuild/issues/302, the `substrate_runtime` +// cfg is also unexpected. This is a `trybuild` bug, and this part of error is not +// exposed to a real developer. + use sp_runtime_interface::runtime_interface; #[runtime_interface] diff --git a/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr b/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr index 35be091749e6b..32d2085e64d71 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr @@ -1,46 +1,100 @@ error[E0425]: cannot find function `bar` in module `test` - --> tests/ui/no_feature_gated_method.rs:33:8 + --> tests/ui/no_feature_gated_method.rs:37:8 | -33 | test::bar(); +37 | test::bar(); | ^^^ not found in `test` | note: found an item that was configured out - --> tests/ui/no_feature_gated_method.rs:25:5 + --> tests/ui/no_feature_gated_method.rs:29:5 | -25 | fn bar() {} +29 | fn bar() {} | ^^^ note: the item is gated behind the `bar-feature` feature - --> tests/ui/no_feature_gated_method.rs:24:8 + --> tests/ui/no_feature_gated_method.rs:28:8 | -24 | #[cfg(feature = "bar-feature")] +28 | #[cfg(feature = "bar-feature")] | ^^^^^^^^^^^^^^^^^^^^^^^ note: found an item that was configured out - --> tests/ui/no_feature_gated_method.rs:25:5 + --> tests/ui/no_feature_gated_method.rs:29:5 | -25 | fn bar() {} +29 | fn bar() {} | ^^^ note: the item is gated here - --> tests/ui/no_feature_gated_method.rs:20:1 + --> tests/ui/no_feature_gated_method.rs:24:1 | -20 | #[runtime_interface] +24 | #[runtime_interface] | ^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the attribute macro `runtime_interface` (in Nightly builds, run with -Z macro-backtrace for more info) +warning: unexpected `cfg` condition name: `substrate_runtime` + --> tests/ui/no_feature_gated_method.rs:28:2 + | +28 | #[cfg(feature = "bar-feature")] + | ^ + | + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `docsrs`, `doctest`, `feature`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` + = help: consider using a Cargo feature instead + = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: + [lints.rust] + unexpected_cfgs = { level = "warn", check-cfg = ['cfg(substrate_runtime)'] } + = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(substrate_runtime)");` to the top of the `build.rs` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + warning: unexpected `cfg` condition value: `bar-feature` - --> tests/ui/no_feature_gated_method.rs:24:8 + --> tests/ui/no_feature_gated_method.rs:28:8 | -24 | #[cfg(feature = "bar-feature")] +28 | #[cfg(feature = "bar-feature")] | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: expected values for `feature` are: `default`, `disable_target_static_assertions`, and `std` = help: consider adding `bar-feature` as a feature in `Cargo.toml` = note: see for more information about checking conditional configuration - = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `substrate_runtime` + --> tests/ui/no_feature_gated_method.rs:24:1 + | +24 | #[runtime_interface] + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a Cargo feature instead + = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: + [lints.rust] + unexpected_cfgs = { level = "warn", check-cfg = ['cfg(substrate_runtime)'] } + = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(substrate_runtime)");` to the top of the `build.rs` + = note: see for more information about checking conditional configuration + = note: this warning originates in the attribute macro `runtime_interface` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: unexpected `cfg` condition name: `substrate_runtime` + --> tests/ui/no_feature_gated_method.rs:26:2 + | +26 | fn foo() {} + | ^^ + | + = help: consider using a Cargo feature instead + = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: + [lints.rust] + unexpected_cfgs = { level = "warn", check-cfg = ['cfg(substrate_runtime)'] } + = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(substrate_runtime)");` to the top of the `build.rs` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `substrate_runtime` + --> tests/ui/no_feature_gated_method.rs:31:2 + | +31 | #[cfg(not(feature = "bar-feature"))] + | ^ + | + = help: consider using a Cargo feature instead + = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: + [lints.rust] + unexpected_cfgs = { level = "warn", check-cfg = ['cfg(substrate_runtime)'] } + = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(substrate_runtime)");` to the top of the `build.rs` + = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `bar-feature` - --> tests/ui/no_feature_gated_method.rs:27:12 + --> tests/ui/no_feature_gated_method.rs:31:12 | -27 | #[cfg(not(feature = "bar-feature"))] +31 | #[cfg(not(feature = "bar-feature"))] | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: expected values for `feature` are: `default`, `disable_target_static_assertions`, and `std` diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.rs b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.rs deleted file mode 100644 index dcc8fb0930bdf..0000000000000 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.rs +++ /dev/null @@ -1,23 +0,0 @@ -// This file is part of Substrate. - -// 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. - -use sp_runtime_interface::pass_by::PassByEnum; - -#[derive(PassByEnum)] -struct Test; - -fn main() {} diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr deleted file mode 100644 index c5b69d426abf4..0000000000000 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: `PassByEnum` only supports enums as input type. - --> tests/ui/pass_by_enum_with_struct.rs:20:10 - | -20 | #[derive(PassByEnum)] - | ^^^^^^^^^^ - | - = note: this error originates in the derive macro `PassByEnum` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr deleted file mode 100644 index ad94efed3c659..0000000000000 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: `PassByEnum` only supports unit variants. - --> tests/ui/pass_by_enum_with_value_variant.rs:20:10 - | -20 | #[derive(PassByEnum)] - | ^^^^^^^^^^ - | - = note: this error originates in the derive macro `PassByEnum` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.rs b/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.rs deleted file mode 100644 index 2b7e98165ba53..0000000000000 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.rs +++ /dev/null @@ -1,26 +0,0 @@ -// This file is part of Substrate. - -// 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. - -use sp_runtime_interface::pass_by::PassByInner; - -#[derive(PassByInner)] -struct Test { - data: u32, - data2: u32, -} - -fn main() {} diff --git a/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr b/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr deleted file mode 100644 index 3ca1362fb424c..0000000000000 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: Only newtype/one field structs are supported by `PassByInner`! - --> tests/ui/pass_by_inner_with_two_fields.rs:20:10 - | -20 | #[derive(PassByInner)] - | ^^^^^^^^^^^ - | - = note: this error originates in the derive macro `PassByInner` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/primitives/state-machine/src/basic.rs b/substrate/primitives/state-machine/src/basic.rs index 6201d60ababd2..7edf9b6f96823 100644 --- a/substrate/primitives/state-machine/src/basic.rs +++ b/substrate/primitives/state-machine/src/basic.rs @@ -18,7 +18,12 @@ //! Basic implementation for Externalities. use crate::{Backend, OverlayedChanges, StorageKey, StorageValue}; +use alloc::{boxed::Box, collections::BTreeMap, vec::Vec}; use codec::Encode; +use core::{ + any::{Any, TypeId}, + iter::FromIterator, +}; use hash_db::Hasher; use log::warn; use sp_core::{ @@ -30,10 +35,6 @@ use sp_core::{ }; use sp_externalities::{Extension, Extensions, MultiRemovalResults}; use sp_trie::{empty_child_trie_root, LayoutV0, LayoutV1, TrieConfiguration}; -use std::{ - any::{Any, TypeId}, - collections::BTreeMap, -}; /// Simple Map-based Externalities impl. #[derive(Debug)] @@ -93,7 +94,7 @@ impl BasicExternalities { storage: &mut sp_core::storage::Storage, f: impl FnOnce() -> R, ) -> R { - let mut ext = Self::new(std::mem::take(storage)); + let mut ext = Self::new(core::mem::take(storage)); let r = ext.execute_with(f); diff --git a/substrate/primitives/state-machine/src/in_memory_backend.rs b/substrate/primitives/state-machine/src/in_memory_backend.rs index 7ba7457a6bf18..e2af837faded6 100644 --- a/substrate/primitives/state-machine/src/in_memory_backend.rs +++ b/substrate/primitives/state-machine/src/in_memory_backend.rs @@ -21,11 +21,17 @@ use crate::{ backend::Backend, trie_backend::TrieBackend, StorageCollection, StorageKey, StorageValue, TrieBackendBuilder, }; +use alloc::{collections::BTreeMap, vec::Vec}; use codec::Codec; use hash_db::Hasher; use sp_core::storage::{ChildInfo, StateVersion, Storage}; use sp_trie::{empty_trie_root, LayoutV1, PrefixedMemoryDB}; -use std::collections::{BTreeMap, HashMap}; + +#[cfg(feature = "std")] +use std::collections::HashMap as MapType; + +#[cfg(not(feature = "std"))] +use alloc::collections::BTreeMap as MapType; /// Create a new empty instance of in-memory backend. pub fn new_in_mem() -> TrieBackend, H> @@ -110,14 +116,14 @@ where } } -impl From<(HashMap, BTreeMap>, StateVersion)> +impl From<(MapType, BTreeMap>, StateVersion)> for TrieBackend, H> where H::Out: Codec + Ord, { fn from( (inner, state_version): ( - HashMap, BTreeMap>, + MapType, BTreeMap>, StateVersion, ), ) -> Self { @@ -138,7 +144,7 @@ where H::Out: Codec + Ord, { fn from((inners, state_version): (Storage, StateVersion)) -> Self { - let mut inner: HashMap, BTreeMap> = inners + let mut inner: MapType, BTreeMap> = inners .children_default .into_values() .map(|c| (Some(c.child_info), c.data)) @@ -154,7 +160,7 @@ where H::Out: Codec + Ord, { fn from((inner, state_version): (BTreeMap, StateVersion)) -> Self { - let mut expanded = HashMap::new(); + let mut expanded = MapType::new(); expanded.insert(None, inner); (expanded, state_version).into() } @@ -168,8 +174,8 @@ where fn from( (inner, state_version): (Vec<(Option, StorageCollection)>, StateVersion), ) -> Self { - let mut expanded: HashMap, BTreeMap> = - HashMap::new(); + let mut expanded: MapType, BTreeMap> = + MapType::new(); for (child_info, key_values) in inner { let entry = expanded.entry(child_info).or_default(); for (key, value) in key_values { diff --git a/substrate/primitives/state-machine/src/lib.rs b/substrate/primitives/state-machine/src/lib.rs index 289b08755f680..d31348c330ac3 100644 --- a/substrate/primitives/state-machine/src/lib.rs +++ b/substrate/primitives/state-machine/src/lib.rs @@ -23,16 +23,16 @@ extern crate alloc; pub mod backend; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] mod basic; mod error; mod ext; #[cfg(feature = "fuzzing")] pub mod fuzzing; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] mod in_memory_backend; pub(crate) mod overlayed_changes; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] mod read_only; mod stats; #[cfg(feature = "std")] @@ -142,15 +142,16 @@ pub use crate::{ trie_backend_essence::{Storage, TrieBackendStorage}, }; +#[cfg(not(substrate_runtime))] +pub use crate::{ + basic::BasicExternalities, + in_memory_backend::new_in_mem, + read_only::{InspectState, ReadOnlyExternalities}, +}; + #[cfg(feature = "std")] mod std_reexport { - pub use crate::{ - basic::BasicExternalities, - in_memory_backend::new_in_mem, - read_only::{InspectState, ReadOnlyExternalities}, - testing::TestExternalities, - trie_backend::create_proof_check_backend, - }; + pub use crate::{testing::TestExternalities, trie_backend::create_proof_check_backend}; pub use sp_trie::{ trie_types::{TrieDBMutV0, TrieDBMutV1}, CompactProof, DBValue, LayoutV0, LayoutV1, MemoryDB, StorageProof, TrieMut, diff --git a/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs b/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs index c478983e979af..2febb76b3700e 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs @@ -210,7 +210,7 @@ impl Default for OverlayedMap { } } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] impl From for OverlayedMap { fn from(storage: sp_core::storage::StorageMap) -> Self { Self { diff --git a/substrate/primitives/state-machine/src/overlayed_changes/mod.rs b/substrate/primitives/state-machine/src/overlayed_changes/mod.rs index c2dc637bc71a7..a5f370eb88e11 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/mod.rs @@ -771,7 +771,7 @@ impl OverlayedChanges { } } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] impl From for OverlayedChanges { fn from(storage: sp_core::storage::Storage) -> Self { Self { diff --git a/substrate/primitives/state-machine/src/read_only.rs b/substrate/primitives/state-machine/src/read_only.rs index b78d17138b0ff..e5da2fde1fd55 100644 --- a/substrate/primitives/state-machine/src/read_only.rs +++ b/substrate/primitives/state-machine/src/read_only.rs @@ -18,17 +18,18 @@ //! Read-only version of Externalities. use crate::{Backend, StorageKey, StorageValue}; +use alloc::{boxed::Box, vec::Vec}; use codec::Encode; +use core::{ + any::{Any, TypeId}, + marker::PhantomData, +}; use hash_db::Hasher; use sp_core::{ storage::{ChildInfo, StateVersion, TrackedStorageKey}, traits::Externalities, }; use sp_externalities::MultiRemovalResults; -use std::{ - any::{Any, TypeId}, - marker::PhantomData, -}; /// Trait for inspecting state in any backend. /// diff --git a/substrate/primitives/statement-store/src/lib.rs b/substrate/primitives/statement-store/src/lib.rs index d765ddad3ed8c..a1d4a5e9d8d52 100644 --- a/substrate/primitives/statement-store/src/lib.rs +++ b/substrate/primitives/statement-store/src/lib.rs @@ -28,7 +28,6 @@ use scale_info::TypeInfo; use sp_application_crypto::RuntimeAppPublic; #[cfg(feature = "std")] use sp_core::Pair; -use sp_runtime_interface::pass_by::PassByCodec; /// Statement topic. pub type Topic = [u8; 32]; @@ -176,16 +175,7 @@ impl Field { } /// Statement structure. -#[derive( - DecodeWithMemTracking, - TypeInfo, - sp_core::RuntimeDebug, - PassByCodec, - Clone, - PartialEq, - Eq, - Default, -)] +#[derive(DecodeWithMemTracking, TypeInfo, sp_core::RuntimeDebug, Clone, PartialEq, Eq, Default)] pub struct Statement { proof: Option, decryption_key: Option, diff --git a/substrate/primitives/statement-store/src/runtime_api.rs b/substrate/primitives/statement-store/src/runtime_api.rs index 4d25576c801fa..a95885a362ad7 100644 --- a/substrate/primitives/statement-store/src/runtime_api.rs +++ b/substrate/primitives/statement-store/src/runtime_api.rs @@ -22,7 +22,13 @@ use alloc::vec::Vec; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; -use sp_runtime_interface::{pass_by::PassByEnum, runtime_interface}; +use sp_runtime_interface::{ + pass_by::{ + AllocateAndReturnByCodec, PassFatPointerAndDecode, PassFatPointerAndDecodeSlice, + PassPointerAndRead, PassPointerAndReadCopy, ReturnAs, + }, + runtime_interface, +}; #[cfg(feature = "std")] use sp_externalities::ExternalitiesExt; @@ -98,18 +104,38 @@ impl StatementStoreExt { } /// Submission result. -#[derive(Debug, Eq, PartialEq, Clone, Copy, Encode, Decode, PassByEnum)] +#[derive(Debug, Eq, PartialEq, Clone, Copy, Encode, Decode)] pub enum SubmitResult { /// Accepted as new. - OkNew, + OkNew = 0, /// Known statement - OkKnown, + OkKnown = 1, /// Statement failed validation. - Bad, + Bad = 2, /// The store is not available. - NotAvailable, + NotAvailable = 3, /// Statement could not be inserted because of priority or size checks. - Full, + Full = 4, +} + +impl TryFrom for SubmitResult { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(SubmitResult::OkNew), + 1 => Ok(SubmitResult::OkKnown), + 2 => Ok(SubmitResult::Bad), + 3 => Ok(SubmitResult::NotAvailable), + 4 => Ok(SubmitResult::Full), + _ => Err(()), + } + } +} + +impl From for u8 { + fn from(value: SubmitResult) -> Self { + value as u8 + } } /// Export functions for the WASM host. @@ -121,7 +147,10 @@ pub type HostFunctions = (statement_store::HostFunctions,); pub trait StatementStore { /// Submit a new new statement. The statement will be broadcast to the network. /// This is meant to be used by the offchain worker. - fn submit_statement(&mut self, statement: Statement) -> SubmitResult { + fn submit_statement( + &mut self, + statement: PassFatPointerAndDecode, + ) -> ReturnAs { if let Some(StatementStoreExt(store)) = self.extension::() { match store.submit(statement, StatementSource::Chain) { crate::SubmitResult::New(_) => SubmitResult::OkNew, @@ -139,7 +168,7 @@ pub trait StatementStore { } /// Return all statements. - fn statements(&mut self) -> Vec<(Hash, Statement)> { + fn statements(&mut self) -> AllocateAndReturnByCodec> { if let Some(StatementStoreExt(store)) = self.extension::() { store.statements().unwrap_or_default() } else { @@ -149,7 +178,10 @@ pub trait StatementStore { /// Return the data of all known statements which include all topics and have no `DecryptionKey` /// field. - fn broadcasts(&mut self, match_all_topics: &[Topic]) -> Vec> { + fn broadcasts( + &mut self, + match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>, + ) -> AllocateAndReturnByCodec>> { if let Some(StatementStoreExt(store)) = self.extension::() { store.broadcasts(match_all_topics).unwrap_or_default() } else { @@ -160,7 +192,11 @@ pub trait StatementStore { /// Return the data of all known statements whose decryption key is identified as `dest` (this /// will generally be the public key or a hash thereof for symmetric ciphers, or a hash of the /// private key for symmetric ciphers). - fn posted(&mut self, match_all_topics: &[Topic], dest: [u8; 32]) -> Vec> { + fn posted( + &mut self, + match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>, + dest: PassPointerAndReadCopy<[u8; 32], 32>, + ) -> AllocateAndReturnByCodec>> { if let Some(StatementStoreExt(store)) = self.extension::() { store.posted(match_all_topics, dest).unwrap_or_default() } else { @@ -170,7 +206,11 @@ pub trait StatementStore { /// Return the decrypted data of all known statements whose decryption key is identified as /// `dest`. The key must be available to the client. - fn posted_clear(&mut self, match_all_topics: &[Topic], dest: [u8; 32]) -> Vec> { + fn posted_clear( + &mut self, + match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>, + dest: PassPointerAndReadCopy<[u8; 32], 32>, + ) -> AllocateAndReturnByCodec>> { if let Some(StatementStoreExt(store)) = self.extension::() { store.posted_clear(match_all_topics, dest).unwrap_or_default() } else { @@ -179,7 +219,7 @@ pub trait StatementStore { } /// Remove a statement from the store by hash. - fn remove(&mut self, hash: &Hash) { + fn remove(&mut self, hash: PassPointerAndRead<&Hash, 32>) { if let Some(StatementStoreExt(store)) = self.extension::() { store.remove(hash).unwrap_or_default() } diff --git a/substrate/primitives/storage/src/lib.rs b/substrate/primitives/storage/src/lib.rs index df7570a185481..3a50ca1fe6183 100644 --- a/substrate/primitives/storage/src/lib.rs +++ b/substrate/primitives/storage/src/lib.rs @@ -34,11 +34,8 @@ use core::{ use ref_cast::RefCast; /// Storage key. -#[derive(PartialEq, Eq, RuntimeDebug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize, Hash, PartialOrd, Ord, Clone, Encode, Decode) -)] +#[derive(PartialEq, Eq, RuntimeDebug, Hash, PartialOrd, Ord, Clone, Encode, Decode)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct StorageKey( #[cfg_attr(feature = "serde", serde(with = "impl_serde::serialize"))] pub Vec, ); @@ -98,8 +95,8 @@ impl From> for TrackedStorageKey { } /// Storage key of a child trie, it contains the prefix to the key. -#[derive(PartialEq, Eq, RuntimeDebug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, Hash, PartialOrd, Ord, Clone))] +#[derive(PartialEq, Eq, RuntimeDebug, Hash, PartialOrd, Ord, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(transparent)] #[derive(RefCast)] pub struct PrefixedStorageKey( @@ -139,22 +136,24 @@ impl PrefixedStorageKey { } /// Storage data associated to a [`StorageKey`]. -#[derive(PartialEq, Eq, RuntimeDebug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize, Hash, PartialOrd, Ord, Clone, Encode, Decode, Default) -)] +#[derive(PartialEq, Eq, RuntimeDebug, Hash, PartialOrd, Ord, Clone, Encode, Decode, Default)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct StorageData( #[cfg_attr(feature = "serde", serde(with = "impl_serde::serialize"))] pub Vec, ); /// Map of data to use in a storage, it is a collection of /// byte key and values. +pub type StorageMap = alloc::collections::BTreeMap, Vec>; + +/// Map of storage children. #[cfg(feature = "std")] -pub type StorageMap = std::collections::BTreeMap, Vec>; +pub type ChildrenMap = std::collections::HashMap, StorageChild>; + +#[cfg(not(feature = "std"))] +pub type ChildrenMap = alloc::collections::BTreeMap, StorageChild>; /// Child trie storage data. -#[cfg(feature = "std")] #[derive(Debug, PartialEq, Eq, Clone)] pub struct StorageChild { /// Child data for storage. @@ -165,19 +164,18 @@ pub struct StorageChild { } /// Struct containing data needed for a storage. -#[cfg(feature = "std")] #[derive(Default, Debug, Clone)] pub struct Storage { /// Top trie storage data. pub top: StorageMap, /// Children trie storage data. Key does not include prefix, only for the `default` trie kind, /// of `ChildType::ParentKeyId` type. - pub children_default: std::collections::HashMap, StorageChild>, + pub children_default: ChildrenMap, } /// Storage change set -#[derive(RuntimeDebug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, PartialEq, Eq, Clone))] +#[derive(RuntimeDebug, PartialEq, Eq, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct StorageChangeSet { /// Block hash @@ -249,8 +247,7 @@ pub mod well_known_keys { pub const TRIE_VALUE_NODE_THRESHOLD: u32 = 33; /// Information related to a child state. -#[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(PartialEq, Eq, Hash, PartialOrd, Ord, Encode, Decode))] +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Encode, Decode, Debug, Clone)] pub enum ChildInfo { /// This is the one used by default. ParentKeyId(ChildTrieParentKeyId), @@ -396,8 +393,7 @@ impl ChildType { /// It shares its trie nodes backend storage with every other child trie, so its storage key needs /// to be a unique id that will be use only once. Those unique id also required to be long enough to /// avoid any unique id to be prefixed by an other unique id. -#[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(PartialEq, Eq, Hash, PartialOrd, Ord, Encode, Decode))] +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Encode, Decode, Debug, Clone)] pub struct ChildTrieParentKeyId { /// Data is the storage key without prefix. data: Vec, diff --git a/substrate/primitives/tracing/src/lib.rs b/substrate/primitives/tracing/src/lib.rs index ed6feeebb692c..a39bf95ab3806 100644 --- a/substrate/primitives/tracing/src/lib.rs +++ b/substrate/primitives/tracing/src/lib.rs @@ -53,7 +53,7 @@ pub use crate::types::{ WasmEntryAttributes, WasmFieldName, WasmFields, WasmLevel, WasmMetadata, WasmValue, WasmValuesSet, }; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub use crate::types::{WASM_NAME_KEY, WASM_TARGET_KEY, WASM_TRACE_IDENTIFIER}; /// Tracing facilities and helpers. diff --git a/substrate/primitives/tracing/src/types.rs b/substrate/primitives/tracing/src/types.rs index 46f38383d9806..f1be2ac3445fa 100644 --- a/substrate/primitives/tracing/src/types.rs +++ b/substrate/primitives/tracing/src/types.rs @@ -437,7 +437,7 @@ impl core::default::Default for WasmEntryAttributes { } } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] mod std_features { use tracing_core::callsite; @@ -629,11 +629,11 @@ mod std_features { impl From for tracing::Span { fn from(a: crate::WasmEntryAttributes) -> tracing::Span { - let name = std::str::from_utf8(&a.metadata.name).unwrap_or_default(); - let target = std::str::from_utf8(&a.metadata.target).unwrap_or_default(); - let file = std::str::from_utf8(&a.metadata.file).unwrap_or_default(); + let name = core::str::from_utf8(&a.metadata.name).unwrap_or_default(); + let target = core::str::from_utf8(&a.metadata.target).unwrap_or_default(); + let file = core::str::from_utf8(&a.metadata.file).unwrap_or_default(); let line = a.metadata.line; - let module_path = std::str::from_utf8(&a.metadata.module_path).unwrap_or_default(); + let module_path = core::str::from_utf8(&a.metadata.module_path).unwrap_or_default(); let params = a.fields; let metadata: &tracing_core::metadata::Metadata<'static> = (&a.metadata).into(); @@ -648,11 +648,11 @@ mod std_features { impl crate::WasmEntryAttributes { /// convert the given Attributes to an event and emit it using `tracing_core`. pub fn emit(self: crate::WasmEntryAttributes) { - let name = std::str::from_utf8(&self.metadata.name).unwrap_or_default(); - let target = std::str::from_utf8(&self.metadata.target).unwrap_or_default(); - let file = std::str::from_utf8(&self.metadata.file).unwrap_or_default(); + let name = core::str::from_utf8(&self.metadata.name).unwrap_or_default(); + let target = core::str::from_utf8(&self.metadata.target).unwrap_or_default(); + let file = core::str::from_utf8(&self.metadata.file).unwrap_or_default(); let line = self.metadata.line; - let module_path = std::str::from_utf8(&self.metadata.module_path).unwrap_or_default(); + let module_path = core::str::from_utf8(&self.metadata.module_path).unwrap_or_default(); let params = self.fields; let metadata: &tracing_core::metadata::Metadata<'static> = (&self.metadata).into(); @@ -665,5 +665,5 @@ mod std_features { } } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub use std_features::*; diff --git a/substrate/primitives/wasm-interface/src/lib.rs b/substrate/primitives/wasm-interface/src/lib.rs index 4fc78ca15535b..f6948d8cb88e9 100644 --- a/substrate/primitives/wasm-interface/src/lib.rs +++ b/substrate/primitives/wasm-interface/src/lib.rs @@ -21,8 +21,8 @@ extern crate alloc; -use alloc::{borrow::Cow, vec, vec::Vec}; -use core::{iter::Iterator, marker::PhantomData, mem, result}; +use alloc::{borrow::Cow, string::String, vec, vec::Vec}; +use core::{iter::Iterator, marker::PhantomData, mem}; #[cfg(not(all(feature = "std", feature = "wasmtime")))] #[macro_export] @@ -47,10 +47,7 @@ if_wasmtime_is_enabled! { } /// Result type used by traits in this crate. -#[cfg(feature = "std")] -pub type Result = result::Result; -#[cfg(not(feature = "std"))] -pub type Result = result::Result; +pub type Result = core::result::Result; /// Value types supported by Substrate on the boundary between host/Wasm. #[derive(Copy, Clone, PartialEq, Debug, Eq)] @@ -155,12 +152,19 @@ impl PointerType for u32 {} impl PointerType for u64 {} /// Type to represent a pointer in wasm at the host. -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct Pointer { +#[derive(Debug, PartialEq, Eq)] +pub struct Pointer { ptr: u32, _marker: PhantomData, } +impl Copy for Pointer {} +impl Clone for Pointer { + fn clone(&self) -> Self { + Pointer { ptr: self.ptr, _marker: PhantomData } + } +} + impl Pointer { /// Create a new instance of `Self`. pub fn new(ptr: u32) -> Self {