Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions pallets/dactr/src/extensions/check_app_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,17 @@ where
/// production.
pub fn do_validate(
&self,
who: &T::AccountId,
call: &<T as SystemConfig>::RuntimeCall,
len: usize,
) -> TransactionValidity {
self.ensure_valid_app_id(call)?;
if let Some(DACall::<T>::submit_data { .. }) = call.is_sub_type() {
ensure!(
<Pallet<T>>::is_submit_data_whitelisted(who),
InvalidTransaction::BadSigner
);

let all_extrinsics_len = self
.next_all_extrinsics_len(len)
.ok_or(InvalidTransaction::ExhaustsResources)?;
Expand Down Expand Up @@ -254,7 +260,7 @@ where
_info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> TransactionValidity {
self.do_validate(call, len)
self.do_validate(_who, call, len)
}

fn pre_dispatch(
Expand All @@ -264,7 +270,7 @@ where
_info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
self.do_validate(call, len)?;
self.do_validate(_who, call, len)?;
Ok(())
}

Expand Down Expand Up @@ -298,6 +304,7 @@ mod tests {
};
use frame_system::pallet::Call as SysCall;
use sp_runtime::transaction_validity::InvalidTransaction;
use sp_runtime::AccountId32;
use test_case::test_case;

use super::*;
Expand All @@ -320,6 +327,12 @@ mod tests {
))
}

fn alice() -> AccountId32 {
let mut account = [0u8; 32];
account[0] = 1;
AccountId32::new(account)
}

#[test_case(1, submit_data_call() => Ok(ValidTransaction::default()); "Submit Data call should be allowed to use any valid AppId" )]
#[test_case(100, submit_data_call() => to_invalid_tx(InvalidAppId); "Submit Data call with invalid AppId should be blocked" )]
#[test_case(0, remark_call() => Ok(ValidTransaction::default()); "Any Non-Submit-Data call with AppId == 0 should be allowed" )]
Expand All @@ -328,6 +341,9 @@ mod tests {
let extrinsic =
AppUncheckedExtrinsic::<u32, RuntimeCall, (), ()>::new_unsigned(call.clone());
let len = extrinsic.encoded_size();
new_test_ext().execute_with(|| CheckAppId::<Test>::from(AppId(id)).do_validate(&call, len))
new_test_ext().execute_with(|| {
crate::SubmitDataWhitelist::<Test>::insert(alice(), ());
CheckAppId::<Test>::from(AppId(id)).do_validate(&alice(), &call, len)
})
}
}
12 changes: 11 additions & 1 deletion pallets/dactr/src/extensions/check_batch_transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ mod tests {
use pallet_utility::pallet::Call as UtilityCall;
use sp_core::H256;
use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidityError};
use sp_runtime::AccountId32;
use test_case::test_case;

use super::*;
Expand Down Expand Up @@ -442,11 +443,20 @@ mod tests {
))
}

fn alice() -> AccountId32 {
let mut account = [0u8; 32];
account[0] = 1;
AccountId32::new(account)
}

fn validate(call: RuntimeCall) -> TransactionValidity {
let extrinsic =
AppUncheckedExtrinsic::<u32, RuntimeCall, (), ()>::new_unsigned(call.clone());
let len = extrinsic.encoded_size();
new_test_ext().execute_with(|| CheckAppId::<Test>::from(AppId(0)).do_validate(&call, len))
new_test_ext().execute_with(|| {
crate::SubmitDataWhitelist::<Test>::insert(alice(), ());
CheckAppId::<Test>::from(AppId(0)).do_validate(&alice(), &call, len)
})
}

