diff --git a/prdoc/pr_10193.prdoc b/prdoc/pr_10193.prdoc new file mode 100644 index 0000000000000..f09baf807f393 --- /dev/null +++ b/prdoc/pr_10193.prdoc @@ -0,0 +1,11 @@ +title: '[v2] pallet-revive: support uploading EVM bytecode via upload_code' +doc: +- audience: Runtime Dev + description: |- + Fixes https://github.com/paritytech/contract-issues/issues/182 + + Add support for EVM bytecode to the upload_code extrinsic. + Tests in issue https://github.com/paritytech/contract-issues/issues/182 send hardhat_setCode, which uses revive's upload_code API; this change makes that flow accept and store the EVM bytecode using upload_code extrinsic. +crates: +- name: pallet-revive + bump: patch diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 2e3fee1a89b83..f054e4f0651c7 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -1986,10 +1986,20 @@ impl Pallet { storage_deposit_limit: BalanceOf, ) -> CodeUploadResult> { let origin = T::UploadOrigin::ensure_origin(origin)?; + + let bytecode_type = if code.starts_with(&polkavm_common::program::BLOB_MAGIC) { + BytecodeType::Pvm + } else { + if !T::AllowEVMBytecode::get() { + return Err(>::CodeRejected.into()) + } + BytecodeType::Evm + }; + let (module, deposit) = Self::try_upload_code( origin, code, - BytecodeType::Pvm, + bytecode_type, storage_deposit_limit, &ExecConfig::new_substrate_tx(), )?; diff --git a/substrate/frame/revive/src/tests/sol.rs b/substrate/frame/revive/src/tests/sol.rs index fd58c9fa45491..96d3f91033b08 100644 --- a/substrate/frame/revive/src/tests/sol.rs +++ b/substrate/frame/revive/src/tests/sol.rs @@ -23,9 +23,9 @@ use crate::{ tests::{ builder, test_utils::{contract_base_deposit, ensure_stored, get_contract}, - DebugFlag, ExtBuilder, Test, + AllowEvmBytecode, DebugFlag, ExtBuilder, RuntimeOrigin, Test, }, - Code, Config, Error, GenesisConfig, PristineCode, + Code, Config, Error, GenesisConfig, Pallet, PristineCode, }; use alloy_core::sol_types::{SolCall, SolInterface}; use frame_support::{assert_err, assert_ok, traits::fungible::Mutate}; @@ -206,7 +206,6 @@ fn upload_evm_runtime_code_works() { exec::Executable, primitives::ExecConfig, storage::{AccountInfo, ContractInfo}, - Pallet, }; let (runtime_code, _runtime_hash) = @@ -242,6 +241,44 @@ fn upload_evm_runtime_code_works() { }); } +#[test] +fn upload_and_remove_code_works_for_evm() { + let (code, code_hash) = compile_module_with_type("Dummy", FixtureType::SolcRuntime).unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let _ = Pallet::::set_evm_balance(&ALICE_ADDR, 5_000_000_000u64.into()); + + // Ensure the code is not already stored. + assert!(!PristineCode::::contains_key(&code_hash)); + + // Upload the code. + assert_ok!(Pallet::::upload_code(RuntimeOrigin::signed(ALICE), code, 1000u64)); + + // Ensure the contract was stored. + ensure_stored(code_hash); + + // Remove the code. + assert_ok!(Pallet::::remove_code(RuntimeOrigin::signed(ALICE), code_hash)); + + // Ensure the code is no longer stored. + assert!(!PristineCode::::contains_key(&code_hash)); + }); +} + +#[test] +fn upload_fails_if_evm_bytecode_disabled() { + let (code, _) = compile_module_with_type("Dummy", FixtureType::SolcRuntime).unwrap(); + + AllowEvmBytecode::set(false); // Disable support for EVM bytecode. + ExtBuilder::default().build().execute_with(|| { + // Upload should fail since support for EVM bytecode is disabled. + assert_err!( + Pallet::::upload_code(RuntimeOrigin::signed(ALICE), code, 1000u64), + >::CodeRejected + ); + }); +} + #[test_case(FixtureType::Solc)] #[test_case(FixtureType::Resolc)] fn dust_work_with_child_calls(fixture_type: FixtureType) {