Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: dispatch precompile filter #1022

Merged
merged 16 commits into from
Sep 27, 2023
Merged
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pallet-evm = { workspace = true }

# Astar pallets & dependencies
pallet-evm-precompile-assets-erc20 = { workspace = true }
pallet-evm-precompile-dispatch = { workspace = true }
pallet-xc-asset-config = { workspace = true }

[features]
Expand All @@ -64,5 +65,6 @@ std = [
"pallet-assets/std",
"pallet-evm/std",
"pallet-evm-precompile-assets-erc20/std",
"pallet-evm-precompile-dispatch/std",
]
runtime-benchmarks = ["xcm-builder/runtime-benchmarks", "pallet-assets/runtime-benchmarks"]
3 changes: 3 additions & 0 deletions primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub mod xvm;
/// EVM primitives.
pub mod evm;

/// Precompiles
pub mod precompiles;

/// Benchmark primitives
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarks;
Expand Down
57 changes: 57 additions & 0 deletions primitives/src/precompiles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// This file is part of Astar.

// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later

// Astar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Astar is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Astar. If not, see <http://www.gnu.org/licenses/>.

#![cfg_attr(not(feature = "std"), no_std)]

use core::marker::PhantomData;

use fp_evm::{ExitError, PrecompileFailure};
use frame_support::{
dispatch::{DispatchClass, GetDispatchInfo, Pays},
traits::Contains,
};
use pallet_evm_precompile_dispatch::DispatchValidateT;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add Rustdoc to public structs.

/// Struct that allows only calls based on `Filter` to pass through.
pub struct DispatchFilterValidate<RuntimeCall, Filter: Contains<RuntimeCall>>(
PhantomData<(RuntimeCall, Filter)>,
);

impl<AccountId, RuntimeCall: GetDispatchInfo, Filter: Contains<RuntimeCall>>
DispatchValidateT<AccountId, RuntimeCall> for DispatchFilterValidate<RuntimeCall, Filter>
{
fn validate_before_dispatch(
_origin: &AccountId,
call: &RuntimeCall,
) -> Option<PrecompileFailure> {
let info = call.get_dispatch_info();
let paid_normal_call = info.pays_fee == Pays::Yes && info.class == DispatchClass::Normal;
if !paid_normal_call {
return Some(PrecompileFailure::Error {
exit_status: ExitError::Other("invalid call".into()),
});
}
if Filter::contains(call) {
None
} else {
Some(PrecompileFailure::Error {
exit_status: ExitError::Other("call filtered out".into()),
})
}
}
}
1 change: 1 addition & 0 deletions runtime/astar/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit = "256"]

pub use crate::precompiles::WhitelistedCalls;
pub use astar_primitives::{
evm::EvmRevertCodeHandler, xcm::AssetLocationIdConverter, AccountId, Address, AssetId, Balance,
BlockNumber, Hash, Header, Index, Signature,
Expand Down
27 changes: 25 additions & 2 deletions runtime/astar/src/precompiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

//! The Astar Network EVM precompiles. This can be compiled with ``#[no_std]`, ready for Wasm.

use crate::RuntimeCall;
use astar_primitives::precompiles::DispatchFilterValidate;
use frame_support::traits::Contains;
use pallet_evm::{
ExitRevert, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
PrecompileResult, PrecompileSet,
Expand Down Expand Up @@ -45,6 +48,23 @@ use xcm::latest::prelude::MultiLocation;
/// to Erc20AssetsPrecompileSet
pub const ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4];

/// Filter that only allows whitelisted runtime call to pass through dispatch precompile

pub struct WhitelistedCalls;

impl Contains<RuntimeCall> for WhitelistedCalls {
fn contains(t: &RuntimeCall) -> bool {
match t {
RuntimeCall::Utility(pallet_utility::Call::batch { calls })
| RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => {
calls.iter().all(|call| WhitelistedCalls::contains(call))
}
RuntimeCall::DappsStaking(_) => true,
RuntimeCall::Assets(pallet_assets::Call::transfer { .. }) => true,
_ => false,
}
}
}
/// The PrecompileSet installed in the Astar runtime.
#[derive(Debug, Default, Clone, Copy)]
pub struct AstarNetworkPrecompiles<R, C>(PhantomData<(R, C)>);
Expand Down Expand Up @@ -74,7 +94,7 @@ where
DappsStakingWrapper<R>: Precompile,
BatchPrecompile<R>: Precompile,
XcmPrecompile<R, C>: Precompile,
Dispatch<R>: Precompile,
Dispatch<R, DispatchFilterValidate<RuntimeCall, WhitelistedCalls>>: Precompile,
R: pallet_evm::Config
+ pallet_assets::Config
+ pallet_xcm::Config
Expand Down Expand Up @@ -106,7 +126,10 @@ where
a if a == hash(9) => Some(Blake2F::execute(handle)),
// nor Ethereum precompiles :
a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)),
a if a == hash(1025) => Some(Dispatch::<R>::execute(handle)),
a if a == hash(1025) => Some(Dispatch::<
R,
DispatchFilterValidate<RuntimeCall, WhitelistedCalls>,
>::execute(handle)),
a if a == hash(1026) => Some(ECRecoverPublicKey::execute(handle)),
a if a == hash(1027) => Some(Ed25519Verify::execute(handle)),
// Astar precompiles (starts from 0x5000):
Expand Down
1 change: 1 addition & 0 deletions runtime/local/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ pub use astar_primitives::{
Balance, BlockNumber, Hash, Header, Index, Signature,
};

