Skip to content

Commit

Permalink
feat(fc-pallet-pass): register deposit logic
Browse files Browse the repository at this point in the history
  • Loading branch information
pandres95 committed Oct 4, 2024
1 parent f3e2a7b commit b1c1ce7
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 19 deletions.
7 changes: 5 additions & 2 deletions pallets/pass/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use super::*;
use crate::Pallet;
use frame_benchmarking::v2::*;
use frame_support::traits::OriginTrait;
use sp_runtime::traits::Hash;

type RuntimeEventFor<T, I> = <T as Config<I>>::RuntimeEvent;
Expand All @@ -11,6 +12,7 @@ fn assert_has_event<T: Config<I>, I: 'static>(generic_event: RuntimeEventFor<T,
frame_system::Pallet::<T>::assert_has_event(generic_event.into());
}

#[allow(dead_code)]
fn setup_signers<T: frame_system::Config>() -> (T::AccountId, T::AccountId) {
(
frame_benchmarking::account("signer", 0, 0),
Expand All @@ -28,6 +30,7 @@ where
#[instance_benchmarks(
where
T: frame_system::Config + crate::Config<I>,
OriginFor<T>: From<frame_system::Origin<T>>,
T::Hash: Into<HashedUserId>,
RuntimeEventFor<T, I>: From<frame_system::Event<T>>,
)]

Check warning on line 36 in pallets/pass/src/benchmarking.rs

View workflow job for this annotation

GitHub Actions / clippy

bound is defined in more than one place

