Skip to content

Commit

Permalink
Merge branch 'main' into feat/caller-for-jobs
Browse files Browse the repository at this point in the history
  • Loading branch information
salman01zp authored Nov 24, 2023
2 parents 8070b6e + 973f230 commit f3fefce
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 82 deletions.
20 changes: 6 additions & 14 deletions pallets/jobs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use sp_std::{prelude::*, vec::Vec};
use tangle_primitives::{
jobs::{JobId, JobInfo, JobKey, PhaseOneResult, ValidatorOffence},
traits::{
jobs::{JobResultVerifier, JobToFee},
jobs::{JobToFee, MPCHandler},
roles::RolesHandler,
},
};
Expand Down Expand Up @@ -71,11 +71,7 @@ pub mod module {
type RolesHandler: RolesHandler<Self::AccountId>;

/// The job result verifying mechanism
type JobResultVerifier: JobResultVerifier<
Self::AccountId,
BlockNumberFor<Self>,
BalanceOf<Self>,
>;
type MPCHandler: MPCHandler<Self::AccountId, BlockNumberFor<Self>, BalanceOf<Self>>;

/// The origin which may set filter.
type ForceOrigin: EnsureOrigin<Self::RuntimeOrigin>;
Expand Down Expand Up @@ -210,7 +206,7 @@ pub mod module {

for participant in participants {
ensure!(
T::RolesHandler::is_validator(participant.clone(), job_key.clone().into()),
T::RolesHandler::is_validator(participant.clone(), job_key.clone()),
Error::<T>::InvalidValidator
);

Expand Down Expand Up @@ -238,7 +234,7 @@ pub mod module {
// Ensure the phase one participants are still validators
for participant in result.participants {
ensure!(
T::RolesHandler::is_validator(participant.clone(), job_key.clone().into()),
T::RolesHandler::is_validator(participant.clone(), job_key.clone()),
Error::<T>::InvalidValidator
);

Expand Down Expand Up @@ -341,7 +337,7 @@ pub mod module {
};

// Validate the result
T::JobResultVerifier::verify(&job_info, phase1_result.clone(), result.clone())?;
T::MPCHandler::verify(&job_info, phase1_result.clone(), result.clone())?;

// If phase 1, store in known result
if job_info.job_type.is_phase_one() {
Expand Down Expand Up @@ -486,11 +482,7 @@ pub mod module {
ensure!(participants.contains(&validator), Error::<T>::JobNotFound);

// Validate the result
T::JobResultVerifier::verify_validator_report(
validator.clone(),
offence.clone(),
signatures,
)?;
T::MPCHandler::verify_validator_report(validator.clone(), offence.clone(), signatures)?;

// Slash the validator
T::RolesHandler::slash_validator(validator.clone(), offence)?;
Expand Down
14 changes: 9 additions & 5 deletions pallets/jobs/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub type AccountId = u128;
pub type Balance = u128;
pub type BlockNumber = u64;

use tangle_primitives::{jobs::*, roles::RoleType};
use tangle_primitives::jobs::*;

impl frame_system::Config for Runtime {
type RuntimeOrigin = RuntimeOrigin;
Expand Down Expand Up @@ -128,7 +128,7 @@ impl JobToFee<AccountId, BlockNumber> for MockJobToFeeHandler {
pub struct MockRolesHandler;

impl RolesHandler<AccountId> for MockRolesHandler {
fn is_validator(address: AccountId, _role_type: RoleType) -> bool {
fn is_validator(address: AccountId, _role_type: JobKey) -> bool {
let validators = [1, 2, 3, 4, 5];
validators.contains(&address)
}
Expand All @@ -138,9 +138,9 @@ impl RolesHandler<AccountId> for MockRolesHandler {
}
}

pub struct MockJobResultVerifier;
pub struct MockMPCHandler;

impl JobResultVerifier<AccountId, BlockNumber, Balance> for MockJobResultVerifier {
impl MPCHandler<AccountId, BlockNumber, Balance> for MockMPCHandler {
fn verify(
job: &JobInfo<AccountId, BlockNumber, Balance>,
phase_one_data: Option<PhaseOneResult<AccountId, BlockNumber>>,
Expand All @@ -161,6 +161,10 @@ impl JobResultVerifier<AccountId, BlockNumber, Balance> for MockJobResultVerifie
) -> DispatchResult {
Ok(())
}

fn validate_authority_key(_validator: AccountId, _authority_key: Vec<u8>) -> DispatchResult {
Ok(())
}
}

parameter_types! {
Expand All @@ -173,7 +177,7 @@ impl Config for Runtime {
type Currency = Balances;
type JobToFee = MockJobToFeeHandler;
type RolesHandler = MockRolesHandler;
type JobResultVerifier = MockJobResultVerifier;
type MPCHandler = MockMPCHandler;
type PalletId = JobsPalletId;
type WeightInfo = ();
}
Expand Down
13 changes: 8 additions & 5 deletions pallets/roles/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,24 @@
// along with Tangle. If not, see <http://www.gnu.org/licenses/>.

use super::*;
use sp_runtime::{DispatchResult, Percent, Saturating};
use tangle_primitives::{roles::RoleType, traits::roles::RolesHandler};
use frame_support::pallet_prelude::DispatchResult;
use sp_runtime::{Percent, Saturating};
use tangle_primitives::{jobs::JobKey, traits::roles::RolesHandler};

/// Implements RolesHandler for the pallet.
impl<T: Config> RolesHandler<T::AccountId> for Pallet<T> {
/// Validates if the given address has the given role.
///
/// # Parameters
/// - `address`: The account ID of the validator.
/// - `role`: The key representing the type of job.
/// - `job`: The key representing the type of job.
///
/// # Returns
/// Returns `true` if the validator is permitted to work with this job type, otherwise `false`.
fn is_validator(address: T::AccountId, role: RoleType) -> bool {
Self::has_role(address, role)
fn is_validator(address: T::AccountId, job_key: JobKey) -> bool {
let assigned_roles = AccountRolesMapping::<T>::get(address);
let job_role = job_key.get_role_type();
assigned_roles.contains(&job_role)
}

/// Slash validator stake for the reported offence. The function should be a best effort
Expand Down
82 changes: 68 additions & 14 deletions pallets/roles/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ use parity_scale_codec::{Decode, Encode};
use scale_info::TypeInfo;
use sp_runtime::{codec, traits::Zero, Saturating};
use sp_std::{convert::TryInto, prelude::*, vec};
use tangle_primitives::roles::RoleType;
use tangle_primitives::{
roles::{RoleType, RoleTypeMetadata},
traits::jobs::JobsHandler,
};
mod impls;
#[cfg(test)]
pub(crate) mod mock;
Expand Down Expand Up @@ -66,8 +69,8 @@ pub struct RoleStakingLedger<T: Config> {
#[derive(PartialEqNoBound, EqNoBound, Encode, Decode, RuntimeDebugNoBound, TypeInfo, Clone)]
#[scale_info(skip_type_params(T))]
pub struct RoleStakingRecord<T: Config> {
/// Role type
pub role: RoleType,
/// Metadata associated with the role.
pub metadata: RoleTypeMetadata,
/// The total amount of the stash's balance that is re-staked for selected role.
#[codec(compact)]
pub re_staked: BalanceOf<T>,
Expand All @@ -94,6 +97,10 @@ pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use tangle_primitives::{
jobs::{JobId, JobKey},
traits::jobs::MPCHandler,
};

#[pallet::pallet]
#[pallet::without_storage_info]
Expand All @@ -105,9 +112,16 @@ pub mod pallet {
/// The overarching event type.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

/// The job manager mechanism.
type JobsHandler: JobsHandler<Self::AccountId>;

/// Max roles per account.
#[pallet::constant]
type MaxRolesPerAccount: Get<u32>;

/// The config that verifies MPC related functions
type MPCHandler: MPCHandler<Self::AccountId, BlockNumberFor<Self>, BalanceOf<Self>>;

type WeightInfo: WeightInfo;
}

Expand All @@ -120,6 +134,8 @@ pub mod pallet {
RoleRemoved { account: T::AccountId, role: RoleType },
/// Slashed validator.
Slashed { account: T::AccountId, amount: BalanceOf<T> },
/// Pending jobs,that cannot be opted out at the moment.
PendingJobs { pending_jobs: Vec<(JobKey, JobId)> },
}

#[pallet::error]
Expand All @@ -140,6 +156,8 @@ pub mod pallet {
AccountAlreadyPaired,
/// Stash controller account not found in Roles Ledger.
AccountNotPaired,
/// Role clear request failed due to pending jobs, which can't be opted out at the moment.
RoleClearRequestFailed,
}

/// Map from all "controller" accounts to the info regarding the staking.
Expand Down Expand Up @@ -200,10 +218,19 @@ pub mod pallet {

// Validate role staking records.
for record in records.clone() {
let role = record.role;
let role = record.metadata.get_role_type();
let re_stake_amount = record.re_staked;
// Check if role is already assigned.
ensure!(!Self::has_role(stash_account.clone(), role), Error::<T>::HasRoleAssigned);
ensure!(
!Self::has_role(stash_account.clone(), role.clone()),
Error::<T>::HasRoleAssigned
);

// validate the metadata
T::MPCHandler::validate_authority_key(
stash_account.clone(),
record.metadata.get_authority_key(),
)?;

// Re-staking amount of record should meet min re-staking amount requirement.
let min_re_staking_bond = MinReStakingBond::<T>::get();
Expand All @@ -219,16 +246,16 @@ pub mod pallet {
);

ledger.total = ledger.total.saturating_add(re_stake_amount);
let role_info = RoleStakingRecord { role, re_staked: re_stake_amount };
ledger.roles.push(role_info);
ledger.roles.push(record);
}

// Now that records are validated we can add them and update ledger
for record in records {
Self::add_role(stash_account.clone(), record.role)?;
let role = record.metadata.get_role_type();
Self::add_role(stash_account.clone(), role.clone())?;
Self::deposit_event(Event::<T>::RoleAssigned {
account: stash_account.clone(),
role: record.role,
role,
});
}
Self::update_ledger(&stash_account, &ledger);
Expand Down Expand Up @@ -258,14 +285,41 @@ pub mod pallet {
);

// check if role is assigned.
ensure!(Self::has_role(stash_account.clone(), role), Error::<T>::NoRoleAssigned);
ensure!(
Self::has_role(stash_account.clone(), role.clone()),
Error::<T>::NoRoleAssigned
);

// Get active jobs for the role.
let active_jobs = T::JobsHandler::get_active_jobs(stash_account.clone());
let mut role_cleared = true;
let mut pending_jobs = Vec::new();
for job in active_jobs {
let job_key = job.0;
if job_key.get_role_type() == role {
// Submit request to exit from the known set.
let res = T::JobsHandler::exit_from_known_set(
stash_account.clone(),
job_key.clone(),
job.1,
);

if res.is_err() {
role_cleared = false;
pending_jobs.push((job_key.clone(), job.1));
}
}
}

// TODO: Call jobs manager to remove the services.
// On successful removal of services, remove the role from the mapping.
// Issue link for reference : https://github.com/webb-tools/tangle/issues/292
if !role_cleared {
// Role clear request failed due to pending jobs, which can't be opted out at the
// moment.
Self::deposit_event(Event::<T>::PendingJobs { pending_jobs });
return Err(Error::<T>::RoleClearRequestFailed.into())
};

// Remove role from the mapping.
Self::remove_role(stash_account.clone(), role)?;
Self::remove_role(stash_account.clone(), role.clone())?;
// Remove stash account related info.
Self::kill_stash(&stash_account);

Expand Down
47 changes: 46 additions & 1 deletion pallets/roles/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ use sp_core::H256;
use sp_runtime::{
testing::{Header, UintAuthorityId},
traits::IdentityLookup,
BuildStorage, Perbill,
BuildStorage, DispatchResult, Perbill,
};
use tangle_primitives::{jobs::*, traits::jobs::MPCHandler};

pub type AccountId = u64;
pub type Balance = u128;
pub type BlockNumber = u64;

impl frame_system::Config for Runtime {
type RuntimeOrigin = RuntimeOrigin;
Expand Down Expand Up @@ -74,6 +77,30 @@ impl pallet_balances::Config for Runtime {
type MaxFreezes = ();
}

pub struct MockMPCHandler;

impl MPCHandler<AccountId, BlockNumber, Balance> for MockMPCHandler {
fn verify(
_job: &JobInfo<AccountId, BlockNumber, Balance>,
_phase_one_data: Option<PhaseOneResult<AccountId, BlockNumber>>,
_result: Vec<u8>,
) -> DispatchResult {
Ok(())
}

fn verify_validator_report(
_validator: AccountId,
_offence: ValidatorOffence,
_report: Vec<u8>,
) -> DispatchResult {
Ok(())
}

fn validate_authority_key(_validator: AccountId, _authority_key: Vec<u8>) -> DispatchResult {
Ok(())
}
}

impl pallet_timestamp::Config for Runtime {
type Moment = u64;
type OnTimestampSet = ();
Expand Down Expand Up @@ -200,9 +227,27 @@ impl pallet_staking::Config for Runtime {
type WeightInfo = ();
}

pub struct MockJobsHandler;

impl JobsHandler<AccountId> for MockJobsHandler {
fn get_active_jobs(_validator: AccountId) -> Vec<(JobKey, JobId)> {
Default::default()
}

fn exit_from_known_set(
_validator: AccountId,
_job_key: JobKey,
_job_id: JobId,
) -> sp_runtime::DispatchResult {
Ok(())
}
}

impl Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type JobsHandler = MockJobsHandler;
type MaxRolesPerAccount = ConstU32<2>;
type MPCHandler = MockMPCHandler;
type WeightInfo = ();
}

Expand Down
Loading

0 comments on commit f3fefce

Please sign in to comment.