pub use crate::precompiles::WhitelistedCalls;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
Expand Down
27 changes: 25 additions & 2 deletions runtime/local/src/precompiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

//! The Local EVM precompiles. This can be compiled with ``#[no_std]`, ready for Wasm.

use crate::RuntimeCall;
use astar_primitives::precompiles::DispatchFilterValidate;
use frame_support::traits::Contains;
use pallet_evm::{
ExitRevert, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
PrecompileResult, PrecompileSet,
Expand All @@ -43,6 +46,23 @@ use sp_std::marker::PhantomData;
/// to Erc20AssetsPrecompileSet
pub const ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4];

/// Filter that only allows whitelisted runtime call to pass through dispatch precompile
pub struct WhitelistedCalls;

impl Contains<RuntimeCall> for WhitelistedCalls {
fn contains(t: &RuntimeCall) -> bool {
match t {
RuntimeCall::Utility(pallet_utility::Call::batch { calls })
| RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => {
calls.iter().all(|call| WhitelistedCalls::contains(call))
}
RuntimeCall::Assets(pallet_assets::Call::transfer { .. }) => true,
RuntimeCall::DappsStaking(_) => true,
_ => false,
}
}
}

/// The PrecompileSet installed in the Local runtime.
#[derive(Debug, Default, Clone, Copy)]
pub struct LocalNetworkPrecompiles<R>(PhantomData<R>);
Expand Down Expand Up @@ -72,7 +92,7 @@ where
DappsStakingWrapper<R>: Precompile,
BatchPrecompile<R>: Precompile,
XvmPrecompile<R, pallet_xvm::Pallet<R>>: Precompile,
Dispatch<R>: Precompile,
Dispatch<R, DispatchFilterValidate<RuntimeCall, WhitelistedCalls>>: Precompile,
R: pallet_evm::Config
+ pallet_xvm::Config
+ pallet_assets::Config
Expand Down Expand Up @@ -103,7 +123,10 @@ where
a if a == hash(9) => Some(Blake2F::execute(handle)),
// nor Ethereum precompiles :
a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)),
a if a == hash(1025) => Some(Dispatch::<R>::execute(handle)),
a if a == hash(1025) => Some(Dispatch::<
R,
DispatchFilterValidate<RuntimeCall, WhitelistedCalls>,
>::execute(handle)),
a if a == hash(1026) => Some(ECRecoverPublicKey::execute(handle)),
a if a == hash(1027) => Some(Ed25519Verify::execute(handle)),
// Astar precompiles (starts from 0x5000):
Expand Down
2 changes: 2 additions & 0 deletions runtime/shibuya/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ pub use astar_primitives::{
AccountId, Address, AssetId, Balance, BlockNumber, Hash, Header, Index, Signature,
};

pub use crate::precompiles::WhitelistedCalls;

use pallet_evm_precompile_assets_erc20::AddressToAssetId;

#[cfg(any(feature = "std", test))]
Expand Down
27 changes: 25 additions & 2 deletions runtime/shibuya/src/precompiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

//! The Shibuya Network EVM precompiles. This can be compiled with ``#[no_std]`, ready for Wasm.

use crate::RuntimeCall;
use astar_primitives::precompiles::DispatchFilterValidate;
use frame_support::traits::Contains;
use pallet_evm::{
ExitRevert, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
PrecompileResult, PrecompileSet,
Expand Down Expand Up @@ -46,6 +49,23 @@ use xcm::latest::prelude::MultiLocation;
/// to Erc20AssetsPrecompileSet
pub const ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4];

/// Filter that only allows whitelisted runtime call to pass through dispatch precompile
pub struct WhitelistedCalls;

impl Contains<RuntimeCall> for WhitelistedCalls {
fn contains(t: &RuntimeCall) -> bool {
match t {
RuntimeCall::Utility(pallet_utility::Call::batch { calls })
| RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => {
calls.iter().all(|call| WhitelistedCalls::contains(call))
}
RuntimeCall::Assets(pallet_assets::Call::transfer { .. }) => true,
RuntimeCall::DappsStaking(_) => true,
_ => false,
}
}
}

