diff --git a/.cargo/config.toml b/.cargo/config.toml index b677b9b2ae3..28e7939f391 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,4 +1,7 @@ [env] # We need to enable `RUSTC_BOOTSTRAP` so that the nightly ink! # features still work on stable. -RUSTC_BOOTSTRAP = "1" \ No newline at end of file +RUSTC_BOOTSTRAP = "1" + +[build] +rustflags = ["--cfg", "substrate_runtime"] diff --git a/CHANGELOG.md b/CHANGELOG.md index f25c3f859a4..db4c143e351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Restrict which `cfg` attributes can be used ‒ [#2313](https://github.com/use-ink/ink/pull/2313) ## Added +- Add feature flag to compile contracts for `pallet-revive` ‒ [#2318](https://github.com/use-ink/ink/pull/2318) - Support for `caller_is_root` - [#2332] (https://github.com/use-ink/ink/pull/2332) ## Fixed diff --git a/Cargo.lock b/Cargo.lock index 00e1317b275..bf151590890 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "approx" @@ -848,9 +848,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" dependencies = [ "clap_builder", "clap_derive", @@ -858,9 +858,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" dependencies = [ "anstream", "anstyle", @@ -2648,8 +2648,11 @@ dependencies = [ "ink_primitives", "ink_storage", "pallet-contracts-uapi", + "pallet-revive-uapi", "parity-scale-codec", + "polkavm-derive 0.17.1", "scale-info", + "sp-io", "staging-xcm", "trybuild", ] @@ -2676,6 +2679,7 @@ dependencies = [ "ink_primitives", "itertools 0.13.0", "parity-scale-codec", + "polkavm-derive 0.17.1", "proc-macro2", "quote", "serde", @@ -2745,6 +2749,7 @@ dependencies = [ "derive_more 1.0.0", "ink_primitives", "pallet-contracts-uapi", + "pallet-revive-uapi", "parity-scale-codec", "secp256k1 0.30.0", "sha2 0.10.8", @@ -2767,8 +2772,10 @@ dependencies = [ "ink_storage_traits", "num-traits", "pallet-contracts-uapi", + "pallet-revive-uapi", "parity-scale-codec", "paste", + "polkavm-derive 0.17.1", "rlibc", "scale-decode", "scale-encode", @@ -2777,6 +2784,7 @@ dependencies = [ "secp256k1 0.30.0", "sha2 0.10.8", "sha3", + "sp-io", "staging-xcm", "static_assertions", ] @@ -2886,6 +2894,7 @@ dependencies = [ "ink_storage_traits", "itertools 0.13.0", "pallet-contracts-uapi", + "pallet-revive-uapi", "parity-scale-codec", "quickcheck", "quickcheck_macros", @@ -3776,7 +3785,7 @@ dependencies = [ "bitflags 1.3.2", "parity-scale-codec", "paste", - "polkavm-derive", + "polkavm-derive 0.9.1", "scale-info", ] @@ -3847,6 +3856,16 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "pallet-revive-uapi" +version = "0.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk?tag=polkadot-stable2412-rc2#a86fb861573b31fb35db97d6ffe3eb4ff4a80359" +dependencies = [ + "bitflags 1.3.2", + "paste", + "polkavm-derive 0.14.0", +] + [[package]] name = "pallet-session" version = "38.0.0" @@ -4288,13 +4307,43 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d9428a5cfcc85c5d7b9fc4b6a18c4b802d0173d768182a51cc7751640f08b92" +[[package]] +name = "polkavm-common" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711952a783e9c5ad407cdacb1ed147f36d37c5d43417c1091d86456d2999417b" + +[[package]] +name = "polkavm-common" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0dbafef4ab6ceecb4982ac3b550df430ef4f9fdbf07c108b7d4f91a0682fce" + [[package]] name = "polkavm-derive" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606" dependencies = [ - "polkavm-derive-impl-macro", + "polkavm-derive-impl-macro 0.9.0", +] + +[[package]] +name = "polkavm-derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4832a0aebf6cefc988bb7b2d74ea8c86c983164672e2fc96300f356a1babfc1" +dependencies = [ + "polkavm-derive-impl-macro 0.14.0", +] + +[[package]] +name = "polkavm-derive" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206caf322dfc02144510ad8360ff2051e5072f0874dcab3b410f78cdd52d0ebb" +dependencies = [ + "polkavm-derive-impl-macro 0.17.0", ] [[package]] @@ -4303,7 +4352,31 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ - "polkavm-common", + "polkavm-common 0.9.0", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "polkavm-derive-impl" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e339fc7c11310fe5adf711d9342278ac44a75c9784947937cce12bd4f30842f2" +dependencies = [ + "polkavm-common 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "polkavm-derive-impl" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42565aed4adbc4034612d0b17dea8db3681fb1bd1aed040d6edc5455a9f478a1" +dependencies = [ + "polkavm-common 0.17.0", "proc-macro2", "quote", "syn 2.0.90", @@ -4315,7 +4388,27 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ - "polkavm-derive-impl", + "polkavm-derive-impl 0.9.0", + "syn 2.0.90", +] + +[[package]] +name = "polkavm-derive-impl-macro" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b569754b15060d03000c09e3bf11509d527f60b75d79b4c30c3625b5071d9702" +dependencies = [ + "polkavm-derive-impl 0.14.0", + "syn 2.0.90", +] + +[[package]] +name = "polkavm-derive-impl-macro" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d9838e95241b0bce4fe269cdd4af96464160505840ed5a8ac8536119ba19e2" +dependencies = [ + "polkavm-derive-impl 0.17.0", "syn 2.0.90", ] @@ -5826,7 +5919,7 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", - "polkavm-derive", + "polkavm-derive 0.9.1", "rustversion", "secp256k1 0.28.2", "sp-core", @@ -5954,7 +6047,7 @@ dependencies = [ "bytes", "impl-trait-for-tuples", "parity-scale-codec", - "polkavm-derive", + "polkavm-derive 0.9.1", "primitive-types 0.12.2", "sp-externalities", "sp-runtime-interface-proc-macro", @@ -6758,9 +6851,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", diff --git a/Cargo.toml b/Cargo.toml index 1097e38a6fb..4b7cff9ff97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,8 @@ pallet-contracts = { version = "38.0.0", default-features = false } pallet-balances = { version = "39.0.0", default-features = false } pallet-timestamp = { version = "37.0.0", default-features = false } pallet-contracts-uapi = { version = "12.0.0", default-features = false } +pallet-revive-uapi = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-rc2", default-features = false } +# TODO include mock-network for revive pallet-contracts-mock-network = { version = "14.0.0", default-features = false } sp-externalities = { version = "0.29.0", default-features = false } sp-io = { version = "38.0.0", default-features = false } @@ -101,6 +103,9 @@ sp-runtime = { version = "39.0.2", default-features = false } sp-weights = { version = "31.0.0", default-features = false } xcm = { package = "staging-xcm", version = "14.2.0", default-features = false } +# PolkaVM dependencies +polkavm-derive = { version = "0.17.1", default-features = false } + # Local dependencies ink = { version = "=5.1.0", path = "crates/ink", default-features = false } ink_allocator = { version = "=5.1.0", path = "crates/allocator", default-features = false } diff --git a/crates/allocator/src/bump.rs b/crates/allocator/src/bump.rs index 39b8abfb505..56aef9c1ae6 100644 --- a/crates/allocator/src/bump.rs +++ b/crates/allocator/src/bump.rs @@ -28,6 +28,9 @@ const PAGE_SIZE: usize = 64 * 1024; static mut INNER: Option = None; +#[cfg(target_arch = "riscv32")] +static mut RISCV_HEAP: [u8; 1024 * 1024] = [0; 1024 * 1024]; + /// A bump allocator suitable for use in a Wasm environment. pub struct BumpAllocator; @@ -146,15 +149,14 @@ impl InnerAlloc { Some(prev_page * PAGE_SIZE) } } else if #[cfg(target_arch = "riscv32")] { - const fn heap_start() -> usize { - // Placeholder value until we specified our riscv VM - 0x7000_0000 + fn heap_start() -> usize { + unsafe { + RISCV_HEAP.as_mut_ptr() as usize + } } - const fn heap_end() -> usize { - // Placeholder value until we specified our riscv VM - // Let's just assume a cool megabyte of mem for now - 0x7000_0400 + fn heap_end() -> usize { + Self::heap_start() + unsafe { RISCV_HEAP.len() } } fn request_pages(&mut self, _pages: usize) -> Option { diff --git a/crates/e2e/Cargo.toml b/crates/e2e/Cargo.toml index c1a43a79d60..fac65b83791 100644 --- a/crates/e2e/Cargo.toml +++ b/crates/e2e/Cargo.toml @@ -78,3 +78,7 @@ sandbox = [ "pallet-contracts-mock-network", "ink_e2e_macro/sandbox", ] +revive = [ + "ink/revive", + "ink_env/revive" +] diff --git a/crates/engine/Cargo.toml b/crates/engine/Cargo.toml index 015f3f01558..5afd2e36dc4 100644 --- a/crates/engine/Cargo.toml +++ b/crates/engine/Cargo.toml @@ -18,6 +18,7 @@ include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"] ink_primitives = { workspace = true } scale = { workspace = true } pallet-contracts-uapi = { workspace = true } +pallet-revive-uapi = { workspace = true } derive_more = { workspace = true, features = ["from", "display"] } sha2 = { workspace = true } @@ -32,6 +33,7 @@ default = [ "std" ] std = [ "ink_primitives/std", "scale/std", - "secp256k1", + "secp256k1", "derive_more/std" ] +revive = [] diff --git a/crates/engine/src/ext.rs b/crates/engine/src/ext.rs index fd94a70fcbb..976f891dffc 100644 --- a/crates/engine/src/ext.rs +++ b/crates/engine/src/ext.rs @@ -31,7 +31,10 @@ use crate::{ BlockTimestamp, }, }; +#[cfg(not(feature = "revive"))] pub use pallet_contracts_uapi::ReturnErrorCode as Error; +#[cfg(feature = "revive")] +pub use pallet_revive_uapi::ReturnErrorCode as Error; use scale::Encode; use std::panic::panic_any; @@ -320,6 +323,7 @@ impl Engine { set_output(output, &block_timestamp[..]) } + #[cfg(not(feature = "revive"))] pub fn gas_left(&self, _output: &mut &mut [u8]) { unimplemented!("off-chain environment does not yet support `gas_left`"); } diff --git a/crates/env/Cargo.toml b/crates/env/Cargo.toml index 50519619d94..ac23f175042 100644 --- a/crates/env/Cargo.toml +++ b/crates/env/Cargo.toml @@ -21,6 +21,7 @@ ink_storage_traits = { workspace = true } ink_prelude = { workspace = true } ink_primitives = { workspace = true } pallet-contracts-uapi = { workspace = true } +pallet-revive-uapi = { workspace = true } scale = { workspace = true, features = ["max-encoded-len"] } derive_more = { workspace = true, features = ["from", "display"] } @@ -31,10 +32,17 @@ static_assertions = { workspace = true } const_env = { workspace = true } xcm = { workspace = true } +# We add the `sp-io` here to disable those features +sp-io = { version = "38.0.0", default-features = false, features = ["disable_panic_handler", "disable_oom", "disable_allocator"] } + [target.'cfg(target_arch = "wasm32")'.dependencies] rlibc = "1" -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +[target.'cfg(target_arch = "riscv32")'.dependencies] +polkavm-derive = { workspace = true, default-features = false } + +# TODO +[target.'cfg(all(not(target_arch = "wasm32"), not(target_arch = "riscv32")))'.dependencies] ink_engine = { workspace = true, default-features = true, optional = true } # Hashes for the off-chain environment. @@ -74,6 +82,7 @@ std = [ "scale-info/std", "secp256k1", "schnorrkel", + "sp-io/std", "num-traits/std", # Enables hashing crates for off-chain environment. "sha2", @@ -92,3 +101,7 @@ no-allocator = [ "ink_allocator/no-allocator" ] # Disable the ink! provided panic handler. no-panic-handler = [] + +revive = [ + "ink_engine/revive" +] diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 0b563ad5b2d..dfd07fff13b 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -14,6 +14,11 @@ //! The public raw interface towards the host Wasm engine. +#[cfg(not(feature = "revive"))] +use crate::call::{ + CallV1, + LimitParamsV1, +}; use crate::{ backend::{ EnvBackend, @@ -22,12 +27,10 @@ use crate::{ call::{ Call, CallParams, - CallV1, ConstructorReturnType, CreateParams, DelegateCall, FromAccountId, - LimitParamsV1, LimitParamsV2, }, engine::{ @@ -44,7 +47,10 @@ use crate::{ Result, }; use ink_storage_traits::Storable; +#[cfg(not(feature = "revive"))] use pallet_contracts_uapi::ReturnFlags; +#[cfg(feature = "revive")] +use pallet_revive_uapi::ReturnFlags; /// Returns the address of the caller of the executed contract. /// @@ -93,6 +99,7 @@ where /// # Errors /// /// If the returned value cannot be properly decoded. +#[cfg(not(feature = "revive"))] pub fn gas_left() -> Gas where E: Environment, @@ -279,6 +286,7 @@ where /// - If the called contract execution has trapped. /// - If the called contract ran out of gas upon execution. /// - If the returned value failed to decode properly. +#[cfg(not(feature = "revive"))] pub fn invoke_contract_v1( params: &CallParams, Args, R>, ) -> Result> @@ -406,6 +414,7 @@ where /// - If the instantiation process runs out of gas. /// - If given insufficient endowment. /// - If the returned account ID failed to decode properly. +#[cfg(not(feature = "revive"))] pub fn instantiate_contract_v1( params: &CreateParams, ) -> Result< diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 8739bbe73ce..b3f09f6ff83 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -12,16 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[cfg(not(feature = "revive"))] +use crate::call::{ + CallV1, + LimitParamsV1, +}; use crate::{ call::{ Call, CallParams, - CallV1, ConstructorReturnType, CreateParams, DelegateCall, FromAccountId, - LimitParamsV1, LimitParamsV2, }, event::Event, @@ -33,7 +36,10 @@ use crate::{ Result, }; use ink_storage_traits::Storable; +#[cfg(not(feature = "revive"))] pub use pallet_contracts_uapi::ReturnFlags; +#[cfg(feature = "revive")] +pub use pallet_revive_uapi::ReturnFlags; /// Environmental contract functionality that does not require `Environment`. pub trait EnvBackend { @@ -245,6 +251,7 @@ pub trait TypedEnvBackend: EnvBackend { /// # Note /// /// For more details visit: [`gas_left`][`crate::gas_left`] + #[cfg(not(feature = "revive"))] fn gas_left(&mut self) -> u64; /// Returns the timestamp of the current block. @@ -300,6 +307,7 @@ pub trait TypedEnvBackend: EnvBackend { /// **This will call into the original `call` host function.** /// /// For more details visit: [`invoke_contract`][`crate::invoke_contract_v1`] + #[cfg(not(feature = "revive"))] fn invoke_contract_v1( &mut self, call_data: &CallParams, Args, R>, @@ -360,6 +368,7 @@ pub trait TypedEnvBackend: EnvBackend { Salt: AsRef<[u8]>, R: ConstructorReturnType; + #[cfg(not(feature = "revive"))] fn instantiate_contract_v1( &mut self, params: &CreateParams, diff --git a/crates/env/src/call/call_builder/call.rs b/crates/env/src/call/call_builder/call.rs index 087d700a61f..1f69556972d 100644 --- a/crates/env/src/call/call_builder/call.rs +++ b/crates/env/src/call/call_builder/call.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[cfg(not(feature = "revive"))] +use crate::call::CallV1; use crate::{ call::{ common::{ @@ -22,7 +24,6 @@ use crate::{ execution::EmptyArgumentList, CallBuilder, CallParams, - CallV1, ExecutionInput, }, Environment, @@ -30,7 +31,10 @@ use crate::{ Gas, }; use num_traits::Zero; +#[cfg(not(feature = "revive"))] use pallet_contracts_uapi::CallFlags; +#[cfg(feature = "revive")] +use pallet_revive_uapi::CallFlags; /// The default call type for cross-contract calls, for calling into the latest `call_v2` /// host function. This adds the additional weight limit parameter `proof_size_limit` as @@ -68,6 +72,7 @@ where /// /// This method instance is used to allow usage of the generated call builder methods /// for messages which initialize the builder with the new [`Call`] type. + #[cfg(not(feature = "revive"))] pub fn call_v1(self) -> CallBuilder>, Args, RetType> { let call_type = self.call_type.value(); CallBuilder { diff --git a/crates/env/src/call/call_builder/call_v1.rs b/crates/env/src/call/call_builder/call_v1.rs index e3563d1bb1d..484d31bd72c 100644 --- a/crates/env/src/call/call_builder/call_v1.rs +++ b/crates/env/src/call/call_builder/call_v1.rs @@ -29,7 +29,10 @@ use crate::{ Gas, }; use num_traits::Zero; +#[cfg(not(feature = "revive"))] use pallet_contracts_uapi::CallFlags; +#[cfg(feature = "revive")] +use pallet_revive_uapi::CallFlags; /// The legacy call type for cross-contract calls. Performs a cross-contract call to /// `callee` with gas limit `gas_limit`, transferring `transferred_value` of currency. diff --git a/crates/env/src/call/call_builder/delegate.rs b/crates/env/src/call/call_builder/delegate.rs index 9473432e714..c78d5e8d8b9 100644 --- a/crates/env/src/call/call_builder/delegate.rs +++ b/crates/env/src/call/call_builder/delegate.rs @@ -27,7 +27,10 @@ use crate::{ Environment, Error, }; +#[cfg(not(feature = "revive"))] use pallet_contracts_uapi::CallFlags; +#[cfg(feature = "revive")] +use pallet_revive_uapi::CallFlags; /// The `delegatecall` call type. Performs a call with the given code hash. #[derive(Clone)] diff --git a/crates/env/src/call/call_builder/mod.rs b/crates/env/src/call/call_builder/mod.rs index bc9acaead7c..395239c2e09 100644 --- a/crates/env/src/call/call_builder/mod.rs +++ b/crates/env/src/call/call_builder/mod.rs @@ -13,10 +13,12 @@ // limitations under the License. mod call; +#[cfg(not(feature = "revive"))] mod call_v1; mod delegate; pub use call::Call; +#[cfg(not(feature = "revive"))] pub use call_v1::CallV1; pub use delegate::DelegateCall; @@ -316,6 +318,7 @@ where { /// Prepares the `CallBuilder` for a cross-contract [`CallV1`], calling into the /// original `call` host function. + #[cfg(not(feature = "revive"))] pub fn call_v1( self, callee: E::AccountId, diff --git a/crates/env/src/call/create_builder.rs b/crates/env/src/call/create_builder.rs index 34a17dd76d6..2b17eb577d4 100644 --- a/crates/env/src/call/create_builder.rs +++ b/crates/env/src/call/create_builder.rs @@ -337,6 +337,7 @@ where } } +#[cfg(not(feature = "revive"))] impl CreateParams where @@ -920,6 +921,7 @@ where } } +#[cfg(not(feature = "revive"))] impl CreateBuilder< E, diff --git a/crates/env/src/call/mod.rs b/crates/env/src/call/mod.rs index 59156e23950..b3922cb8378 100644 --- a/crates/env/src/call/mod.rs +++ b/crates/env/src/call/mod.rs @@ -39,13 +39,17 @@ pub mod utils { }; } +#[cfg(not(feature = "revive"))] +pub use self::{ + call_builder::CallV1, + create_builder::LimitParamsV1 +}; pub use self::{ call_builder::{ build_call, Call, CallBuilder, CallParams, - CallV1, DelegateCall, }, create_builder::{ @@ -55,7 +59,6 @@ pub use self::{ CreateBuilder, CreateParams, FromAccountId, - LimitParamsV1, LimitParamsV2, }, execution::{ diff --git a/crates/env/src/engine/mod.rs b/crates/env/src/engine/mod.rs index 08a72ff4379..8cb83f551cd 100644 --- a/crates/env/src/engine/mod.rs +++ b/crates/env/src/engine/mod.rs @@ -30,7 +30,10 @@ use ink_primitives::{ LangError, }; +#[cfg(not(feature = "revive"))] use pallet_contracts_uapi::ReturnErrorCode; +#[cfg(feature = "revive")] +use pallet_revive_uapi::ReturnErrorCode; /// Convert a slice into an array reference. /// diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index afca3fe8624..9f1e0718c90 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -13,16 +13,19 @@ // limitations under the License. use super::EnvInstance; +#[cfg(not(feature = "revive"))] +use crate::call::{ + CallV1, + LimitParamsV1, +}; use crate::{ call::{ Call, CallParams, - CallV1, ConstructorReturnType, CreateParams, DelegateCall, FromAccountId, - LimitParamsV1, LimitParamsV2, }, event::{ @@ -48,10 +51,16 @@ use ink_storage_traits::{ decode_all, Storable, }; +#[cfg(not(feature = "revive"))] use pallet_contracts_uapi::{ ReturnErrorCode, ReturnFlags, }; +#[cfg(feature = "revive")] +use pallet_revive_uapi::{ + ReturnErrorCode, + ReturnFlags, +}; use schnorrkel::{ PublicKey, Signature, @@ -386,6 +395,7 @@ impl TypedEnvBackend for EnvInstance { }) } + #[cfg(not(feature = "revive"))] fn gas_left(&mut self) -> u64 { self.get_property::(Engine::gas_left) .unwrap_or_else(|error| { @@ -439,6 +449,7 @@ impl TypedEnvBackend for EnvInstance { self.engine.deposit_event(&enc_topics[..], enc_data); } + #[cfg(not(feature = "revive"))] fn invoke_contract_v1( &mut self, _params: &CallParams, Args, R>, @@ -503,6 +514,7 @@ impl TypedEnvBackend for EnvInstance { unimplemented!("off-chain environment does not support contract instantiation") } + #[cfg(not(feature = "revive"))] fn instantiate_contract_v1( &mut self, params: &CreateParams, diff --git a/crates/env/src/engine/on_chain/impls/mod.rs b/crates/env/src/engine/on_chain/impls/mod.rs new file mode 100644 index 00000000000..56a0bd1c4a9 --- /dev/null +++ b/crates/env/src/engine/on_chain/impls/mod.rs @@ -0,0 +1,5 @@ +#[cfg(target_arch = "wasm32")] +mod pallet_contracts; + +#[cfg(target_arch = "riscv32")] +mod pallet_revive; diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls/pallet_contracts.rs similarity index 99% rename from crates/env/src/engine/on_chain/impls.rs rename to crates/env/src/engine/on_chain/impls/pallet_contracts.rs index 27d465b0da9..1bb27d193a6 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls/pallet_contracts.rs @@ -12,10 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::{ - EnvInstance, - ScopedBuffer, -}; use crate::{ call::{ Call, @@ -28,6 +24,13 @@ use crate::{ LimitParamsV1, LimitParamsV2, }, + engine::{ + on_chain::{ + EncodeScope, + ScopedBuffer, + }, + EnvInstance, + }, event::{ Event, TopicsBuilderBackend, @@ -277,7 +280,7 @@ impl EnvBackend for EnvInstance { where R: scale::Encode, { - let mut scope = super::EncodeScope::from(&mut self.buffer[..]); + let mut scope = EncodeScope::from(&mut self.buffer[..]); return_value.encode_to(&mut scope); let len = scope.len(); ext::return_value(flags, &self.buffer[..][..len]); diff --git a/crates/env/src/engine/on_chain/impls/pallet_revive.rs b/crates/env/src/engine/on_chain/impls/pallet_revive.rs new file mode 100644 index 00000000000..8a15edd1eaf --- /dev/null +++ b/crates/env/src/engine/on_chain/impls/pallet_revive.rs @@ -0,0 +1,742 @@ +// Copyright (C) Use Ink (UK) Ltd. +// +// 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 crate::{ + call::{ + Call, + CallParams, + ConstructorReturnType, + CreateParams, + DelegateCall, + FromAccountId, + LimitParamsV2, + }, + engine::on_chain::{ + EncodeScope, + EnvInstance, + ScopedBuffer, + }, + event::{ + Event, + TopicsBuilderBackend, + }, + hash::{ + Blake2x128, + Blake2x256, + CryptoHash, + HashOutput, + Keccak256, + Sha2x256, + }, + Clear, + EnvBackend, + Environment, + FromLittleEndian, + Result, + TypedEnvBackend, +}; +use ink_storage_traits::{ + decode_all, + Storable, +}; +use pallet_revive_uapi::{ + CallFlags, + HostFn, + HostFnImpl as ext, + ReturnErrorCode, + ReturnFlags, + StorageFlags, +}; +use xcm::VersionedXcm; + +impl CryptoHash for Blake2x128 { + fn hash(input: &[u8], output: &mut ::Type) { + type OutputType = [u8; 16]; + static_assertions::assert_type_eq_all!( + ::Type, + OutputType + ); + let output: &mut OutputType = array_mut_ref!(output, 0, 16); + ext::hash_blake2_128(input, output); + } +} + +impl CryptoHash for Blake2x256 { + fn hash(input: &[u8], output: &mut ::Type) { + type OutputType = [u8; 32]; + static_assertions::assert_type_eq_all!( + ::Type, + OutputType + ); + let output: &mut OutputType = array_mut_ref!(output, 0, 32); + ext::hash_blake2_256(input, output); + } +} + +impl CryptoHash for Sha2x256 { + fn hash(input: &[u8], output: &mut ::Type) { + type OutputType = [u8; 32]; + static_assertions::assert_type_eq_all!( + ::Type, + OutputType + ); + let output: &mut OutputType = array_mut_ref!(output, 0, 32); + ext::hash_sha2_256(input, output); + } +} + +impl CryptoHash for Keccak256 { + fn hash(input: &[u8], output: &mut ::Type) { + type OutputType = [u8; 32]; + static_assertions::assert_type_eq_all!( + ::Type, + OutputType + ); + let output: &mut OutputType = array_mut_ref!(output, 0, 32); + ext::hash_keccak_256(input, output); + } +} + +pub struct TopicsBuilder<'a, E> { + scoped_buffer: ScopedBuffer<'a>, + marker: core::marker::PhantomData E>, +} + +impl<'a, E> From> for TopicsBuilder<'a, E> +where + E: Environment, +{ + fn from(scoped_buffer: ScopedBuffer<'a>) -> Self { + Self { + scoped_buffer, + marker: Default::default(), + } + } +} + +impl<'a, E> TopicsBuilderBackend for TopicsBuilder<'a, E> +where + E: Environment, +{ + type Output = (ScopedBuffer<'a>, &'a mut [u8]); + + fn expect(&mut self, expected_topics: usize) { + self.scoped_buffer + .append_encoded(&scale::Compact(expected_topics as u32)); + } + + fn push_topic(&mut self, topic_value: &T) + where + T: scale::Encode, + { + fn inner(encoded: &mut [u8]) -> ::Hash { + let len_encoded = encoded.len(); + let mut result = ::Hash::CLEAR_HASH; + let len_result = result.as_ref().len(); + if len_encoded <= len_result { + result.as_mut()[..len_encoded].copy_from_slice(encoded); + } else { + let mut hash_output = ::Type::default(); + ::hash(encoded, &mut hash_output); + let copy_len = core::cmp::min(hash_output.len(), len_result); + result.as_mut()[0..copy_len].copy_from_slice(&hash_output[0..copy_len]); + } + result + } + + let mut split = self.scoped_buffer.split(); + let encoded = split.take_encoded(topic_value); + let result = inner::(encoded); + self.scoped_buffer.append_encoded(&result); + } + + fn output(mut self) -> Self::Output { + let encoded_topics = self.scoped_buffer.take_appended(); + (self.scoped_buffer, encoded_topics) + } +} + +impl EnvInstance { + #[inline(always)] + /// Returns a new scoped buffer for the entire scope of the static 16 kB buffer. + fn scoped_buffer(&mut self) -> ScopedBuffer { + ScopedBuffer::from(&mut self.buffer[..]) + } + + /// Returns the contract property value from its little-endian representation. + /// + /// # Note + /// + /// This skips the potentially costly decoding step that is often equivalent to a + /// `memcpy`. + #[inline(always)] + fn get_property_little_endian(&mut self, ext_fn: fn(output: &mut [u8; 32])) -> T + where + T: FromLittleEndian, + { + let mut scope = self.scoped_buffer(); + let u256: &mut [u8; 32] = scope.take(32).try_into().unwrap(); + ext_fn(u256); + let mut result = ::Bytes::default(); + let len = result.as_ref().len(); + result.as_mut()[..].copy_from_slice(&u256[..len]); + ::from_le_bytes(result) + } + + /// Returns the contract property value. + #[inline(always)] + fn get_property(&mut self, ext_fn: fn(output: &mut &mut [u8])) -> Result + where + T: scale::Decode, + { + let full_scope = &mut self.scoped_buffer().take_rest(); + ext_fn(full_scope); + scale::Decode::decode(&mut &full_scope[..]).map_err(Into::into) + } +} + +const STORAGE_FLAGS: StorageFlags = StorageFlags::empty(); + +impl EnvBackend for EnvInstance { + fn set_contract_storage(&mut self, key: &K, value: &V) -> Option + where + K: scale::Encode, + V: Storable, + { + let mut buffer = self.scoped_buffer(); + let key = buffer.take_encoded(key); + let value = buffer.take_storable_encoded(value); + ext::set_storage(STORAGE_FLAGS, key, value) + } + + fn get_contract_storage(&mut self, key: &K) -> Result> + where + K: scale::Encode, + R: Storable, + { + let mut buffer = self.scoped_buffer(); + let key = buffer.take_encoded(key); + let output = &mut buffer.take_rest(); + match ext::get_storage(STORAGE_FLAGS, key, output) { + Ok(_) => (), + Err(ReturnErrorCode::KeyNotFound) => return Ok(None), + Err(_) => panic!("encountered unexpected error"), + } + let decoded = decode_all(&mut &output[..])?; + Ok(Some(decoded)) + } + + fn take_contract_storage(&mut self, key: &K) -> Result> + where + K: scale::Encode, + R: Storable, + { + let mut buffer = self.scoped_buffer(); + let key = buffer.take_encoded(key); + let output = &mut buffer.take_rest(); + match ext::take_storage(STORAGE_FLAGS, key, output) { + Ok(_) => (), + Err(ReturnErrorCode::KeyNotFound) => return Ok(None), + Err(_) => panic!("encountered unexpected error"), + } + let decoded = decode_all(&mut &output[..])?; + Ok(Some(decoded)) + } + + fn contains_contract_storage(&mut self, key: &K) -> Option + where + K: scale::Encode, + { + let mut buffer = self.scoped_buffer(); + let key = buffer.take_encoded(key); + ext::contains_storage(STORAGE_FLAGS, key) + } + + fn clear_contract_storage(&mut self, key: &K) -> Option + where + K: scale::Encode, + { + let mut buffer = self.scoped_buffer(); + let key = buffer.take_encoded(key); + ext::clear_storage(STORAGE_FLAGS, key) + } + + fn decode_input(&mut self) -> Result + where + T: scale::Decode, + { + self.get_property::(ext::input) + } + + fn return_value(&mut self, flags: ReturnFlags, return_value: &R) -> ! + where + R: scale::Encode, + { + let mut scope = EncodeScope::from(&mut self.buffer[..]); + return_value.encode_to(&mut scope); + let len = scope.len(); + ext::return_value(flags, &self.buffer[..][..len]); + } + + #[cfg(not(feature = "ink-debug"))] + /// A no-op. Enable the `ink-debug` feature for debug messages. + fn debug_message(&mut self, _content: &str) {} + + #[cfg(feature = "ink-debug")] + fn debug_message(&mut self, content: &str) { + static mut DEBUG_ENABLED: bool = false; + static mut FIRST_RUN: bool = true; + + // SAFETY: safe because executing in a single threaded context + // We need those two variables in order to make sure that the assignment is + // performed in the "logging enabled" case. This is because during RPC + // execution logging might be enabled while it is disabled during the + // actual execution as part of a transaction. The gas estimation takes + // place during RPC execution. We want to overestimate instead + // of underestimate gas usage. Otherwise using this estimate could lead to a out + // of gas error. + if unsafe { DEBUG_ENABLED || FIRST_RUN } { + let ret_code = ext::debug_message(content.as_bytes()); + if !matches!(ret_code, Err(ReturnErrorCode::LoggingDisabled)) { + // SAFETY: safe because executing in a single threaded context + unsafe { DEBUG_ENABLED = true } + } + // SAFETY: safe because executing in a single threaded context + unsafe { FIRST_RUN = false } + } + } + + fn hash_bytes(&mut self, input: &[u8], output: &mut ::Type) + where + H: CryptoHash, + { + ::hash(input, output) + } + + fn hash_encoded(&mut self, input: &T, output: &mut ::Type) + where + H: CryptoHash, + T: scale::Encode, + { + let mut scope = self.scoped_buffer(); + let enc_input = scope.take_encoded(input); + ::hash(enc_input, output) + } + + fn ecdsa_recover( + &mut self, + signature: &[u8; 65], + message_hash: &[u8; 32], + output: &mut [u8; 33], + ) -> Result<()> { + ext::ecdsa_recover(signature, message_hash, output).map_err(Into::into) + } + + fn ecdsa_to_eth_address( + &mut self, + pubkey: &[u8; 33], + output: &mut [u8; 20], + ) -> Result<()> { + ext::ecdsa_to_eth_address(pubkey, output).map_err(Into::into) + } + + fn sr25519_verify( + &mut self, + signature: &[u8; 64], + message: &[u8], + pub_key: &[u8; 32], + ) -> Result<()> { + ext::sr25519_verify(signature, message, pub_key).map_err(Into::into) + } + + fn call_chain_extension( + &mut self, + id: u32, + input: &I, + status_to_result: F, + decode_to_result: D, + ) -> ::core::result::Result + where + I: scale::Encode, + T: scale::Decode, + E: From, + F: FnOnce(u32) -> ::core::result::Result<(), ErrorCode>, + D: FnOnce(&[u8]) -> ::core::result::Result, + { + let mut scope = self.scoped_buffer(); + let enc_input = scope.take_encoded(input); + let output = &mut scope.take_rest(); + status_to_result(ext::call_chain_extension(id, enc_input, Some(output)))?; + let decoded = decode_to_result(output)?; + Ok(decoded) + } + + fn set_code_hash(&mut self, code_hash_ptr: &[u8]) -> Result<()> { + let code_hash: &[u8; 32] = code_hash_ptr.try_into().unwrap(); + ext::set_code_hash(code_hash).map_err(Into::into) + } +} + +impl TypedEnvBackend for EnvInstance { + fn caller(&mut self) -> E::AccountId { + let mut scope = self.scoped_buffer(); + + let h160: &mut [u8; 20] = scope.take(20).try_into().unwrap(); + ext::caller(h160); + + let account_id: &mut [u8; 32] = scope.take(32).try_into().unwrap(); + // TODO + // ext::to_account_id(h160, account_id); + + scale::Decode::decode(&mut &account_id[..]) + .expect("The executed contract must have a caller with a valid account id.") + } + + fn transferred_value(&mut self) -> E::Balance { + self.get_property_little_endian::(ext::value_transferred) + } + + // fn gas_left(&mut self) -> u64 { + // self.get_property_little_endian::(ext::gas_left) + // } + + fn block_timestamp(&mut self) -> E::Timestamp { + self.get_property_little_endian::(ext::now) + } + + fn account_id(&mut self) -> E::AccountId { + let mut scope = self.scoped_buffer(); + + let account_id: &mut [u8; 32] = scope.take(32).try_into().unwrap(); + account_id[20..].fill(0xEE); + let h160: &mut [u8; 20] = account_id[..20].as_mut().try_into().unwrap(); + ext::address(h160); + + scale::Decode::decode(&mut &account_id[..]) + .expect("A contract being executed must have a valid account id.") + } + + fn balance(&mut self) -> E::Balance { + self.get_property_little_endian::(ext::balance) + } + + fn block_number(&mut self) -> E::BlockNumber { + self.get_property_little_endian::(ext::block_number) + } + + fn minimum_balance(&mut self) -> E::Balance { + self.get_property_little_endian::(ext::minimum_balance) + } + + fn emit_event(&mut self, event: Evt) + where + E: Environment, + Evt: Event, + { + let (mut scope, enc_topics) = + event.topics::(TopicsBuilder::from(self.scoped_buffer()).into()); + // TODO: improve + let enc_topics = &enc_topics + .chunks_exact(32) + .map(|c| c.try_into().unwrap()) + .collect::>(); + let enc_data = scope.take_encoded(&event); + ext::deposit_event(enc_topics, enc_data); + } + + fn invoke_contract( + &mut self, + params: &CallParams, Args, R>, + ) -> Result> + where + E: Environment, + Args: scale::Encode, + R: scale::Decode, + { + let mut scope = self.scoped_buffer(); + let ref_time_limit = params.ref_time_limit(); + let proof_size_limit = params.proof_size_limit(); + let storage_deposit_limit = params.storage_deposit_limit().map(|limit| { + let mut enc_storage_limit = EncodeScope::from(scope.take(32)); + scale::Encode::encode_to(&limit, &mut enc_storage_limit); + let enc_storage_limit: &mut [u8; 32] = + enc_storage_limit.into_buffer().try_into().unwrap(); + enc_storage_limit + }); + let enc_callee: &[u8; 20] = params.callee().as_ref().try_into().unwrap(); + let mut enc_transferred_value = EncodeScope::from(scope.take(32)); + scale::Encode::encode_to(¶ms.transferred_value(), &mut enc_transferred_value); + let enc_transferred_value: &mut [u8; 32] = + enc_transferred_value.into_buffer().try_into().unwrap(); + let call_flags = params.call_flags(); + let enc_input = if !call_flags.contains(CallFlags::FORWARD_INPUT) + && !call_flags.contains(CallFlags::CLONE_INPUT) + { + scope.take_encoded(params.exec_input()) + } else { + &mut [] + }; + let output = &mut scope.take_rest(); + let flags = params.call_flags(); + #[allow(deprecated)] + let call_result = ext::call( + *flags, + enc_callee, + ref_time_limit, + proof_size_limit, + storage_deposit_limit.as_deref(), + enc_transferred_value, + enc_input, + Some(output), + ); + match call_result { + Ok(()) | Err(ReturnErrorCode::CalleeReverted) => { + let decoded = scale::DecodeAll::decode_all(&mut &output[..])?; + Ok(decoded) + } + Err(actual_error) => Err(actual_error.into()), + } + } + + fn invoke_contract_delegate( + &mut self, + _params: &CallParams, Args, R>, + ) -> Result> + where + E: Environment, + Args: scale::Encode, + R: scale::Decode, + { + todo!("has to be implemented") + } + + fn instantiate_contract( + &mut self, + params: &CreateParams, Args, Salt, RetType>, + ) -> Result< + ink_primitives::ConstructorResult< + >::Output, + >, + > + where + E: Environment, + ContractRef: FromAccountId, + Args: scale::Encode, + Salt: AsRef<[u8]>, + RetType: ConstructorReturnType, + { + let mut scoped = self.scoped_buffer(); + let ref_time_limit = params.ref_time_limit(); + let proof_size_limit = params.proof_size_limit(); + let storage_deposit_limit = params.storage_deposit_limit().map(|limit| { + let mut enc_storage_limit = EncodeScope::from(scoped.take(32)); + scale::Encode::encode_to(&limit, &mut enc_storage_limit); + let enc_storage_limit: &mut [u8; 32] = + enc_storage_limit.into_buffer().try_into().unwrap(); + enc_storage_limit + }); + let enc_code_hash: &mut [u8; 32] = + scoped.take_encoded(params.code_hash()).try_into().unwrap(); + let mut enc_endowment = EncodeScope::from(scoped.take(32)); + scale::Encode::encode_to(¶ms.endowment(), &mut enc_endowment); + let enc_endowment: &mut [u8; 32] = + enc_endowment.into_buffer().try_into().unwrap(); + let enc_input = scoped.take_encoded(params.exec_input()); + let out_address: &mut [u8; 20] = scoped.take(20).try_into().unwrap(); + let salt: &[u8; 32] = params.salt_bytes().as_ref().try_into().unwrap(); + let out_return_value = &mut scoped.take_rest(); + + let instantiate_result = ext::instantiate( + enc_code_hash, + ref_time_limit, + proof_size_limit, + storage_deposit_limit.as_deref(), + enc_endowment, + enc_input, + Some(out_address), + Some(out_return_value), + Some(salt), + ); + + crate::engine::decode_instantiate_result::<_, E, ContractRef, RetType>( + instantiate_result.map_err(Into::into), + &mut &out_address[..], + &mut &out_return_value[..], + ) + } + + fn terminate_contract(&mut self, beneficiary: E::AccountId) -> ! + where + E: Environment, + { + let buffer: &mut [u8; 20] = self.scoped_buffer().take_encoded(&beneficiary) + [0..20] + .as_mut() + .try_into() + .unwrap(); + ext::terminate(buffer); + } + + fn transfer( + &mut self, + _destination: E::AccountId, + _value: E::Balance, + ) -> Result<()> + where + E: Environment, + { + todo!("has to be implemented") + } + + fn weight_to_fee(&mut self, gas: u64) -> E::Balance { + let mut scope = self.scoped_buffer(); + let u256: &mut [u8; 32] = scope.take(32).try_into().unwrap(); + // TODO: needs ref and proof + ext::weight_to_fee(gas, gas, u256); + let mut result = ::Bytes::default(); + let len = result.as_ref().len(); + result.as_mut().copy_from_slice(&u256[..len]); + ::from_le_bytes(result) + } + + fn is_contract(&mut self, account_id: &E::AccountId) -> bool + where + E: Environment, + { + let mut scope = self.scoped_buffer(); + let enc_account_id: &mut [u8; 20] = scope.take_encoded(account_id)[..20] + .as_mut() + .try_into() + .unwrap(); + ext::is_contract(enc_account_id) + } + + fn caller_is_origin(&mut self) -> bool + where + E: Environment, + { + ext::caller_is_origin() + } + + fn caller_is_root(&mut self) -> bool + where + E: Environment, + { + // `ext::caller_is_root()` currently returns `u32`. + // See https://github.com/paritytech/polkadot-sdk/issues/6767 for more details. + let ret = ext::caller_is_root(); + match ret { + 0u32 => false, + 1u32 => true, + _ => panic!("Invalid value for bool conversion: {}", ret), + } + } + + fn code_hash(&mut self, account_id: &E::AccountId) -> Result + where + E: Environment, + { + let mut scope = self.scoped_buffer(); + let enc_account_id: &mut [u8; 20] = scope.take_encoded(account_id)[..20] + .as_mut() + .try_into() + .unwrap(); + let output: &mut [u8; 32] = + scope.take_max_encoded_len::().try_into().unwrap(); + // TODO + // ext::code_hash(enc_account_id, output)?; + ext::code_hash(enc_account_id, output); + let hash = scale::Decode::decode(&mut &output[..])?; + Ok(hash) + } + + fn own_code_hash(&mut self) -> Result + where + E: Environment, + { + let output: &mut [u8; 32] = &mut self + .scoped_buffer() + .take_max_encoded_len::() + .try_into() + .unwrap(); + ext::own_code_hash(output); + let hash = scale::Decode::decode(&mut &output[..])?; + Ok(hash) + } + + fn call_runtime(&mut self, call: &Call) -> Result<()> + where + E: Environment, + Call: scale::Encode, + { + let mut scope = self.scoped_buffer(); + let enc_call = scope.take_encoded(call); + ext::call_runtime(enc_call).map_err(Into::into) + } + + fn lock_delegate_dependency(&mut self, code_hash: &E::Hash) + where + E: Environment, + { + let mut scope = self.scoped_buffer(); + let enc_code_hash: &mut [u8; 32] = + scope.take_encoded(code_hash).try_into().unwrap(); + ext::lock_delegate_dependency(enc_code_hash) + } + + fn unlock_delegate_dependency(&mut self, code_hash: &E::Hash) + where + E: Environment, + { + let mut scope = self.scoped_buffer(); + let enc_code_hash: &mut [u8; 32] = + scope.take_encoded(code_hash).try_into().unwrap(); + ext::unlock_delegate_dependency(enc_code_hash) + } + + fn xcm_execute(&mut self, msg: &VersionedXcm) -> Result<()> + where + E: Environment, + Call: scale::Encode, + { + let mut scope = self.scoped_buffer(); + + let enc_msg = scope.take_encoded(msg); + + #[allow(deprecated)] + ext::xcm_execute(enc_msg).map_err(Into::into) + } + + fn xcm_send( + &mut self, + dest: &xcm::VersionedLocation, + msg: &VersionedXcm, + ) -> Result + where + E: Environment, + Call: scale::Encode, + { + let mut scope = self.scoped_buffer(); + let output = scope.take(32); + scope.append_encoded(dest); + let enc_dest = scope.take_appended(); + + scope.append_encoded(msg); + let enc_msg = scope.take_appended(); + #[allow(deprecated)] + ext::xcm_send(enc_dest, enc_msg, output.try_into().unwrap())?; + let hash: xcm::v4::XcmHash = scale::Decode::decode(&mut &output[..])?; + Ok(hash) + } +} diff --git a/crates/env/src/error.rs b/crates/env/src/error.rs index 500e0adcf67..195e3978f03 100644 --- a/crates/env/src/error.rs +++ b/crates/env/src/error.rs @@ -16,7 +16,10 @@ use derive_more::From; #[cfg(any(feature = "std", test, doc))] use crate::engine::off_chain::OffChainError; +#[cfg(not(feature = "revive"))] use pallet_contracts_uapi::ReturnErrorCode; +#[cfg(feature = "revive")] +use pallet_revive_uapi::ReturnErrorCode; /// Errors that can be encountered upon environmental interaction. #[derive(Debug, From, PartialEq, Eq)] diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 7c3931ab6cc..eff8fec1aac 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -102,12 +102,20 @@ mod tests; #[doc(inline)] pub use self::engine::off_chain::test_api as test; +#[cfg(not(feature = "revive"))] #[doc(inline)] pub use pallet_contracts_uapi::{ CallFlags, ReturnErrorCode, ReturnFlags, }; +#[cfg(feature = "revive")] +#[doc(inline)] +pub use pallet_revive_uapi::{ + CallFlags, + ReturnErrorCode, + ReturnFlags, +}; use self::backend::{ EnvBackend, diff --git a/crates/ink/Cargo.toml b/crates/ink/Cargo.toml index 500f965dd22..c1b07ea42c3 100644 --- a/crates/ink/Cargo.toml +++ b/crates/ink/Cargo.toml @@ -23,10 +23,16 @@ ink_metadata = { workspace = true, optional = true } ink_prelude = { workspace = true } ink_macro = { workspace = true } pallet-contracts-uapi = { workspace = true } +pallet-revive-uapi = { workspace = true } scale = { workspace = true } scale-info = { workspace = true, default-features = false, features = ["derive"], optional = true } derive_more = { workspace = true, features = ["from"] } -xcm = { workspace = true} + +# TODO add explainer +xcm = { workspace = true, default-features = false } +sp-io = { version = "38.0.0", default-features = false, features = ["disable_panic_handler", "disable_oom", "disable_allocator"] } + +polkavm-derive = { workspace = true } [dev-dependencies] ink_ir = { workspace = true, default-features = true } @@ -45,7 +51,8 @@ std = [ "scale-info/std", "scale/std", "xcm/std", - "derive_more/std" + "derive_more/std", + "sp-io/std" ] # Enable contract debug messages via `debug_print!` and `debug_println!`. ink-debug = [ "ink_env/ink-debug" ] @@ -57,3 +64,9 @@ no-allocator = [ "ink_env/no-allocator" ] # Disable the ink! provided panic handler. no-panic-handler = ["ink_env/no-panic-handler"] + +revive = [ + "ink_env/revive", + "ink_storage/revive", + "ink_macro/revive" +] diff --git a/crates/ink/codegen/Cargo.toml b/crates/ink/codegen/Cargo.toml index 445cdac7015..bb05d9d94b2 100644 --- a/crates/ink/codegen/Cargo.toml +++ b/crates/ink/codegen/Cargo.toml @@ -34,6 +34,8 @@ impl-serde = { workspace = true, default-features = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } +polkavm-derive = { workspace = true } + [features] default = [ "std" ] std = [ @@ -45,3 +47,4 @@ std = [ "serde/std", "derive_more/std" ] +revive = [ ] diff --git a/crates/ink/codegen/src/generator/dispatch.rs b/crates/ink/codegen/src/generator/dispatch.rs index d3b56f14793..22e7bef18bd 100644 --- a/crates/ink/codegen/src/generator/dispatch.rs +++ b/crates/ink/codegen/src/generator/dispatch.rs @@ -83,16 +83,38 @@ impl GenerateCode for Dispatch<'_> { self.generate_constructor_decoder_type(&constructors); let message_decoder_type = self.generate_message_decoder_type(&messages); let entry_points = self.generate_entry_points(&constructors, &messages); - quote! { + + #[cfg(not(feature = "revive"))] + return quote! { #contract_dispatchable_constructor_infos #contract_dispatchable_messages_infos #constructor_decoder_type #message_decoder_type #[cfg(not(any(test, feature = "std", feature = "ink-as-dependency")))] + /* const _: () = { #entry_points - }; + } + */ + mod __do_not_access__ { + use super::*; + #entry_points + } + }; + + #[cfg(feature = "revive")] + quote! { + #contract_dispatchable_constructor_infos + #contract_dispatchable_messages_infos + #constructor_decoder_type + #message_decoder_type + + #[cfg(not(any(test, feature = "std", feature = "ink-as-dependency")))] + mod __do_not_access__ { + use super::*; + #entry_points + } } } } @@ -350,7 +372,9 @@ impl Dispatch<'_> { let any_constructor_accept_payment = self.any_constructor_accepts_payment(constructors); let any_message_accepts_payment = self.any_message_accepts_payment(messages); - quote_spanned!(span=> + + #[cfg(not(feature = "revive"))] + return quote_spanned!(span=> #[allow(clippy::nonminimal_bool)] fn internal_deploy() { if !#any_constructor_accept_payment { @@ -434,17 +458,102 @@ impl Dispatch<'_> { pub extern "C" fn deploy() { internal_deploy() } + ); + #[cfg(feature = "revive")] + let fn_call: syn::ItemFn = syn::parse_quote! { + #[cfg(any(target_arch = "wasm32", target_arch = "riscv32"))] + #[cfg_attr(target_arch = "wasm32", no_mangle)] + #[ink::polkavm_export(abi = ink::polkavm_derive::default_abi)] + pub extern "C" fn call() { + internal_call() + } + }; + #[cfg(feature = "revive")] + let fn_deploy: syn::ItemFn = syn::parse_quote! { + #[cfg(any(target_arch = "wasm32", target_arch = "riscv32"))] + #[cfg_attr(target_arch = "wasm32", no_mangle)] + #[ink::polkavm_export(abi = ink::polkavm_derive::default_abi)] + pub extern "C" fn deploy() { + internal_deploy() + } + }; + #[cfg(feature = "revive")] + quote_spanned!(span=> + #[allow(clippy::nonminimal_bool)] + fn internal_deploy() { + if !#any_constructor_accept_payment { + ::ink::codegen::deny_payment::<<#storage_ident as ::ink::env::ContractEnv>::Env>() + .unwrap_or_else(|error| ::core::panic!("{}", error)) + } - #[cfg(target_arch = "riscv32")] - #[no_mangle] - pub extern "C" fn _start(call_flags: u32) { - let is_deploy = (call_flags & 0x0000_0001) == 1; - if is_deploy { - internal_deploy() - } else { - internal_call() + let dispatchable = match ::ink::env::decode_input::< + <#storage_ident as ::ink::reflect::ContractConstructorDecoder>::Type, + >() { + ::core::result::Result::Ok(decoded_dispatchable) => { + decoded_dispatchable + } + ::core::result::Result::Err(_decoding_error) => { + let error = ::ink::ConstructorResult::Err(::ink::LangError::CouldNotReadInput); + + // At this point we're unable to set the `Ok` variant to be the any "real" + // constructor output since we were unable to figure out what the caller wanted + // to dispatch in the first place, so we set it to `()`. + // + // This is okay since we're going to only be encoding the `Err` variant + // into the output buffer anyways. + ::ink::env::return_value::<::ink::ConstructorResult<()>>( + ::ink::env::ReturnFlags::REVERT, + &error, + ); + } + }; + + <<#storage_ident as ::ink::reflect::ContractConstructorDecoder>::Type + as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(dispatchable) + .unwrap_or_else(|error| { + ::core::panic!("dispatching ink! message failed: {}", error) + }) + } + + #[allow(clippy::nonminimal_bool)] + fn internal_call() { + if !#any_message_accepts_payment { + ::ink::codegen::deny_payment::<<#storage_ident as ::ink::env::ContractEnv>::Env>() + .unwrap_or_else(|error| ::core::panic!("{}", error)) } + + let dispatchable = match ::ink::env::decode_input::< + <#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type, + >() { + ::core::result::Result::Ok(decoded_dispatchable) => { + decoded_dispatchable + } + ::core::result::Result::Err(_decoding_error) => { + let error = ::ink::MessageResult::Err(::ink::LangError::CouldNotReadInput); + + // At this point we're unable to set the `Ok` variant to be the any "real" + // message output since we were unable to figure out what the caller wanted + // to dispatch in the first place, so we set it to `()`. + // + // This is okay since we're going to only be encoding the `Err` variant + // into the output buffer anyways. + ::ink::env::return_value::<::ink::MessageResult<()>>( + ::ink::env::ReturnFlags::REVERT, + &error, + ); + } + }; + + <<#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type + as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(dispatchable) + .unwrap_or_else(|error| { + ::core::panic!("dispatching ink! message failed: {}", error) + }) } + + #fn_call + + #fn_deploy ) } diff --git a/crates/ink/macro/Cargo.toml b/crates/ink/macro/Cargo.toml index b58c5843060..678e8f84a57 100644 --- a/crates/ink/macro/Cargo.toml +++ b/crates/ink/macro/Cargo.toml @@ -46,3 +46,9 @@ std = [ "scale/std", "scale-info/std" ] +revive = [ + "ink/revive", + "ink_env/revive", + "ink_codegen/revive", + "ink_storage/revive" +] diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index c0229dc1e06..60439d63e2e 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -14,16 +14,19 @@ use crate::ChainExtensionInstance; use core::marker::PhantomData; +#[cfg(not(feature = "revive"))] +use ink_env::call::{ + CallV1, + LimitParamsV1, +}; use ink_env::{ call::{ Call, CallParams, - CallV1, ConstructorReturnType, CreateParams, DelegateCall, FromAccountId, - LimitParamsV1, LimitParamsV2, }, hash::{ @@ -33,7 +36,10 @@ use ink_env::{ Environment, Result, }; +#[cfg(not(feature = "revive"))] use pallet_contracts_uapi::ReturnErrorCode; +#[cfg(feature = "revive")] +use pallet_revive_uapi::ReturnErrorCode; /// The API behind the `self.env()` and `Self::env()` syntax in ink!. /// @@ -224,6 +230,7 @@ where /// # Note /// /// For more details visit: [`ink_env::gas_left`] + #[cfg(not(feature = "revive"))] pub fn gas_left(self) -> u64 { ink_env::gas_left::() } @@ -586,6 +593,7 @@ where /// /// For more details visit: [`ink_env::instantiate_contract_v1`] + #[cfg(not(feature = "revive"))] pub fn instantiate_contract_v1( self, params: &CreateParams, @@ -663,6 +671,7 @@ where /// # Note /// /// For more details visit: [`ink_env::invoke_contract_v1`] + #[cfg(not(feature = "revive"))] pub fn invoke_contract_v1( self, params: &CallParams, Args, R>, diff --git a/crates/ink/src/lib.rs b/crates/ink/src/lib.rs index 01698cd17e7..d60d7972c0a 100644 --- a/crates/ink/src/lib.rs +++ b/crates/ink/src/lib.rs @@ -46,6 +46,10 @@ pub use scale; pub use scale_info; pub use xcm; +pub extern crate polkavm_derive; +#[doc(hidden)] +pub use polkavm_derive::*; + pub mod storage { pub mod traits { pub use ink_macro::{ diff --git a/crates/ink/tests/ui/storage_item/fail/collections_only_packed_1.stderr b/crates/ink/tests/ui/storage_item/fail/collections_only_packed_1.stderr index 1921cf3e265..0f84d326b28 100644 --- a/crates/ink/tests/ui/storage_item/fail/collections_only_packed_1.stderr +++ b/crates/ink/tests/ui/storage_item/fail/collections_only_packed_1.stderr @@ -49,6 +49,156 @@ error[E0277]: the trait bound `[NonPacked]: Encode` is not satisfied | 10 | struct Contract { | ^^^^^^^^ the trait `Encode` is not implemented for `[NonPacked]`, which is required by `Contract: Sized` + | + = help: the following other types implement trait `Encode`: + [T; N] + [T] + = note: required for `Vec` to implement `Encode` + = note: required for `Vec` to implement `Packed` + = note: required for `Vec` to implement `StorableHint<()>` + = note: required for `Vec` to implement `AutoStorableHint>` +note: required because it appears within the type `Contract` + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ +note: required by a bound in `ink_storage::ink_storage_traits::StorableHint::Type` + --> $WORKSPACE/crates/storage/traits/src/storage.rs + | + | type Type: Storable; + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `StorableHint::Type` + +error[E0277]: the trait bound `Vec: ink::parity_scale_codec::Decode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ the trait `ink::parity_scale_codec::Decode` is not implemented for `Vec`, which is required by `Contract: Sized` + | + = help: the trait `ink::parity_scale_codec::Decode` is implemented for `Vec` + = note: required for `Vec` to implement `Packed` + = note: required for `Vec` to implement `StorableHint<()>` + = note: required for `Vec` to implement `AutoStorableHint>` +note: required because it appears within the type `Contract` + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ +note: required by a bound in `Storable` + --> $WORKSPACE/crates/storage/traits/src/storage.rs + | + | pub trait Storable: Sized { + | ^^^^^ required by this bound in `Storable` + +error[E0277]: the trait bound `[NonPacked]: Encode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ the trait `Encode` is not implemented for `[NonPacked]`, which is required by `Contract: Sized` + | + = help: the following other types implement trait `Encode`: + [T; N] + [T] + = note: required for `Vec` to implement `Encode` + = note: required for `Vec` to implement `Packed` + = note: required for `Vec` to implement `StorableHint<()>` + = note: required for `Vec` to implement `AutoStorableHint>` +note: required because it appears within the type `Contract` + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ +note: required by a bound in `Storable` + --> $WORKSPACE/crates/storage/traits/src/storage.rs + | + | pub trait Storable: Sized { + | ^^^^^ required by this bound in `Storable` + +error[E0277]: the trait bound `Vec: ink::parity_scale_codec::Decode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:9:1 + | +9 | #[ink::storage_item] + | ^^^^^^^^^^^^^^^^^^^^ the trait `ink::parity_scale_codec::Decode` is not implemented for `Vec`, which is required by `Contract: Sized` + | + = help: the trait `ink::parity_scale_codec::Decode` is implemented for `Vec` + = note: required for `Vec` to implement `Packed` + = note: required for `Vec` to implement `StorableHint<()>` + = note: required for `Vec` to implement `AutoStorableHint>` +note: required because it appears within the type `Contract` + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ +note: required by an implicit `Sized` bound in `Result` + --> $RUST/core/src/result.rs + | + | pub enum Result { + | ^ required by the implicit `Sized` requirement on this type parameter in `Result` + = note: this error originates in the derive macro `::ink::storage::traits::Storable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `[NonPacked]: Encode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:9:1 + | +9 | #[ink::storage_item] + | ^^^^^^^^^^^^^^^^^^^^ the trait `Encode` is not implemented for `[NonPacked]`, which is required by `Contract: Sized` + | + = help: the following other types implement trait `Encode`: + [T; N] + [T] + = note: required for `Vec` to implement `Encode` + = note: required for `Vec` to implement `Packed` + = note: required for `Vec` to implement `StorableHint<()>` + = note: required for `Vec` to implement `AutoStorableHint>` +note: required because it appears within the type `Contract` + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ +note: required by an implicit `Sized` bound in `Result` + --> $RUST/core/src/result.rs + | + | pub enum Result { + | ^ required by the implicit `Sized` requirement on this type parameter in `Result` + = note: this error originates in the derive macro `::ink::storage::traits::Storable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Vec: Packed` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:11:5 + | +11 | a: Vec, + | ^^^^^^^^^^^^^^^^^ the trait `ink::parity_scale_codec::Decode` is not implemented for `Vec`, which is required by `Vec: AutoStorableHint>` + | + = help: the trait `ink::parity_scale_codec::Decode` is implemented for `Vec` + = note: required for `Vec` to implement `Packed` + = note: required for `Vec` to implement `StorableHint<()>` + = note: required for `Vec` to implement `AutoStorableHint>` + +error[E0277]: the trait bound `[NonPacked]: Encode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:11:5 + | +11 | a: Vec, + | ^^^^^^^^^^^^^^^^^ the trait `Encode` is not implemented for `[NonPacked]`, which is required by `Vec: AutoStorableHint>` + | + = help: the following other types implement trait `Encode`: + [T; N] + [T] + = note: required for `Vec` to implement `Encode` + = note: required for `Vec` to implement `Packed` + = note: required for `Vec` to implement `StorableHint<()>` + = note: required for `Vec` to implement `AutoStorableHint>` + +error[E0277]: the trait bound `Vec: Packed` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:9:1 + | +9 | #[ink::storage_item] + | ^^^^^^^^^^^^^^^^^^^^ the trait `ink::parity_scale_codec::Decode` is not implemented for `Vec`, which is required by `Vec: AutoStorableHint>` + | + = help: the trait `ink::parity_scale_codec::Decode` is implemented for `Vec` + = note: required for `Vec` to implement `Packed` + = note: required for `Vec` to implement `StorableHint<()>` + = note: required for `Vec` to implement `AutoStorableHint>` + = note: this error originates in the derive macro `::ink::storage::traits::Storable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `[NonPacked]: Encode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_1.rs:9:1 | 9 | #[ink::storage_item] | ^^^^^^^^^^^^^^^^^^^^ the trait `Encode` is not implemented for `[NonPacked]`, which is required by `Vec: AutoStorableHint>` diff --git a/crates/ink/tests/ui/storage_item/fail/collections_only_packed_2.stderr b/crates/ink/tests/ui/storage_item/fail/collections_only_packed_2.stderr index 895c206ee10..e1cb2adaef0 100644 --- a/crates/ink/tests/ui/storage_item/fail/collections_only_packed_2.stderr +++ b/crates/ink/tests/ui/storage_item/fail/collections_only_packed_2.stderr @@ -9,6 +9,206 @@ error[E0277]: the trait bound `BTreeMap: Packed` is not satisfi = note: required for `BTreeMap` to implement `StorableHint<()>` = note: required for `BTreeMap` to implement `AutoStorableHint>` +error[E0277]: the trait bound `BTreeMap: Packed` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:11:8 + | +11 | a: BTreeMap, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Encode` is not implemented for `BTreeMap`, which is required by `BTreeMap: AutoStorableHint>` + | + = help: the trait `Encode` is implemented for `BTreeMap` + = note: required for `BTreeMap` to implement `Packed` + = note: required for `BTreeMap` to implement `StorableHint<()>` + = note: required for `BTreeMap` to implement `AutoStorableHint>` + +error[E0277]: the trait bound `BTreeMap: ink::parity_scale_codec::Decode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ the trait `ink::parity_scale_codec::Decode` is not implemented for `BTreeMap`, which is required by `Contract: Sized` + | + = help: the trait `ink::parity_scale_codec::Decode` is implemented for `BTreeMap` + = note: required for `BTreeMap` to implement `Packed` + = note: required for `BTreeMap` to implement `StorableHint<()>` + = note: required for `BTreeMap` to implement `AutoStorableHint>` +note: required because it appears within the type `Contract` + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ +note: required by a bound in `ink_storage::ink_storage_traits::StorableHint::Type` + --> $WORKSPACE/crates/storage/traits/src/storage.rs + | + | type Type: Storable; + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `StorableHint::Type` + +error[E0277]: the trait bound `BTreeMap: Encode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ the trait `Encode` is not implemented for `BTreeMap`, which is required by `Contract: Sized` + | + = help: the trait `Encode` is implemented for `BTreeMap` + = note: required for `BTreeMap` to implement `Packed` + = note: required for `BTreeMap` to implement `StorableHint<()>` + = note: required for `BTreeMap` to implement `AutoStorableHint>` +note: required because it appears within the type `Contract` + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ +note: required by a bound in `ink_storage::ink_storage_traits::StorableHint::Type` + --> $WORKSPACE/crates/storage/traits/src/storage.rs + | + | type Type: Storable; + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `StorableHint::Type` + +error[E0277]: the trait bound `BTreeMap: ink::parity_scale_codec::Decode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ the trait `ink::parity_scale_codec::Decode` is not implemented for `BTreeMap`, which is required by `Contract: Sized` + | + = help: the trait `ink::parity_scale_codec::Decode` is implemented for `BTreeMap` + = note: required for `BTreeMap` to implement `Packed` + = note: required for `BTreeMap` to implement `StorableHint<()>` + = note: required for `BTreeMap` to implement `AutoStorableHint>` +note: required because it appears within the type `Contract` + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ +note: required by a bound in `Storable` + --> $WORKSPACE/crates/storage/traits/src/storage.rs + | + | pub trait Storable: Sized { + | ^^^^^ required by this bound in `Storable` + +error[E0277]: the trait bound `BTreeMap: Encode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ the trait `Encode` is not implemented for `BTreeMap`, which is required by `Contract: Sized` + | + = help: the trait `Encode` is implemented for `BTreeMap` + = note: required for `BTreeMap` to implement `Packed` + = note: required for `BTreeMap` to implement `StorableHint<()>` + = note: required for `BTreeMap` to implement `AutoStorableHint>` +note: required because it appears within the type `Contract` + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ +note: required by a bound in `Storable` + --> $WORKSPACE/crates/storage/traits/src/storage.rs + | + | pub trait Storable: Sized { + | ^^^^^ required by this bound in `Storable` + +error[E0277]: the trait bound `BTreeMap: ink::parity_scale_codec::Decode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:9:1 + | +9 | #[ink::storage_item] + | ^^^^^^^^^^^^^^^^^^^^ the trait `ink::parity_scale_codec::Decode` is not implemented for `BTreeMap`, which is required by `Contract: Sized` + | + = help: the trait `ink::parity_scale_codec::Decode` is implemented for `BTreeMap` + = note: required for `BTreeMap` to implement `Packed` + = note: required for `BTreeMap` to implement `StorableHint<()>` + = note: required for `BTreeMap` to implement `AutoStorableHint>` +note: required because it appears within the type `Contract` + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ +note: required by an implicit `Sized` bound in `Result` + --> $RUST/core/src/result.rs + | + | pub enum Result { + | ^ required by the implicit `Sized` requirement on this type parameter in `Result` + = note: this error originates in the derive macro `::ink::storage::traits::Storable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `BTreeMap: Encode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:9:1 + | +9 | #[ink::storage_item] + | ^^^^^^^^^^^^^^^^^^^^ the trait `Encode` is not implemented for `BTreeMap`, which is required by `Contract: Sized` + | + = help: the trait `Encode` is implemented for `BTreeMap` + = note: required for `BTreeMap` to implement `Packed` + = note: required for `BTreeMap` to implement `StorableHint<()>` + = note: required for `BTreeMap` to implement `AutoStorableHint>` +note: required because it appears within the type `Contract` + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:10:8 + | +10 | struct Contract { + | ^^^^^^^^ +note: required by an implicit `Sized` bound in `Result` + --> $RUST/core/src/result.rs + | + | pub enum Result { + | ^ required by the implicit `Sized` requirement on this type parameter in `Result` + = note: this error originates in the derive macro `::ink::storage::traits::Storable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `BTreeMap: Packed` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:11:5 + | +11 | a: BTreeMap, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ink::parity_scale_codec::Decode` is not implemented for `BTreeMap`, which is required by `BTreeMap: AutoStorableHint>` + | + = help: the trait `ink::parity_scale_codec::Decode` is implemented for `BTreeMap` + = note: required for `BTreeMap` to implement `Packed` + = note: required for `BTreeMap` to implement `StorableHint<()>` + = note: required for `BTreeMap` to implement `AutoStorableHint>` + +error[E0277]: the trait bound `BTreeMap: Packed` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:11:5 + | +11 | a: BTreeMap, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Encode` is not implemented for `BTreeMap`, which is required by `BTreeMap: AutoStorableHint>` + | + = help: the trait `Encode` is implemented for `BTreeMap` + = note: required for `BTreeMap` to implement `Packed` + = note: required for `BTreeMap` to implement `StorableHint<()>` + = note: required for `BTreeMap` to implement `AutoStorableHint>` + +error[E0277]: the trait bound `BTreeMap: Packed` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:9:1 + | +9 | #[ink::storage_item] + | ^^^^^^^^^^^^^^^^^^^^ the trait `ink::parity_scale_codec::Decode` is not implemented for `BTreeMap`, which is required by `BTreeMap: AutoStorableHint>` + | + = help: the trait `ink::parity_scale_codec::Decode` is implemented for `BTreeMap` + = note: required for `BTreeMap` to implement `Packed` + = note: required for `BTreeMap` to implement `StorableHint<()>` + = note: required for `BTreeMap` to implement `AutoStorableHint>` + = note: this error originates in the derive macro `::ink::storage::traits::Storable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `BTreeMap: Packed` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:9:1 + | +9 | #[ink::storage_item] + | ^^^^^^^^^^^^^^^^^^^^ the trait `Encode` is not implemented for `BTreeMap`, which is required by `BTreeMap: AutoStorableHint>` + | + = help: the trait `Encode` is implemented for `BTreeMap` + = note: required for `BTreeMap` to implement `Packed` + = note: required for `BTreeMap` to implement `StorableHint<()>` + = note: required for `BTreeMap` to implement `AutoStorableHint>` + = note: this error originates in the derive macro `::ink::storage::traits::Storable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `NonPacked: WrapperTypeDecode` is not satisfied + --> tests/ui/storage_item/fail/collections_only_packed_2.rs:11:8 + | +11 | a: BTreeMap, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonPacked`, which is required by `BTreeMap: StorageLayout` + | + = help: the following other types implement trait `WrapperTypeDecode`: + Arc + Box + Rc + sp_core::Bytes + = note: required for `NonPacked` to implement `ink::parity_scale_codec::Decode` + = note: required for `NonPacked` to implement `Packed` + = note: required for `BTreeMap` to implement `StorageLayout` + error[E0277]: the trait bound `NonPacked: WrapperTypeEncode` is not satisfied --> tests/ui/storage_item/fail/collections_only_packed_2.rs:11:8 | diff --git a/crates/storage/Cargo.toml b/crates/storage/Cargo.toml index 90ab2fb406b..ad7d8b5a498 100644 --- a/crates/storage/Cargo.toml +++ b/crates/storage/Cargo.toml @@ -21,6 +21,7 @@ ink_primitives = { workspace = true } ink_storage_traits = { workspace = true } ink_prelude = { workspace = true } pallet-contracts-uapi = { workspace = true} +pallet-revive-uapi = { workspace = true} scale = { workspace = true } derive_more = { workspace = true, features = ["from", "display"] } @@ -48,3 +49,4 @@ std = [ "derive_more/std" ] ink-fuzz-tests = [ "std" ] +revive = [ "ink_env/revive", "ink/revive"] diff --git a/crates/storage/src/lazy/vec.rs b/crates/storage/src/lazy/vec.rs index 8fd4f404d96..3d7ae0bb3b0 100644 --- a/crates/storage/src/lazy/vec.rs +++ b/crates/storage/src/lazy/vec.rs @@ -28,7 +28,6 @@ use ink_storage_traits::{ StorableHint, StorageKey, }; -use pallet_contracts_uapi::ReturnErrorCode; use scale::EncodeLike; use crate::{ @@ -412,7 +411,7 @@ where T: Storable + EncodeLike, { if index >= self.len() { - return Err(ReturnErrorCode::KeyNotFound.into()); + return Err(ink_env::ReturnErrorCode::KeyNotFound.into()); } self.elements.try_insert(index, value) diff --git a/integration-tests/public/flipper/Cargo.toml b/integration-tests/public/flipper/Cargo.toml index f2afe5abd39..3211be6eb7f 100644 --- a/integration-tests/public/flipper/Cargo.toml +++ b/integration-tests/public/flipper/Cargo.toml @@ -22,3 +22,4 @@ std = [ ] ink-as-dependency = [] e2e-tests = [] +revive = ["ink/revive", "ink_e2e/revive"] diff --git a/linting/extra/Cargo.toml b/linting/extra/Cargo.toml index 65958c946be..0fd19323e4e 100644 --- a/linting/extra/Cargo.toml +++ b/linting/extra/Cargo.toml @@ -89,3 +89,8 @@ std = [ "scale-info/std", ] ink-as-dependency = [] +revive = [ + "ink/revive", + "ink_env/revive", + "ink_storage/revive" +] diff --git a/linting/rust-toolchain.toml b/linting/rust-toolchain.toml index 49c342491c9..4e7138b8d15 100644 --- a/linting/rust-toolchain.toml +++ b/linting/rust-toolchain.toml @@ -2,5 +2,5 @@ # https://github.com/trailofbits/dylint/blob/ef7210cb08aac920c18d2141604efe210029f2a2/internal/template/rust-toolchain [toolchain] -channel = "nightly-2024-09-05" +channel = "nightly-2024-11-01" components = ["llvm-tools-preview", "rustc-dev"]