Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(vouchers): Remove gear-pallet explicit dependency on vouchers #3586

Merged
merged 9 commits into from
Dec 17, 2023
16 changes: 0 additions & 16 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,19 +350,3 @@ where
self.function.clone()
}
}

pub trait PaymentVoucher<AccountId, ProgramId, Balance> {
type VoucherId;
type Error;

fn voucher_id(who: AccountId, program: ProgramId) -> Self::VoucherId;
}

impl<AccountId: Default, ProgramId, Balance> PaymentVoucher<AccountId, ProgramId, Balance> for () {
type VoucherId = AccountId;
type Error = &'static str;

fn voucher_id(_who: AccountId, _program: ProgramId) -> Self::VoucherId {
unimplemented!()
}
}
5 changes: 5 additions & 0 deletions common/src/storage/complex/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ pub trait MailboxError {
fn element_not_found() -> Self;
}

impl MailboxError for () {
breathx marked this conversation as resolved.
Show resolved Hide resolved
fn duplicate_key() -> Self {}
fn element_not_found() -> Self {}
}

/// `Mailbox` implementation based on `DoubleMapStorage`.
///
/// Generic parameter `Error` requires `MailboxError` implementation.
Expand Down
9 changes: 3 additions & 6 deletions gsdk/src/metadata/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2667,12 +2667,9 @@ pub mod runtime_types {
#[doc = "Program with the specified id is not found."]
ProgramNotFound,
#[codec(index = 14)]
#[doc = "Voucher can't be redeemed"]
FailureRedeemingVoucher,
#[codec(index = 15)]
#[doc = "Gear::run() already included in current block."]
GearRunAlreadyInBlock,
#[codec(index = 16)]
#[codec(index = 15)]
#[doc = "The program rent logic is disabled."]
ProgramRentDisabled,
}
Expand Down Expand Up @@ -3339,9 +3336,9 @@ pub mod runtime_types {
#[doc = "\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/)\n\t\t\tof this pallet.\n\t\t\t"]
pub enum Error {
#[codec(index = 0)]
FailureToCreateVoucher,
InsufficientBalance,
#[codec(index = 1)]
FailureToRedeemVoucher,
InvalidVoucher,
}
#[derive(Debug, crate::gp::Decode, crate::gp::DecodeAsType, crate::gp::Encode)]
#[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"]
Expand Down
4 changes: 2 additions & 2 deletions pallets/gear-voucher/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ benchmarks! {
let holder_lookup = T::Lookup::unlookup(holder.clone());
}: _(RawOrigin::Signed(issuer), holder_lookup, program_id, 10_000_000_000_000_u128.unique_saturated_into())
verify {
let voucher_account_id = GearVoucher::<T>::voucher_account_id(&holder, &program_id);
let voucher_id = GearVoucher::<T>::voucher_id(&holder, &program_id);
assert_eq!(
CurrencyOf::<T>::free_balance(&voucher_account_id),
CurrencyOf::<T>::free_balance(&voucher_id),
10_000_000_000_000_u128.unique_saturated_into(),
);
}
Expand Down
54 changes: 32 additions & 22 deletions pallets/gear-voucher/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ mod mock;
#[cfg(test)]
mod tests;

use common::PaymentVoucher;
use frame_support::{
pallet_prelude::*,
traits::{Currency, ExistenceRequirement, ReservableCurrency, StorageVersion},
Expand All @@ -82,7 +81,9 @@ const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
#[frame_support::pallet]
pub mod pallet {
use super::*;
use common::storage::Mailbox;
use frame_system::pallet_prelude::*;
use gear_core::message::UserStoredMessage;

#[pallet::config]
pub trait Config: frame_system::Config {
Expand All @@ -103,6 +104,8 @@ pub mod pallet {
AccountId = Self::AccountId,
Balance = BalanceOf<Self>,
>;

type Mailbox: Mailbox<Key1 = Self::AccountId, Key2 = MessageId, Value = UserStoredMessage>;
}

#[pallet::pallet]
Expand All @@ -124,8 +127,8 @@ pub mod pallet {
// Gas pallet error.
#[pallet::error]
pub enum Error<T> {
FailureToCreateVoucher,
FailureToRedeemVoucher,
InsufficientBalance,
InvalidVoucher,
breathx marked this conversation as resolved.
Show resolved Hide resolved
}

#[pallet::hooks]
Expand Down Expand Up @@ -158,13 +161,13 @@ pub mod pallet {
let to = T::Lookup::lookup(to)?;

// Generate unique account id corresponding to the pair (user, program)
let voucher_id = Self::voucher_account_id(&to, &program);
let voucher_id = Self::voucher_id(&to, &program);

// Transfer funds to the keyless account
T::Currency::transfer(&who, &voucher_id, value, ExistenceRequirement::KeepAlive)
.map_err(|e| {
log::debug!("Failed to transfer funds to the voucher account: {:?}", e);
Error::<T>::FailureToCreateVoucher
Error::<T>::InsufficientBalance
})?;

Self::deposit_event(Event::VoucherIssued {
Expand All @@ -185,27 +188,33 @@ pub mod pallet {
) -> DispatchResultWithPostInfo {
let origin = ensure_signed(origin)?;

T::CallsDispatcher::dispatch(origin, call)
let sponsor = Self::sponsor_of(&origin, &call).ok_or(Error::<T>::InvalidVoucher)?;

T::CallsDispatcher::dispatch(origin, sponsor, call)
}
}
}

impl<T: Config> Pallet<T> {
/// Derive a synthesized account ID from an account ID and a program ID.
pub fn voucher_account_id(who: &T::AccountId, program_id: &ProgramId) -> T::AccountId {
let entropy = (b"modlpy/voucher__", who, program_id).using_encoded(blake2_256);
Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref()))
.expect("infinite length input; no invalid inputs for type; qed")
}
}

impl<T: Config> PaymentVoucher<T::AccountId, ProgramId, BalanceOf<T>> for Pallet<T> {
type VoucherId = T::AccountId;
type Error = DispatchError;
impl<T: Config> Pallet<T> {
/// Derive a synthesized account ID from an account ID and a program ID.
pub fn voucher_id(who: &T::AccountId, program_id: &ProgramId) -> T::AccountId {
let entropy = (b"modlpy/voucher__", who, program_id).using_encoded(blake2_256);
Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref()))
.expect("infinite length input; no invalid inputs for type; qed")
}

#[inline]
fn voucher_id(who: T::AccountId, program: ProgramId) -> Self::VoucherId {
Self::voucher_account_id(&who, &program)
/// Return synthesized account ID based on call data.
pub fn sponsor_of(
who: &T::AccountId,
call: &PrepaidCall<BalanceOf<T>>,
) -> Option<T::AccountId> {
match call {
PrepaidCall::SendMessage { destination, .. } => {
Some(Self::voucher_id(who, destination))
}
PrepaidCall::SendReply { reply_to_id, .. } => T::Mailbox::peek(who, reply_to_id)
.map(|stored_message| Self::voucher_id(who, &stored_message.source())),
}
}
}
}

Expand Down Expand Up @@ -235,6 +244,7 @@ pub trait PrepaidCallsDispatcher {

fn dispatch(
account_id: Self::AccountId,
sponsor_id: Self::AccountId,
call: PrepaidCall<Self::Balance>,
) -> DispatchResultWithPostInfo;
}
34 changes: 34 additions & 0 deletions pallets/gear-voucher/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use crate as pallet_gear_voucher;
use common::storage::{Interval, Mailbox};
use frame_support::{
construct_runtime, parameter_types, weights::constants::RocksDbWeight, PalletId,
};
use frame_system as system;
use gear_core::{ids::MessageId, message::UserStoredMessage};
use primitive_types::H256;
use sp_runtime::{
generic,
Expand Down Expand Up @@ -71,18 +73,50 @@ impl crate::PrepaidCallsDispatcher for () {
}
fn dispatch(
_account_id: Self::AccountId,
_sponsor_id: Self::AccountId,
_call: pallet_gear_voucher::PrepaidCall<Balance>,
) -> frame_support::pallet_prelude::DispatchResultWithPostInfo {
unimplemented!()
}
}

pub struct MailboxMock;

impl Mailbox for MailboxMock {
type BlockNumber = ();
type Error = ();
type Key1 = AccountId;
type Key2 = MessageId;
type Value = UserStoredMessage;
type OutputError = ();

fn clear() {
unimplemented!()
}
fn contains(_key1: &Self::Key1, _key2: &Self::Key2) -> bool {
unimplemented!()
}
fn insert(_value: Self::Value, _bn: Self::BlockNumber) -> Result<(), Self::OutputError> {
unimplemented!()
}
fn peek(_key1: &Self::Key1, _key2: &Self::Key2) -> Option<Self::Value> {
unimplemented!()
}
fn remove(
_key1: Self::Key1,
_key2: Self::Key2,
) -> Result<(Self::Value, Interval<Self::BlockNumber>), Self::OutputError> {
unimplemented!()
}
}

impl pallet_gear_voucher::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type PalletId = VoucherPalletId;
type WeightInfo = ();
type CallsDispatcher = ();
type Mailbox = MailboxMock;
}

// Build genesis storage according to the mock runtime.
Expand Down
10 changes: 5 additions & 5 deletions pallets/gear-voucher/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use primitive_types::H256;
fn voucher_issue_works() {
new_test_ext().execute_with(|| {
let program_id = H256::from(b"some//quasy//random//program//id").cast();
let synthesized = Voucher::voucher_account_id(&BOB, &program_id);
let synthesized = Voucher::voucher_id(&BOB, &program_id);

assert_ok!(Voucher::issue(
RuntimeOrigin::signed(ALICE),
Expand All @@ -47,7 +47,7 @@ fn voucher_issue_works() {
// Insufficient funds
assert_noop!(
Voucher::issue(RuntimeOrigin::signed(ALICE), BOB, program_id, 100_000_000,),
Error::<Test>::FailureToCreateVoucher
Error::<Test>::InsufficientBalance
);
});
}
Expand All @@ -56,7 +56,7 @@ fn voucher_issue_works() {
fn voucher_redemption_works() {
new_test_ext().execute_with(|| {
let program_id = H256::from(b"some//quasy//random//program//id").cast();
let synthesized = Voucher::voucher_account_id(&BOB, &program_id);
let synthesized = Voucher::voucher_id(&BOB, &program_id);

assert_ok!(Voucher::issue(
RuntimeOrigin::signed(ALICE),
Expand All @@ -69,13 +69,13 @@ fn voucher_redemption_works() {

// Redemption ok
assert_ok!(Balances::reserve(
&Voucher::voucher_id(BOB, program_id),
&Voucher::voucher_id(&BOB, &program_id),
2_000
));

// Redemption fails
assert_noop!(
Balances::reserve(&Voucher::voucher_id(BOB, program_id), 100_000_000),
Balances::reserve(&Voucher::voucher_id(&BOB, &program_id), 100_000_000),
pallet_balances::Error::<Test>::InsufficientBalance
);
});
Expand Down
Loading