/// The PrecompileSet installed in the Shiden runtime.
#[derive(Debug, Default, Clone, Copy)]
pub struct ShibuyaNetworkPrecompiles<R, C>(PhantomData<(R, C)>);
Expand Down Expand Up @@ -77,7 +97,7 @@ where
XcmPrecompile<R, C>: Precompile,
BatchPrecompile<R>: Precompile,
XvmPrecompile<R, pallet_xvm::Pallet<R>>: Precompile,
Dispatch<R>: Precompile,
Dispatch<R, DispatchFilterValidate<RuntimeCall, WhitelistedCalls>>: Precompile,
R: pallet_evm::Config
+ pallet_assets::Config
+ pallet_xcm::Config
Expand Down Expand Up @@ -110,7 +130,10 @@ where
a if a == hash(9) => Some(Blake2F::execute(handle)),
// nor Ethereum precompiles :
a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)),
a if a == hash(1025) => Some(Dispatch::<R>::execute(handle)),
a if a == hash(1025) => Some(Dispatch::<
R,
DispatchFilterValidate<RuntimeCall, WhitelistedCalls>,
>::execute(handle)),
a if a == hash(1026) => Some(ECRecoverPublicKey::execute(handle)),
a if a == hash(1027) => Some(Ed25519Verify::execute(handle)),
// Astar precompiles (starts from 0x5000):
Expand Down
1 change: 1 addition & 0 deletions runtime/shiden/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ use sp_runtime::{
};
use sp_std::prelude::*;

pub use crate::precompiles::WhitelistedCalls;
pub use astar_primitives::{
evm::EvmRevertCodeHandler, xcm::AssetLocationIdConverter, AccountId, Address, AssetId, Balance,
BlockNumber, Hash, Header, Index, Signature,
Expand Down
27 changes: 25 additions & 2 deletions runtime/shiden/src/precompiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

//! The Shiden Network EVM precompiles. This can be compiled with ``#[no_std]`, ready for Wasm.

use crate::RuntimeCall;
use astar_primitives::precompiles::DispatchFilterValidate;
use frame_support::traits::Contains;
use pallet_evm::{
ExitRevert, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
PrecompileResult, PrecompileSet,
Expand Down Expand Up @@ -45,6 +48,23 @@ use xcm::latest::prelude::MultiLocation;
/// to Erc20AssetsPrecompileSet
pub const ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4];

/// Filter that only allows whitelisted runtime call to pass through dispatch precompile
pub struct WhitelistedCalls;

impl Contains<RuntimeCall> for WhitelistedCalls {
fn contains(t: &RuntimeCall) -> bool {
match t {
RuntimeCall::Utility(pallet_utility::Call::batch { calls })
| RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => {
calls.iter().all(|call| WhitelistedCalls::contains(call))
}
RuntimeCall::DappsStaking(_) => true,
RuntimeCall::Assets(pallet_assets::Call::transfer { .. }) => true,
_ => false,
}
}
}

/// The PrecompileSet installed in the Shiden runtime.
#[derive(Debug, Default, Clone, Copy)]
pub struct ShidenNetworkPrecompiles<R, C>(PhantomData<(R, C)>);
Expand Down Expand Up @@ -74,7 +94,7 @@ where
DappsStakingWrapper<R>: Precompile,
BatchPrecompile<R>: Precompile,
XcmPrecompile<R, C>: Precompile,
Dispatch<R>: Precompile,
Dispatch<R, DispatchFilterValidate<RuntimeCall, WhitelistedCalls>>: Precompile,
R: pallet_evm::Config
+ pallet_assets::Config
+ pallet_xcm::Config
Expand Down Expand Up @@ -106,7 +126,10 @@ where
a if a == hash(9) => Some(Blake2F::execute(handle)),
// nor Ethereum precompiles :
a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)),
a if a == hash(1025) => Some(Dispatch::<R>::execute(handle)),
a if a == hash(1025) => Some(Dispatch::<
R,
DispatchFilterValidate<RuntimeCall, WhitelistedCalls>,
>::execute(handle)),
a if a == hash(1026) => Some(ECRecoverPublicKey::execute(handle)),
a if a == hash(1027) => Some(Ed25519Verify::execute(handle)),
// Astar precompiles (starts from 0x5000):
Expand Down
1 change: 1 addition & 0 deletions tests/integration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ sp-runtime = { workspace = true }
# astar dependencies
pallet-ethereum-checked = { workspace = true }
pallet-evm-precompile-assets-erc20 = { workspace = true }
pallet-evm-precompile-dispatch = { workspace = true }
pallet-unified-accounts = { workspace = true }
precompile-utils = { workspace = true }

Expand Down
Loading
Loading