diff --git a/Cargo.lock b/Cargo.lock index 050d53cf6c..8fb988a1c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4876,7 +4876,6 @@ dependencies = [ "pallet-scheduler", "pallet-session", "pallet-sidechain", - "pallet-sudo", "pallet-teeracle", "pallet-teerex", "pallet-timestamp", diff --git a/node/src/chain_specs/litentry.rs b/node/src/chain_specs/litentry.rs index 3161a323a3..2a1b41ca23 100644 --- a/node/src/chain_specs/litentry.rs +++ b/node/src/chain_specs/litentry.rs @@ -79,6 +79,10 @@ pub fn get_chain_spec_dev() -> ChainSpec { get_account_id_from_seed::("Charlie"), DEFAULT_ENDOWED_ACCOUNT_BALANCE, ), + ( + get_account_id_from_seed::("Eve"), + DEFAULT_ENDOWED_ACCOUNT_BALANCE, + ), ], vec![ get_account_id_from_seed::("Alice"), diff --git a/node/src/chain_specs/litmus.rs b/node/src/chain_specs/litmus.rs index 252e24ca06..e76f993be6 100644 --- a/node/src/chain_specs/litmus.rs +++ b/node/src/chain_specs/litmus.rs @@ -18,7 +18,7 @@ use super::*; use cumulus_primitives_core::ParaId; use litmus_parachain_runtime::{ AccountId, AuraId, Balance, BalancesConfig, CollatorSelectionConfig, CouncilMembershipConfig, - GenesisConfig, ParachainInfoConfig, PolkadotXcmConfig, SessionConfig, SudoConfig, SystemConfig, + GenesisConfig, ParachainInfoConfig, PolkadotXcmConfig, SessionConfig, SystemConfig, TechnicalCommitteeMembershipConfig, TeerexConfig, UNIT, WASM_BINARY, }; use sc_service::ChainType; @@ -45,6 +45,7 @@ const DEFAULT_ENDOWED_ACCOUNT_BALANCE: Balance = 1000 * UNIT; /// GenesisInfo struct to store the parsed genesis_info JSON #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] +#[allow(dead_code)] struct GenesisInfo { root_key: AccountId, invulnerables: Vec<(AccountId, AuraId)>, @@ -63,7 +64,6 @@ pub fn get_chain_spec_dev() -> ChainSpec { ChainType::Development, move || { generate_genesis( - get_account_id_from_seed::("Alice"), vec![( get_account_id_from_seed::("Alice"), get_collator_keys_from_seed("Alice"), @@ -82,6 +82,10 @@ pub fn get_chain_spec_dev() -> ChainSpec { get_account_id_from_seed::("Charlie"), DEFAULT_ENDOWED_ACCOUNT_BALANCE, ), + ( + get_account_id_from_seed::("Eve"), + DEFAULT_ENDOWED_ACCOUNT_BALANCE, + ), ], vec![ get_account_id_from_seed::("Alice"), @@ -152,7 +156,6 @@ fn get_chain_spec_from_genesis_info( use std::str::FromStr; let genesis_info_cloned = genesis_info.clone(); generate_genesis( - genesis_info_cloned.root_key, genesis_info_cloned.invulnerables, u128::from_str(&genesis_info_cloned.candidacy_bond) .expect("Bad candicy bond; qed."), @@ -187,7 +190,6 @@ fn get_chain_spec_from_genesis_info( } fn generate_genesis( - root_key: AccountId, invulnerables: Vec<(AccountId, AuraId)>, candicy_bond: Balance, endowed_accounts: Vec<(AccountId, Balance)>, @@ -200,7 +202,6 @@ fn generate_genesis( code: WASM_BINARY.expect("WASM binary was not build, please build it!").to_vec(), }, balances: BalancesConfig { balances: endowed_accounts }, - sudo: SudoConfig { key: Some(root_key) }, parachain_info: ParachainInfoConfig { parachain_id: id }, collator_selection: CollatorSelectionConfig { invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), diff --git a/node/src/chain_specs/rococo.rs b/node/src/chain_specs/rococo.rs index e2b5556cf6..db0505e51d 100644 --- a/node/src/chain_specs/rococo.rs +++ b/node/src/chain_specs/rococo.rs @@ -80,6 +80,10 @@ pub fn get_chain_spec_dev() -> ChainSpec { get_account_id_from_seed::("Charlie"), DEFAULT_ENDOWED_ACCOUNT_BALANCE, ), + ( + get_account_id_from_seed::("Eve"), + DEFAULT_ENDOWED_ACCOUNT_BALANCE, + ), ], vec![ get_account_id_from_seed::("Alice"), diff --git a/runtime/litmus/Cargo.toml b/runtime/litmus/Cargo.toml index 6a91e6596b..3c311cafac 100644 --- a/runtime/litmus/Cargo.toml +++ b/runtime/litmus/Cargo.toml @@ -49,7 +49,6 @@ pallet-preimage = { git = "https://github.com/paritytech/substrate", default-fea pallet-proxy = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.29" } pallet-scheduler = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.29" } pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.29" } -pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.29" } pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.29" } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.29" } pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.29" } @@ -155,7 +154,6 @@ std = [ "pallet-proxy/std", "pallet-scheduler/std", "pallet-session/std", - "pallet-sudo/std", "pallet-timestamp/std", "pallet-transaction-payment/std", "pallet-transaction-payment-rpc-runtime-api/std", @@ -263,7 +261,6 @@ try-runtime = [ "pallet-scheduler/try-runtime", "pallet-session/try-runtime", "pallet-sidechain/try-runtime", - "pallet-sudo/try-runtime", "pallet-teeracle/try-runtime", "pallet-teerex/try-runtime", "pallet-timestamp/try-runtime", diff --git a/runtime/litmus/src/lib.rs b/runtime/litmus/src/lib.rs index e11e9aae87..addb57d432 100644 --- a/runtime/litmus/src/lib.rs +++ b/runtime/litmus/src/lib.rs @@ -33,7 +33,7 @@ use frame_support::{ weights::{constants::RocksDbWeight, ConstantMultiplier, IdentityFee, Weight}, PalletId, RuntimeDebug, }; -use frame_system::{EnsureRoot, EnsureSignedBy}; +use frame_system::EnsureSignedBy; use hex_literal::hex; // for TEE @@ -80,6 +80,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod asset_config; pub mod constants; +pub mod migration; pub mod weights; pub mod xcm_config; @@ -129,6 +130,7 @@ pub type Executive = frame_executive::Executive< // it was reverse order before. // See the comment before collation related pallets too. AllPalletsWithSystem, + migration::RemoveSudoAndStorage, >; impl_opaque_keys! { @@ -352,7 +354,7 @@ impl pallet_scheduler::Config for Runtime { type PalletsOrigin = OriginCaller; type Call = Call; type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureRoot; + type ScheduleOrigin = EnsureRootOrAllCouncil; type MaxScheduledPerBlock = ConstU32<50>; type WeightInfo = weights::pallet_scheduler::WeightInfo; type OriginPrivilegeCmp = frame_support::traits::EqualPrivilegeOnly; @@ -369,7 +371,7 @@ impl pallet_preimage::Config for Runtime { type WeightInfo = weights::pallet_preimage::WeightInfo; type Event = Event; type Currency = Balances; - type ManagerOrigin = EnsureRoot; + type ManagerOrigin = EnsureRootOrAllCouncil; type MaxSize = PreimageMaxSize; type BaseDeposit = PreimageBaseDeposit; type ByteDeposit = PreimageByteDeposit; @@ -454,7 +456,7 @@ impl pallet_democracy::Config for Runtime { // To cancel a proposal before it has been passed, the technical committee must be unanimous or // Root must agree. type CancelProposalOrigin = EnsureRootOrAllTechnicalCommittee; - type BlacklistOrigin = EnsureRoot; + type BlacklistOrigin = EnsureRootOrAllCouncil; // Any single technical committee member may veto a coming council proposal, however they can // only do it once and it lasts only for the cool-off period. type VetoOrigin = pallet_collective::EnsureMember; @@ -581,11 +583,6 @@ impl pallet_bounties::Config for Runtime { type ChildBountyManager = (); } -impl pallet_sudo::Config for Runtime { - type Call = Call; - type Event = Event; -} - parameter_types! { pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); @@ -613,8 +610,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ChannelInfo = ParachainSystem; // We use pallet_xcm to confirm the version of xcm type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; - type ControllerOrigin = EnsureRoot; + type ExecuteOverweightOrigin = EnsureRootOrAllCouncil; + type ControllerOrigin = EnsureRootOrAllCouncil; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; } @@ -622,7 +619,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { impl cumulus_pallet_dmp_queue::Config for Runtime { type Event = Event; type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type ExecuteOverweightOrigin = EnsureRootOrAllCouncil; } parameter_types! { @@ -802,7 +799,7 @@ ord_parameter_types! { impl pallet_identity_management_mock::Config for Runtime { type Event = Event; - type ManageWhitelistOrigin = EnsureRoot; + type ManageWhitelistOrigin = EnsureRootOrAllCouncil; type MaxVerificationDelay = ConstU32<10>; // intentionally use ALICE for the IMP mock type TEECallOrigin = EnsureSignedBy; @@ -892,9 +889,6 @@ construct_runtime! { // Mock IdentityManagementMock: pallet_identity_management_mock = 100, - - // TMP - Sudo: pallet_sudo = 255, } } @@ -904,8 +898,8 @@ impl Contains for BaseCallFilter { fn contains(call: &Call) -> bool { if matches!( call, - Call::Sudo(_) | - Call::System(_) | Call::Timestamp(_) | + Call::System(_) | + Call::Timestamp(_) | Call::ParachainSystem(_) | Call::ExtrinsicFilter(_) | Call::Multisig(_) | diff --git a/runtime/litmus/src/migration/mod.rs b/runtime/litmus/src/migration/mod.rs new file mode 100644 index 0000000000..f684510cff --- /dev/null +++ b/runtime/litmus/src/migration/mod.rs @@ -0,0 +1,70 @@ +// Copyright 2020-2021 Litentry Technologies GmbH. +// This file is part of Litentry. +// +// Litentry 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. +// +// Litentry 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 Litentry. If not, see . +use frame_support::{ + traits::{Get, OnRuntimeUpgrade}, + StorageHasher, Twox128, +}; +use sp_std::marker::PhantomData; + +pub struct RemoveSudoAndStorage(PhantomData); +impl OnRuntimeUpgrade for RemoveSudoAndStorage +where + T: frame_system::Config, +{ + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + log::info!("Pre check pallet Sudo exists"); + assert!( + frame_support::storage::migration::have_storage_value(b"Sudo", b"Key", b"",), + "Storage query fails: Sudo Key" + ); + Ok(()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + use sp_io::KillStorageResult; + // Remove Sudo Storage + // TODO: Very Weak safety + let entries: u64 = 4 + 100; + let _res: KillStorageResult = frame_support::storage::unhashed::clear_prefix( + &Twox128::hash(b"Sudo"), + Some(entries.try_into().unwrap()), + None, + ) + .into(); + ::DbWeight::get().writes(entries) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + use sp_io::KillStorageResult; + + log::info!("Post check Sudo"); + let res: KillStorageResult = + frame_support::storage::unhashed::clear_prefix(&Twox128::hash(b"Sudo"), Some(0), None) + .into(); + + match res { + KillStorageResult::AllRemoved(0) | KillStorageResult::SomeRemaining(0) => {}, + KillStorageResult::AllRemoved(n) | KillStorageResult::SomeRemaining(n) => { + log::error!("Remaining entries: {:?}", n); + return Err("Sudo not removed") + }, + }; + + Ok(()) + } +} diff --git a/ts-tests/tests/base-filter.test.ts b/ts-tests/tests/base-filter.test.ts index 781ec55704..cd46a4cc0a 100644 --- a/ts-tests/tests/base-filter.test.ts +++ b/ts-tests/tests/base-filter.test.ts @@ -27,16 +27,23 @@ describeLitentry('Test Base Filter', ``, (context) => { expect(eveCurrentNonce.toNumber()).to.equal(eveInitNonce.toNumber() + 1); // the balance transfer should work for litmus|rococo but not for litentry - if (context.parachain === 'litentry') { + const parachain = (await context.api.rpc.system.chain()).toString().toLowerCase(); + if (parachain === 'litentry-dev') { expect(bobCurrentBalance.free.toBigInt()).to.equal(bobInitBalance.free.toBigInt()); - } else if (context.parachain === 'litmus' || context.parachain === 'rococo') { + } else if (parachain === 'litmus-dev' || parachain === 'litentry-rococo-dev') { expect(bobCurrentBalance.free.toBigInt()).to.equal(bobInitBalance.free.toBigInt() + BigInt(1000)); } else { - assert.fail('unsupported parachain type'); + assert.fail('unsupported parachain type', parachain); } }); step('Transfer 1000 unit from Eve to Bob with Sudo', async function () { + // only work for litentry|rococo + const parachain = (await context.api.rpc.system.chain()).toString().toLowerCase(); + if (parachain === 'litmus-dev') { + console.log("skip test.") + return + } // Get the initial balance of Alice and Bob const { nonce: aliceInitNonce, data: aliceInitBalance } = await context.api.query.system.account( context.alice.address diff --git a/ts-tests/tests/bridge.test.ts b/ts-tests/tests/bridge.test.ts index 5121034147..60267a84ec 100644 --- a/ts-tests/tests/bridge.test.ts +++ b/ts-tests/tests/bridge.test.ts @@ -20,17 +20,25 @@ describeCrossChainTransfer('Test Cross-chain Transfer', ``, (context) => { //FERDIE key command: polkadot key inspect //Ferdie const destinationRecipientAddress = '0x1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c'; - await erc20.approve(context.ethConfig.erc20Handler.address, depositAmount); - await sleep(2); - let data = createERCDepositData(depositAmount, 32, destinationRecipientAddress); const beforeAccountData = await context.parachainConfig.api.query.system.account( context.parachainConfig.ferdie.address ); + console.log("before deposit: ", beforeAccountData.toString()) + + // approve + await erc20.approve(context.ethConfig.erc20Handler.address, depositAmount); + await sleep(6); + + // deposit + let data = createERCDepositData(depositAmount, 32, destinationRecipientAddress); await bridge.deposit(destinationChainID, destResourceId, data); - await sleep(36); + await sleep(12 * 4); + const afterAccountData = await context.parachainConfig.api.query.system.account( context.parachainConfig.ferdie.address ); + console.log("after deposit: ", afterAccountData.toString()) + assert.equal( bn100e12.add(beforeAccountData.data.free.toBn()).toString(), afterAccountData.data.free.toBn().toString() diff --git a/ts-tests/tests/setup-bridge.ts b/ts-tests/tests/setup-bridge.ts index 34d4d54110..3749106c7e 100644 --- a/ts-tests/tests/setup-bridge.ts +++ b/ts-tests/tests/setup-bridge.ts @@ -5,7 +5,14 @@ import { Contract, ethers, Wallet } from 'ethers'; import { BN } from '@polkadot/util'; import fs from 'fs'; import { spawn } from 'child_process'; -import { initApiPromise, loadConfig, ParachainConfig, signAndSend, sleep } from './utils'; +import { + initApiPromise, + loadConfig, + ParachainConfig, + signAndSend, + sleep, + sudoWrapper +} from './utils'; import { toWei } from 'web3-utils'; const path = require('path'); @@ -137,30 +144,30 @@ async function setupCrossChainTransfer( for (let i = 0; i < parachainRelayers.length; i++) { const isRelayer = await pConfig.api.query.chainBridge.relayers(parachainRelayers[i]); if (!isRelayer.toHuman()) { - extrinsic.push(pConfig.api.tx.sudo.sudo(pConfig.api.tx.chainBridge.addRelayer(parachainRelayers[i]))); + extrinsic.push(await sudoWrapper(pConfig.api, pConfig.api.tx.chainBridge.addRelayer(parachainRelayers[i]))); } } - const filterMode = (await pConfig.api.query.extrinsicFilter.mode()).toHuman(); - if ('Test' !== filterMode) { - extrinsic.push(pConfig.api.tx.sudo.sudo(pConfig.api.tx.extrinsicFilter.setMode('Test'))); - } + // const filterMode = (await pConfig.api.query.extrinsicFilter.mode()).toHuman(); + // if ('Test' !== filterMode) { + // extrinsic.push(pConfig.api.tx.sudo.sudo(pConfig.api.tx.extrinsicFilter.setMode('Test'))); + // } const whitelist = await pConfig.api.query.chainBridge.chainNonces(sourceChainID); if (!whitelist.toHuman()) { - extrinsic.push(pConfig.api.tx.sudo.sudo(pConfig.api.tx.chainBridge.whitelistChain(sourceChainID))); + extrinsic.push(await sudoWrapper(pConfig.api, pConfig.api.tx.chainBridge.whitelistChain(sourceChainID))); } const resource = await pConfig.api.query.chainBridge.resources(destResourceId); if (resource.toHuman() !== 'BridgeTransfer.transfer') { extrinsic.push( - pConfig.api.tx.sudo.sudo(pConfig.api.tx.chainBridge.setResource(destResourceId, 'BridgeTransfer.transfer')) + await sudoWrapper(pConfig.api, pConfig.api.tx.chainBridge.setResource(destResourceId, 'BridgeTransfer.transfer')) ); } const fee = await pConfig.api.query.chainBridge.bridgeFee(sourceChainID); if (!fee || fee.toString() !== parachainFee.toString()) { - extrinsic.push(pConfig.api.tx.sudo.sudo(pConfig.api.tx.chainBridge.updateFee(0, parachainFee))); + extrinsic.push(await sudoWrapper(pConfig.api, pConfig.api.tx.chainBridge.updateFee(0, parachainFee))); } if (extrinsic.length > 0) { @@ -235,7 +242,7 @@ async function startChainBridge( require('dotenv').config(); const dataDir = './bridge/data'; if (!fs.existsSync(dataDir)) { - fs.mkdirSync(dataDir, { recursive: true }); + fs.mkdirSync(dataDir, {recursive: true}); } emptyDir(dataDir); const ethBlock = await ethConfig.wallets.bob.provider.getBlockNumber(); @@ -243,12 +250,12 @@ async function startChainBridge( const parachainChainID = parseInt(parachainConfig.api.consts.chainBridge.bridgeChainId.toString()) //parachain generateBridgeConfig(ethConfig, ethRelayer, parachainRelayer, ethBlock, subBlock.number.toNumber(), parachainChainID, config); - const logging = fs.createWriteStream(log, { flags: 'w+' }); + const logging = fs.createWriteStream(log, {flags: 'w+'}); const lsProcess = spawn( // `${process.env.GOPATH}/bin/chainbridge`, bridgePath, ['--verbosity', 'trace', '--blockstore', dataDir, '--config', config, '--keystore', './bridge/keys'], - { env: { STAGE: 'dev' } } + {env: {STAGE: 'dev'}} ); lsProcess.stdout.pipe(logging); lsProcess.stderr.pipe(logging); @@ -296,7 +303,13 @@ export function describeCrossChainTransfer( dave: new ethers.Wallet(generateTestKeys().dave, provider), eve: new ethers.Wallet(generateTestKeys().eve, provider), }; - const { bridge, erc20Handler, erc721Handler, genericHandler, erc20 } = await deployBridgeContracts( + const { + bridge, + erc20Handler, + erc721Handler, + genericHandler, + erc20 + } = await deployBridgeContracts( wallets.alice ); @@ -331,7 +344,8 @@ export function describeCrossChainTransfer( await sleep(5); }); - after(async function () {}); + after(async function () { + }); cb(context); }); diff --git a/ts-tests/tests/utils.ts b/ts-tests/tests/utils.ts index 4f520152ea..8a17a72a24 100644 --- a/ts-tests/tests/utils.ts +++ b/ts-tests/tests/utils.ts @@ -64,12 +64,6 @@ export async function initApiPromise(config: any): Promise { '0x8c35b97c56099cf3b5c631d1f296abbb11289857e74a8f60936290080d56da6d' ); - // Set Eve's balance to 1000000000000000 - const eve_info = await api.query.system.account(eve.address); - if (eve_info.data.free.lt(new BN(1000000000000000))) { - const txSetBalance = api.tx.sudo.sudo(api.tx.balances.setBalance(eve.address, 1000000000000000, 0)); - await signAndSend(txSetBalance, alice); - } const { nonce: nonceAlice, data: balanceAlice } = await api.query.system.account(alice.address); const { nonce: nonceBob, data: balanceBob } = await api.query.system.account(bob.address); const { nonce: nonceEve, data: balanceEve } = await api.query.system.account(eve.address); @@ -106,6 +100,21 @@ export function signAndSend(tx: SubmittableExtrinsic, account: Address }); } +/// After removing the sudo module, we use `EnsureRootOrHalfCouncil` instead of `Sudo`, +// and there are only two council members in litmus-dev/rococo-dev/litentry-dev. +// So only `propose` is required, no vote. +// TODO support to send the `vote extrinsic`, if the number of council members is greater than 2. +export async function sudoWrapper(api: ApiPromise, tx: SubmittableExtrinsic) { + const chain = (await api.rpc.system.chain()).toString().toLowerCase(); + if (chain == 'litmus-dev') { + const threshold = api.createType("Compact", 1); + const call = api.createType("Call", tx); + return api.tx.council.propose(threshold, call, api.createType("Compact", tx.length)) + } else { + return api.tx.sudo.sudo(tx); + } +} + export function describeLitentry(title: string, specFilename: string, cb: (context: ParachainConfig) => void) { describe(title, function () { // Set timeout to 6000 seconds (Because of 50-blocks delay of rococo, so called "training wheels")