From 14e1bb0e93b7f40b69727e927f7b8a4e1c770324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20=C5=BBuk?= Date: Tue, 23 Jul 2024 12:04:49 +0200 Subject: [PATCH] BLOCKCHAIN-481 - add Ministry of Finance office --- substrate/bin/node/cli/src/chain_spec.rs | 6 +- substrate/bin/node/runtime/src/impls.rs | 163 +++++++++++++++++++ substrate/bin/node/runtime/src/lib.rs | 18 +- substrate/bin/node/runtime/src/migrations.rs | 58 ++----- 4 files changed, 194 insertions(+), 51 deletions(-) diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index f904bf8a7..fcd36e997 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -35,7 +35,7 @@ use kitchensink_runtime::{ IdentityOfficePalletId, AssetRegistryOfficeConfig, LandRegistryOfficePalletId, AssetRegistryOfficePalletId, MetaverseLandRegistryOfficeConfig, MetaverseLandRegistryOfficePalletId, - SenateConfig, + SenateConfig, MinistryOfFinanceOfficeConfig, impls::{RegistryCallFilter, IdentityCallFilter, NftsCallFilter}, }; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; @@ -455,6 +455,10 @@ pub fn testnet_genesis( admin: offices_admin.clone(), clerks: nfts_clerks.clone(), }, + ministry_of_finance_office: MinistryOfFinanceOfficeConfig { + admin: offices_admin.clone(), + clerks: vec![], + }, asset_registry_office: AssetRegistryOfficeConfig { admin: offices_admin, clerks: nfts_clerks, diff --git a/substrate/bin/node/runtime/src/impls.rs b/substrate/bin/node/runtime/src/impls.rs index c06d791f2..2ac5f5363 100644 --- a/substrate/bin/node/runtime/src/impls.rs +++ b/substrate/bin/node/runtime/src/impls.rs @@ -167,6 +167,67 @@ impl InstanceFilter for RegistryCallFilter { } } +#[derive( + Clone, + Eq, + PartialEq, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, + Serialize, + Deserialize, +)] +pub enum MinistryOfFinanceCallFilter { + FullRights, // all balances, assets and llm transfers, + batch + llm.remark + PooledMeritsRightsOnly, // llm.send_llm_to_politipool only, + batch + llm.remark +} + +impl Default for MinistryOfFinanceCallFilter { + fn default() -> Self { + MinistryOfFinanceCallFilter::PooledMeritsRightsOnly + } +} + +impl MinistryOfFinanceCallFilter { + fn tier_filter(&self, c: &RuntimeCall) -> bool { + match self { + Self::FullRights => matches!(c, + 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 { .. }) + ), + Self::PooledMeritsRightsOnly => matches!(c, + RuntimeCall::LLM(pallet_llm::Call::send_llm_to_politipool { .. }) + ), + } + } +} + +impl InstanceFilter for MinistryOfFinanceCallFilter { + fn filter(&self, c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Utility(pallet_utility::Call::batch { calls }) => calls.iter().all(|call| self.filter(call)), + RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => calls.iter().all(|call| self.filter(call)), + RuntimeCall::LLM(pallet_llm::Call::remark { .. }) => true, + _ => self.tier_filter(c), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (MinistryOfFinanceCallFilter::FullRights, _) => true, + (_, MinistryOfFinanceCallFilter::PooledMeritsRightsOnly) => false, + _ => false, + } + } +} + #[derive( Clone, Eq, @@ -953,6 +1014,108 @@ mod council_filter_tests { } } +#[cfg(test)] +mod ministry_of_finance_call_filter_tests { + use super::{MinistryOfFinanceCallFilter, RuntimeCall}; + use frame_support::{PalletId, traits::InstanceFilter}; + 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_remark() { + sp_io::TestExternalities::default().execute_with(|| { + let call = RuntimeCall::LLM(pallet_llm::Call::remark { data: vec![].try_into().unwrap() }); + assert!(MinistryOfFinanceCallFilter::FullRights.filter(&call)); + assert!(MinistryOfFinanceCallFilter::PooledMeritsRightsOnly.filter(&call)); + }); + } + + #[test] + fn allows_batch() { + sp_io::TestExternalities::default().execute_with(|| { + let call = RuntimeCall::LLM(pallet_llm::Call::remark { data: vec![].try_into().unwrap() }); + let call = RuntimeCall::Utility(pallet_utility::Call::batch { calls: vec![call] }).into(); + assert!(MinistryOfFinanceCallFilter::FullRights.filter(&call)); + assert!(MinistryOfFinanceCallFilter::PooledMeritsRightsOnly.filter(&call)); + }); + } + + #[test] + fn allows_batch_all() { + sp_io::TestExternalities::default().execute_with(|| { + let call = RuntimeCall::LLM(pallet_llm::Call::remark { data: vec![].try_into().unwrap() }); + let call = RuntimeCall::Utility(pallet_utility::Call::batch_all { calls: vec![call] }).into(); + assert!(MinistryOfFinanceCallFilter::FullRights.filter(&call)); + assert!(MinistryOfFinanceCallFilter::PooledMeritsRightsOnly.filter(&call)); + }); + } + + #[test] + fn allows_send_to_politipool() { + sp_io::TestExternalities::default().execute_with(|| { + let call = RuntimeCall::LLM(pallet_llm::Call::send_llm_to_politipool { to_account: accid(), amount: 1u8.into() }); + assert!(MinistryOfFinanceCallFilter::FullRights.filter(&call)); + assert!(MinistryOfFinanceCallFilter::PooledMeritsRightsOnly.filter(&call)); + }); + } + + #[test] + fn allows_tier1_liquid_transfer_lld() { + sp_io::TestExternalities::default().execute_with(|| { + let call = RuntimeCall::Balances(pallet_balances::Call::transfer { dest: acc(), value: 1u8.into() }); + assert!(MinistryOfFinanceCallFilter::FullRights.filter(&call)); + }); + } + + #[test] + fn allows_tier1_liquid_transfer_llm() { + sp_io::TestExternalities::default().execute_with(|| { + let call = RuntimeCall::LLM(pallet_llm::Call::send_llm { to_account: accid(), amount: 1u8.into() }); + assert!(MinistryOfFinanceCallFilter::FullRights.filter(&call)); + }); + } + + #[test] + fn allows_tier1_liquid_transfer_assets() { + sp_io::TestExternalities::default().execute_with(|| { + let call = RuntimeCall::Assets(pallet_assets::Call::transfer { id: 1u32.into(), target: acc(), amount: 1u8.into() }); + assert!(MinistryOfFinanceCallFilter::FullRights.filter(&call)); + }); + } + + #[test] + fn disallows_tier2_liquid_transfer_lld() { + sp_io::TestExternalities::default().execute_with(|| { + let call = RuntimeCall::Balances(pallet_balances::Call::transfer { dest: acc(), value: 1u8.into() }); + assert!(!MinistryOfFinanceCallFilter::PooledMeritsRightsOnly.filter(&call)); + }); + } + + #[test] + fn disallows_tier2_liquid_transfer_llm() { + sp_io::TestExternalities::default().execute_with(|| { + let call = RuntimeCall::LLM(pallet_llm::Call::send_llm { to_account: accid(), amount: 1u8.into() }); + assert!(!MinistryOfFinanceCallFilter::PooledMeritsRightsOnly.filter(&call)); + }); + } + + #[test] + fn disallows_tier2_liquid_transfer_assets() { + sp_io::TestExternalities::default().execute_with(|| { + let call = RuntimeCall::Assets(pallet_assets::Call::transfer { id: 1u32.into(), target: acc(), amount: 1u8.into() }); + assert!(!MinistryOfFinanceCallFilter::PooledMeritsRightsOnly.filter(&call)); + }); + } +} + #[cfg(test)] mod multiplier_tests { use frame_support::{ diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 3371c7d95..9290e50cc 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -112,6 +112,7 @@ use impls::{ Author, ToAccountId, IdentityCallFilter, RegistryCallFilter, NftsCallFilter, OnLLMPoliticsUnlock, ContainsMember, CouncilAccountCallFilter, EnsureCmp, ContractsCallFilter, SenateAccountCallFilter, + MinistryOfFinanceCallFilter, }; /// Constant values used within the runtime. @@ -1476,6 +1477,7 @@ parameter_types! { pub const LandRegistryOfficePalletId: PalletId = PalletId(*b"off/land"); pub const MetaverseLandRegistryOfficePalletId: PalletId = PalletId(*b"off/meta"); pub const AssetRegistryOfficePalletId: PalletId = PalletId(*b"off/asse"); + pub const MinistryOfFinanceOfficePalletId: PalletId = PalletId(*b"off/fina"); } type IdentityOfficeInstance = pallet_office::Instance1; @@ -1483,6 +1485,7 @@ type CompanyRegistryOfficeInstance = pallet_office::Instance2; type LandRegistryOfficeInstance = pallet_office::Instance3; type MetaverseLandRegistryOfficeInstance = pallet_office::Instance4; type AssetRegistryOfficeInstance = pallet_office::Instance5; +type MinistryOfFinanceOfficeInstance = pallet_office::Instance6; impl pallet_office::Config for Runtime { type RuntimeCall = RuntimeCall; @@ -1534,6 +1537,16 @@ impl pallet_office::Config for Runtime { type WeightInfo = (); } +impl pallet_office::Config for Runtime { + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type PalletId = MinistryOfFinanceOfficePalletId; + type ForceOrigin = EnsureRoot; + type AdminOrigin = EnsureSigned; + type CallFilter = MinistryOfFinanceCallFilter; + type WeightInfo = (); +} + parameter_types! { pub const LLDBridgePalletId: PalletId = PalletId(*b"lldbridg"); pub const LLMBridgePalletId: PalletId = PalletId(*b"llmbridg"); @@ -1794,6 +1807,7 @@ construct_runtime!( AssetConversionTxPayment: pallet_asset_conversion_tx_payment = 64, ContractsRegistry: pallet_contracts_registry = 65, SenateAccount: pallet_custom_account:: = 66, + MinistryOfFinanceOffice: pallet_office:: = 67, // Sora Bridge: LeafProvider: leaf_provider = 80, @@ -1853,8 +1867,8 @@ pub type Executive = frame_executive::Executive< // All migrations executed on runtime upgrade as a nested tuple of types implementing // `OnRuntimeUpgrade`. type Migrations = ( - // Migrations for spec version 26 - delete when bumping to v27 - crate::migrations::add_onchain_identities::Migration, + // Migrations for spec version 27 - delete when bumping to v28 + crate::migrations::add_ministry_of_finance_office_pallet::Migration, ); type EventRecord = frame_system::EventRecord< diff --git a/substrate/bin/node/runtime/src/migrations.rs b/substrate/bin/node/runtime/src/migrations.rs index e25510ecc..d524fd0cb 100644 --- a/substrate/bin/node/runtime/src/migrations.rs +++ b/substrate/bin/node/runtime/src/migrations.rs @@ -1,5 +1,5 @@ use super::*; -use frame_support::traits::OnRuntimeUpgrade; +use frame_support::{pallet_prelude::*, traits::OnRuntimeUpgrade}; #[cfg(feature = "try-runtime")] use sp_std::vec::Vec; @@ -9,11 +9,8 @@ use sp_runtime::TryRuntimeError; type DbWeight = ::DbWeight; -pub mod add_onchain_identities { +pub mod add_ministry_of_finance_office_pallet { use super::*; - use crate::Identity; - use pallet_identity::{Data, IdentityInfo, Judgement}; - use sp_core::crypto::Ss58Codec; pub struct Migration(sp_std::marker::PhantomData); @@ -24,49 +21,14 @@ pub mod add_onchain_identities { } fn on_runtime_upgrade() -> Weight { - let identities = vec![ - ("5EYCAe5hvejUE1BUTDSnxDfCqVkADRicSKqbcJrduV1KCDmk", b"Vault".to_vec()), - ("5EYCAe5hveooUENA5d7dwq3caqM4LLBzktNumMKmhNRXu4JE", b"Senate".to_vec()), - ( - "5EYCAe5iXF2YZuVZv1vig4xvf1CcDVocZCWYrv3TVSXpMTYA", - b"Citizenship Office".to_vec(), - ), - //("5EYCAe5ijiYfyeZ2JJCGq56LmPyNRAKzpG4QkoQkkQNB5e6Z", b"Treasury"), - skipping this as Polkadot.js Apps have it builtin - ("5EYCAe5g8CDuMsTief7QBxfvzDFEfws6ueXTUhsbx5V81nGH", b"Congress".to_vec()), - ("5GmkwXZ94cuLMMbtE5VtBaLpFDehoEpy6MZnJhkCSicxePs2", b"SORA Bridge".to_vec()), - ("5DSfG3S7qSZzrDMj3F3qYybXAy1BLsVpRG5CNwRdwwNPjgVm", b"MEXC".to_vec()), - ("5HEX1wk33NHAeEJV3B6goDHMJTqhy411znCUmfEAxKkQeqds", b"Coinstore".to_vec()), - ("5EYCAe5iXF2YZiuxDWAcwtPMDaG7ihsYzPxajcNKRpNyD1Zi", b"Company Registry Office".to_vec()), - ("5EYCAe5iXF2YZzoQHqGhj9dtcsUNB4puM5GqR1BwVHZyaWxM", b"Land Registry Office".to_vec()), - ("5EYCAe5iXF2Ya2c2iKjeFWUAXAEcMyoKCBPvhRy8YprHTLNd", b"Metaverse Land Registry Office".to_vec()), - ("5EYCAe5iXF2YZfPZ4arKGSYZvQruDacGHkuw4qAsQSQsKpMK", b"Asset Registry Office".to_vec()), - ("5EYCAe5iXF2YZpCZr7ALYUUYaNpMXde3NUXxYn1Sc1YRM4gV", b"Ministry of Finance Office".to_vec()), - ("5FBQRNJfzsttYvw1XnSwxwSUmb7A3EYm4q8aiscADREqvzYz", b"Wrapped LLD Token Contract".to_vec()), - ("5EYCAe5ijGqt3WEM9aKUBdth51NEBNz9P84NaUMWZazzWt7c", b"LLM Politipool Technical Account".to_vec()), - ("5GsBCWqN6mnrq4arSMBuT4uQ8GJKwgeBsa5UyCvTN6DyVj3S", b"Emirex".to_vec()), - ("5FhqVhuxGtcUBYXhyjtyvjh9jLucmoWzejcomA4HcqW9tBbP", b"LLM/LLD DEX Pool".to_vec()), - ]; - let mut weight = DbWeight::get().reads(0); - for (addr, display) in identities { - let account = AccountId::from_ss58check(addr).unwrap(); - let id = IdentityInfo { - twitter: Data::None, - additional: vec![].try_into().unwrap(), - display: Data::Raw(display.try_into().unwrap()), - legal: Data::None, - web: Data::None, - riot: Data::None, - email: Data::None, - pgp_fingerprint: None, - image: Data::None, - }; - let judgements = vec![(0, Judgement::KnownGood)].try_into().unwrap(); - let set_identity_weight = - Identity::set_identity_no_deposit(&account, judgements, id); - weight = weight.saturating_add(set_identity_weight); - } + let mut weight = DbWeight::get().reads(1); - weight + if StorageVersion::get::() == 0 { + StorageVersion::new(1).put::(); + weight = weight.saturating_add(DbWeight::get().reads_writes(1, 1)); + } + + weight } #[cfg(feature = "try-runtime")] @@ -74,4 +36,4 @@ pub mod add_onchain_identities { Ok(()) } } -} +} \ No newline at end of file