diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 535e41518d811..a0483ccf86345 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -1955,12 +1955,27 @@ impl Pallet { storage_deposit_limit: BalanceOf, ) -> CodeUploadResult> { let origin = T::UploadOrigin::ensure_origin(origin)?; - let (module, deposit) = Self::try_upload_pvm_code( - origin, - code, - storage_deposit_limit, - &ExecConfig::new_substrate_tx(), - )?; + + let result = if code.starts_with(&polkavm_common::program::BLOB_MAGIC) { + Self::try_upload_pvm_code( + origin, + code, + storage_deposit_limit, + &ExecConfig::new_substrate_tx(), + ) + } else { + if !T::AllowEVMBytecode::get() { + return Err(>::CodeRejected.into()); + } + Self::try_upload_evm_code( + origin, + code, + storage_deposit_limit, + &ExecConfig::new_eth_tx(Self::evm_gas_price()), + ) + }; + + let (module, deposit) = result?; Ok(CodeUploadReturnValue { code_hash: *module.code_hash(), deposit }) } @@ -2077,6 +2092,20 @@ impl Pallet { Ok((module, deposit)) } + /// Uploads new EVM code and returns the Vm binary contract blob and deposit amount collected. + /// TODO: consider merging with `try_upload_pvm_code` + fn try_upload_evm_code( + origin: T::AccountId, + code: Vec, + storage_deposit_limit: BalanceOf, + exec_config: &ExecConfig, + ) -> Result<(ContractBlob, BalanceOf), DispatchError> { + let mut module: ContractBlob = ContractBlob::from_evm_runtime_code(code, origin)?; + let deposit = module.store_code(exec_config, None)?; + ensure!(storage_deposit_limit >= deposit, >::StorageDepositLimitExhausted); + Ok((module, deposit)) + } + /// Run the supplied function `f` if no other instance of this pallet is on the stack. fn run_guarded Result>(f: F) -> Result { executing_contract::using_once(&mut false, || { diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index f202477ebf518..dc0045d1663da 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -489,7 +489,7 @@ impl ExtBuilder { } } -fn initialize_block(number: u64) { +pub fn initialize_block(number: u64) { System::reset_events(); System::initialize(&number, &[0u8; 32].into(), &Default::default()); } diff --git a/substrate/frame/revive/src/tests/sol.rs b/substrate/frame/revive/src/tests/sol.rs index 275b44db2f0ca..871c87477c2d4 100644 --- a/substrate/frame/revive/src/tests/sol.rs +++ b/substrate/frame/revive/src/tests/sol.rs @@ -20,13 +20,15 @@ use crate::{ test_utils::{builder::Contract, ALICE}, tests::{ builder, - test_utils::{contract_base_deposit, ensure_stored, get_contract}, - ExtBuilder, Test, + test_utils::{contract_base_deposit, ensure_stored, expected_deposit, get_contract}, + Contracts, ExtBuilder, initialize_block, RuntimeOrigin, Test, }, Code, Config, PristineCode, + evm::fees::InfoT, }; use alloy_core::sol_types::{SolCall, SolInterface}; -use frame_support::traits::fungible::Mutate; +use frame_support::assert_ok; +use frame_support::traits::fungible::{Balanced, Mutate}; use pallet_revive_fixtures::{compile_module_with_type, Fibonacci, FixtureType}; use pretty_assertions::assert_eq; @@ -157,3 +159,29 @@ fn basic_evm_flow_tracing_works() { ); }); } + +#[test] +fn upload_and_remove_code_works_for_evm() { + let storage_deposit_limit = 1000u64; + let (code, code_hash) = compile_module_with_type("dummy", FixtureType::Solc).unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let amount = ::Currency::issue(5_000_000_000); + ::FeeInfo::deposit_txfee(amount); + + // Drop previous events + initialize_block(2); + + // Ensure the code is not already stored. + assert!(!PristineCode::::contains_key(&code_hash)); + + // Upload the code. + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), code, storage_deposit_limit)); + + // Ensure the contract was stored and get expected deposit amount to be reserved. + expected_deposit(ensure_stored(code_hash)); + + // Now remove the code. + assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash)); + }); +}