Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions substrate/frame/revive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1955,12 +1955,27 @@ impl<T: Config> Pallet<T> {
storage_deposit_limit: BalanceOf<T>,
) -> CodeUploadResult<BalanceOf<T>> {
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(<Error<T>>::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 })
}

Expand Down Expand Up @@ -2077,6 +2092,20 @@ impl<T: Config> Pallet<T> {
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<u8>,
storage_deposit_limit: BalanceOf<T>,
exec_config: &ExecConfig,
) -> Result<(ContractBlob<T>, BalanceOf<T>), DispatchError> {
let mut module: ContractBlob<T> = ContractBlob::from_evm_runtime_code(code, origin)?;
let deposit = module.store_code(exec_config, None)?;
ensure!(storage_deposit_limit >= deposit, <Error<T>>::StorageDepositLimitExhausted);
Ok((module, deposit))
}

/// Run the supplied function `f` if no other instance of this pallet is on the stack.
fn run_guarded<R, F: FnOnce() -> Result<R, ExecError>>(f: F) -> Result<R, ExecError> {
executing_contract::using_once(&mut false, || {
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/revive/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down
34 changes: 31 additions & 3 deletions substrate/frame/revive/src/tests/sol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 = <Test as Config>::Currency::issue(5_000_000_000);
<Test as Config>::FeeInfo::deposit_txfee(amount);

// Drop previous events
initialize_block(2);

// Ensure the code is not already stored.
assert!(!PristineCode::<Test>::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));
});
}
Loading