diff --git a/modules/evm/src/lib.rs b/modules/evm/src/lib.rs index a9aeb405c..c3d222934 100644 --- a/modules/evm/src/lib.rs +++ b/modules/evm/src/lib.rs @@ -1387,6 +1387,16 @@ impl Pallet { Self::codes(&Self::code_hash_at_address(address)) } + pub fn is_contract(address: &EvmAddress) -> bool { + matches!( + Self::accounts(address), + Some(AccountInfo { + contract_info: Some(_), + .. + }) + ) + } + pub fn update_contract_storage_size(address: &EvmAddress, change: i32) { if change == 0 { return; diff --git a/runtime/common/src/precompile/mod.rs b/runtime/common/src/precompile/mod.rs index 5cce43226..57f0f5e37 100644 --- a/runtime/common/src/precompile/mod.rs +++ b/runtime/common/src/precompile/mod.rs @@ -280,6 +280,15 @@ where })); } + if !module_evm::Pallet::::is_contract(&context.caller) { + log::debug!(target: "evm", "Caller is not a system contract: {:?}", context.caller); + return Some(Err(PrecompileFailure::Revert { + exit_status: ExitRevert::Reverted, + output: "Caller is not a system contract".into(), + cost: target_gas.unwrap_or_default(), + })); + } + if address == MULTI_CURRENCY { Some(MultiCurrencyPrecompile::::execute( input, target_gas, context, is_static, diff --git a/ts-tests/tests/test-precompile-filter.ts b/ts-tests/tests/test-precompile-filter.ts index 66f64b722..a41fecc53 100644 --- a/ts-tests/tests/test-precompile-filter.ts +++ b/ts-tests/tests/test-precompile-filter.ts @@ -39,4 +39,34 @@ describeWithAcala("Acala RPC (Precompile Filter Calls)", (context) => { await contract.test_call(ecrecover, input, expect_addr); await contract.test_delegate_call(ecrecover, input, expect_addr); }); + + + it('standard precompiles can be called directly', async function () { + expect(await context.provider.call({ + to: ecrecover, + from: await alice.getAddress(), + data: input, + }), expect_pk); + }); + + it('Acala precompiles cannot be called directly', async function () { + await expect(context.provider.call({ + to: '0x0000000000000000000000000000000000000400', + from: await alice.getAddress(), + data: input, + })).to.be.rejectedWith("NoPermission"); + + await expect(context.provider.call({ + to: '0x0000000000000000000000000000000000000400', + from: '0x0000000000000000000111111111111111111111', + data: input, + })).to.be.rejectedWith("Caller is not a system contract"); + + // 41555344 -> AUSD + expect(await context.provider.call({ + to: '0x0000000000000000000000000000000000000400', + from: '0x0000000000000000000100000000000000000001', + data: '0x95d89b410000000000000000000000000000000000000000000100000000000000000001', + })).to.be.eq("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000044155534400000000000000000000000000000000000000000000000000000000"); + }); });