#[test]
Expand Down
38 changes: 38 additions & 0 deletions pallets/dactr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ pub mod pallet {
#[pallet::storage]
pub type SubmitDataFeeModifier<T: Config> = StorageValue<_, DispatchFeeModifier, ValueQuery>;

/// Accounts allowed to submit DA transactions after the hard cutover.
#[pallet::storage]
pub type SubmitDataWhitelist<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, (), OptionQuery>;

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Creates an application key if `key` does not exist yet.
Expand Down Expand Up @@ -188,6 +193,10 @@ pub mod pallet {
data: AppDataFor<T>,
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
ensure!(
SubmitDataWhitelist::<T>::contains_key(&who),
Error::<T>::SubmitDataSignerNotWhitelisted
);
ensure!(!data.is_empty(), Error::<T>::DataCannotBeEmpty);

let data_hash = blake2_256(&data);
Expand Down Expand Up @@ -300,6 +309,25 @@ pub mod pallet {

Ok(().into())
}

#[pallet::call_index(5)]
#[pallet::weight(<T as frame_system::Config>::DbWeight::get().writes(1))]
pub fn set_submit_data_whitelist(
origin: OriginFor<T>,
account: T::AccountId,
allowed: bool,
) -> DispatchResultWithPostInfo {
ensure_root(origin)?;

if allowed {
SubmitDataWhitelist::<T>::insert(&account, ());
} else {
SubmitDataWhitelist::<T>::remove(&account);
}

Self::deposit_event(Event::SubmitDataWhitelistUpdated { account, allowed });
Ok(().into())
}
}

/// Event for the pallet.
Expand Down Expand Up @@ -327,6 +355,10 @@ pub mod pallet {
SubmitDataFeeModifierSet {
value: DispatchFeeModifier,
},
SubmitDataWhitelistUpdated {
account: T::AccountId,
allowed: bool,
},
}

/// Error for the System pallet
Expand Down Expand Up @@ -354,6 +386,8 @@ pub mod pallet {
UnknownAppKey,
/// Submit block length proposal was made with values not power of 2
NotPowerOfTwo,
/// Submit data signer is not whitelisted after the hard cutover.
SubmitDataSignerNotWhitelisted,
}

#[pallet::genesis_config]
Expand Down Expand Up @@ -391,6 +425,10 @@ pub mod pallet {
}

impl<T: Config> Pallet<T> {
pub fn is_submit_data_whitelisted(who: &T::AccountId) -> bool {
SubmitDataWhitelist::<T>::contains_key(who)
}

/// Returns the latest available application ID and increases it.
pub fn next_application_id() -> Result<AppId, Error<T>> {
NextAppId::<T>::try_mutate(|id| {
Expand Down
15 changes: 14 additions & 1 deletion pallets/dactr/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::config_preludes::{
};
use crate::{
mock::{new_test_ext, DataAvailability, RuntimeEvent, RuntimeOrigin, System, Test},
AppDataFor, AppKeyFor, AppKeyInfoFor, Event, DA_DISPATCH_RATIO_PERBILL,
AppDataFor, AppKeyFor, AppKeyInfoFor, Event, SubmitDataWhitelist, DA_DISPATCH_RATIO_PERBILL,
};

type Error = crate::Error<Test>;
Expand Down Expand Up @@ -81,6 +81,7 @@ mod submit_data {
#[test]
fn submit_data() {
new_test_ext().execute_with(|| {
SubmitDataWhitelist::<Test>::insert(ALICE, ());
let alice: RuntimeOrigin = RawOrigin::Signed(ALICE).into();
let max_app_key_length: usize = MaxAppDataLength::get().try_into().unwrap();
let data = AppDataFor::<Test>::try_from(vec![b'X'; max_app_key_length]).unwrap();
Expand All @@ -99,6 +100,7 @@ mod submit_data {
#[test]
fn data_cannot_be_empty() {
new_test_ext().execute_with(|| {
SubmitDataWhitelist::<Test>::insert(ALICE, ());
let alice: RuntimeOrigin = RawOrigin::Signed(ALICE).into();
let data = AppDataFor::<Test>::try_from(vec![]).unwrap();

Expand All @@ -107,6 +109,17 @@ mod submit_data {
})
}

#[test]
fn signer_must_be_whitelisted() {
new_test_ext().execute_with(|| {
let alice: RuntimeOrigin = RawOrigin::Signed(ALICE).into();
let data = AppDataFor::<Test>::try_from(vec![b'X']).unwrap();

let err = DataAvailability::submit_data(alice, data);
assert_noop!(err, Error::SubmitDataSignerNotWhitelisted);
})
}

#[test]
fn submit_data_too_long() {
new_test_ext().execute_with(|| {
Expand Down
Loading
Loading