Skip to content

Commit

Permalink
feat(runtime): Add support of upload_code for vouchers (#3672)
Browse files Browse the repository at this point in the history
  • Loading branch information
breathx authored Jan 19, 2024
1 parent 0f8775e commit c213881
Show file tree
Hide file tree
Showing 8 changed files with 426 additions and 45 deletions.
13 changes: 13 additions & 0 deletions gsdk/src/metadata/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2856,6 +2856,10 @@ pub mod runtime_types {
value: _0,
keep_alive: ::core::primitive::bool,
},
#[codec(index = 2)]
UploadCode {
code: ::std::vec::Vec<::core::primitive::u8>,
},
}
#[derive(Debug, crate::gp::Decode, crate::gp::DecodeAsType, crate::gp::Encode)]
pub struct VoucherId(pub [::core::primitive::u8; 32usize]);
Expand All @@ -2865,6 +2869,7 @@ pub mod runtime_types {
pub programs: ::core::option::Option<
::std::vec::Vec<runtime_types::gear_core::ids::ProgramId>,
>,
pub code_uploading: ::core::primitive::bool,
pub expiry: _1,
}
}
Expand All @@ -2881,6 +2886,7 @@ pub mod runtime_types {
programs: ::core::option::Option<
::std::vec::Vec<runtime_types::gear_core::ids::ProgramId>,
>,
code_uploading: ::core::primitive::bool,
duration: ::core::primitive::u32,
},
#[codec(index = 1)]
Expand Down Expand Up @@ -2909,6 +2915,7 @@ pub mod runtime_types {
::std::vec::Vec<runtime_types::gear_core::ids::ProgramId>,
>,
>,
code_uploading: ::core::option::Option<::core::primitive::bool>,
prolong_duration: ::core::option::Option<::core::primitive::u32>,
},
#[codec(index = 4)]
Expand Down Expand Up @@ -2949,6 +2956,12 @@ pub mod runtime_types {
#[codec(index = 8)]
#[doc = "Voucher issue/prolongation duration out of [min; max] constants."]
DurationOutOfBounds,
#[codec(index = 9)]
#[doc = "Voucher update function tries to cut voucher ability of code upload."]
CodeUploadingEnabled,
#[codec(index = 10)]
#[doc = "Voucher is disabled for code uploading, but requested."]
CodeUploadingDisabled,
}
#[derive(Debug, crate::gp::Decode, crate::gp::DecodeAsType, crate::gp::Encode)]
#[doc = "Pallet Gear Voucher event."]
Expand Down
20 changes: 16 additions & 4 deletions pallets/gear-voucher/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,13 @@ benchmarks! {
.map(|i| benchmarking::account::<T::AccountId>("program", 0, i).cast())
.collect();

// Allow uploading codes.
let code_uploading = true;

// Voucher validity.
let validity = <<T as Config>::MinDuration as Get<BlockNumberFor<T>>>::get();

}: _(RawOrigin::Signed(origin.clone()), spender.clone(), balance, Some(set), validity)
}: _(RawOrigin::Signed(origin.clone()), spender.clone(), balance, Some(set), code_uploading, validity)
verify {
let (key_spender, voucher_id, voucher_info) = Vouchers::<T>::iter().next().expect("Couldn't find voucher");

Expand All @@ -80,11 +83,14 @@ benchmarks! {
// Voucher balance.
let balance = 10_000_000_000_000_u128.unique_saturated_into();

// Forbid uploading codes.
let code_uploading = false;

// Voucher validity.
let validity = <<T as Config>::MinDuration as Get<BlockNumberFor<T>>>::get();

// Issue voucher.
assert!(Pallet::<T>::issue(RawOrigin::Signed(origin.clone()).into(), spender.clone(), balance, None, validity).is_ok());
assert!(Pallet::<T>::issue(RawOrigin::Signed(origin.clone()).into(), spender.clone(), balance, None, code_uploading, validity).is_ok());
let (_, voucher_id, _) = Vouchers::<T>::iter().next().expect("Couldn't find voucher");

frame_system::Pallet::<T>::set_block_number(frame_system::Pallet::<T>::block_number() + validity + One::one());
Expand Down Expand Up @@ -113,11 +119,14 @@ benchmarks! {
.map(|i| benchmarking::account::<T::AccountId>("program", 0, i).cast())
.collect();

// Forbid uploading codes.
let code_uploading = false;

// Voucher validity.
let validity = <<T as Config>::MinDuration as Get<BlockNumberFor<T>>>::get();

// Issue voucher.
assert!(Pallet::<T>::issue(RawOrigin::Signed(origin.clone()).into(), spender.clone(), balance, Some(set), validity).is_ok());
assert!(Pallet::<T>::issue(RawOrigin::Signed(origin.clone()).into(), spender.clone(), balance, Some(set), code_uploading, validity).is_ok());
let (_, voucher_id, _) = Vouchers::<T>::iter().next().expect("Couldn't find voucher");

// New owner account.
Expand All @@ -132,9 +141,12 @@ benchmarks! {
.collect();
let append_programs = Some(Some(append_programs_set));

// Allow uploading codes.
let code_uploading = Some(true);

// prolong duration.
let prolong_duration = Some(validity);
}: _(RawOrigin::Signed(origin.clone()), spender.clone(), voucher_id, move_ownership, balance_top_up, append_programs, prolong_duration)
}: _(RawOrigin::Signed(origin.clone()), spender.clone(), voucher_id, move_ownership, balance_top_up, append_programs, code_uploading, prolong_duration)
verify {
let voucher_info = Vouchers::<T>::get(spender, voucher_id).expect("Must be");
assert_eq!(voucher_info.programs.map(|v| v.len()), Some(<<T as Config>::MaxProgramsAmount as Get<u8>>::get() as usize));
Expand Down
44 changes: 31 additions & 13 deletions pallets/gear-voucher/src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,22 @@ where
T::AccountId: Origin,
{
/// Returns account id that pays for gas purchase and transaction fee
/// for processing this ['pallet_gear_voucher::Call']s processing if:
/// for processing this ['pallet_gear_voucher::Call'], if:
///
/// * Call is [`Self::call`]:
/// * Voucher with the given voucher id exists;
/// * Caller is eligible to use the voucher;
/// * The voucher is not expired;
/// * Destination program of the given prepaid call can be determined;
/// * The voucher destinations limitations accept determined destination.
/// * For messaging calls: The destination program of the given prepaid
/// call can be determined;
/// * For messaging calls: The voucher destinations limitations accept
/// determined destination;
/// * For codes uploading: The voucher allows code uploading.
///
/// * Call is [`Self::call_deprecated`]:
/// * Destination program of the given prepaid call can be determined.
/// * For messaging calls: The destination program of the given prepaid
/// call can be determined.
/// * For codes uploading: NEVER.
///
/// Returns [`None`] for other cases.
pub fn get_sponsor(&self, caller: AccountIdOf<T>) -> Option<AccountIdOf<T>> {
Expand Down Expand Up @@ -92,20 +97,27 @@ impl<T: Config> Pallet<T> {
Error::<T>::VoucherExpired
);

if let Some(ref programs) = voucher.programs {
let destination = Self::prepaid_call_destination(&origin, call)
.ok_or(Error::<T>::UnknownDestination)?;

ensure!(
programs.contains(&destination),
Error::<T>::InappropriateDestination
);
match call {
PrepaidCall::UploadCode { .. } => {
ensure!(voucher.code_uploading, Error::<T>::CodeUploadingDisabled)
}
PrepaidCall::SendMessage { .. } | PrepaidCall::SendReply { .. } => {
if let Some(ref programs) = voucher.programs {
let destination = Self::prepaid_call_destination(&origin, call)
.ok_or(Error::<T>::UnknownDestination)?;

ensure!(
programs.contains(&destination),
Error::<T>::InappropriateDestination
);
}
}
}

Ok(())
}

/// Return destination program of the [`PrepaidCall`].
/// Return destination program of the [`PrepaidCall`], if exists.
pub fn prepaid_call_destination(
who: &T::AccountId,
call: &PrepaidCall<BalanceOf<T>>,
Expand All @@ -115,6 +127,7 @@ impl<T: Config> Pallet<T> {
PrepaidCall::SendReply { reply_to_id, .. } => {
T::Mailbox::peek(who, reply_to_id).map(|stored_message| stored_message.source())
}
PrepaidCall::UploadCode { .. } => None,
}
}
}
Expand Down Expand Up @@ -169,6 +182,8 @@ pub struct VoucherInfo<AccountId, BlockNumber> {
/// Set of programs this voucher could be used to interact with.
/// In case of [`None`] means any gear program.
pub programs: Option<BTreeSet<ProgramId>>,
/// Flag if this voucher's covers uploading codes as prepaid call.
pub code_uploading: bool,
/// The block number at and after which voucher couldn't be used and
/// can be revoked by owner.
pub expiry: BlockNumber,
Expand Down Expand Up @@ -199,4 +214,7 @@ pub enum PrepaidCall<Balance> {
value: Balance,
keep_alive: bool,
},
UploadCode {
code: Vec<u8>,
},
}
32 changes: 31 additions & 1 deletion pallets/gear-voucher/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ pub mod pallet {
VoucherExpired,
/// Voucher issue/prolongation duration out of [min; max] constants.
DurationOutOfBounds,
/// Voucher update function tries to cut voucher ability of code upload.
CodeUploadingEnabled,
/// Voucher is disabled for code uploading, but requested.
CodeUploadingDisabled,
}

/// Storage containing amount of the total vouchers issued.
Expand Down Expand Up @@ -224,6 +228,9 @@ pub mod pallet {
/// * programs: pool of programs spender can interact with,
/// if None - means any program,
/// limited by Config param;
/// * code_uploading:
/// allow voucher to be used as payer for `upload_code`
/// transactions fee;
/// * duration: amount of blocks voucher could be used by spender
/// and couldn't be revoked by owner.
/// Must be out in [MinDuration; MaxDuration] constants.
Expand All @@ -236,6 +243,7 @@ pub mod pallet {
spender: AccountIdOf<T>,
balance: BalanceOf<T>,
programs: Option<BTreeSet<ProgramId>>,
code_uploading: bool,
duration: BlockNumberFor<T>,
) -> DispatchResultWithPostInfo {
// Ensuring origin.
Expand Down Expand Up @@ -276,6 +284,7 @@ pub mod pallet {
let voucher_info = VoucherInfo {
owner: owner.clone(),
programs,
code_uploading,
expiry,
};

Expand Down Expand Up @@ -401,13 +410,16 @@ pub mod pallet {
/// `Some(programs_set)` passed or allows
/// it to interact with any program by
/// `None` passed;
/// * code_uploading: optionally allows voucher to be used to pay
/// fees for `upload_code` extrinsics;
/// * prolong_duration: optionally increases expiry block number.
/// If voucher is expired, prolongs since current bn.
/// Validity prolongation (since current block number
/// for expired or since storage written expiry)
/// should be in [MinDuration; MaxDuration], in other
/// words voucher couldn't have expiry greater than
/// current block number + MaxDuration.
#[allow(clippy::too_many_arguments)]
#[pallet::call_index(3)]
#[pallet::weight(T::WeightInfo::update())]
pub fn update(
Expand All @@ -417,6 +429,7 @@ pub mod pallet {
move_ownership: Option<AccountIdOf<T>>,
balance_top_up: Option<BalanceOf<T>>,
append_programs: Option<Option<BTreeSet<ProgramId>>>,
code_uploading: Option<bool>,
prolong_duration: Option<BlockNumberFor<T>>,
) -> DispatchResultWithPostInfo {
// Ensuring origin.
Expand All @@ -433,7 +446,10 @@ pub mod pallet {
let mut updated = false;

// Flattening move ownership back to current owner.
let new_owner = move_ownership.filter(|addr| addr.ne(&voucher.owner));
let new_owner = move_ownership.filter(|addr| *addr != voucher.owner);

// Flattening code uploading.
let code_uploading = code_uploading.filter(|v| *v != voucher.code_uploading);

// Flattening duration prolongation.
let prolong_duration = prolong_duration.filter(|dur| !dur.is_zero());
Expand Down Expand Up @@ -482,6 +498,14 @@ pub mod pallet {
_ => (),
}

// Optionally enabling code uploading.
if let Some(code_uploading) = code_uploading {
ensure!(code_uploading, Error::<T>::CodeUploadingEnabled);

voucher.code_uploading = true;
updated = true;
}

// Optionally prolongs validity of the voucher.
if let Some(duration) = prolong_duration {
let current_bn = <frame_system::Pallet<T>>::block_number();
Expand Down Expand Up @@ -534,6 +558,12 @@ pub mod pallet {
// Ensuring origin.
let origin = ensure_signed(origin)?;

// Validating the call for legacy implementation.
ensure!(
!matches!(call, PrepaidCall::UploadCode { .. }),
Error::<T>::CodeUploadingDisabled
);

// Looking for sponsor synthetic account.
#[allow(deprecated)]
let sponsor = Self::call_deprecated_sponsor(&origin, &call)
Expand Down
Loading

0 comments on commit c213881

Please sign in to comment.