diff --git a/substrate/bin/node/runtime/src/impls.rs b/substrate/bin/node/runtime/src/impls.rs index 12280c073..4d8c46657 100644 --- a/substrate/bin/node/runtime/src/impls.rs +++ b/substrate/bin/node/runtime/src/impls.rs @@ -236,6 +236,29 @@ impl InstanceFilter for NftsCallFilter { } } +#[derive( + Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, MaxEncodedLen, scale_info::TypeInfo, Serialize, Deserialize, +)] +pub struct SenateAccountCallFilter; + +impl Contains for SenateAccountCallFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Utility(pallet_utility::Call::batch { calls }) => calls.iter().all(|inner_call| Self::contains(inner_call)), + RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => calls.iter().all(|inner_call| Self::contains(inner_call)), + _ => matches!(c, + RuntimeCall::LLM(pallet_llm::Call::remark { .. }) | + RuntimeCall::LLM(pallet_llm::Call::send_llm { .. }) | + RuntimeCall::LLM(pallet_llm::Call::send_llm_to_politipool { .. }) | + RuntimeCall::Assets(pallet_assets::Call::transfer { .. }) | + RuntimeCall::Assets(pallet_assets::Call::transfer_keep_alive { .. }) | + RuntimeCall::Balances(pallet_balances::Call::transfer { .. }) | + RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { .. }) + ) + } + } +} + #[derive( Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, MaxEncodedLen, scale_info::TypeInfo, Serialize, Deserialize, )] @@ -672,6 +695,106 @@ pub fn get_account_id_from_string_hash(seed: &str) -> AccountId32 { AccountId32::from(public_key) } +#[cfg(test)] +mod senate_filter_tests { + use super::{SenateAccountCallFilter, RuntimeCall}; + use frame_support::{PalletId, traits::Contains}; + use sp_runtime::{traits::AccountIdConversion, AccountId32}; + + fn accid() -> AccountId32 { + PalletId(*b"12345678").into_account_truncating() + } + + fn acc() -> sp_runtime::MultiAddress { + accid().into() + } + + #[test] + fn allows_batch_all() { + sp_io::TestExternalities::default().execute_with(|| { + let calls = vec![ + RuntimeCall::LLM(pallet_llm::Call::remark { data: vec![].try_into().unwrap() }), + RuntimeCall::LLM(pallet_llm::Call::send_llm { to_account: accid(), amount: 1u8.into() }), + RuntimeCall::LLM(pallet_llm::Call::send_llm_to_politipool { to_account: accid(), amount: 1u8.into() }), + RuntimeCall::Balances(pallet_balances::Call::transfer { dest: acc(), value: 1u8.into() }), + RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { dest: acc(), value: 1u8.into() }), + RuntimeCall::Assets(pallet_assets::Call::transfer { id: 100.into(), target: acc(), amount: 1u8.into() }), + RuntimeCall::Assets(pallet_assets::Call::transfer_keep_alive { id: 100.into(), target: acc(), amount: 1u8.into() }), + ]; + let call = RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }); + assert!(SenateAccountCallFilter::contains(&call)); + }); + } + + #[test] + fn allows_batch() { + sp_io::TestExternalities::default().execute_with(|| { + let calls = vec![ + RuntimeCall::LLM(pallet_llm::Call::remark { data: vec![].try_into().unwrap() }), + RuntimeCall::LLM(pallet_llm::Call::send_llm { to_account: accid(), amount: 1u8.into() }), + RuntimeCall::LLM(pallet_llm::Call::send_llm_to_politipool { to_account: accid(), amount: 1u8.into() }), + RuntimeCall::Balances(pallet_balances::Call::transfer { dest: acc(), value: 1u8.into() }), + RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { dest: acc(), value: 1u8.into() }), + RuntimeCall::Assets(pallet_assets::Call::transfer { id: 100.into(), target: acc(), amount: 1u8.into() }), + RuntimeCall::Assets(pallet_assets::Call::transfer_keep_alive { id: 100.into(), target: acc(), amount: 1u8.into() }), + ]; + let call = RuntimeCall::Utility(pallet_utility::Call::batch { calls }); + assert!(SenateAccountCallFilter::contains(&call)); + }); + } + + #[test] + fn allows_lld_transfers() { + sp_io::TestExternalities::default().execute_with(|| { + let c = RuntimeCall::Balances(pallet_balances::Call::transfer { dest: acc(), value: 1u8.into() }); + assert!(SenateAccountCallFilter::contains(&c)); + let c = RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { dest: acc(), value: 1u8.into() }); + assert!(SenateAccountCallFilter::contains(&c)); + }); + } + + #[test] + fn allows_assets_transfers() { + sp_io::TestExternalities::default().execute_with(|| { + let c = RuntimeCall::Assets(pallet_assets::Call::transfer { id: 100.into(), target: acc(), amount: 1u8.into() }); + assert!(SenateAccountCallFilter::contains(&c)); + let c = RuntimeCall::Assets(pallet_assets::Call::transfer_keep_alive { id: 100.into(), target: acc(), amount: 1u8.into() }); + assert!(SenateAccountCallFilter::contains(&c)); + }); + } + + #[test] + fn allows_llm_transfers() { + sp_io::TestExternalities::default().execute_with(|| { + let c = RuntimeCall::LLM(pallet_llm::Call::remark { data: vec![].try_into().unwrap() }); + assert!(SenateAccountCallFilter::contains(&c)); + let c = RuntimeCall::LLM(pallet_llm::Call::send_llm { to_account: accid(), amount: 1u8.into() }); + assert!(SenateAccountCallFilter::contains(&c)); + let c = RuntimeCall::LLM(pallet_llm::Call::send_llm_to_politipool { to_account: accid(), amount: 1u8.into() }); + assert!(SenateAccountCallFilter::contains(&c)); + }); + } + + #[test] + fn disallows_other_stuff() { + sp_io::TestExternalities::default().execute_with(|| { + let c = RuntimeCall::System(frame_system::Call::remark { remark: vec![].try_into().unwrap() }); + assert!(!SenateAccountCallFilter::contains(&c)); + }); + } + + #[test] + fn disallows_batched_other_stuff() { + sp_io::TestExternalities::default().execute_with(|| { + let calls = vec![ + RuntimeCall::System(frame_system::Call::remark { remark: vec![].try_into().unwrap() }), + ]; + let call = RuntimeCall::Utility(pallet_utility::Call::batch { calls }); + assert!(!SenateAccountCallFilter::contains(&call)); + }); + } +} + #[cfg(test)] mod council_filter_tests { use crate::DAYS; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 1ddc47c46..5a5191c07 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -111,7 +111,7 @@ mod migrations; use impls::{ Author, ToAccountId, IdentityCallFilter, RegistryCallFilter, NftsCallFilter, OnLLMPoliticsUnlock, - ContainsMember, CouncilAccountCallFilter, EnsureCmp + ContainsMember, CouncilAccountCallFilter, EnsureCmp, SenateAccountCallFilter, }; /// Constant values used within the runtime. @@ -1588,6 +1588,20 @@ impl pallet_custom_account::Config for Runtime type Currency = Balances; } +parameter_types! { + pub const SenateAccountPalletId: PalletId = PalletId(*b"lltreasu"); +} + +impl pallet_custom_account::Config for Runtime { + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type PalletId = SenateAccountPalletId; + type ExecuteOrigin = EnsureSenateMajority; + type CallFilter = SenateAccountCallFilter; + type WeightInfo = (); + type Currency = Balances; +} + pub struct IntoAuthor; impl OnUnbalanced> for IntoAuthor { fn on_nonzero_unbalanced(credit: Credit) { @@ -1784,6 +1798,7 @@ construct_runtime!( PoolAssets: pallet_assets:: = 63, AssetConversionTxPayment: pallet_asset_conversion_tx_payment = 64, ContractsRegistry: pallet_contracts_registry = 65, + SenateAccount: pallet_custom_account:: = 66, // Sora Bridge: LeafProvider: leaf_provider = 80, @@ -1904,7 +1919,9 @@ mod staking_v12 { // All migrations executed on runtime upgrade as a nested tuple of types implementing // `OnRuntimeUpgrade`. -type Migrations = (); +type Migrations = ( + crate::migrations::add_senate_account_pallet::Migration, +); type EventRecord = frame_system::EventRecord< ::RuntimeEvent, diff --git a/substrate/bin/node/runtime/src/migrations.rs b/substrate/bin/node/runtime/src/migrations.rs index 113706b1f..330fd5bb0 100644 --- a/substrate/bin/node/runtime/src/migrations.rs +++ b/substrate/bin/node/runtime/src/migrations.rs @@ -67,6 +67,35 @@ pub mod add_sora_bridge { weight = weight.saturating_add(DbWeight::get().reads_writes(1, 1)); } + weight + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { + Ok(()) + } + } +} + +pub mod add_senate_account_pallet { + use super::*; + + pub struct Migration(sp_std::marker::PhantomData); + + impl OnRuntimeUpgrade for Migration { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + Ok(().encode()) + } + + fn on_runtime_upgrade() -> Weight { + let mut weight = DbWeight::get().reads(1); + + if StorageVersion::get::() == 0 { + StorageVersion::new(1).put::(); + weight = weight.saturating_add(DbWeight::get().reads_writes(1, 1)); + } + weight }