From 20fab0585eb771752ad3112d44405e3749e1f8e7 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Thu, 14 Mar 2024 07:08:33 +0000 Subject: [PATCH 01/31] Refactor the host <-> runtime interface machinery --- Cargo.lock | 1 - prdoc/pr_0000.prdoc | 74 ++ substrate/client/executor/src/executor.rs | 4 +- substrate/primitives/core/src/bandersnatch.rs | 24 +- substrate/primitives/core/src/bls.rs | 27 +- substrate/primitives/core/src/crypto.rs | 15 +- substrate/primitives/core/src/ecdsa.rs | 28 +- substrate/primitives/core/src/ed25519.rs | 28 +- substrate/primitives/core/src/lib.rs | 58 +- substrate/primitives/core/src/offchain/mod.rs | 49 +- .../primitives/core/src/paired_crypto.rs | 29 +- substrate/primitives/core/src/sr25519.rs | 28 +- .../crypto/ec-utils/src/bls12_377.rs | 34 +- .../crypto/ec-utils/src/bls12_381.rs | 34 +- .../primitives/crypto/ec-utils/src/bw6_761.rs | 34 +- .../crypto/ec-utils/src/ed_on_bls12_377.rs | 15 +- .../src/ed_on_bls12_381_bandersnatch.rs | 29 +- substrate/primitives/io/src/lib.rs | 568 +++++++----- .../primitives/runtime-interface/Cargo.toml | 1 - .../runtime-interface/proc-macro/src/lib.rs | 25 +- .../proc-macro/src/pass_by/codec.rs | 59 -- .../proc-macro/src/pass_by/enum_.rs | 101 --- .../proc-macro/src/pass_by/inner.rs | 110 --- .../proc-macro/src/pass_by/mod.rs | 26 - .../bare_function_interface.rs | 45 +- .../host_function_interface.rs | 92 +- .../src/runtime_interface/trait_decl_impl.rs | 8 +- .../runtime-interface/proc-macro/src/utils.rs | 62 +- .../primitives/runtime-interface/src/host.rs | 66 +- .../primitives/runtime-interface/src/impls.rs | 476 ++-------- .../primitives/runtime-interface/src/lib.rs | 163 ++-- .../runtime-interface/src/pass_by.rs | 855 +++++++++++------- .../primitives/runtime-interface/src/wasm.rs | 55 +- .../runtime-interface/test-wasm/src/lib.rs | 158 +++- .../runtime-interface/test/src/lib.rs | 20 +- .../tests/ui/pass_by_enum_with_struct.rs | 23 - .../tests/ui/pass_by_enum_with_struct.stderr | 7 - .../ui/pass_by_enum_with_value_variant.rs | 25 - .../ui/pass_by_enum_with_value_variant.stderr | 7 - .../tests/ui/pass_by_inner_with_two_fields.rs | 26 - .../ui/pass_by_inner_with_two_fields.stderr | 7 - .../primitives/statement-store/src/lib.rs | 3 +- .../statement-store/src/runtime_api.rs | 66 +- .../primitives/wasm-interface/src/lib.rs | 11 +- 44 files changed, 1748 insertions(+), 1828 deletions(-) create mode 100644 prdoc/pr_0000.prdoc delete mode 100644 substrate/primitives/runtime-interface/proc-macro/src/pass_by/codec.rs delete mode 100644 substrate/primitives/runtime-interface/proc-macro/src/pass_by/enum_.rs delete mode 100644 substrate/primitives/runtime-interface/proc-macro/src/pass_by/inner.rs delete mode 100644 substrate/primitives/runtime-interface/proc-macro/src/pass_by/mod.rs delete mode 100644 substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.rs delete mode 100644 substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_struct.stderr delete mode 100644 substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.rs delete mode 100644 substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.stderr delete mode 100644 substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.rs delete mode 100644 substrate/primitives/runtime-interface/tests/ui/pass_by_inner_with_two_fields.stderr diff --git a/Cargo.lock b/Cargo.lock index 8cbbbce209a98..4e06a4bd01a9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19058,7 +19058,6 @@ dependencies = [ "sp-storage 19.0.0", "sp-tracing 16.0.0", "sp-wasm-interface 20.0.0", - "static_assertions", "trybuild", ] diff --git a/prdoc/pr_0000.prdoc b/prdoc/pr_0000.prdoc new file mode 100644 index 0000000000000..ddc0938278526 --- /dev/null +++ b/prdoc/pr_0000.prdoc @@ -0,0 +1,74 @@ +# 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: Runtime Dev + - 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. +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: minor + note: The `Pointer` type now implements `Copy` and `Clone` unconditionally. + - 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 + bump: minor + note: Requires the new `#[runtime_interface]` macro and associated machinery. diff --git a/substrate/client/executor/src/executor.rs b/substrate/client/executor/src/executor.rs index d56a3b389ef42..5ee3b54850956 100644 --- a/substrate/client/executor/src/executor.rs +++ b/substrate/client/executor/src/executor.rs @@ -741,11 +741,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/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index 5cae6047f164e..072ea537be38b 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -37,7 +37,6 @@ use bandersnatch_vrfs::{CanonicalSerialize, SecretKey}; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_runtime_interface::pass_by::PassByInner; use sp_std::{vec, vec::Vec}; /// Identifier used to match public keys against bandersnatch-vrf keys. @@ -54,21 +53,16 @@ const PREOUT_SERIALIZED_SIZE: usize = 33; /// Bandersnatch public key. #[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Encode, - Decode, - PassByInner, - MaxEncodedLen, - TypeInfo, - Hash, + Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, MaxEncodedLen, TypeInfo, Hash, )] pub struct Public(pub [u8; PUBLIC_SERIALIZED_SIZE]); +impl From<[u8; PUBLIC_SERIALIZED_SIZE]> for Public { + fn from(raw: [u8; PUBLIC_SERIALIZED_SIZE]) -> Self { + Public(raw) + } +} + impl UncheckedFrom<[u8; PUBLIC_SERIALIZED_SIZE]> for Public { fn unchecked_from(raw: [u8; PUBLIC_SERIALIZED_SIZE]) -> Self { Public(raw) @@ -150,9 +144,7 @@ impl<'de> Deserialize<'de> for Public { /// /// The signature is created via the [`VrfSecret::vrf_sign`] using [`SIGNING_CTX`] as transcript /// `label`. -#[derive( - Clone, Copy, PartialEq, Eq, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo, Hash, -)] +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo, Hash)] pub struct Signature([u8; SIGNATURE_SERIALIZED_SIZE]); impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 2256e4cd823dc..bf6b1cc013c42 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -45,7 +45,6 @@ use w3f_bls::{ SecretKey, SerializableToBytes, TinyBLS381, }; -use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; /// BLS-377 specialized types @@ -157,26 +156,6 @@ impl ByteArray for Public { const LEN: usize = PUBLIC_KEY_SERIALIZED_SIZE; } -impl PassByInner for Public { - type Inner = [u8; PUBLIC_KEY_SERIALIZED_SIZE]; - - fn into_inner(self) -> Self::Inner { - self.inner - } - - fn inner(&self) -> &Self::Inner { - &self.inner - } - - fn from_inner(inner: Self::Inner) -> Self { - Self { inner, _phantom: PhantomData } - } -} - -impl PassBy for Public { - type PassBy = pass_by::Inner; -} - impl AsRef<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { fn as_ref(&self) -> &[u8; PUBLIC_KEY_SERIALIZED_SIZE] { &self.inner @@ -228,6 +207,12 @@ impl From> for Public { } } +impl From<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { + fn from(data: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { + Public { inner: data, _phantom: PhantomData } + } +} + impl UncheckedFrom<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { fn unchecked_from(data: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { Public { inner: data, _phantom: PhantomData } diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index fab865d8c1f42..d125ca5938e21 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -26,7 +26,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; #[doc(hidden)] pub use sp_std::ops::Deref; #[cfg(all(not(feature = "std"), feature = "serde"))] @@ -1058,11 +1057,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 { @@ -1077,6 +1076,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 = (); diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index fa071e1b03ff8..92c4b04a58796 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -19,7 +19,6 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_runtime_interface::pass_by::PassByInner; #[cfg(feature = "serde")] use crate::crypto::Ss58Codec; @@ -58,18 +57,7 @@ type Seed = [u8; 32]; /// The ECDSA compressed public key. #[derive( - Clone, - Copy, - Encode, - Decode, - PassByInner, - MaxEncodedLen, - TypeInfo, - Eq, - PartialEq, - PartialOrd, - Ord, - Hash, + Clone, Copy, Encode, Decode, MaxEncodedLen, TypeInfo, Eq, PartialEq, PartialOrd, Ord, Hash, )] pub struct Public(pub [u8; PUBLIC_KEY_SERIALIZED_SIZE]); @@ -169,6 +157,12 @@ impl From for Public { } } +impl From<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { + fn from(value: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { + Self(value) + } +} + impl UncheckedFrom<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { fn unchecked_from(x: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { Public(x) @@ -217,7 +211,7 @@ impl<'de> Deserialize<'de> for Public { } /// A signature (a 512-bit value, plus 8 bits for recovery ID). -#[derive(Hash, Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] +#[derive(Hash, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; SIGNATURE_SERIALIZED_SIZE]); impl ByteArray for Signature { @@ -238,6 +232,12 @@ impl TryFrom<&[u8]> for Signature { } } +impl From<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { + fn from(value: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Self { + Self(value) + } +} + #[cfg(feature = "serde")] impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result diff --git a/substrate/primitives/core/src/ed25519.rs b/substrate/primitives/core/src/ed25519.rs index 9f42b36dc8bd5..f693be8d8a627 100644 --- a/substrate/primitives/core/src/ed25519.rs +++ b/substrate/primitives/core/src/ed25519.rs @@ -39,7 +39,6 @@ use core::convert::TryFrom; use ed25519_zebra::{SigningKey, VerificationKey}; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -use sp_runtime_interface::pass_by::PassByInner; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; use sp_std::ops::Deref; @@ -54,18 +53,7 @@ type Seed = [u8; 32]; /// A public key. #[derive( - PartialEq, - Eq, - PartialOrd, - Ord, - Clone, - Copy, - Encode, - Decode, - PassByInner, - MaxEncodedLen, - TypeInfo, - Hash, + PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, MaxEncodedLen, TypeInfo, Hash, )] pub struct Public(pub [u8; 32]); @@ -123,6 +111,12 @@ impl TryFrom<&[u8]> for Public { } } +impl From<[u8; 32]> for Public { + fn from(value: [u8; 32]) -> Self { + Self(value) + } +} + impl From for [u8; 32] { fn from(x: Public) -> Self { x.0 @@ -205,7 +199,7 @@ impl<'de> Deserialize<'de> for Public { } /// A signature (a 512-bit value). -#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)] +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, Hash)] pub struct Signature(pub [u8; 64]); impl TryFrom<&[u8]> for Signature { @@ -222,6 +216,12 @@ impl TryFrom<&[u8]> for Signature { } } +impl From<[u8; 64]> for Signature { + fn from(value: [u8; 64]) -> Self { + Self(value) + } +} + #[cfg(feature = "serde")] impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index c0b41234460da..b2aac75345b90 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -38,7 +38,6 @@ use scale_info::TypeInfo; pub use serde; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use sp_runtime_interface::pass_by::{PassByEnum, PassByInner}; use sp_std::{ops::Deref, prelude::*}; pub use sp_debug_derive::RuntimeDebug; @@ -165,17 +164,7 @@ impl sp_std::ops::Deref for OpaqueMetadata { /// Simple blob to hold a `PeerId` without committing to its format. #[derive( - Default, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Encode, - Decode, - RuntimeDebug, - PassByInner, - TypeInfo, + Default, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo, )] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct OpaquePeerId(pub Vec); @@ -196,7 +185,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, @@ -210,6 +199,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 { @@ -251,7 +260,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, @@ -267,6 +276,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 cef495dfaacdc..ff3ff4f3ad7f2 100644 --- a/substrate/primitives/core/src/offchain/mod.rs +++ b/substrate/primitives/core/src/offchain/mod.rs @@ -20,7 +20,6 @@ use crate::{OpaquePeerId, RuntimeDebug}; use codec::{Decode, Encode}; use scale_info::TypeInfo; -use sp_runtime_interface::pass_by::{PassByCodec, PassByEnum, PassByInner}; use sp_std::prelude::{Box, Vec}; 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); diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 6d2e6ddf3348b..4466d4f130f86 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -33,7 +33,6 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; -use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; use sp_std::convert::TryFrom; /// ECDSA and BLS12-377 paired crypto scheme @@ -187,26 +186,6 @@ impl AsMut<[u8]> for Public PassByInner for Public { - type Inner = [u8; LEFT_PLUS_RIGHT_LEN]; - - fn into_inner(self) -> Self::Inner { - self.0 - } - - fn inner(&self) -> &Self::Inner { - &self.0 - } - - fn from_inner(inner: Self::Inner) -> Self { - Self(inner) - } -} - -impl PassBy for Public { - type PassBy = pass_by::Inner; -} - impl< LeftPair: PairT, RightPair: PairT, @@ -223,6 +202,14 @@ where } } +impl From<[u8; LEFT_PLUS_RIGHT_LEN]> + for Public +{ + fn from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { + Public(data) + } +} + impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Public { diff --git a/substrate/primitives/core/src/sr25519.rs b/substrate/primitives/core/src/sr25519.rs index 6c04eb8def1f4..071b55517658b 100644 --- a/substrate/primitives/core/src/sr25519.rs +++ b/substrate/primitives/core/src/sr25519.rs @@ -44,7 +44,6 @@ use sp_std::ops::Deref; use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH}; #[cfg(feature = "serde")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -use sp_runtime_interface::pass_by::PassByInner; #[cfg(all(not(feature = "std"), feature = "serde"))] use sp_std::alloc::{format, string::String}; @@ -56,18 +55,7 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25"); /// An Schnorrkel/Ristretto x25519 ("sr25519") public key. #[derive( - PartialEq, - Eq, - PartialOrd, - Ord, - Clone, - Copy, - Encode, - Decode, - PassByInner, - MaxEncodedLen, - TypeInfo, - Hash, + PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, MaxEncodedLen, TypeInfo, Hash, )] pub struct Public(pub [u8; 32]); @@ -152,6 +140,12 @@ impl TryFrom<&[u8]> for Public { } } +impl From<[u8; 32]> for Public { + fn from(value: [u8; 32]) -> Self { + Self(value) + } +} + impl UncheckedFrom<[u8; 32]> for Public { fn unchecked_from(x: [u8; 32]) -> Self { Public::from_raw(x) @@ -206,7 +200,7 @@ impl<'de> Deserialize<'de> for Public { } /// An Schnorrkel/Ristretto x25519 ("sr25519") signature. -#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)] +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, Hash)] pub struct Signature(pub [u8; 64]); impl TryFrom<&[u8]> for Signature { @@ -223,6 +217,12 @@ impl TryFrom<&[u8]> for Signature { } } +impl From<[u8; 64]> for Signature { + fn from(value: [u8; 64]) -> Self { + Self(value) + } +} + #[cfg(feature = "serde")] impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result diff --git a/substrate/primitives/crypto/ec-utils/src/bls12_377.rs b/substrate/primitives/crypto/ec-utils/src/bls12_377.rs index 8f19a2c4a1911..8f1f943be72ed 100644 --- a/substrate/primitives/crypto/ec-utils/src/bls12_377.rs +++ b/substrate/primitives/crypto/ec-utils/src/bls12_377.rs @@ -20,7 +20,10 @@ use crate::utils; 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, +}; use sp_std::vec::Vec; /// First pairing group definitions. @@ -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 99a0289b7ad26..24be1d79462a1 100644 --- a/substrate/primitives/crypto/ec-utils/src/bls12_381.rs +++ b/substrate/primitives/crypto/ec-utils/src/bls12_381.rs @@ -20,7 +20,10 @@ use crate::utils; 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, +}; use sp_std::vec::Vec; /// First pairing group definitions. @@ -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 a68abf6e43e03..91bd50909ff8d 100644 --- a/substrate/primitives/crypto/ec-utils/src/bw6_761.rs +++ b/substrate/primitives/crypto/ec-utils/src/bw6_761.rs @@ -20,7 +20,10 @@ use crate::utils; 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, +}; use sp_std::vec::Vec; /// First pairing group definitions. @@ -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 a03be41b85428..95b0763ce1702 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 @@ -20,7 +20,10 @@ use crate::utils; 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, +}; use sp_std::vec::Vec; /// Curve hooks jumping into [`host_calls`] host functions. @@ -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 9d63f35876521..c04bf184e9262 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 @@ -21,7 +21,10 @@ use crate::utils; 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, +}; use sp_std::vec::Vec; /// Curve hooks jumping into [`host_calls`] host functions. @@ -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/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index 684854ea5c8d4..7427208c2a6b8 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -112,7 +112,11 @@ use sp_core::{bls377, ecdsa_bls377}; use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; use sp_runtime_interface::{ - pass_by::{PassBy, PassByCodec}, + pass_by::{ + AllocateAndReturnByCodec, AllocateAndReturnFatPointer, AllocateAndReturnPointer, PassAs, + PassByCodec, PassFatPointerAndRead, PassFatPointerAndReadWrite, PassPointerAndRead, + PassPointerAndReadCopy, PassSliceRefByCodec, ReturnAs, + }, runtime_interface, Pointer, }; @@ -155,7 +159,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. @@ -181,7 +185,10 @@ 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(&self, key: &[u8]) -> Option { + fn get( + &self, + key: PassFatPointerAndRead<&[u8]>, + ) -> AllocateAndReturnByCodec> { self.storage(key).map(|s| bytes::Bytes::from(s.to_vec())) } @@ -190,7 +197,12 @@ 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(&self, key: &[u8], value_out: &mut [u8], value_offset: u32) -> Option { + fn read( + &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())..]; @@ -201,22 +213,22 @@ pub trait Storage { } /// 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(&self, key: &[u8]) -> bool { + fn exists(&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); } @@ -246,7 +258,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: PassByCodec>, + ) -> AllocateAndReturnByCodec { Externalities::clear_prefix(*self, prefix, limit, None).into() } @@ -284,10 +300,10 @@ 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: PassByCodec>, + maybe_cursor: PassByCodec>>, //< TODO Make work or just Option>? + ) -> AllocateAndReturnByCodec { Externalities::clear_prefix( *self, maybe_prefix, @@ -305,7 +321,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); } @@ -314,7 +330,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) } @@ -324,17 +340,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) } @@ -387,7 +409,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(&self, storage_key: &[u8], key: &[u8]) -> Option> { + fn get( + &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()) } @@ -401,11 +427,11 @@ pub trait DefaultChildStorage { /// are copied into `value_out`. fn read( &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; @@ -419,7 +445,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()); } @@ -427,7 +458,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); } @@ -436,7 +471,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); } @@ -445,7 +480,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: PassByCodec>, + ) -> bool { let child_info = ChildInfo::new_default(storage_key); let r = self.kill_child_storage(&child_info, limit, None); r.maybe_cursor.is_none() @@ -455,7 +494,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: PassByCodec>, + ) -> AllocateAndReturnByCodec { let child_info = ChildInfo::new_default(storage_key); self.kill_child_storage(&child_info, limit, None).into() } @@ -466,10 +509,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: PassByCodec>, + maybe_cursor: PassByCodec>>, + ) -> 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() @@ -478,7 +521,11 @@ pub trait DefaultChildStorage { /// Check a child storage key. /// /// Check whether the given `key` exists in default child defined at `storage_key`. - fn exists(&self, storage_key: &[u8], key: &[u8]) -> bool { + fn exists( + &self, + storage_key: PassFatPointerAndRead<&[u8]>, + key: PassFatPointerAndRead<&[u8]>, + ) -> bool { let child_info = ChildInfo::new_default(storage_key); self.exists_child_storage(&child_info, key) } @@ -486,7 +533,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); } @@ -497,10 +548,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: PassByCodec>, + ) -> AllocateAndReturnByCodec { let child_info = ChildInfo::new_default(storage_key); self.clear_child_prefix(&child_info, prefix, limit, None).into() } @@ -511,11 +562,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: PassByCodec>, + maybe_cursor: PassByCodec>>, + ) -> AllocateAndReturnByCodec { let child_info = ChildInfo::new_default(storage_key); self.clear_child_prefix( &child_info, @@ -532,7 +583,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) } @@ -544,7 +598,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) } @@ -552,7 +610,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) } @@ -562,13 +624,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: PassByCodec, 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: PassByCodec, Vec)>>, + version: PassAs, + ) -> AllocateAndReturnPointer { match version { StateVersion::V0 => LayoutV0::::trie_root(input), StateVersion::V1 => LayoutV1::::trie_root(input), @@ -576,13 +643,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: PassByCodec>>, + ) -> 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: PassByCodec>>, + version: PassAs, + ) -> AllocateAndReturnPointer { match version { StateVersion::V0 => LayoutV0::::ordered_trie_root(input), StateVersion::V1 => LayoutV1::::ordered_trie_root(input), @@ -590,13 +662,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: PassByCodec, 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: PassByCodec, Vec)>>, + version: PassAs, + ) -> AllocateAndReturnPointer { match version { StateVersion::V0 => LayoutV0::::trie_root(input), StateVersion::V1 => LayoutV1::::trie_root(input), @@ -604,13 +681,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: PassByCodec>>, + ) -> 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: PassByCodec>>, + version: PassAs, + ) -> AllocateAndReturnPointer { match version { StateVersion::V0 => LayoutV0::::ordered_trie_root(input), StateVersion::V1 => LayoutV1::::ordered_trie_root(input), @@ -618,7 +700,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: PassSliceRefByCodec<&[Vec]>, + key: PassFatPointerAndRead<&[u8]>, + value: PassFatPointerAndRead<&[u8]>, + ) -> bool { sp_trie::verify_trie_proof::, _, _, _>( &root, proof, @@ -630,11 +717,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: PassSliceRefByCodec<&[Vec]>, + key: PassFatPointerAndRead<&[u8]>, + value: PassFatPointerAndRead<&[u8]>, + version: PassAs, ) -> bool { match version { StateVersion::V0 => sp_trie::verify_trie_proof::< @@ -655,7 +742,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: PassSliceRefByCodec<&[Vec]>, + key: PassFatPointerAndRead<&[u8]>, + value: PassFatPointerAndRead<&[u8]>, + ) -> bool { sp_trie::verify_trie_proof::, _, _, _>( &root, proof, @@ -667,11 +759,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: PassSliceRefByCodec<&[Vec]>, + key: PassFatPointerAndRead<&[u8]>, + value: PassFatPointerAndRead<&[u8]>, + version: PassAs, ) -> bool { match version { StateVersion::V0 => sp_trie::verify_trie_proof::< @@ -705,14 +797,14 @@ pub trait Misc { } /// Print any valid `utf8` buffer. - fn print_utf8(utf8: &[u8]) { + fn print_utf8(utf8: PassFatPointerAndRead<&[u8]>) { if let Ok(data) = std::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)); } @@ -731,7 +823,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(); @@ -786,7 +881,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) @@ -798,7 +896,11 @@ 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 { + fn ed25519_generate( + &mut self, + id: PassPointerAndReadCopy, + seed: PassByCodec>>, + ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") @@ -812,10 +914,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) @@ -826,7 +928,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. @@ -863,9 +969,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); @@ -880,7 +986,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) } @@ -900,9 +1010,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); @@ -950,7 +1060,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) @@ -962,7 +1075,11 @@ 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 { + fn sr25519_generate( + &mut self, + id: PassPointerAndReadCopy, + seed: PassByCodec>>, + ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") @@ -976,10 +1093,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) @@ -991,12 +1108,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) @@ -1008,7 +1132,11 @@ 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 { + fn ecdsa_generate( + &mut self, + id: PassPointerAndReadCopy, + seed: PassByCodec>>, + ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") @@ -1022,10 +1150,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) @@ -1039,10 +1167,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) @@ -1054,7 +1182,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) } @@ -1063,7 +1195,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) } @@ -1071,9 +1207,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) } @@ -1094,9 +1230,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); @@ -1116,9 +1252,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, ) @@ -1142,9 +1278,9 @@ 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) @@ -1165,9 +1301,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, ) @@ -1188,9 +1324,9 @@ 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) @@ -1209,7 +1345,11 @@ pub trait Crypto { /// /// Returns the public key. #[cfg(feature = "bls-experimental")] - fn bls377_generate(&mut self, id: KeyTypeId, seed: Option>) -> bls377::Public { + fn bls377_generate( + &mut self, + id: PassPointerAndReadCopy, + seed: PassByCodec>>, + ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") @@ -1226,9 +1366,9 @@ pub trait Crypto { #[cfg(feature = "bls-experimental")] fn ecdsa_bls377_generate( &mut self, - id: KeyTypeId, - seed: Option>, - ) -> ecdsa_bls377::Public { + id: PassPointerAndReadCopy, + seed: PassByCodec>>, + ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") @@ -1245,9 +1385,9 @@ pub trait Crypto { #[cfg(feature = "bandersnatch-experimental")] fn bandersnatch_generate( &mut self, - id: KeyTypeId, - seed: Option>, - ) -> bandersnatch::Public { + id: PassPointerAndReadCopy, + seed: PassByCodec>>, + ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() .expect("No `keystore` associated for the current context!") @@ -1260,42 +1400,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) } } @@ -1304,12 +1444,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); } } @@ -1318,12 +1463,12 @@ 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); } } @@ -1354,7 +1499,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 @@ -1364,21 +1512,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) @@ -1388,7 +1536,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() @@ -1398,7 +1546,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 @@ -1411,7 +1564,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 @@ -1431,10 +1588,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: PassByCodec>>, + new_value: PassFatPointerAndRead<&[u8]>, ) -> bool { self.extension::() .expect( @@ -1449,7 +1606,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 @@ -1464,10 +1625,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) @@ -1476,10 +1637,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) @@ -1493,10 +1654,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: PassByCodec>, + ) -> 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) @@ -1511,9 +1672,9 @@ pub trait Offchain { /// Passing `None` as deadline blocks forever. fn http_response_wait( &mut self, - ids: &[HttpRequestId], - deadline: Option, - ) -> Vec { + ids: PassSliceRefByCodec<&[HttpRequestId]>, + deadline: PassByCodec>, + ) -> AllocateAndReturnByCodec> { self.extension::() .expect("http_response_wait can be called only in the offchain worker context") .http_response_wait(ids, deadline) @@ -1523,7 +1684,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) @@ -1539,10 +1703,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: PassByCodec>, + ) -> 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) @@ -1550,7 +1714,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: PassByCodec>, + authorized_only: bool, + ) { self.extension::() .expect("set_authorized_nodes can be called only in the offchain worker context") .set_authorized_nodes(nodes, authorized_only) @@ -1577,7 +1745,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); } } @@ -1591,44 +1759,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]) { + fn log( + level: PassAs, + target: PassFatPointerAndRead<&str>, + message: PassFatPointerAndRead<&[u8]>, + ) { if let Ok(message) = std::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)] @@ -1642,8 +1788,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: PassByCodec) -> bool { + let metadata: &tracing_core::metadata::Metadata<'static> = (&metadata).into(); tracing::dispatcher::get_default(|d| d.enabled(metadata)) } @@ -1653,8 +1799,8 @@ 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: PassByCodec) -> 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 @@ -1668,8 +1814,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: PassByCodec) { + event.emit(); } /// Signal that a given span-id has been exited. On native, this directly @@ -1684,7 +1830,7 @@ pub trait WasmTracing { #[cfg(all(not(feature = "std"), 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}, @@ -1700,10 +1846,10 @@ mod tracing_setup { impl tracing_core::Subscriber for PassingTracingSubsciber { 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 @@ -1719,7 +1865,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()) diff --git a/substrate/primitives/runtime-interface/Cargo.toml b/substrate/primitives/runtime-interface/Cargo.toml index b4fab17eeb7c1..50a6266c8b81b 100644 --- a/substrate/primitives/runtime-interface/Cargo.toml +++ b/substrate/primitives/runtime-interface/Cargo.toml @@ -24,7 +24,6 @@ sp-tracing = { path = "../tracing", default-features = false } sp-runtime-interface-proc-macro = { path = "proc-macro" } sp-externalities = { path = "../externalities", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bytes"] } -static_assertions = "1.0.0" primitive-types = { version = "0.12.0", default-features = false } sp-storage = { path = "../storage", default-features = false } impl-trait-for-tuples = "0.2.2" diff --git a/substrate/primitives/runtime-interface/proc-macro/src/lib.rs b/substrate/primitives/runtime-interface/proc-macro/src/lib.rs index e6f060c219e01..60754527c57f4 100644 --- a/substrate/primitives/runtime-interface/proc-macro/src/lib.rs +++ b/substrate/primitives/runtime-interface/proc-macro/src/lib.rs @@ -29,10 +29,9 @@ 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 +84,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 0d05dd9aa51e2..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) -> #crate_::sp_std::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..4e1d20ba3a357 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::{ @@ -95,11 +95,15 @@ 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")] @@ -145,9 +149,9 @@ fn function_no_std_impl( /// 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); @@ -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); 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..79dc38eb01833 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::{ @@ -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; @@ -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(), @@ -270,20 +292,12 @@ fn generate_host_function_implementation( .map_err(|err| 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", @@ -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 } 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..b5683dc2c0872 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 }); diff --git a/substrate/primitives/runtime-interface/proc-macro/src/utils.rs b/substrate/primitives/runtime-interface/proc-macro/src/utils.rs index 7d97f9f3e1ca0..6362f51a882d7 100644 --- a/substrate/primitives/runtime-interface/proc-macro/src/utils.rs +++ b/substrate/primitives/runtime-interface/proc-macro/src/utils.rs @@ -237,37 +237,12 @@ 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( +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 +345,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 3530b62662a53..911b79c1d2128 100644 --- a/substrate/primitives/runtime-interface/src/impls.rs +++ b/substrate/primitives/runtime-interface/src/impls.rs @@ -15,36 +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 sp_std::{any::TypeId, mem, vec::Vec}; - -#[cfg(feature = "std")] -use sp_std::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 { @@ -57,37 +45,54 @@ macro_rules! impl_traits_for_primitives { /// The type is passed directly. impl RIType for $rty { type FFIType = $fty; + type Inner = Self; + } + + impl<'a> RIType for &'a $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) + } + } + + #[cfg(not(substrate_runtime))] + impl<'a> IntoFFIValue for &'a $rty { + fn into_ffi_value(value: Self::Inner, _: &mut dyn FunctionContext) -> Result<$fty> { + Ok(*value as $fty) } } )* @@ -111,425 +116,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) - } -} - -#[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) + fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner { + *owned } } -impl PassBy for sp_std::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 8b0edf1ec818e..672abfd0ac527 100644 --- a/substrate/primitives/runtime-interface/src/lib.rs +++ b/substrate/primitives/runtime-interface/src/lib.rs @@ -21,98 +21,53 @@ //! 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)] 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)] @@ -131,14 +86,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::{PassByCodec, 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() @@ -149,7 +106,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() @@ -165,7 +122,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() @@ -174,7 +131,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: PassByCodec>>) { /// match optional { /// Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value), /// None => self.clear_storage(&[1, 2, 3, 4]), @@ -187,10 +144,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: @@ -340,13 +298,36 @@ pub use sp_std; /// } /// ``` /// -/// # Argument types +/// # Argument and return types /// -/// 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. +/// Every argument type and return type must be wrapped in a marker newtype specifying the +/// marshalling strategy used to pass the value through the FFI boundary between the host +/// and the runtime. The only exceptions to this rule are a couple of basic, primitive types +/// which can be passed directly through the FFI boundary and which don't require any special +/// handling besides a straightforward, direct conversion. +/// +/// The following table documents those types which can be passed between the host and the runtime +/// without a marshalling strategy wrapper: +/// +/// | Type | FFI type | Conversion | +/// |----|----|----| +/// | `u8` | `u32` | zero-extended to 32-bits | +/// | `u16` | `u32` | zero-extended to 32-bits | +/// | `u32` | `u32` | `Identity` | +/// | `u64` | `u64` | `Identity` | +/// | `i8` | `i32` | sign-extended to 32-bits | +/// | `i16` | `i32` | sign-extended to 32-bits | +/// | `i32` | `i32` | `Identity` | +/// | `i64` | `i64` | `Identity` | +/// | `bool` | `u32` | `if v { 1 } else { 0 }` | +/// | `*const T` | `u32` | `Identity` | +/// +/// `Identity` means that the value is passed as-is directly in a bit-exact fashion. +/// +/// You can find the strategy wrapper types in the [`crate::pass_by`] module. +/// +/// The newtype wrappers are automatically stripped away when the function is called +/// and applied when the function returns by the `runtime_interface` macro. /// /// # Wasm only interfaces /// @@ -379,36 +360,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 103e9c1622054..3fa29e49f7dba 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -15,419 +15,664 @@ // 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 sp_std::marker::PhantomData; - -#[cfg(not(feature = "std"))] -use sp_std::vec::Vec; +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.) +/// 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 copy. /// -/// ``` -/// # use sp_runtime_interface::pass_by::PassByInner; -/// #[derive(PassByInner)] -/// struct Data([u8; 32]); -/// ``` +/// 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. /// -/// ``` -/// # 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. -/// -/// 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<'a, T, const N: usize> 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; - /// 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 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 + } } -/// Something that provides a strategy for passing a type between wasm and the host. +#[cfg(substrate_runtime)] +impl<'a, T, const N: usize> IntoFFIValue for PassPointerAndRead<&'a T, N> +where + T: AsRef<[u8]>, +{ + type Destructor = (); + + fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) { + assert_eq!(value.as_ref().len(), N); + (value.as_ref().as_ptr() as u32, ()) + } +} + +/// Pass a value into the host by a fat pointer. /// -/// This 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; +/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer) +pub struct PassFatPointerAndRead(PhantomData); - /// 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; - - /// 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<'a, T> 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. -/// -/// This type expects the type that wants to implement this strategy as generic parameter. +/// Pass a value into the host by a fat pointer, writing it back after the host call ends. /// -/// [`PassByCodec`](derive.PassByCodec.html) is a derive macro to implement this strategy. +/// 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. /// -/// # 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 take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner { + &mut *owned } - fn from_ffi_value(context: &mut dyn FunctionContext, arg: Self::FFIType) -> Result { + 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) + } +} - codec::decode_from_bytes(encoded).expect("Host to wasm values are encoded correctly; qed") +#[cfg(substrate_runtime)] +impl<'a, T, const N: usize> IntoFFIValue for PassPointerAndWrite<&'a mut T, N> +where + T: AsMut<[u8]>, +{ + type Destructor = (); + + fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) { + let value = value.as_mut(); + assert_eq!(value.len(), N); + (value.as_ptr() as u32, ()) } } -/// 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 PassByCodec(PhantomData); + +impl RIType for PassByCodec { 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 PassByCodec { + 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 PassByCodec { + 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. +/// Pass a `&[T]` into the host using the SCALE codec. /// -/// This type expects the type that wants to use this strategy as generic parameter `T` and the -/// inner type as generic parameter `I`. +/// 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. /// -/// [`PassByInner`](derive.PassByInner.html) is a derive macro to implement this strategy. -/// -/// # Example -/// ``` -/// # use sp_runtime_interface::pass_by::{PassBy, Inner, PassByInner}; -/// struct Test([u8; 32]); -/// -/// 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 PassSliceRefByCodec(PhantomData); + +impl RIType for PassSliceRefByCodec { + type FFIType = u64; + type Inner = T; +} + +#[cfg(not(substrate_runtime))] +impl<'a, T: codec::Decode> FromFFIValue<'a> for PassSliceRefByCodec<&'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 PassSliceRefByCodec<&'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. +pub unsafe trait Primitive: Copy {} + +unsafe impl Primitive for u8 {} +unsafe impl Primitive for u16 {} +unsafe impl Primitive for u32 {} +unsafe impl Primitive for u64 {} + +unsafe impl Primitive for i8 {} +unsafe impl Primitive for i16 {} +unsafe impl Primitive for i32 {} +unsafe 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<'a, T, U> 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)>); - fn from_ffi_value(arg: Self::FFIType) -> T { - T::from_inner(I::from_ffi_value(arg)) +impl RIType for ReturnAs +where + U: RIType, +{ + type FFIType = ::FFIType; + type Inner = T; +} + +#[cfg(not(substrate_runtime))] +impl<'a, T, U> 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. -/// -/// Use this type as associated type for [`PassBy`] to implement this strategy for a type. -/// -/// 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`. +/// (DEPRECATED) Return `T` as a blob of bytes into the runtime. /// -/// [`PassByEnum`](derive.PassByEnum.html) is a derive macro to implement this strategy. +/// 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. /// -/// # Example -/// ``` -/// # use sp_runtime_interface::pass_by::{PassBy, Enum}; -/// #[derive(Clone, Copy)] -/// enum Test { -/// Test1, -/// Test2, -/// } +/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS! /// -/// impl From for u8 { -/// fn from(val: Test) -> u8 { -/// match val { -/// Test::Test1 => 0, -/// Test::Test2 => 1, -/// } -/// } -/// } +/// 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<'a, T, const N: usize> IntoFFIValue for AllocateAndReturnPointer +where + T: AsRef<[u8]>, +{ + fn into_ffi_value(value: Self::Inner, context: &mut dyn FunctionContext) -> Result { + let value = value.as_ref(); + 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 { + let value = unsafe { Vec::from_raw_parts(arg as *mut u8, N, N) }; + 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 TryFrom for Test { -/// type Error = (); +/// 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. /// -/// fn try_from(val: u8) -> Result { -/// match val { -/// 0 => Ok(Test::Test1), -/// 1 => Ok(Test::Test2), -/// _ => Err(()), -/// } -/// } -/// } +/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS! /// -/// 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 { + 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! +/// +/// 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 { + 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/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 cf1ff3bca088f..1a13aa9f8586d 100644 --- a/substrate/primitives/runtime-interface/test-wasm/src/lib.rs +++ b/substrate/primitives/runtime-interface/test-wasm/src/lib.rs @@ -19,7 +19,14 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_runtime_interface::runtime_interface; +use sp_runtime_interface::{ + pass_by::{ + AllocateAndReturnByCodec, AllocateAndReturnFatPointer, AllocateAndReturnPointer, PassAs, + PassByCodec, PassFatPointerAndRead, PassFatPointerAndReadWrite, PassPointerAndRead, + PassPointerAndReadCopy, PassPointerAndWrite, PassSliceRefByCodec, ReturnAs, + }, + runtime_interface, +}; #[cfg(not(feature = "std"))] use sp_std::{mem, prelude::*}; @@ -45,7 +52,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 } @@ -56,59 +63,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.as_bytes().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`. @@ -116,16 +133,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_versionning(&self, data: u32) -> bool { data == 42 || data == 50 } @@ -146,13 +153,81 @@ pub trait TestApi { /// Returns the input values as tuple. fn return_input_as_tuple( - a: Vec, + a: PassFatPointerAndRead>, b: u32, - c: Option>, + c: PassByCodec>>, 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: PassByCodec>) { + assert_eq!(value, [1, 2, 3]); + } + + fn pass_slice_ref_by_codec(value: PassSliceRefByCodec<&[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`. @@ -248,16 +323,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 { @@ -320,4 +385,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 215704a112154..fba7ff6d5dd2e 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_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.rs b/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.rs deleted file mode 100644 index b6faa46605bf7..0000000000000 --- a/substrate/primitives/runtime-interface/tests/ui/pass_by_enum_with_value_variant.rs +++ /dev/null @@ -1,25 +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)] -enum Test { - Var0(u32), -} - -fn main() {} 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/statement-store/src/lib.rs b/substrate/primitives/statement-store/src/lib.rs index 04175f6d6160e..81bd221372cfa 100644 --- a/substrate/primitives/statement-store/src/lib.rs +++ b/substrate/primitives/statement-store/src/lib.rs @@ -25,7 +25,6 @@ use scale_info::TypeInfo; use sp_application_crypto::RuntimeAppPublic; #[cfg(feature = "std")] use sp_core::Pair; -use sp_runtime_interface::pass_by::PassByCodec; use sp_std::vec::Vec; /// Statement topic. @@ -172,7 +171,7 @@ impl Field { } /// Statement structure. -#[derive(TypeInfo, sp_core::RuntimeDebug, PassByCodec, Clone, PartialEq, Eq, Default)] +#[derive(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 13f88bc977e9e..eb59439eda724 100644 --- a/substrate/primitives/statement-store/src/runtime_api.rs +++ b/substrate/primitives/statement-store/src/runtime_api.rs @@ -21,7 +21,13 @@ use crate::{Hash, Statement, Topic}; 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, PassByCodec, PassPointerAndRead, PassPointerAndReadCopy, + PassSliceRefByCodec, ReturnAs, + }, + runtime_interface, +}; use sp_std::vec::Vec; #[cfg(feature = "std")] @@ -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: PassByCodec, + ) -> 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: PassSliceRefByCodec<&[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: PassSliceRefByCodec<&[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: PassSliceRefByCodec<&[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/wasm-interface/src/lib.rs b/substrate/primitives/wasm-interface/src/lib.rs index 9d5d2bb358d57..aab55ab38a5f3 100644 --- a/substrate/primitives/wasm-interface/src/lib.rs +++ b/substrate/primitives/wasm-interface/src/lib.rs @@ -152,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 { From e854ff39adf560f6a9083beb9ec024bfd6d9fb86 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Thu, 14 Mar 2024 07:18:12 +0000 Subject: [PATCH 02/31] Rename the prdoc file to the correct PR number --- prdoc/{pr_0000.prdoc => pr_3689.prdoc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename prdoc/{pr_0000.prdoc => pr_3689.prdoc} (100%) diff --git a/prdoc/pr_0000.prdoc b/prdoc/pr_3689.prdoc similarity index 100% rename from prdoc/pr_0000.prdoc rename to prdoc/pr_3689.prdoc From b1346cc04d46c3064df4f10a372298cc4bcb3a46 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Thu, 14 Mar 2024 07:20:38 +0000 Subject: [PATCH 03/31] Remove redundant lifetimes --- substrate/primitives/runtime-interface/src/pass_by.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/runtime-interface/src/pass_by.rs b/substrate/primitives/runtime-interface/src/pass_by.rs index 3fa29e49f7dba..9701ffed60b7a 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -503,7 +503,7 @@ where } #[cfg(not(substrate_runtime))] -impl<'a, T, U> IntoFFIValue for ReturnAs +impl IntoFFIValue for ReturnAs where U: RIType + IntoFFIValue + Primitive, ::Inner: From, @@ -556,7 +556,7 @@ impl RIType for AllocateAndReturnPointer { } #[cfg(not(substrate_runtime))] -impl<'a, T, const N: usize> IntoFFIValue for AllocateAndReturnPointer +impl IntoFFIValue for AllocateAndReturnPointer where T: AsRef<[u8]>, { From 5180738649fe0a26954b8db302906ce3a13a81e5 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Thu, 14 Mar 2024 07:23:12 +0000 Subject: [PATCH 04/31] Fix crate name in prdocs --- prdoc/pr_3689.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/pr_3689.prdoc b/prdoc/pr_3689.prdoc index ddc0938278526..2ca560ee7de07 100644 --- a/prdoc/pr_3689.prdoc +++ b/prdoc/pr_3689.prdoc @@ -69,6 +69,6 @@ crates: - 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 + - name: sp-crypto-ec-utils bump: minor note: Requires the new `#[runtime_interface]` macro and associated machinery. From 27457744d3b9f833bcde647dd075ee42e481cd36 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Thu, 14 Mar 2024 07:25:19 +0000 Subject: [PATCH 05/31] Remove more redundant lifetimes --- substrate/primitives/runtime-interface/src/pass_by.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/primitives/runtime-interface/src/pass_by.rs b/substrate/primitives/runtime-interface/src/pass_by.rs index 9701ffed60b7a..ce7246161d814 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -75,7 +75,7 @@ where } #[cfg(substrate_runtime)] -impl<'a, T, const N: usize> IntoFFIValue for PassPointerAndReadCopy +impl IntoFFIValue for PassPointerAndReadCopy where T: AsRef<[u8]>, { @@ -207,7 +207,7 @@ impl<'a> FromFFIValue<'a> for PassFatPointerAndRead> { } #[cfg(substrate_runtime)] -impl<'a, T> IntoFFIValue for PassFatPointerAndRead +impl IntoFFIValue for PassFatPointerAndRead where T: AsRef<[u8]>, { @@ -474,7 +474,7 @@ where } #[cfg(substrate_runtime)] -impl<'a, T, U> IntoFFIValue for PassAs +impl IntoFFIValue for PassAs where U: RIType + IntoFFIValue + Primitive, U::Inner: From, From d13c67fc5718fb055b7962ba18ab4b42e397a2f5 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Thu, 14 Mar 2024 07:58:57 +0000 Subject: [PATCH 06/31] Also adjust FRAME benchmarking runtime interface --- prdoc/pr_3689.prdoc | 6 ++++ substrate/frame/benchmarking/src/utils.rs | 34 ++++++++++++++----- substrate/frame/benchmarking/src/v1.rs | 8 ++--- .../frame/support/procedural/src/benchmark.rs | 8 ++--- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/prdoc/pr_3689.prdoc b/prdoc/pr_3689.prdoc index 2ca560ee7de07..a529d64ce657e 100644 --- a/prdoc/pr_3689.prdoc +++ b/prdoc/pr_3689.prdoc @@ -72,3 +72,9 @@ crates: - 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`. diff --git a/substrate/frame/benchmarking/src/utils.rs b/substrate/frame/benchmarking/src/utils.rs index b9b3f91e2dd7b..f2b2625128fbb 100644 --- a/substrate/frame/benchmarking/src/utils.rs +++ b/substrate/frame/benchmarking/src/utils.rs @@ -23,6 +23,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, PassByCodec, PassFatPointerAndRead, PassPointerAndWrite, +}; use sp_std::{prelude::Box, vec::Vec}; use sp_storage::TrackedStorageKey; @@ -242,6 +245,16 @@ 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 { @@ -249,11 +262,12 @@ pub trait Benchmarking { /// /// 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. @@ -267,7 +281,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() } @@ -277,17 +291,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: PassByCodec>) { 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: PassByCodec) { 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 @@ -306,18 +320,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() } } diff --git a/substrate/frame/benchmarking/src/v1.rs b/substrate/frame/benchmarking/src/v1.rs index 4ad8cc0edd46c..1a2ba28354fd7 100644 --- a/substrate/frame/benchmarking/src/v1.rs +++ b/substrate/frame/benchmarking/src/v1.rs @@ -1109,11 +1109,11 @@ macro_rules! impl_benchmark { ); let start_pov = $crate::benchmarking::proof_size(); - let start_extrinsic = $crate::benchmarking::current_time(); + let start_extrinsic = $crate::current_time(); closure_to_benchmark()?; - let finish_extrinsic = $crate::benchmarking::current_time(); + let finish_extrinsic = $crate::current_time(); let end_pov = $crate::benchmarking::proof_size(); // Calculate the diff caused by the benchmark. @@ -1140,9 +1140,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/support/procedural/src/benchmark.rs b/substrate/frame/support/procedural/src/benchmark.rs index 27c75a7f054cf..a9e3ea60f1b92 100644 --- a/substrate/frame/support/procedural/src/benchmark.rs +++ b/substrate/frame/support/procedural/src/benchmark.rs @@ -630,11 +630,11 @@ pub fn benchmarks( ); let start_pov = #krate::benchmarking::proof_size(); - let start_extrinsic = #krate::benchmarking::current_time(); + let start_extrinsic = #krate::current_time(); closure_to_benchmark()?; - let finish_extrinsic = #krate::benchmarking::current_time(); + let finish_extrinsic = #krate::current_time(); let end_pov = #krate::benchmarking::proof_size(); // Calculate the diff caused by the benchmark. @@ -657,9 +657,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),* ]; From e0fb03b5374fde911be22562ce47f04a5ac2f103 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Thu, 14 Mar 2024 08:19:45 +0000 Subject: [PATCH 07/31] Update `polkadot-runtime-metrics` crate --- polkadot/runtime/metrics/src/with_runtime_metrics.rs | 2 +- prdoc/pr_3689.prdoc | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/polkadot/runtime/metrics/src/with_runtime_metrics.rs b/polkadot/runtime/metrics/src/with_runtime_metrics.rs index 562aa9ca162b5..15609f261ce66 100644 --- a/polkadot/runtime/metrics/src/with_runtime_metrics.rs +++ b/polkadot/runtime/metrics/src/with_runtime_metrics.rs @@ -143,5 +143,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_3689.prdoc b/prdoc/pr_3689.prdoc index a529d64ce657e..bd6706440cbab 100644 --- a/prdoc/pr_3689.prdoc +++ b/prdoc/pr_3689.prdoc @@ -78,3 +78,6 @@ crates: - 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`. From 3b87116f8a76c797cdbf4e0c718a69aea8618c94 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Thu, 14 Mar 2024 10:08:01 +0000 Subject: [PATCH 08/31] Remove `sp-std` dependency from `sp-wasm-interface` --- Cargo.lock | 1 - substrate/primitives/wasm-interface/Cargo.toml | 3 +-- substrate/primitives/wasm-interface/src/lib.rs | 11 +++++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e06a4bd01a9f..79a3d12271ca8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19378,7 +19378,6 @@ dependencies = [ "impl-trait-for-tuples", "log", "parity-scale-codec", - "sp-std 14.0.0", "wasmtime", ] diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index f7d1038903eab..6c051b71c8e0a 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -22,9 +22,8 @@ impl-trait-for-tuples = "0.2.2" log = { optional = true, workspace = true, default-features = true } wasmtime = { version = "8.0.1", default-features = false, optional = true } anyhow = { version = "1.0.68", optional = true } -sp-std = { path = "../std", default-features = false } [features] default = ["std"] -std = ["codec/std", "log/std", "sp-std/std", "wasmtime"] +std = ["codec/std", "log/std", "wasmtime"] wasmtime = ["anyhow", "dep:wasmtime"] diff --git a/substrate/primitives/wasm-interface/src/lib.rs b/substrate/primitives/wasm-interface/src/lib.rs index aab55ab38a5f3..13aa1ac881aa5 100644 --- a/substrate/primitives/wasm-interface/src/lib.rs +++ b/substrate/primitives/wasm-interface/src/lib.rs @@ -19,7 +19,10 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_std::{borrow::Cow, iter::Iterator, marker::PhantomData, mem, result, vec, vec::Vec}; +extern crate alloc; + +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] @@ -45,9 +48,9 @@ if_wasmtime_is_enabled! { /// Result type used by traits in this crate. #[cfg(feature = "std")] -pub type Result = result::Result; +pub type Result = core::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)] @@ -76,7 +79,7 @@ impl From for u8 { impl TryFrom for ValueType { type Error = (); - fn try_from(val: u8) -> sp_std::result::Result { + fn try_from(val: u8) -> core::result::Result { match val { 0 => Ok(Self::I32), 1 => Ok(Self::I64), From 1aab744e164d3730aae97b3475ea9bf413c0c1ba Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Thu, 14 Mar 2024 10:08:37 +0000 Subject: [PATCH 09/31] Add missing imports to `sp-runtime-interface` --- substrate/primitives/runtime-interface/src/pass_by.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/substrate/primitives/runtime-interface/src/pass_by.rs b/substrate/primitives/runtime-interface/src/pass_by.rs index ce7246161d814..05c52903383dd 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -32,6 +32,9 @@ use crate::wasm::*; #[cfg(not(substrate_runtime))] use sp_wasm_interface::{FunctionContext, Pointer, Result}; +#[cfg(not(substrate_runtime))] +use alloc::{format, string::String}; + use alloc::vec::Vec; use core::{any::type_name, marker::PhantomData}; From 64c37e568d1722032750e6db2766550108839046 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Thu, 14 Mar 2024 10:08:58 +0000 Subject: [PATCH 10/31] Make `sp_wasm_interface::Result` always return a `String` as an error --- prdoc/pr_3689.prdoc | 4 ++-- substrate/primitives/wasm-interface/src/lib.rs | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/prdoc/pr_3689.prdoc b/prdoc/pr_3689.prdoc index bd6706440cbab..23fda6cd42ebf 100644 --- a/prdoc/pr_3689.prdoc +++ b/prdoc/pr_3689.prdoc @@ -58,8 +58,8 @@ crates: bump: major note: Rework of the `#[runtime_interface]` macro. - name: sp-wasm-interface - bump: minor - note: The `Pointer` type now implements `Copy` and `Clone` unconditionally. + 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. diff --git a/substrate/primitives/wasm-interface/src/lib.rs b/substrate/primitives/wasm-interface/src/lib.rs index 13aa1ac881aa5..f6948d8cb88e9 100644 --- a/substrate/primitives/wasm-interface/src/lib.rs +++ b/substrate/primitives/wasm-interface/src/lib.rs @@ -47,10 +47,7 @@ if_wasmtime_is_enabled! { } /// Result type used by traits in this crate. -#[cfg(feature = "std")] pub type Result = core::result::Result; -#[cfg(not(feature = "std"))] -pub type Result = core::result::Result; /// Value types supported by Substrate on the boundary between host/Wasm. #[derive(Copy, Clone, PartialEq, Debug, Eq)] From d71e09332cd9c5f5e527c3713521f9d9e02d2454 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Thu, 14 Mar 2024 10:12:54 +0000 Subject: [PATCH 11/31] Make `sp-runtime-interface` always `#[no_std]` --- substrate/primitives/runtime-interface/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/runtime-interface/src/lib.rs b/substrate/primitives/runtime-interface/src/lib.rs index 672abfd0ac527..832ef046eb109 100644 --- a/substrate/primitives/runtime-interface/src/lib.rs +++ b/substrate/primitives/runtime-interface/src/lib.rs @@ -61,7 +61,7 @@ //! [`#[runtime_interface]`](./attr.runtime_interface.html). -#![cfg_attr(not(feature = "std"), no_std)] +#![no_std] extern crate self as sp_runtime_interface; extern crate alloc; From b8aebe1b8e2a2526fe7debb5fe236bcaebdad1e6 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Mon, 18 Mar 2024 08:42:02 +0000 Subject: [PATCH 12/31] Switch `runtime-interface` macros to use `substrate_runtime` --- .../runtime_interface/bare_function_interface.rs | 12 ++++++------ .../runtime_interface/host_function_interface.rs | 14 +++++++------- .../src/runtime_interface/trait_decl_impl.rs | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) 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 4e1d20ba3a357..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 @@ -90,7 +90,7 @@ 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, @@ -134,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 @@ -144,7 +144,7 @@ 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 { @@ -157,7 +157,7 @@ fn function_std_latest_impl(method: &TraitItemFn, latest_version: u32) -> Result 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( @@ -167,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, @@ -210,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 79dc38eb01833..2dd39908d4206 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 @@ -62,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::*; @@ -174,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(); @@ -355,11 +355,11 @@ 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, @@ -374,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 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 b5683dc2c0872..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 @@ -168,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 )* } From feeda1aeaf4906e482e8bf56b18bfe12b39fbedc Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Mon, 18 Mar 2024 08:42:56 +0000 Subject: [PATCH 13/31] Fix `check-features-variants.sh` scripts --- .../application-crypto/check-features-variants.sh | 4 +++- substrate/primitives/core/check-features-variants.sh | 2 +- substrate/primitives/keyring/check-features-variants.sh | 7 ++++--- 3 files changed, 8 insertions(+), 5 deletions(-) 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/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/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 From 11dfa9f3ec839563abad886a49dbf58b1f320b83 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Mon, 18 Mar 2024 13:37:56 +0000 Subject: [PATCH 14/31] More `feature = "std"` cleanups; fix `full-crypto` feature compilation --- Cargo.lock | 6 +-- substrate/primitives/core/Cargo.toml | 10 ++-- substrate/primitives/core/src/lib.rs | 10 ++-- substrate/primitives/core/src/offchain/mod.rs | 14 ++--- substrate/primitives/core/src/sr25519.rs | 2 +- substrate/primitives/core/src/traits.rs | 24 ++++----- substrate/primitives/io/Cargo.toml | 25 +++++---- substrate/primitives/io/src/lib.rs | 54 ++++++++++--------- .../host_function_interface.rs | 22 ++++---- .../primitives/runtime-interface/src/lib.rs | 4 +- .../primitives/runtime-interface/src/util.rs | 4 +- .../primitives/state-machine/src/basic.rs | 12 ++--- .../state-machine/src/in_memory_backend.rs | 8 ++- substrate/primitives/state-machine/src/lib.rs | 21 ++++---- .../src/overlayed_changes/changeset.rs | 2 +- .../src/overlayed_changes/mod.rs | 2 +- .../primitives/state-machine/src/read_only.rs | 9 ++-- substrate/primitives/tracing/src/lib.rs | 2 +- substrate/primitives/tracing/src/types.rs | 20 +++---- 19 files changed, 131 insertions(+), 120 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 750dba2e375a4..f47c89ec3008c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4815,9 +4815,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 = "ecdsa" @@ -18600,7 +18600,7 @@ dependencies = [ "bounded-collections", "bs58 0.5.0", "criterion 0.4.0", - "dyn-clonable", + "dyn-clone", "ed25519-zebra 3.1.0", "futures", "hash-db", diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 908f2498de533..501b51b5b2979 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -37,9 +37,6 @@ ss58-registry = { version = "1.34.0", default-features = false } sp-std = { path = "../std", default-features = false } sp-debug-derive = { path = "../debug-derive", default-features = false } sp-storage = { path = "../storage", default-features = false } -sp-externalities = { path = "../externalities", optional = true } -futures = { version = "0.3.21", optional = true } -dyn-clonable = { version = "0.9.0", optional = true } thiserror = { optional = true, workspace = true } tracing = { version = "0.1.29", optional = true } bitflags = "1.3" @@ -65,6 +62,11 @@ w3f-bls = { version = "0.1.3", default-features = false, optional = true } # bandersnatch crypto bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "e9782f9", default-features = false, features = ["substrate-curves"], optional = true } +[target.'cfg(not(substrate_runtime))'.dependencies] +sp-externalities = { path = "../externalities" } +futures = { version = "0.3.21", default-features = false, features = ["alloc"] } +dyn-clone = "1.0.17" + [dev-dependencies] criterion = "0.4.0" serde_json = { workspace = true, default-features = true } @@ -89,10 +91,8 @@ std = [ "bounded-collections/std", "bs58/std", "codec/std", - "dyn-clonable", "ed25519-zebra/std", "full_crypto", - "futures", "futures/thread-pool", "hash-db/std", "hash256-std-hasher/std", diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index b2aac75345b90..e50f7e895f2d2 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. @@ -65,13 +67,13 @@ pub mod defer; pub mod ecdsa; pub mod ed25519; pub mod hash; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] mod hasher; pub mod offchain; pub mod paired_crypto; pub mod sr25519; pub mod testing; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub mod traits; pub mod uint; @@ -86,9 +88,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; diff --git a/substrate/primitives/core/src/offchain/mod.rs b/substrate/primitives/core/src/offchain/mod.rs index ff3ff4f3ad7f2..6f92ee2a74d5d 100644 --- a/substrate/primitives/core/src/offchain/mod.rs +++ b/substrate/primitives/core/src/offchain/mod.rs @@ -621,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 { @@ -727,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 { @@ -746,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. /// @@ -754,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 071b55517658b..21e156de3eb49 100644 --- a/substrate/primitives/core/src/sr25519.rs +++ b/substrate/primitives/core/src/sr25519.rs @@ -502,7 +502,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/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index e47775d56d9e5..d89af50c3bd55 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -22,21 +22,23 @@ bytes = { version = "1.1.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bytes"] } sp-core = { path = "../core", default-features = false } sp-crypto-hashing = { path = "../crypto/hashing", default-features = false } -sp-keystore = { path = "../keystore", default-features = false, optional = true } sp-std = { path = "../std", default-features = false } -libsecp256k1 = { version = "0.7", optional = true } -sp-state-machine = { path = "../state-machine", default-features = false, optional = true } sp-runtime-interface = { path = "../runtime-interface", default-features = false } -sp-trie = { path = "../trie", default-features = false, optional = true } sp-externalities = { path = "../externalities", default-features = false } sp-tracing = { path = "../tracing", default-features = false } -log = { optional = true, workspace = true, default-features = true } -secp256k1 = { version = "0.28.0", features = ["global-context", "recovery"], optional = true } tracing = { version = "0.1.29", default-features = false } tracing-core = { version = "0.1.32", default-features = false } +[target.'cfg(not(substrate_runtime))'.dependencies] +sp-keystore = { path = "../keystore", default-features = false } +sp-trie = { path = "../trie", default-features = false } +sp-state-machine = { path = "../state-machine", default-features = false } +log = { workspace = true, default-features = true } +libsecp256k1 = { version = "0.7" } +secp256k1 = { version = "0.28.0", features = ["global-context", "recovery"] } + # Required for backwards compatibility reason, but only used for verifying when `UseDalekExt` is set. -ed25519-dalek = { version = "2.1", default-features = false, optional = true } +ed25519-dalek = { version = "2.1", default-features = false } [target.'cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), substrate_runtime))'.dependencies] polkavm-derive = { workspace = true } @@ -49,11 +51,8 @@ default = ["std"] std = [ "bytes/std", "codec/std", - "ed25519-dalek", - "ed25519-dalek?/std", - "libsecp256k1", + "ed25519-dalek/std", "log/std", - "secp256k1", "sp-core/std", "sp-crypto-hashing/std", "sp-externalities/std", @@ -99,9 +98,9 @@ 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 # be subject to significant changes. -bandersnatch-experimental = ["sp-keystore/bandersnatch-experimental"] +bandersnatch-experimental = ["sp-core/bandersnatch-experimental", "sp-keystore/bandersnatch-experimental"] diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index 7427208c2a6b8..f0891dd9416a5 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -77,19 +77,21 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(enable_alloc_error_handler, feature(alloc_error_handler))] -use sp_std::vec::Vec; +extern crate alloc; -#[cfg(feature = "std")] +use alloc::vec::Vec; + +#[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")] @@ -108,7 +110,7 @@ use sp_core::{ #[cfg(feature = "bls-experimental")] use sp_core::{bls377, ecdsa_bls377}; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; use sp_runtime_interface::{ @@ -122,13 +124,13 @@ use sp_runtime_interface::{ use codec::{Decode, Encode}; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, Message, SECP256K1, }; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] use sp_externalities::{Externalities, ExternalitiesExt}; pub use sp_externalities::MultiRemovalResults; @@ -143,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 @@ -206,7 +208,7 @@ pub trait Storage { 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 }) @@ -436,7 +438,7 @@ pub trait DefaultChildStorage { 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 }) @@ -798,7 +800,7 @@ pub trait Misc { /// Print any valid `utf8` buffer. fn print_utf8(utf8: PassFatPointerAndRead<&[u8]>) { - if let Ok(data) = std::str::from_utf8(utf8) { + if let Ok(data) = core::str::from_utf8(utf8) { log::debug!(target: "runtime", "{}", data) } } @@ -849,7 +851,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. /// @@ -870,7 +872,7 @@ sp_externalities::decl_extension! { pub struct UseDalekExt; } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] impl Default for UseDalekExt { fn default() -> Self { Self @@ -901,7 +903,7 @@ pub trait Crypto { id: PassPointerAndReadCopy, seed: PassByCodec>>, ) -> AllocateAndReturnPointer { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + 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) @@ -1080,7 +1082,7 @@ pub trait Crypto { id: PassPointerAndReadCopy, seed: PassByCodec>>, ) -> AllocateAndReturnPointer { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + 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) @@ -1137,7 +1139,7 @@ pub trait Crypto { id: PassPointerAndReadCopy, seed: PassByCodec>>, ) -> AllocateAndReturnPointer { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + 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) @@ -1350,7 +1352,7 @@ pub trait Crypto { id: PassPointerAndReadCopy, seed: PassByCodec>>, ) -> AllocateAndReturnPointer { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + 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!") .bls377_generate_new(id, seed) @@ -1369,7 +1371,7 @@ pub trait Crypto { id: PassPointerAndReadCopy, seed: PassByCodec>>, ) -> AllocateAndReturnPointer { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + 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_bls377_generate_new(id, seed) @@ -1388,7 +1390,7 @@ pub trait Crypto { id: PassPointerAndReadCopy, seed: PassByCodec>>, ) -> AllocateAndReturnPointer { - let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + 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) @@ -1473,7 +1475,7 @@ pub trait OffchainIndex { } } -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] sp_externalities::decl_extension! { /// Deprecated verification context. /// @@ -1764,7 +1766,7 @@ pub trait Logging { target: PassFatPointerAndRead<&str>, message: PassFatPointerAndRead<&[u8]>, ) { - if let Ok(message) = std::str::from_utf8(message) { + if let Ok(message) = core::str::from_utf8(message) { log::log!(target: target, log::Level::from(level), "{}", message) } } @@ -1828,7 +1830,7 @@ 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; use core::sync::atomic::{AtomicBool, Ordering}; @@ -1884,7 +1886,7 @@ 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. @@ -1917,7 +1919,7 @@ pub fn unreachable() -> ! { #[panic_handler] #[no_mangle] pub fn panic(info: &core::panic::PanicInfo) -> ! { - let message = sp_std::alloc::format!("{}", info); + let message = alloc::format!("{}", info); #[cfg(feature = "improved_panic_error_reporting")] { panic_handler::abort_on_panic(&message); @@ -1945,13 +1947,13 @@ 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. -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] pub type SubstrateHostFunctions = ( storage::HostFunctions, default_child_storage::HostFunctions, 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 2dd39908d4206..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 @@ -289,7 +289,7 @@ 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))?; }); host_names_with_ref.push( @@ -306,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))?; }); } @@ -364,7 +364,7 @@ fn generate_host_function_implementation( 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)* @@ -388,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__, @@ -405,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(|| { @@ -418,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)); } @@ -458,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/src/lib.rs b/substrate/primitives/runtime-interface/src/lib.rs index 832ef046eb109..95b9ccf2c45fe 100644 --- a/substrate/primitives/runtime-interface/src/lib.rs +++ b/substrate/primitives/runtime-interface/src/lib.rs @@ -64,7 +64,7 @@ #![no_std] extern crate self as sp_runtime_interface; -extern crate alloc; +pub extern crate alloc; #[doc(hidden)] #[cfg(not(substrate_runtime))] @@ -348,7 +348,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, 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/state-machine/src/basic.rs b/substrate/primitives/state-machine/src/basic.rs index ace88aee2628f..5141f24e2d30c 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,11 +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, - iter::FromIterator, -}; /// Simple Map-based Externalities impl. #[derive(Debug)] @@ -92,7 +92,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 06fe6d4162a7f..960a76354e43d 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; + +#[cfg(not(feature = "std"))] +use alloc::collections::BTreeMap as HashMap; /// Create a new empty instance of in-memory backend. pub fn new_in_mem() -> TrieBackend, H> diff --git a/substrate/primitives/state-machine/src/lib.rs b/substrate/primitives/state-machine/src/lib.rs index 200cebe68de5d..1fdbef44f58a7 100644 --- a/substrate/primitives/state-machine/src/lib.rs +++ b/substrate/primitives/state-machine/src/lib.rs @@ -23,14 +23,14 @@ extern crate alloc; pub mod backend; -#[cfg(feature = "std")] +#[cfg(not(substrate_runtime))] mod basic; mod error; mod ext; -#[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")] @@ -140,15 +140,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 a25a5b810522d..aa19bbdcdd26f 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs @@ -119,7 +119,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 039631e4a6303..431e7c40efb3f 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/mod.rs @@ -749,7 +749,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 2056bf9866358..35c30cad0182b 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/tracing/src/lib.rs b/substrate/primitives/tracing/src/lib.rs index b8b99230db574..f397c33f1bb3b 100644 --- a/substrate/primitives/tracing/src/lib.rs +++ b/substrate/primitives/tracing/src/lib.rs @@ -50,7 +50,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 3692a81e03c8e..4be33e0dd301e 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::*; From 8a8dcb06a42b3570297986ad6d1e66adc43f9892 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Tue, 19 Mar 2024 09:47:30 +0000 Subject: [PATCH 15/31] Update `secp256k1` and `secp256k1-sys` to fix WASM compilation --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f47c89ec3008c..92177d1cee4ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17157,18 +17157,18 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.28.0" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09e67c467c38fd24bd5499dc9a18183b31575c12ee549197e3e20d57aa4fe3b7" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" dependencies = [ "cc", ] From 116380185f520295902155cc69a4a735fdc9d3ea Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Tue, 19 Mar 2024 09:46:55 +0000 Subject: [PATCH 16/31] Fix `sp-io` compilation under non-runtime `no_std` --- substrate/primitives/io/Cargo.toml | 7 +++++-- substrate/primitives/io/src/lib.rs | 18 +++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index d89af50c3bd55..e3c1d9fac9ee3 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -34,8 +34,8 @@ sp-keystore = { path = "../keystore", default-features = false } sp-trie = { path = "../trie", default-features = false } sp-state-machine = { path = "../state-machine", default-features = false } log = { workspace = true, default-features = true } -libsecp256k1 = { version = "0.7" } -secp256k1 = { version = "0.28.0", features = ["global-context", "recovery"] } +libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"] } +secp256k1 = { version = "0.28.2", default-features = false, features = ["alloc", "recovery"] } # Required for backwards compatibility reason, but only used for verifying when `UseDalekExt` is set. ed25519-dalek = { version = "2.1", default-features = false } @@ -52,7 +52,10 @@ std = [ "bytes/std", "codec/std", "ed25519-dalek/std", + "libsecp256k1/std", "log/std", + "secp256k1/global-context", + "secp256k1/std", "sp-core/std", "sp-crypto-hashing/std", "sp-externalities/std", diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index f0891dd9416a5..0bc6197a0ba49 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -127,7 +127,7 @@ use codec::{Decode, Encode}; #[cfg(not(substrate_runtime))] use secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, - Message, SECP256K1, + Message, }; #[cfg(not(substrate_runtime))] @@ -1288,9 +1288,11 @@ pub trait Crypto { 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) @@ -1334,9 +1336,11 @@ pub trait Crypto { 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()) } From af464733090a2e0938976f197c5704fe1a276817 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Tue, 19 Mar 2024 10:11:39 +0000 Subject: [PATCH 17/31] Build frame examples with `--cfg substrate_runtime` on the CI --- .gitlab/pipeline/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 26e55e9385f34..99412aa67d263 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -342,9 +342,9 @@ test-frame-examples-compile-to-wasm: RUST_BACKTRACE: 1 script: - cd ./substrate/frame/examples/offchain-worker/ - - cargo build --locked --target=wasm32-unknown-unknown --no-default-features + - RUSTFLAGS="--cfg substrate_runtime" cargo build --locked --target=wasm32-unknown-unknown --no-default-features - cd ../basic - - cargo build --locked --target=wasm32-unknown-unknown --no-default-features + - RUSTFLAGS="--cfg substrate_runtime" cargo build --locked --target=wasm32-unknown-unknown --no-default-features # FIXME allow_failure: true From 0a254f5c7b2f5f3066398ca1f245f47846ab39ea Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Tue, 19 Mar 2024 10:16:43 +0000 Subject: [PATCH 18/31] Propagate `sp-core/std` -> `futures/std` cargo feature --- substrate/primitives/core/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 501b51b5b2979..42cded86c422c 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -93,6 +93,7 @@ std = [ "codec/std", "ed25519-zebra/std", "full_crypto", + "futures/std", "futures/thread-pool", "hash-db/std", "hash256-std-hasher/std", From 2763e818765c6ec3773069994285fb89d1e9b7e4 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Wed, 20 Mar 2024 07:33:33 +0000 Subject: [PATCH 19/31] Fix `pallet_ui` tests --- .../storage_ensure_span_are_ok_on_wrong_gen.stderr | 12 ++++++------ ...ge_ensure_span_are_ok_on_wrong_gen_unnamed.stderr | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index 4229d1e8a5458..d269e6d2726d7 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -13,8 +13,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -65,8 +65,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others @@ -106,8 +106,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -148,8 +148,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others @@ -168,8 +168,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -210,8 +210,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 855d289d0a160..13d761d65d201 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -13,8 +13,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -65,8 +65,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others @@ -106,8 +106,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -148,8 +148,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others @@ -168,8 +168,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | = help: the following other types implement trait `WrapperTypeDecode`: Box - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` @@ -210,8 +210,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied bytes::bytes::Bytes Cow<'a, T> parity_scale_codec::Ref<'a, T, U> - Rc frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes + Rc Arc Vec and $N others From 022c32ccef1393ff5eb44e9465d5acfa0368c54b Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Wed, 20 Mar 2024 07:50:55 +0000 Subject: [PATCH 20/31] Disable default features for `sp-externalities` dep in `sp-core` --- substrate/primitives/core/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 42cded86c422c..c08eeb53ddb4b 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -63,7 +63,7 @@ w3f-bls = { version = "0.1.3", default-features = false, optional = true } bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "e9782f9", default-features = false, features = ["substrate-curves"], optional = true } [target.'cfg(not(substrate_runtime))'.dependencies] -sp-externalities = { path = "../externalities" } +sp-externalities = { path = "../externalities", default-features = false } futures = { version = "0.3.21", default-features = false, features = ["alloc"] } dyn-clone = "1.0.17" From 9a446a8fb67b3cc53ec5ef777eac43c2078988a4 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Wed, 20 Mar 2024 08:24:11 +0000 Subject: [PATCH 21/31] More `feature = "std"` cleanups to fix `full_crypto` compilation --- .../externalities/src/extensions.rs | 5 +-- substrate/primitives/storage/src/lib.rs | 40 +++++++++---------- 2 files changed, 20 insertions(+), 25 deletions(-) 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/storage/src/lib.rs b/substrate/primitives/storage/src/lib.rs index b55cc8f217405..15c7437e92c21 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 @@ -245,8 +243,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), @@ -392,8 +389,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, From 1e53458e91c831ce9bc24186a2ee2c1a62f8308d Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Fri, 5 Apr 2024 09:23:53 +0000 Subject: [PATCH 22/31] Remove unnecessary `RIType` and `IntoFFIValue` impls --- substrate/primitives/runtime-interface/src/impls.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/substrate/primitives/runtime-interface/src/impls.rs b/substrate/primitives/runtime-interface/src/impls.rs index 911b79c1d2128..5b903d1da3ccd 100644 --- a/substrate/primitives/runtime-interface/src/impls.rs +++ b/substrate/primitives/runtime-interface/src/impls.rs @@ -48,11 +48,6 @@ macro_rules! impl_traits_for_primitives { type Inner = Self; } - impl<'a> RIType for &'a $rty { - type FFIType = $fty; - type Inner = Self; - } - #[cfg(substrate_runtime)] impl IntoFFIValue for $rty { type Destructor = (); @@ -88,13 +83,6 @@ macro_rules! impl_traits_for_primitives { Ok(value as $fty) } } - - #[cfg(not(substrate_runtime))] - impl<'a> IntoFFIValue for &'a $rty { - fn into_ffi_value(value: Self::Inner, _: &mut dyn FunctionContext) -> Result<$fty> { - Ok(*value as $fty) - } - } )* } } From c240e1e10c566db75166b634227075518513c255 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Fri, 5 Apr 2024 09:27:19 +0000 Subject: [PATCH 23/31] Use associated types in return types --- substrate/primitives/runtime-interface/src/pass_by.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/runtime-interface/src/pass_by.rs b/substrate/primitives/runtime-interface/src/pass_by.rs index 05c52903383dd..9c8ce642dc5f7 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -563,7 +563,7 @@ impl IntoFFIValue for AllocateAndReturnPointer where T: AsRef<[u8]>, { - fn into_ffi_value(value: Self::Inner, context: &mut dyn FunctionContext) -> Result { + fn into_ffi_value(value: Self::Inner, context: &mut dyn FunctionContext) -> Result { let value = value.as_ref(); let addr = context.allocate_memory(value.len() as u32)?; context.write_memory(addr, value)?; @@ -604,7 +604,7 @@ impl IntoFFIValue for AllocateAndReturnFatPointer where T: AsRef<[u8]>, { - fn into_ffi_value(value: Self::Inner, context: &mut dyn FunctionContext) -> Result { + 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)?; From 6ac3d061e1ffc531c08f1da71e8a8c0ef94b3cea Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Fri, 5 Apr 2024 09:34:38 +0000 Subject: [PATCH 24/31] Make `Primitive` safe and private --- .../runtime-interface/src/pass_by.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/substrate/primitives/runtime-interface/src/pass_by.rs b/substrate/primitives/runtime-interface/src/pass_by.rs index 9c8ce642dc5f7..8be704f6fc7bf 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -424,17 +424,17 @@ impl<'a, T: codec::Encode> IntoFFIValue for PassSliceRefByCodec<&'a [T]> { } /// A trait signifying a primitive type. -pub unsafe trait Primitive: Copy {} +trait Primitive: Copy {} -unsafe impl Primitive for u8 {} -unsafe impl Primitive for u16 {} -unsafe impl Primitive for u32 {} -unsafe impl Primitive for u64 {} +impl Primitive for u8 {} +impl Primitive for u16 {} +impl Primitive for u32 {} +impl Primitive for u64 {} -unsafe impl Primitive for i8 {} -unsafe impl Primitive for i16 {} -unsafe impl Primitive for i32 {} -unsafe impl Primitive for i64 {} +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. From ba683e74f1f8a8be1d09b4d7efe04851451fc8b6 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Fri, 5 Apr 2024 10:04:36 +0000 Subject: [PATCH 25/31] Cleanups --- .../runtime-interface/src/pass_by.rs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/runtime-interface/src/pass_by.rs b/substrate/primitives/runtime-interface/src/pass_by.rs index 8be704f6fc7bf..dba28c740fc52 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -563,8 +563,19 @@ impl IntoFFIValue for AllocateAndReturnPointer where T: AsRef<[u8]>, { - fn into_ffi_value(value: Self::Inner, context: &mut dyn FunctionContext) -> Result { + 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()) @@ -577,7 +588,11 @@ 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) } @@ -604,7 +619,10 @@ impl IntoFFIValue for AllocateAndReturnFatPointer where T: AsRef<[u8]>, { - fn into_ffi_value(value: Self::Inner, context: &mut dyn FunctionContext) -> Result { + 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)?; @@ -623,6 +641,8 @@ where 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) } }; @@ -665,6 +685,8 @@ impl FromFFIValue for AllocateAndReturnByCodec { 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) }) }; From 1cb22ca5f0544f8b362fd4161f0852f5dc9c393c Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Fri, 5 Apr 2024 11:25:50 +0000 Subject: [PATCH 26/31] Rename `PassByCodec` to `PassFatPointerAndDecode` --- substrate/frame/benchmarking/src/utils.rs | 6 +- substrate/primitives/io/src/lib.rs | 72 ++++++++++--------- .../primitives/runtime-interface/src/lib.rs | 4 +- .../runtime-interface/src/pass_by.rs | 8 +-- .../runtime-interface/test-wasm/src/lib.rs | 9 +-- .../statement-store/src/runtime_api.rs | 6 +- 6 files changed, 55 insertions(+), 50 deletions(-) diff --git a/substrate/frame/benchmarking/src/utils.rs b/substrate/frame/benchmarking/src/utils.rs index f2b2625128fbb..033363304cad0 100644 --- a/substrate/frame/benchmarking/src/utils.rs +++ b/substrate/frame/benchmarking/src/utils.rs @@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize}; use sp_io::hashing::blake2_256; use sp_runtime::{traits::TrailingZeroInput, DispatchError}; use sp_runtime_interface::pass_by::{ - AllocateAndReturnByCodec, PassByCodec, PassFatPointerAndRead, PassPointerAndWrite, + AllocateAndReturnByCodec, PassFatPointerAndDecode, PassFatPointerAndRead, PassPointerAndWrite, }; use sp_std::{prelude::Box, vec::Vec}; use sp_storage::TrackedStorageKey; @@ -296,12 +296,12 @@ pub trait Benchmarking { } /// Set the DB whitelist. - fn set_whitelist(&mut self, new: PassByCodec>) { + 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: PassByCodec) { + 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 diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index 766cfefb30deb..3264d3d1fd01d 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -116,8 +116,8 @@ use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; use sp_runtime_interface::{ pass_by::{ AllocateAndReturnByCodec, AllocateAndReturnFatPointer, AllocateAndReturnPointer, PassAs, - PassByCodec, PassFatPointerAndRead, PassFatPointerAndReadWrite, PassPointerAndRead, - PassPointerAndReadCopy, PassSliceRefByCodec, ReturnAs, + PassFatPointerAndDecode, PassFatPointerAndRead, PassFatPointerAndReadWrite, + PassPointerAndRead, PassPointerAndReadCopy, PassSliceRefByCodec, ReturnAs, }, runtime_interface, Pointer, }; @@ -263,7 +263,7 @@ pub trait Storage { fn clear_prefix( &mut self, prefix: PassFatPointerAndRead<&[u8]>, - limit: PassByCodec>, + limit: PassFatPointerAndDecode>, ) -> AllocateAndReturnByCodec { Externalities::clear_prefix(*self, prefix, limit, None).into() } @@ -303,8 +303,9 @@ pub trait Storage { fn clear_prefix( &mut self, maybe_prefix: PassFatPointerAndRead<&[u8]>, - maybe_limit: PassByCodec>, - maybe_cursor: PassByCodec>>, //< TODO Make work or just Option>? + maybe_limit: PassFatPointerAndDecode>, + maybe_cursor: PassFatPointerAndDecode>>, /* TODO Make work or just + * Option>? */ ) -> AllocateAndReturnByCodec { Externalities::clear_prefix( *self, @@ -485,7 +486,7 @@ pub trait DefaultChildStorage { fn storage_kill( &mut self, storage_key: PassFatPointerAndRead<&[u8]>, - limit: PassByCodec>, + limit: PassFatPointerAndDecode>, ) -> bool { let child_info = ChildInfo::new_default(storage_key); let r = self.kill_child_storage(&child_info, limit, None); @@ -499,7 +500,7 @@ pub trait DefaultChildStorage { fn storage_kill( &mut self, storage_key: PassFatPointerAndRead<&[u8]>, - limit: PassByCodec>, + limit: PassFatPointerAndDecode>, ) -> AllocateAndReturnByCodec { let child_info = ChildInfo::new_default(storage_key); self.kill_child_storage(&child_info, limit, None).into() @@ -512,8 +513,8 @@ pub trait DefaultChildStorage { fn storage_kill( &mut self, storage_key: PassFatPointerAndRead<&[u8]>, - maybe_limit: PassByCodec>, - maybe_cursor: PassByCodec>>, + 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[..])) @@ -552,7 +553,7 @@ pub trait DefaultChildStorage { &mut self, storage_key: PassFatPointerAndRead<&[u8]>, prefix: PassFatPointerAndRead<&[u8]>, - limit: PassByCodec>, + limit: PassFatPointerAndDecode>, ) -> AllocateAndReturnByCodec { let child_info = ChildInfo::new_default(storage_key); self.clear_child_prefix(&child_info, prefix, limit, None).into() @@ -566,8 +567,8 @@ pub trait DefaultChildStorage { &mut self, storage_key: PassFatPointerAndRead<&[u8]>, prefix: PassFatPointerAndRead<&[u8]>, - maybe_limit: PassByCodec>, - maybe_cursor: PassByCodec>>, + maybe_limit: PassFatPointerAndDecode>, + maybe_cursor: PassFatPointerAndDecode>>, ) -> AllocateAndReturnByCodec { let child_info = ChildInfo::new_default(storage_key); self.clear_child_prefix( @@ -627,7 +628,7 @@ pub trait DefaultChildStorage { pub trait Trie { /// A trie root formed from the iterated items. fn blake2_256_root( - input: PassByCodec, Vec)>>, + input: PassFatPointerAndDecode, Vec)>>, ) -> AllocateAndReturnPointer { LayoutV0::::trie_root(input) } @@ -635,7 +636,7 @@ pub trait Trie { /// A trie root formed from the iterated items. #[version(2)] fn blake2_256_root( - input: PassByCodec, Vec)>>, + input: PassFatPointerAndDecode, Vec)>>, version: PassAs, ) -> AllocateAndReturnPointer { match version { @@ -646,7 +647,7 @@ pub trait Trie { /// A trie root formed from the enumerated items. fn blake2_256_ordered_root( - input: PassByCodec>>, + input: PassFatPointerAndDecode>>, ) -> AllocateAndReturnPointer { LayoutV0::::ordered_trie_root(input) } @@ -654,7 +655,7 @@ pub trait Trie { /// A trie root formed from the enumerated items. #[version(2)] fn blake2_256_ordered_root( - input: PassByCodec>>, + input: PassFatPointerAndDecode>>, version: PassAs, ) -> AllocateAndReturnPointer { match version { @@ -665,7 +666,7 @@ pub trait Trie { /// A trie root formed from the iterated items. fn keccak_256_root( - input: PassByCodec, Vec)>>, + input: PassFatPointerAndDecode, Vec)>>, ) -> AllocateAndReturnPointer { LayoutV0::::trie_root(input) } @@ -673,7 +674,7 @@ pub trait Trie { /// A trie root formed from the iterated items. #[version(2)] fn keccak_256_root( - input: PassByCodec, Vec)>>, + input: PassFatPointerAndDecode, Vec)>>, version: PassAs, ) -> AllocateAndReturnPointer { match version { @@ -684,7 +685,7 @@ pub trait Trie { /// A trie root formed from the enumerated items. fn keccak_256_ordered_root( - input: PassByCodec>>, + input: PassFatPointerAndDecode>>, ) -> AllocateAndReturnPointer { LayoutV0::::ordered_trie_root(input) } @@ -692,7 +693,7 @@ pub trait Trie { /// A trie root formed from the enumerated items. #[version(2)] fn keccak_256_ordered_root( - input: PassByCodec>>, + input: PassFatPointerAndDecode>>, version: PassAs, ) -> AllocateAndReturnPointer { match version { @@ -901,7 +902,7 @@ pub trait Crypto { fn ed25519_generate( &mut self, id: PassPointerAndReadCopy, - seed: PassByCodec>>, + seed: PassFatPointerAndDecode>>, ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() @@ -1080,7 +1081,7 @@ pub trait Crypto { fn sr25519_generate( &mut self, id: PassPointerAndReadCopy, - seed: PassByCodec>>, + seed: PassFatPointerAndDecode>>, ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() @@ -1137,7 +1138,7 @@ pub trait Crypto { fn ecdsa_generate( &mut self, id: PassPointerAndReadCopy, - seed: PassByCodec>>, + seed: PassFatPointerAndDecode>>, ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() @@ -1354,7 +1355,7 @@ pub trait Crypto { fn bls377_generate( &mut self, id: PassPointerAndReadCopy, - seed: PassByCodec>>, + seed: PassFatPointerAndDecode>>, ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() @@ -1373,7 +1374,7 @@ pub trait Crypto { fn ecdsa_bls377_generate( &mut self, id: PassPointerAndReadCopy, - seed: PassByCodec>>, + seed: PassFatPointerAndDecode>>, ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() @@ -1392,7 +1393,7 @@ pub trait Crypto { fn bandersnatch_generate( &mut self, id: PassPointerAndReadCopy, - seed: PassByCodec>>, + seed: PassFatPointerAndDecode>>, ) -> AllocateAndReturnPointer { let seed = seed.as_ref().map(|s| core::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::() @@ -1596,7 +1597,7 @@ pub trait Offchain { &mut self, kind: PassAs, key: PassFatPointerAndRead<&[u8]>, - old_value: PassByCodec>>, + old_value: PassFatPointerAndDecode>>, new_value: PassFatPointerAndRead<&[u8]>, ) -> bool { self.extension::() @@ -1662,7 +1663,7 @@ pub trait Offchain { &mut self, request_id: PassAs, chunk: PassFatPointerAndRead<&[u8]>, - deadline: PassByCodec>, + deadline: PassFatPointerAndDecode>, ) -> AllocateAndReturnByCodec> { self.extension::() .expect("http_request_write_body can be called only in the offchain worker context") @@ -1679,7 +1680,7 @@ pub trait Offchain { fn http_response_wait( &mut self, ids: PassSliceRefByCodec<&[HttpRequestId]>, - deadline: PassByCodec>, + deadline: PassFatPointerAndDecode>, ) -> AllocateAndReturnByCodec> { self.extension::() .expect("http_response_wait can be called only in the offchain worker context") @@ -1711,7 +1712,7 @@ pub trait Offchain { &mut self, request_id: PassAs, buffer: PassFatPointerAndReadWrite<&mut [u8]>, - deadline: PassByCodec>, + deadline: PassFatPointerAndDecode>, ) -> AllocateAndReturnByCodec> { self.extension::() .expect("http_response_read_body can be called only in the offchain worker context") @@ -1722,7 +1723,7 @@ pub trait Offchain { /// Set the authorized nodes and authorized_only flag. fn set_authorized_nodes( &mut self, - nodes: PassByCodec>, + nodes: PassFatPointerAndDecode>, authorized_only: bool, ) { self.extension::() @@ -1794,7 +1795,7 @@ 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: PassByCodec) -> bool { + fn enabled(&mut self, metadata: PassFatPointerAndDecode) -> bool { let metadata: &tracing_core::metadata::Metadata<'static> = (&metadata).into(); tracing::dispatcher::get_default(|d| d.enabled(metadata)) } @@ -1805,7 +1806,10 @@ 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: PassByCodec) -> u64 { + fn enter_span( + &mut self, + span: PassFatPointerAndDecode, + ) -> u64 { let span: tracing::Span = span.into(); match span.id() { Some(id) => tracing::dispatcher::get_default(|d| { @@ -1820,7 +1824,7 @@ pub trait WasmTracing { } /// Emit the given event to the global tracer on the native side - fn event(&mut self, event: PassByCodec) { + fn event(&mut self, event: PassFatPointerAndDecode) { event.emit(); } diff --git a/substrate/primitives/runtime-interface/src/lib.rs b/substrate/primitives/runtime-interface/src/lib.rs index e11a529118b94..3ce02f2461483 100644 --- a/substrate/primitives/runtime-interface/src/lib.rs +++ b/substrate/primitives/runtime-interface/src/lib.rs @@ -88,7 +88,7 @@ pub use sp_std; /// ``` /// # mod wrapper { /// # use sp_runtime_interface::runtime_interface; -/// # use sp_runtime_interface::pass_by::{PassByCodec, PassFatPointerAndRead, AllocateAndReturnFatPointer}; +/// # use sp_runtime_interface::pass_by::{PassFatPointerAndDecode, PassFatPointerAndRead, AllocateAndReturnFatPointer}; /// /// #[runtime_interface] /// trait Interface { @@ -131,7 +131,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: PassByCodec>>) { +/// 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]), diff --git a/substrate/primitives/runtime-interface/src/pass_by.rs b/substrate/primitives/runtime-interface/src/pass_by.rs index dba28c740fc52..9475a525398ef 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -339,15 +339,15 @@ where /// which then reads it and decodes back into `T`. /// /// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer) -pub struct PassByCodec(PhantomData); +pub struct PassFatPointerAndDecode(PhantomData); -impl RIType for PassByCodec { +impl RIType for PassFatPointerAndDecode { type FFIType = u64; type Inner = T; } #[cfg(not(substrate_runtime))] -impl<'a, T: codec::Decode> FromFFIValue<'a> for PassByCodec { +impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecode { type Owned = Option; fn from_ffi_value( @@ -368,7 +368,7 @@ impl<'a, T: codec::Decode> FromFFIValue<'a> for PassByCodec { } #[cfg(substrate_runtime)] -impl IntoFFIValue for PassByCodec { +impl IntoFFIValue for PassFatPointerAndDecode { type Destructor = Vec; fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) { diff --git a/substrate/primitives/runtime-interface/test-wasm/src/lib.rs b/substrate/primitives/runtime-interface/test-wasm/src/lib.rs index 1a281569baffc..0a77c89ed8461 100644 --- a/substrate/primitives/runtime-interface/test-wasm/src/lib.rs +++ b/substrate/primitives/runtime-interface/test-wasm/src/lib.rs @@ -22,8 +22,9 @@ use sp_runtime_interface::{ pass_by::{ AllocateAndReturnByCodec, AllocateAndReturnFatPointer, AllocateAndReturnPointer, PassAs, - PassByCodec, PassFatPointerAndRead, PassFatPointerAndReadWrite, PassPointerAndRead, - PassPointerAndReadCopy, PassPointerAndWrite, PassSliceRefByCodec, ReturnAs, + PassFatPointerAndDecode, PassFatPointerAndRead, PassFatPointerAndReadWrite, + PassPointerAndRead, PassPointerAndReadCopy, PassPointerAndWrite, PassSliceRefByCodec, + ReturnAs, }, runtime_interface, }; @@ -155,7 +156,7 @@ pub trait TestApi { fn return_input_as_tuple( a: PassFatPointerAndRead>, b: u32, - c: PassByCodec>>, + c: PassFatPointerAndDecode>>, d: u8, ) -> AllocateAndReturnByCodec<(Vec, u32, Option>, u8)> { (a, b, c, d) @@ -185,7 +186,7 @@ pub trait TestApi { *value = [1, 2, 3]; } - fn pass_by_codec(value: PassByCodec>) { + fn pass_by_codec(value: PassFatPointerAndDecode>) { assert_eq!(value, [1, 2, 3]); } diff --git a/substrate/primitives/statement-store/src/runtime_api.rs b/substrate/primitives/statement-store/src/runtime_api.rs index 144455de5cfca..06bc6e28f67de 100644 --- a/substrate/primitives/statement-store/src/runtime_api.rs +++ b/substrate/primitives/statement-store/src/runtime_api.rs @@ -24,8 +24,8 @@ use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; use sp_runtime_interface::{ pass_by::{ - AllocateAndReturnByCodec, PassByCodec, PassPointerAndRead, PassPointerAndReadCopy, - PassSliceRefByCodec, ReturnAs, + AllocateAndReturnByCodec, PassFatPointerAndDecode, PassPointerAndRead, + PassPointerAndReadCopy, PassSliceRefByCodec, ReturnAs, }, runtime_interface, }; @@ -149,7 +149,7 @@ pub trait StatementStore { /// This is meant to be used by the offchain worker. fn submit_statement( &mut self, - statement: PassByCodec, + statement: PassFatPointerAndDecode, ) -> ReturnAs { if let Some(StatementStoreExt(store)) = self.extension::() { match store.submit(statement, StatementSource::Chain) { From 6e606ad020889e66ff0540deaae34447d184bb0b Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Fri, 5 Apr 2024 11:28:13 +0000 Subject: [PATCH 27/31] Rename `PassSliceRefByCodec` -> `PassFatPointerAndDecodeSlice` --- substrate/primitives/io/src/lib.rs | 14 +++++++------- .../primitives/runtime-interface/src/pass_by.rs | 8 ++++---- .../runtime-interface/test-wasm/src/lib.rs | 8 ++++---- .../primitives/statement-store/src/runtime_api.rs | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index 3264d3d1fd01d..329f29e17e47b 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -116,8 +116,8 @@ use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; use sp_runtime_interface::{ pass_by::{ AllocateAndReturnByCodec, AllocateAndReturnFatPointer, AllocateAndReturnPointer, PassAs, - PassFatPointerAndDecode, PassFatPointerAndRead, PassFatPointerAndReadWrite, - PassPointerAndRead, PassPointerAndReadCopy, PassSliceRefByCodec, ReturnAs, + PassFatPointerAndDecode, PassFatPointerAndDecodeSlice, PassFatPointerAndRead, + PassFatPointerAndReadWrite, PassPointerAndRead, PassPointerAndReadCopy, ReturnAs, }, runtime_interface, Pointer, }; @@ -705,7 +705,7 @@ pub trait Trie { /// Verify trie proof fn blake2_256_verify_proof( root: PassPointerAndReadCopy, - proof: PassSliceRefByCodec<&[Vec]>, + proof: PassFatPointerAndDecodeSlice<&[Vec]>, key: PassFatPointerAndRead<&[u8]>, value: PassFatPointerAndRead<&[u8]>, ) -> bool { @@ -721,7 +721,7 @@ pub trait Trie { #[version(2)] fn blake2_256_verify_proof( root: PassPointerAndReadCopy, - proof: PassSliceRefByCodec<&[Vec]>, + proof: PassFatPointerAndDecodeSlice<&[Vec]>, key: PassFatPointerAndRead<&[u8]>, value: PassFatPointerAndRead<&[u8]>, version: PassAs, @@ -747,7 +747,7 @@ pub trait Trie { /// Verify trie proof fn keccak_256_verify_proof( root: PassPointerAndReadCopy, - proof: PassSliceRefByCodec<&[Vec]>, + proof: PassFatPointerAndDecodeSlice<&[Vec]>, key: PassFatPointerAndRead<&[u8]>, value: PassFatPointerAndRead<&[u8]>, ) -> bool { @@ -763,7 +763,7 @@ pub trait Trie { #[version(2)] fn keccak_256_verify_proof( root: PassPointerAndReadCopy, - proof: PassSliceRefByCodec<&[Vec]>, + proof: PassFatPointerAndDecodeSlice<&[Vec]>, key: PassFatPointerAndRead<&[u8]>, value: PassFatPointerAndRead<&[u8]>, version: PassAs, @@ -1679,7 +1679,7 @@ pub trait Offchain { /// Passing `None` as deadline blocks forever. fn http_response_wait( &mut self, - ids: PassSliceRefByCodec<&[HttpRequestId]>, + ids: PassFatPointerAndDecodeSlice<&[HttpRequestId]>, deadline: PassFatPointerAndDecode>, ) -> AllocateAndReturnByCodec> { self.extension::() diff --git a/substrate/primitives/runtime-interface/src/pass_by.rs b/substrate/primitives/runtime-interface/src/pass_by.rs index 9475a525398ef..c5725998f3c87 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -385,15 +385,15 @@ impl IntoFFIValue for PassFatPointerAndDecode { /// a reference to that (as `&[T]`) into the host function. /// /// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer) -pub struct PassSliceRefByCodec(PhantomData); +pub struct PassFatPointerAndDecodeSlice(PhantomData); -impl RIType for PassSliceRefByCodec { +impl RIType for PassFatPointerAndDecodeSlice { type FFIType = u64; type Inner = T; } #[cfg(not(substrate_runtime))] -impl<'a, T: codec::Decode> FromFFIValue<'a> for PassSliceRefByCodec<&'a [T]> { +impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecodeSlice<&'a [T]> { type Owned = Vec; fn from_ffi_value( @@ -414,7 +414,7 @@ impl<'a, T: codec::Decode> FromFFIValue<'a> for PassSliceRefByCodec<&'a [T]> { } #[cfg(substrate_runtime)] -impl<'a, T: codec::Encode> IntoFFIValue for PassSliceRefByCodec<&'a [T]> { +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) { diff --git a/substrate/primitives/runtime-interface/test-wasm/src/lib.rs b/substrate/primitives/runtime-interface/test-wasm/src/lib.rs index 0a77c89ed8461..fbda65f6cef33 100644 --- a/substrate/primitives/runtime-interface/test-wasm/src/lib.rs +++ b/substrate/primitives/runtime-interface/test-wasm/src/lib.rs @@ -22,9 +22,9 @@ use sp_runtime_interface::{ pass_by::{ AllocateAndReturnByCodec, AllocateAndReturnFatPointer, AllocateAndReturnPointer, PassAs, - PassFatPointerAndDecode, PassFatPointerAndRead, PassFatPointerAndReadWrite, - PassPointerAndRead, PassPointerAndReadCopy, PassPointerAndWrite, PassSliceRefByCodec, - ReturnAs, + PassFatPointerAndDecode, PassFatPointerAndDecodeSlice, PassFatPointerAndRead, + PassFatPointerAndReadWrite, PassPointerAndRead, PassPointerAndReadCopy, + PassPointerAndWrite, ReturnAs, }, runtime_interface, }; @@ -190,7 +190,7 @@ pub trait TestApi { assert_eq!(value, [1, 2, 3]); } - fn pass_slice_ref_by_codec(value: PassSliceRefByCodec<&[u16]>) { + fn pass_slice_ref_by_codec(value: PassFatPointerAndDecodeSlice<&[u16]>) { assert_eq!(value, [1, 2, 3]); } diff --git a/substrate/primitives/statement-store/src/runtime_api.rs b/substrate/primitives/statement-store/src/runtime_api.rs index 06bc6e28f67de..a95885a362ad7 100644 --- a/substrate/primitives/statement-store/src/runtime_api.rs +++ b/substrate/primitives/statement-store/src/runtime_api.rs @@ -24,8 +24,8 @@ use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; use sp_runtime_interface::{ pass_by::{ - AllocateAndReturnByCodec, PassFatPointerAndDecode, PassPointerAndRead, - PassPointerAndReadCopy, PassSliceRefByCodec, ReturnAs, + AllocateAndReturnByCodec, PassFatPointerAndDecode, PassFatPointerAndDecodeSlice, + PassPointerAndRead, PassPointerAndReadCopy, ReturnAs, }, runtime_interface, }; @@ -180,7 +180,7 @@ pub trait StatementStore { /// field. fn broadcasts( &mut self, - match_all_topics: PassSliceRefByCodec<&[Topic]>, + match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>, ) -> AllocateAndReturnByCodec>> { if let Some(StatementStoreExt(store)) = self.extension::() { store.broadcasts(match_all_topics).unwrap_or_default() @@ -194,7 +194,7 @@ pub trait StatementStore { /// private key for symmetric ciphers). fn posted( &mut self, - match_all_topics: PassSliceRefByCodec<&[Topic]>, + match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>, dest: PassPointerAndReadCopy<[u8; 32], 32>, ) -> AllocateAndReturnByCodec>> { if let Some(StatementStoreExt(store)) = self.extension::() { @@ -208,7 +208,7 @@ pub trait StatementStore { /// `dest`. The key must be available to the client. fn posted_clear( &mut self, - match_all_topics: PassSliceRefByCodec<&[Topic]>, + match_all_topics: PassFatPointerAndDecodeSlice<&[Topic]>, dest: PassPointerAndReadCopy<[u8; 32], 32>, ) -> AllocateAndReturnByCodec>> { if let Some(StatementStoreExt(store)) = self.extension::() { From 6d90a1d21bf2ef545eea60cd4a81c807280a0117 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Fri, 5 Apr 2024 11:30:10 +0000 Subject: [PATCH 28/31] Update doc comment --- .../primitives/runtime-interface/proc-macro/src/lib.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/substrate/primitives/runtime-interface/proc-macro/src/lib.rs b/substrate/primitives/runtime-interface/proc-macro/src/lib.rs index 60754527c57f4..6ca7827acae58 100644 --- a/substrate/primitives/runtime-interface/proc-macro/src/lib.rs +++ b/substrate/primitives/runtime-interface/proc-macro/src/lib.rs @@ -18,14 +18,8 @@ //! 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}, From 0001db01d80be140e5fa48e94e006289c28b8b1e Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Fri, 5 Apr 2024 11:36:31 +0000 Subject: [PATCH 29/31] Update the docs about the deprecated marshaling strategies --- substrate/primitives/runtime-interface/src/pass_by.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/substrate/primitives/runtime-interface/src/pass_by.rs b/substrate/primitives/runtime-interface/src/pass_by.rs index c5725998f3c87..8358722a2c429 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -550,6 +550,9 @@ where /// /// 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`](PassPointerAndWrite) strategy. +/// /// Raw FFI type: `u32` (a pointer to the byte blob) pub struct AllocateAndReturnPointer(PhantomData<(T, [u8; N])>); @@ -606,6 +609,9 @@ where /// /// 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`](PassPointerAndWrite) strategy. +/// /// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer) pub struct AllocateAndReturnFatPointer(PhantomData); @@ -658,6 +664,9 @@ where /// /// 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`](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); From 182a6e8218cafc8f5d57159b077ce9f15c2bffd4 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Fri, 5 Apr 2024 12:04:22 +0000 Subject: [PATCH 30/31] Remove redundant links in the docs --- substrate/primitives/runtime-interface/src/pass_by.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/primitives/runtime-interface/src/pass_by.rs b/substrate/primitives/runtime-interface/src/pass_by.rs index 8358722a2c429..796bab10ba234 100644 --- a/substrate/primitives/runtime-interface/src/pass_by.rs +++ b/substrate/primitives/runtime-interface/src/pass_by.rs @@ -551,7 +551,7 @@ where /// 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`](PassPointerAndWrite) strategy. +/// the [`PassPointerAndWrite`] strategy. /// /// Raw FFI type: `u32` (a pointer to the byte blob) pub struct AllocateAndReturnPointer(PhantomData<(T, [u8; N])>); @@ -610,7 +610,7 @@ where /// 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`](PassPointerAndWrite) strategy. +/// the [`PassPointerAndWrite`] strategy. /// /// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer) pub struct AllocateAndReturnFatPointer(PhantomData); @@ -665,7 +665,7 @@ where /// 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`](PassPointerAndWrite) strategy. +/// 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); From c7946009f25665a704008d85ff550be498fdeea2 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Mon, 8 Apr 2024 07:40:23 +0000 Subject: [PATCH 31/31] Update prdoc --- prdoc/pr_3689.prdoc | 1 - 1 file changed, 1 deletion(-) diff --git a/prdoc/pr_3689.prdoc b/prdoc/pr_3689.prdoc index 23fda6cd42ebf..9b6f6ad2cb899 100644 --- a/prdoc/pr_3689.prdoc +++ b/prdoc/pr_3689.prdoc @@ -4,7 +4,6 @@ title: Refactor the host <-> runtime interface machinery (the `#[runtime_interface]` macro) and the way host functions are defined doc: - - audience: Runtime Dev - audience: Node Dev description: | This PR refactors the way the host functions are defined.