diff --git a/Cargo.lock b/Cargo.lock index f6c3a59..879683d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6683,6 +6683,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-balances", + "pallet-collective", "pallet-evm", "pallet-session", "pallet-timestamp", diff --git a/pallets/upgrade-runtime-proposal/src/lib.rs b/pallets/upgrade-runtime-proposal/src/lib.rs index a953de2..bb1116f 100644 --- a/pallets/upgrade-runtime-proposal/src/lib.rs +++ b/pallets/upgrade-runtime-proposal/src/lib.rs @@ -14,6 +14,7 @@ use frame_support::dispatch::UnfilteredDispatchable; use frame_support::traits::EnsureOrigin; use frame_system::pallet_prelude::BlockNumberFor; use frame_system::pallet_prelude::OriginFor; +use frame_support::sp_runtime::traits::Hash; #[frame_support::pallet] pub mod pallet { @@ -173,6 +174,12 @@ pub mod pallet { >::get() } + pub fn hash_of_proposed_code() -> Option { + >::get().map(|code| { + T::Hashing::hash(&code) + }) + } + pub fn set_application_block_number(block_number: T::BlockNumber) { >::put(block_number); } diff --git a/precompiles/upgrade-runtime-controller/Cargo.toml b/precompiles/upgrade-runtime-controller/Cargo.toml index 66079f6..c7cc6e4 100644 --- a/precompiles/upgrade-runtime-controller/Cargo.toml +++ b/precompiles/upgrade-runtime-controller/Cargo.toml @@ -22,6 +22,7 @@ pallet-evm = { workspace = true, features = [ "forbid-evm-reentrancy" ] } # Stability pallet-upgrade-runtime-proposal = { workspace = true } precompile-utils = { workspace = true } +pallet-collective = { workspace = true } [dev-dependencies] pallet-balances = { workspace = true } diff --git a/precompiles/upgrade-runtime-controller/UpgradeRuntimeController.sol b/precompiles/upgrade-runtime-controller/UpgradeRuntimeController.sol index d90756c..61b68c5 100644 --- a/precompiles/upgrade-runtime-controller/UpgradeRuntimeController.sol +++ b/precompiles/upgrade-runtime-controller/UpgradeRuntimeController.sol @@ -4,4 +4,7 @@ pragma solidity >=0.8.3; interface UpgradeRuntimeController { function setApplicationBlock(uint32 block) external; // onlyOwner function rejectProposedCode() external; // onlyOwner + function addMemberToTechnicalCommittee(address member) external; // onlyOwner + function removeMemberFromTechnicalCommittee(address member) external; // onlyOwner + function getHashOfProposedCode() external view returns (bytes32); } \ No newline at end of file diff --git a/precompiles/upgrade-runtime-controller/src/lib.rs b/precompiles/upgrade-runtime-controller/src/lib.rs index 6494c2b..78a7a0d 100644 --- a/precompiles/upgrade-runtime-controller/src/lib.rs +++ b/precompiles/upgrade-runtime-controller/src/lib.rs @@ -31,6 +31,8 @@ use frame_support::parameter_types; use frame_support::storage::types::{StorageValue, ValueQuery}; use frame_support::traits::StorageInstance; +use frame_support::traits::ChangeMembers; +use frame_support::inherent::Vec; use precompile_utils::prelude::*; use sp_core::Get; @@ -83,13 +85,14 @@ pub struct UpgradeRuntimeControllerPrecompile + impl UpgradeRuntimeControllerPrecompile where DefaultOwner: Get + 'static, - Runtime: - pallet_upgrade_runtime_proposal::Config + pallet_timestamp::Config + pallet_evm::Config, + Runtime: pallet_upgrade_runtime_proposal::Config + pallet_collective::Config + pallet_timestamp::Config + pallet_evm::Config, Runtime::RuntimeCall: From>, ::RuntimeOrigin: From>, Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, ::Moment: Into, ::BlockNumber: From, + ::Hash: Into, + ::AccountId: From, { #[precompile::public("owner()")] #[precompile::view] @@ -221,4 +224,80 @@ where Ok(()) } + + #[precompile::public("addMemberToTechnicalCommittee(address)")] + fn add_member_to_technical_committee( + handle: &mut impl PrecompileHandle, + member: Address, + ) -> EvmResult { + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + + let member_id: H160 = member.into(); + + let old_members = pallet_collective::Pallet::::members(); + + if old_members.contains(&member_id.into()) { + return Err(revert("Already a member")); + } + + let mut new_members = old_members + .iter() + .cloned() + .chain(Some(member_id.into())) + .collect::>(); + + new_members.sort(); + + pallet_collective::Pallet::::set_members_sorted( + &new_members, + &old_members + ); + + Ok(()) + } + + #[precompile::public("removeMemberFromTechnicalCommittee(address)")] + fn remove_member_to_technical_committee( + handle: &mut impl PrecompileHandle, + member: Address, + ) -> EvmResult { + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + + let member_id: H160 = member.into(); + let member_account = ::AccountId::from(member_id); + + let old_members = pallet_collective::Pallet::::members(); + + if !old_members.contains(&member_account) { + return Err(revert("Not a member")); + } + + let mut new_members = old_members + .iter() + .cloned() + .filter(|m| *m != member_account) + .collect::>(); + + new_members.sort(); + + pallet_collective::Pallet::::set_members_sorted( + &new_members, + &old_members + ); + + Ok(()) + } + + #[precompile::public("getHashOfProposedCode()")] + #[precompile::view] + fn get_hash_of_proposed_code(handle: &mut impl PrecompileHandle) -> EvmResult { + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + + let hash = pallet_upgrade_runtime_proposal::Pallet::::hash_of_proposed_code(); + + match hash { + Some(hash) => Ok(hash.into()), + None => Ok(H256::default()), + } + } }