warning: bound is defined in more than one place --> pallets/pass/src/benchmarking.rs:30:1 | 30 | / #[instance_benchmarks( 31 | | where 32 | | T: frame_system::Config + crate::Config<I>, | | ^ 33 | | OriginFor<T>: From<frame_system::Origin<T>>, 34 | | T::Hash: Into<HashedUserId>, 35 | | RuntimeEventFor<T, I>: From<frame_system::Event<T>>, 36 | | )] | |__^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#multiple_bound_locations = note: `#[warn(clippy::multiple_bound_locations)]` on by default = note: this warning originates in the attribute macro `instance_benchmarks` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -37,14 +40,14 @@ mod benchmarks {
#[benchmark]
pub fn register() -> Result<(), BenchmarkError> {
// Setup code
let (one, _) = setup_signers::<T>();
let origin = T::BenchmarkHelper::register_origin();
let user_id = hash::<T>(&*b"my-account");

Check warning on line 44 in pallets/pass/src/benchmarking.rs

View workflow job for this annotation

GitHub Actions / clippy

deref on an immutable reference

warning: deref on an immutable reference --> pallets/pass/src/benchmarking.rs:44:33 | 44 | let user_id = hash::<T>(&*b"my-account"); | ^^^^^^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `b"my-account"` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#borrow_deref_ref = note: `#[warn(clippy::borrow_deref_ref)]` on by default
let account_id = Pallet::<T, I>::account_id_for(user_id)?;
let device_id = [0u8; 32];

#[extrinsic_call]
_(
RawOrigin::Signed(one),
origin.into_caller(),
user_id,
T::BenchmarkHelper::device_attestation(device_id),
);
Expand Down
19 changes: 12 additions & 7 deletions pallets/pass/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ pub mod pallet {
#[pallet::constant]
type MaxSessionDuration: Get<BlockNumberFor<Self>>;

type RegisterOrigin: EnsureOriginWithArg<Self::RuntimeOrigin, HashedUserId>;
type RegisterOrigin: EnsureOriginWithArg<
Self::RuntimeOrigin,
HashedUserId,
Success = Option<DepositInformation<Self, I>>,
>;

#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper: BenchmarkHelper<Self, I>;
Expand Down Expand Up @@ -127,13 +131,16 @@ pub mod pallet {
user: HashedUserId,
attestation: DeviceAttestationOf<T, I>,
) -> DispatchResult {
T::RegisterOrigin::ensure_origin(origin, &user)?;
let maybe_deposit_info = T::RegisterOrigin::ensure_origin(origin, &user)?;
let account_id = Self::account_id_for(user)?;
ensure!(
!Self::account_exists(&account_id),
Error::<T, I>::AccountAlreadyRegistered
);

if let Some(deposit_info) = maybe_deposit_info {
Self::charge_register_deposit(deposit_info)?;
}
Self::create_account(&account_id)?;
Self::deposit_event(Event::<T, I>::Registered {
who: account_id.clone(),
Expand Down Expand Up @@ -224,13 +231,11 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {

#[allow(dead_code)]
pub(crate) fn charge_register_deposit(
who: &T::AccountId,
amount: BalanceOf<T, I>,
beneficiary: &T::AccountId,
(source, amount, dest): DepositInformation<T, I>,
) -> DispatchResult {
T::Currency::transfer(
who,
beneficiary,
&source,
&dest,
amount,
frame_support::traits::tokens::Preservation::Expendable,
)
Expand Down
22 changes: 18 additions & 4 deletions pallets/pass/src/mock.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
//! Test environment for pallet pass.
use crate::{self as pallet_pass, Config, CredentialOf, DeviceAttestationOf};
use crate::{self as pallet_pass, Config};
pub use authenticators::*;
use codec::{Decode, Encode, MaxEncodedLen};
use fc_traits_authn::{composite_authenticators, util::AuthorityFromPalletId, Challenger};
use frame_support::{
derive_impl, parameter_types,
traits::{ConstU32, ConstU64, EqualPrivilegeOnly, OnInitialize},
traits::{ConstU32, ConstU64, EitherOf, EqualPrivilegeOnly, OnInitialize},
weights::Weight,
DebugNoBound, EqNoBound, PalletId,
};
use frame_system::{EnsureRoot, EnsureSigned};
use frame_system::{pallet_prelude::OriginFor, EnsureRoot, EnsureRootWithSuccess};
use scale_info::TypeInfo;
use sp_core::{blake2_256, H256};
use sp_io::TestExternalities;
Expand Down Expand Up @@ -81,7 +81,9 @@ impl pallet_scheduler::Config for Test {
}

parameter_types! {
pub const RootAccount: AccountId = AccountId::new([0u8; 32]);
pub PassPalletId: PalletId = PalletId(*b"py/pass_");
pub RootDoesNotPay: Option<pallet_pass::DepositInformation<Test>> = None;
}

composite_authenticators! {
Expand All @@ -96,7 +98,12 @@ impl Config for Test {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type Authenticator = PassAuthenticator;
type RegisterOrigin = EnsureSigned<Self::AccountId>;
type RegisterOrigin = EitherOf<
// Root does not pay
EnsureRootWithSuccess<Self::AccountId, RootDoesNotPay>,
// Anyone else pays
pallet_pass::EnsureSignedPays<Test, ConstU64<1>, RootAccount>,
>;
type RuntimeCall = RuntimeCall;
type PalletId = PassPalletId;
type PalletsOrigin = OriginCaller;
Expand All @@ -105,11 +112,18 @@ impl Config for Test {
type BenchmarkHelper = BenchmarkHelper;
}

#[cfg(feature = "runtime-benchmarks")]
use pallet_pass::{CredentialOf, DeviceAttestationOf};

#[cfg(feature = "runtime-benchmarks")]
pub struct BenchmarkHelper;

#[cfg(feature = "runtime-benchmarks")]
impl pallet_pass::BenchmarkHelper<Test> for BenchmarkHelper {
fn register_origin() -> OriginFor<Test> {
RuntimeOrigin::root()
}

fn device_attestation(device_id: DeviceId) -> DeviceAttestationOf<Test, ()> {
PassDeviceAttestation::AuthenticatorAAuthenticator(authenticator_a::DeviceAttestation {
device_id,
Expand Down
43 changes: 41 additions & 2 deletions pallets/pass/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use super::{Error, Event};
use crate::mock::*;

use fc_traits_authn::{Challenger, HashedUserId};
use frame_support::{assert_noop, assert_ok, parameter_types};
use frame_support::{assert_noop, assert_ok, parameter_types, traits::fungible::Mutate};
use sp_core::Hasher;
use sp_runtime::ArithmeticError;

const SIGNER: AccountId = AccountId::new([0u8; 32]);
const OTHER: AccountId = AccountId::new([1u8; 32]);
Expand All @@ -22,7 +23,6 @@ parameter_types! {
}

mod register {

use super::*;

#[test]
Expand All @@ -48,9 +48,43 @@ mod register {
});
}

#[test]
fn register_deposit_logic_works() {
new_test_ext().execute_with(|| {
assert_ok!(Pass::register(
RuntimeOrigin::root(),
AccountNameA::get(),
PassDeviceAttestation::AuthenticatorAAuthenticator(
authenticator_a::DeviceAttestation {
device_id: THE_DEVICE,
challenge: authenticator_a::Authenticator::generate(&()),
}
),
));
});

new_test_ext().execute_with(|| {
assert_noop!(
Pass::register(
RuntimeOrigin::signed(SIGNER),
AccountNameA::get(),
PassDeviceAttestation::AuthenticatorAAuthenticator(
authenticator_a::DeviceAttestation {
device_id: THE_DEVICE,
challenge: authenticator_a::Authenticator::generate(&()),
}
),
),
ArithmeticError::Underflow,
);
});
}

#[test]
fn fail_if_attestation_is_invalid() {
new_test_ext().execute_with(|| {
assert_ok!(Balances::mint_into(&SIGNER, 2));

assert_noop!(
Pass::register(
RuntimeOrigin::signed(SIGNER),
Expand All @@ -68,6 +102,8 @@ mod register {
#[test]
fn it_works() {
new_test_ext().execute_with(|| {
assert_ok!(Balances::mint_into(&SIGNER, 2));

let account_id =
Pass::account_id_for(AccountNameA::get()).expect("account exists; qed");

Expand Down Expand Up @@ -102,6 +138,7 @@ mod register {
fn prepare(user_id: HashedUserId) -> sp_io::TestExternalities {
let mut t = new_test_ext();
t.execute_with(|| {
assert_ok!(Balances::mint_into(&SIGNER, 2));
assert_ok!(Pass::register(
RuntimeOrigin::signed(SIGNER),
user_id,
Expand Down Expand Up @@ -160,6 +197,8 @@ mod authenticate {
#[test]
fn fail_if_attestation_is_invalid() {
new_test_ext().execute_with(|| {
assert_ok!(Balances::mint_into(&SIGNER, 2));

assert_ok!(Pass::register(
RuntimeOrigin::signed(SIGNER),
AccountNameA::get(),
Expand Down
31 changes: 27 additions & 4 deletions pallets/pass/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::Config;
use fc_traits_authn::HashedUserId;
use frame_support::traits::fungible::Inspect;
use sp_runtime::traits::StaticLookup;
use frame_support::traits::{fungible::Inspect, MapSuccess};
use frame_system::{pallet_prelude::OriginFor, EnsureSigned};
use sp_core::TypedGet;
use sp_runtime::{morph_types, traits::StaticLookup};

// pub type HashedUserId<T> = <T as frame_system::Config>::Hash;
type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
pub type ContextOf<T, I> =
<<<T as Config<I>>::Authenticator as fc_traits_authn::Authenticator>::Challenger as fc_traits_authn::Challenger>::Context;
<<<T as Config<I>>::Authenticator as fc_traits_authn::Authenticator>::Challenger as fc_traits_authn::Challenger>::Context;
pub type DeviceOf<T, I> =
<<T as Config<I>>::Authenticator as fc_traits_authn::Authenticator>::Device;
pub type CredentialOf<T, I> = <DeviceOf<T, I> as fc_traits_authn::UserAuthenticator>::Credential;
Expand All @@ -14,13 +16,34 @@ pub type DeviceAttestationOf<T, I> =
pub type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
pub type BalanceOf<T, I> =
<<T as Config<I>>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
pub type DepositInformation<T, I = ()> = (
<T as frame_system::Config>::AccountId,
BalanceOf<T, I>,
<T as frame_system::Config>::AccountId,
);

morph_types! {
pub type PaymentForCreate<
AccountId,
GetAmount: TypedGet,
GetReceiver: TypedGet<Type = AccountId>
>: Morph = |sender: AccountId| -> Option<(AccountId, GetAmount::Type, GetReceiver::Type)> {
Some((sender, GetAmount::get(), GetReceiver::get()))
};
}

pub type EnsureSignedPays<T, Amount, Beneficiary> =
MapSuccess<EnsureSigned<AccountIdOf<T>>, PaymentForCreate<AccountIdOf<T>, Amount, Beneficiary>>;

#[cfg(feature = "runtime-benchmarks")]
use fc_traits_authn::HashedUserId;
#[cfg(feature = "runtime-benchmarks")]
pub trait BenchmarkHelper<T, I = ()>
where
T: Config<I>,
I: 'static,
{
fn register_origin() -> OriginFor<T>;
fn device_attestation(device_id: fc_traits_authn::DeviceId) -> DeviceAttestationOf<T, I>;
fn credential(user_id: HashedUserId) -> CredentialOf<T, I>;
}

0 comments on commit b1c1ce7

Please sign in to comment.