Skip to content

Commit

Permalink
Merge pull request #2083 from subspace/allow_list_for_operators
Browse files Browse the repository at this point in the history
Domains: Operator allow list
  • Loading branch information
vedhavyas authored Oct 11, 2023
2 parents 1c68f46 + 310ad04 commit fec4665
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 34 deletions.
58 changes: 48 additions & 10 deletions crates/pallet-domains/src/domain_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use frame_support::{ensure, PalletError};
use frame_system::pallet_prelude::*;
use scale_info::TypeInfo;
use sp_core::Get;
use sp_domains::{DomainId, DomainsDigestItem, ReceiptHash, RuntimeId};
use sp_domains::{DomainId, DomainsDigestItem, OperatorAllowList, ReceiptHash, RuntimeId};
use sp_runtime::traits::{CheckedAdd, Zero};
use sp_runtime::DigestItem;
use sp_std::collections::btree_map::BTreeMap;
Expand All @@ -34,10 +34,12 @@ pub enum Error {
DomainNameTooLong,
BalanceFreeze,
FailedToGenerateGenesisStateRoot,
DomainNotFound,
NotDomainOwner,
}

#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
pub struct DomainConfig {
pub struct DomainConfig<AccountId: Ord> {
/// A user defined name for this domain, should be a human-readable UTF-8 encoded string.
pub domain_name: String,
/// A pointer to the `RuntimeRegistry` entry for this domain.
Expand All @@ -51,23 +53,25 @@ pub struct DomainConfig {
pub bundle_slot_probability: (u64, u64),
/// The expected number of bundles for a domain block, must be `≥ 1` and `≤ MaxBundlesPerBlock`.
pub target_bundles_per_block: u32,
/// Allowed operators to operate for this domain.
pub operator_allow_list: OperatorAllowList<AccountId>,
}

#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
pub struct DomainObject<Number, AccountId> {
pub struct DomainObject<Number, AccountId: Ord> {
/// The address of the domain creator, used to validate updating the domain config.
pub owner_account_id: AccountId,
/// The consensus chain block number when the domain first instantiated.
pub created_at: Number,
/// The hash of the genesis execution receipt for this domain.
pub genesis_receipt_hash: ReceiptHash,
/// The domain config.
pub domain_config: DomainConfig,
pub domain_config: DomainConfig<AccountId>,
}

pub(crate) fn can_instantiate_domain<T: Config>(
owner_account_id: &T::AccountId,
domain_config: &DomainConfig,
domain_config: &DomainConfig<T::AccountId>,
) -> Result<(), Error> {
ensure!(
domain_config.domain_name.len() as u32 <= T::MaxDomainNameLength::get(),
Expand Down Expand Up @@ -108,7 +112,7 @@ pub(crate) fn can_instantiate_domain<T: Config>(
}

pub(crate) fn do_instantiate_domain<T: Config>(
domain_config: DomainConfig,
domain_config: DomainConfig<T::AccountId>,
owner_account_id: T::AccountId,
created_at: BlockNumberFor<T>,
) -> Result<DomainId, Error> {
Expand Down Expand Up @@ -165,14 +169,33 @@ pub(crate) fn do_instantiate_domain<T: Config>(
Ok(domain_id)
}

pub(crate) fn do_update_domain_allow_list<T: Config>(
domain_owner: T::AccountId,
domain_id: DomainId,
updated_operator_allow_list: OperatorAllowList<T::AccountId>,
) -> Result<(), Error> {
DomainRegistry::<T>::try_mutate(domain_id, |maybe_domain_object| {
let domain_obj = maybe_domain_object.as_mut().ok_or(Error::DomainNotFound)?;
ensure!(
domain_obj.owner_account_id == domain_owner,
Error::NotDomainOwner
);

domain_obj.domain_config.operator_allow_list = updated_operator_allow_list;
Ok(())
})
}

#[cfg(test)]
mod tests {
use super::*;
use crate::pallet::{DomainRegistry, NextDomainId, RuntimeRegistry};
use crate::runtime_registry::RuntimeObject;
use crate::tests::{new_test_ext, Test};
use frame_support::assert_ok;
use frame_support::traits::Currency;
use sp_domains::storage::RawGenesis;
use sp_std::collections::btree_set::BTreeSet;
use sp_std::vec;
use sp_version::RuntimeVersion;

Expand All @@ -190,6 +213,7 @@ mod tests {
max_block_weight: Weight::MAX,
bundle_slot_probability: (0, 0),
target_bundles_per_block: 0,
operator_allow_list: OperatorAllowList::Anyone,
};

let mut ext = new_test_ext();
Expand Down Expand Up @@ -307,10 +331,24 @@ mod tests {
assert_eq!(Balances::usable_balance(creator), Zero::zero());

// cannot use the locked funds to create a new domain instance
assert!(
do_instantiate_domain::<Test>(domain_config, creator, created_at)
== Err(Error::InsufficientFund)
)
assert_eq!(
do_instantiate_domain::<Test>(domain_config, creator, created_at),
Err(Error::InsufficientFund)
);

// update operator allow list
let updated_operator_allow_list =
OperatorAllowList::Operators(BTreeSet::from_iter(vec![1, 2, 3]));
assert_ok!(do_update_domain_allow_list::<Test>(
creator,
domain_id,
updated_operator_allow_list.clone()
));
let domain_obj = DomainRegistry::<Test>::get(domain_id).unwrap();
assert_eq!(
domain_obj.domain_config.operator_allow_list,
updated_operator_allow_list
);
});
}
}
34 changes: 30 additions & 4 deletions crates/pallet-domains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ mod pallet {
ReceiptType,
};
use crate::domain_registry::{
do_instantiate_domain, DomainConfig, DomainObject, Error as DomainRegistryError,
do_instantiate_domain, do_update_domain_allow_list, DomainConfig, DomainObject,
Error as DomainRegistryError,
};
use crate::runtime_registry::{
do_register_runtime, do_schedule_runtime_upgrade, do_upgrade_runtimes,
Expand Down Expand Up @@ -147,8 +148,8 @@ mod pallet {
use sp_domains::fraud_proof::FraudProof;
use sp_domains::transaction::InvalidTransactionCode;
use sp_domains::{
BundleDigest, DomainId, EpochIndex, GenesisDomain, OperatorId, ReceiptHash, RuntimeId,
RuntimeType,
BundleDigest, DomainId, EpochIndex, GenesisDomain, OperatorAllowList, OperatorId,
ReceiptHash, RuntimeId, RuntimeType,
};
use sp_runtime::traits::{
AtLeast32BitUnsigned, BlockNumberProvider, Bounded, CheckEqual, CheckedAdd, Hash,
Expand Down Expand Up @@ -706,6 +707,9 @@ mod pallet {
domain_id: DomainId,
new_head_receipt_number: Option<T::DomainNumber>,
},
DomainOperatorAllowListUpdated {
domain_id: DomainId,
},
}

/// Per-domain state for tx range calculation.
Expand Down Expand Up @@ -1041,7 +1045,7 @@ mod pallet {
#[pallet::weight(T::WeightInfo::instantiate_domain())]
pub fn instantiate_domain(
origin: OriginFor<T>,
domain_config: DomainConfig,
domain_config: DomainConfig<T::AccountId>,
) -> DispatchResult {
let who = ensure_signed(origin)?;

Expand Down Expand Up @@ -1126,6 +1130,27 @@ mod pallet {

Ok(())
}

/// Extrinsic to update domain's operator allow list.
/// Note:
/// - If the previous allowed list is set to specific operators and new allow list is set
/// to `Anyone`, then domain will become permissioned to open for all operators.
/// - If the previous allowed list is set to `Anyone` or specific operators and the new
/// allow list is set to specific operators, then all the registered not allowed operators
/// will continue to operate until they de-register themselves.
#[pallet::call_index(12)]
#[pallet::weight(Weight::from_all(10_000))]
pub fn update_domain_operator_allow_list(
origin: OriginFor<T>,
domain_id: DomainId,
operator_allow_list: OperatorAllowList<T::AccountId>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
do_update_domain_allow_list::<T>(who, domain_id, operator_allow_list)
.map_err(Error::<T>::from)?;
Self::deposit_event(crate::pallet::Event::DomainOperatorAllowListUpdated { domain_id });
Ok(())
}
}

#[pallet::genesis_config]
Expand Down Expand Up @@ -1163,6 +1188,7 @@ mod pallet {
max_block_weight: genesis_domain.max_block_weight,
bundle_slot_probability: genesis_domain.bundle_slot_probability,
target_bundles_per_block: genesis_domain.target_bundles_per_block,
operator_allow_list: genesis_domain.operator_allow_list,
};
let domain_owner = genesis_domain.owner_account_id;
let domain_id =
Expand Down
Loading

0 comments on commit fec4665

Please sign in to comment.