Skip to content

Commit

Permalink
Fix: transfer filters (#1702)
Browse files Browse the repository at this point in the history
* fix: start fixing filtering of balances calls

* fix: trying to add remarks to altair

* feat: restricted transfers normal integration

* fix: find calls correctly

* feat: add tests batch

* feat: add test remark

* chore: code style

* fix: tapli

* fix: code docs

* fix: naming

* feat: add default ok test
  • Loading branch information
mustermeiszer authored Jan 30, 2024
1 parent a262fe9 commit 9152130
Show file tree
Hide file tree
Showing 12 changed files with 1,575 additions and 1,875 deletions.
2,788 changes: 954 additions & 1,834 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions runtime/altair/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ pallet-pool-registry = { workspace = true }
pallet-pool-system = { workspace = true }
pallet-preimage = { workspace = true }
pallet-proxy = { workspace = true }
pallet-remarks = { workspace = true }
pallet-restricted-tokens = { workspace = true }
pallet-restricted-xtokens = { workspace = true }
pallet-rewards = { workspace = true }
Expand Down Expand Up @@ -257,6 +258,7 @@ std = [
"pallet-restricted-tokens/std",
"pallet-restricted-xtokens/std",
"pallet-rewards/std",
"pallet-remarks/std",
"pallet-scheduler/std",
"pallet-session/std",
"pallet-sudo/std",
Expand Down Expand Up @@ -346,6 +348,7 @@ runtime-benchmarks = [
"pallet-restricted-tokens/runtime-benchmarks",
"pallet-restricted-xtokens/runtime-benchmarks",
"pallet-rewards/runtime-benchmarks",
"pallet-remarks/runtime-benchmarks",
"pallet-scheduler/runtime-benchmarks",
"pallet-sudo/runtime-benchmarks",
"pallet-timestamp/runtime-benchmarks",
Expand Down Expand Up @@ -435,6 +438,7 @@ try-runtime = [
"pallet-restricted-tokens/try-runtime",
"pallet-restricted-xtokens/try-runtime",
"pallet-rewards/try-runtime",
"pallet-remarks/try-runtime",
"pallet-scheduler/try-runtime",
"pallet-session/try-runtime",
"pallet-sudo/try-runtime",
Expand Down
17 changes: 17 additions & 0 deletions runtime/altair/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ use runtime_common::{
fees::{DealWithFees, FeeToTreasury, WeightToFee},
oracle::{Feeder, OracleConverterBridge},
permissions::PoolAdminCheck,
remarks::Remark,
xcm::AccountIdToMultiLocation,
xcm_transactor, AllowanceDeposit, CurrencyED, HoldId,
};
Expand Down Expand Up @@ -1739,6 +1740,19 @@ impl pallet_order_book::Config for Runtime {
type Weights = weights::pallet_order_book::WeightInfo<Runtime>;
}

parameter_types! {
pub const MaxRemarksPerCall: u32 = 10;
}

impl pallet_remarks::Config for Runtime {
type MaxRemarksPerCall = MaxRemarksPerCall;
type Remark = Remark;
type RemarkDispatchHandler = pallet_remarks::NoopRemarkDispatchHandler<Runtime>;
type RuntimeCall = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type WeightInfo = weights::pallet_remarks::WeightInfo<Runtime>;
}

impl pallet_transfer_allowlist::Config for Runtime {
type CurrencyId = FilterCurrency;
type Deposit = AllowanceDeposit<Fees>;
Expand Down Expand Up @@ -1818,6 +1832,7 @@ construct_runtime!(
OraclePriceFeed: pallet_oracle_feed::{Pallet, Call, Storage, Event<T>} = 116,
OraclePriceCollection: pallet_oracle_collection::{Pallet, Call, Storage, Event<T>} = 117,
PoolFees: pallet_pool_fees::{Pallet, Call, Storage, Event<T>} = 118,
Remarks: pallet_remarks::{Pallet, Call, Event<T>} = 119,

// XCM
XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 120,
Expand Down Expand Up @@ -2494,6 +2509,7 @@ impl_runtime_apis! {
list_benchmark!(list, extra, pallet_oracle_feed, OraclePriceFeed);
list_benchmark!(list, extra, pallet_oracle_collection, OraclePriceCollection);
list_benchmark!(list, extra, pallet_pool_fees, PoolFees);
list_benchmark!(list, extra, pallet_remarks, Remarks);

let storage_info = AllPalletsWithSystem::storage_info();

Expand Down Expand Up @@ -2574,6 +2590,7 @@ impl_runtime_apis! {
add_benchmark!(params, batches, pallet_oracle_feed, OraclePriceFeed);
add_benchmark!(params, batches, pallet_oracle_collection, OraclePriceCollection);
add_benchmark!(params, batches, pallet_pool_fees, PoolFees);
add_benchmark!(params, batches, pallet_remarks, Remarks);

if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
Ok(batches)
Expand Down
1 change: 1 addition & 0 deletions runtime/altair/src/weights/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub mod pallet_pool_registry;
pub mod pallet_pool_system;
pub mod pallet_preimage;
pub mod pallet_proxy;
pub mod pallet_remarks;
pub mod pallet_restricted_tokens;
pub mod pallet_scheduler;
pub mod pallet_session;
Expand Down
46 changes: 46 additions & 0 deletions runtime/altair/src/weights/pallet_remarks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

//! Autogenerated weights for `pallet_remarks`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2024-01-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner`, CPU: `AMD EPYC 7763 64-Core Processor`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("centrifuge-dev"), DB CACHE: 1024
// Executed Command:
// target/release/centrifuge-chain
// benchmark
// pallet
// --chain=centrifuge-dev
// --steps=50
// --repeat=20
// --pallet=pallet_remarks
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --heap-pages=4096
// --output=/tmp/runtime/centrifuge/src/weights/pallet_remarks.rs

#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]

use frame_support::{traits::Get, weights::Weight};
use core::marker::PhantomData;

/// Weight functions for `pallet_remarks`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> pallet_remarks::WeightInfo for WeightInfo<T> {
/// The range of component `n` is `[1, 10]`.
fn remark(n: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 16_792_000 picoseconds.
Weight::from_parts(17_287_221, 0)
.saturating_add(Weight::from_parts(0, 0))
// Standard Error: 2_915
.saturating_add(Weight::from_parts(145_247, 0).saturating_mul(n.into()))
}
}
4 changes: 4 additions & 0 deletions runtime/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ pallet-pool-registry = { workspace = true }
pallet-pool-system = { workspace = true }
pallet-preimage = { workspace = true }
pallet-proxy = { workspace = true }
pallet-remarks = { workspace = true }
pallet-restricted-tokens = { workspace = true }
pallet-restricted-xtokens = { workspace = true }
pallet-rewards = { workspace = true }
Expand Down Expand Up @@ -243,6 +244,7 @@ std = [
"pallet-restricted-tokens/std",
"pallet-restricted-xtokens/std",
"pallet-rewards/std",
"pallet-remarks/std",
"pallet-scheduler/std",
"pallet-session/std",
"pallet-sudo/std",
Expand Down Expand Up @@ -323,6 +325,7 @@ runtime-benchmarks = [
"pallet-proxy/runtime-benchmarks",
"pallet-restricted-tokens/runtime-benchmarks",
"pallet-rewards/runtime-benchmarks",
"pallet-remarks/runtime-benchmarks",
"pallet-scheduler/runtime-benchmarks",
"pallet-sudo/runtime-benchmarks",
"pallet-timestamp/runtime-benchmarks",
Expand Down Expand Up @@ -402,6 +405,7 @@ try-runtime = [
"pallet-restricted-tokens/try-runtime",
"pallet-restricted-xtokens/try-runtime",
"pallet-rewards/try-runtime",
"pallet-remarks/try-runtime",
"pallet-scheduler/try-runtime",
"pallet-session/try-runtime",
"pallet-sudo/try-runtime",
Expand Down
164 changes: 127 additions & 37 deletions runtime/common/src/transfer_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ use sp_runtime::{
transaction_validity::{InvalidTransaction, TransactionValidityError},
DispatchError, DispatchResult, TokenError,
};
use sp_std::vec::Vec;
use xcm::v3::{MultiAsset, MultiLocation};

pub struct PreXcmTransfer<T, C>(sp_std::marker::PhantomData<(T, C)>);

impl<
Expand Down Expand Up @@ -176,31 +176,137 @@ impl<T: TransferAllowance<AccountId, CurrencyId = FilterCurrency, Location = Loc
}
}

// NOTE: This code here is really critical. The test are resided in the
// integration tests section for this reason. The importance is, that
// nobody is able to create a call that can possibly bypass this filtering.
#[derive(
Clone, Copy, PartialOrd, Ord, PartialEq, Eq, RuntimeDebugNoBound, Encode, Decode, TypeInfo,
)]
#[scale_info(skip_type_params(T))]
pub struct PreBalanceTransferExtension<T: frame_system::Config>(sp_std::marker::PhantomData<T>);

#[allow(clippy::new_without_default)]
impl<T: frame_system::Config> PreBalanceTransferExtension<T> {
impl<T> PreBalanceTransferExtension<T>
where
T: frame_system::Config<AccountId = AccountId>
+ pallet_balances::Config
+ pallet_utility::Config<RuntimeCall = <T as frame_system::Config>::RuntimeCall>
+ pallet_proxy::Config<RuntimeCall = <T as frame_system::Config>::RuntimeCall>
+ pallet_remarks::Config<RuntimeCall = <T as frame_system::Config>::RuntimeCall>
+ Sync
+ Send,
<T as frame_system::Config>::RuntimeCall: IsSubType<pallet_balances::Call<T>>
+ IsSubType<pallet_utility::Call<T>>
+ IsSubType<pallet_proxy::Call<T>>
+ IsSubType<pallet_remarks::Call<T>>,
{
pub fn new() -> Self {
Self(sp_std::marker::PhantomData)
}

#[allow(clippy::type_complexity)]
fn retrieve(
caller: &T::AccountId,
call: &<T as frame_system::Config>::RuntimeCall,
) -> Result<Vec<(T::AccountId, T::AccountId)>, TransactionValidityError> {
Self::recursive_search(caller.clone(), call, |who, balance_call, checks| {
match balance_call {
pallet_balances::Call::transfer { dest, .. }
| pallet_balances::Call::transfer_all { dest, .. }
| pallet_balances::Call::transfer_allow_death { dest, .. }
| pallet_balances::Call::transfer_keep_alive { dest, .. } => {
let recv: T::AccountId = <T as frame_system::Config>::Lookup::lookup(
dest.clone(),
)
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Call))?;

checks.push((who, recv));
Ok(())
}

// If the call is not a transfer we are fine with it to go through without
// further checks
_ => Ok(()),
}
})
}

#[allow(clippy::type_complexity)]
#[allow(clippy::single_match)]
#[allow(clippy::collapsible_match)]
fn recursive_search<F>(
caller: T::AccountId,
call: &<T as frame_system::Config>::RuntimeCall,
check: F,
) -> Result<Vec<(T::AccountId, T::AccountId)>, TransactionValidityError>
where
F: Fn(
T::AccountId,
pallet_balances::Call<T>,
&mut Vec<(T::AccountId, T::AccountId)>,
) -> Result<(), TransactionValidityError>
+ Clone,
{
let mut checks = Vec::new();

if let Some(balance_call) = IsSubType::<pallet_balances::Call<T>>::is_sub_type(call) {
check(caller, balance_call.clone(), &mut checks)?;
} else if let Some(call) = IsSubType::<pallet_proxy::Call<T>>::is_sub_type(call) {
match call {
pallet_proxy::Call::<T>::proxy { real, call, .. }
| pallet_proxy::Call::<T>::proxy_announced { real, call, .. } => {
let caller = T::Lookup::lookup(real.clone())
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Call))?;

checks.extend(Self::recursive_search(caller, call, check)?);
}
_ => {}
}
} else if let Some(utility_call) = IsSubType::<pallet_utility::Call<T>>::is_sub_type(call) {
match utility_call {
pallet_utility::Call::<T>::batch { calls: batch_calls }
| pallet_utility::Call::<T>::batch_all { calls: batch_calls } => {
for batch_call in batch_calls {
checks.extend(Self::recursive_search(
caller.clone(),
batch_call,
check.clone(),
)?);
}
}
_ => {}
}
} else if let Some(remarks_call) = IsSubType::<pallet_remarks::Call<T>>::is_sub_type(call) {
match remarks_call {
pallet_remarks::Call::<T>::remark {
call: remark_call, ..
} => checks.extend(Self::recursive_search(caller, remark_call, check)?),
_ => {}
}
}

Ok(checks)
}
}

impl<T> SignedExtension for PreBalanceTransferExtension<T>
where
T: frame_system::Config<AccountId = AccountId>
+ pallet_balances::Config
+ pallet_utility::Config<RuntimeCall = <T as frame_system::Config>::RuntimeCall>
+ pallet_proxy::Config<RuntimeCall = <T as frame_system::Config>::RuntimeCall>
+ pallet_remarks::Config<RuntimeCall = <T as frame_system::Config>::RuntimeCall>
+ pallet_transfer_allowlist::Config<CurrencyId = FilterCurrency, Location = Location>
+ Sync
+ Send,
<T as frame_system::Config>::RuntimeCall: IsSubType<pallet_balances::Call<T>>,
<T as frame_system::Config>::RuntimeCall: IsSubType<pallet_balances::Call<T>>
+ IsSubType<pallet_utility::Call<T>>
+ IsSubType<pallet_proxy::Call<T>>
+ IsSubType<pallet_remarks::Call<T>>,
{
type AccountId = T::AccountId;
type AdditionalSigned = ();
type Call = T::RuntimeCall;
type Call = <T as frame_system::Config>::RuntimeCall;
type Pre = ();

const IDENTIFIER: &'static str = "PreBalanceTransferExtension";
Expand All @@ -216,39 +322,23 @@ where
_: &DispatchInfoOf<Self::Call>,
_: usize,
) -> Result<Self::Pre, TransactionValidityError> {
let recv: T::AccountId = if let Some(call) =
IsSubType::<pallet_balances::Call<T>>::is_sub_type(call)
{
match call {
pallet_balances::Call::transfer { dest, .. }
| pallet_balances::Call::transfer_all { dest, .. }
| pallet_balances::Call::transfer_allow_death { dest, .. }
| pallet_balances::Call::transfer_keep_alive { dest, .. } => {
<T as frame_system::Config>::Lookup::lookup(dest.clone())
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Call))?
}

// If the call is not a transfer we are fine with it to go through without futher
// checks
_ => return Ok(()),
}
} else {
return Ok(());
};

amalgamate_allowance(
pallet_transfer_allowlist::pallet::Pallet::<T>::allowance(
who.clone(),
Location::Local(recv.clone()),
FilterCurrency::All,
),
pallet_transfer_allowlist::pallet::Pallet::<T>::allowance(
who.clone(),
Location::Local(recv.clone()),
FilterCurrency::Specific(CurrencyId::Native),
),
)
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Custom(255)))
Self::retrieve(who, call)?
.iter()
.try_for_each(|(who, recv)| {
amalgamate_allowance(
pallet_transfer_allowlist::pallet::Pallet::<T>::allowance(
who.clone(),
Location::Local(recv.clone()),
FilterCurrency::All,
),
pallet_transfer_allowlist::pallet::Pallet::<T>::allowance(
who.clone(),
Location::Local(recv.clone()),
FilterCurrency::Specific(CurrencyId::Native),
),
)
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Custom(255)))
})
}
}

Expand Down
1 change: 1 addition & 0 deletions runtime/integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ pallet-pool-registry = { workspace = true, features = ["std"] }
pallet-pool-system = { workspace = true, features = ["std"] }
pallet-preimage = { workspace = true, features = ["std"] }
pallet-proxy = { workspace = true, features = ["std"] }
pallet-remarks = { workspace = true, features = ["std"] }
pallet-restricted-tokens = { workspace = true, features = ["std"] }
pallet-restricted-xtokens = { workspace = true, features = ["std"] }
pallet-rewards = { workspace = true, features = ["std"] }
Expand Down
Loading

0 comments on commit 9152130

Please sign in to comment.