Skip to content

Commit

Permalink
Changes to sponsored fee ext
Browse files Browse the repository at this point in the history
Signed-off-by: georgepisaltu <[email protected]>
  • Loading branch information
georgepisaltu committed Mar 29, 2024
1 parent 3b639cd commit e508c32
Show file tree
Hide file tree
Showing 8 changed files with 861 additions and 185 deletions.
673 changes: 576 additions & 97 deletions polkadot/runtime/westend/src/lib.rs

Large diffs are not rendered by default.

180 changes: 159 additions & 21 deletions substrate/frame/support/src/transaction_extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,67 +94,205 @@ where

/// Transaction extension that sets the origin to the given account ID if the provided signature by
/// that account is valid for all subsequent extensions. If signature is not provided, this
/// extension is no-op.
/// extension is no-op. Will run wrapped extension logic after the origin validation.
// TODO better doc.
#[derive(
CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, RuntimeDebugNoBound, TypeInfo,
)]
#[codec(encode_bound())]
#[codec(decode_bound())]
pub struct SignedOriginSignature<V: Verify>
pub struct SignedOriginSignature<V: Verify, InnerTx>
where
V: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
<V::Signer as IdentifyAccount>::AccountId:
Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
InnerTx: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
{
signature: Option<(V, <V::Signer as IdentifyAccount>::AccountId)>,
pub signature: Option<(V, <V::Signer as IdentifyAccount>::AccountId)>,
pub extension: InnerTx,
}

impl<V: Verify> Default for SignedOriginSignature<V>
impl<V: Verify, InnerTx> SignedOriginSignature<V, InnerTx>
where
V: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
<V::Signer as IdentifyAccount>::AccountId:
Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
InnerTx: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
{
fn default() -> Self {
Self { signature: None }
pub fn new_with_sign(
signature: V,
account_id: <V::Signer as IdentifyAccount>::AccountId,
extension: InnerTx,
) -> Self {
Self { signature: Some((signature, account_id)), extension }
}
}

impl<V: Verify> SignedOriginSignature<V>
impl<V: Verify, InnerTx> TransactionExtensionBase for SignedOriginSignature<V, InnerTx>
where
V: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
<V::Signer as IdentifyAccount>::AccountId:
Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
InnerTx: Codec
+ Debug
+ Sync
+ Send
+ Clone
+ Eq
+ PartialEq
+ StaticTypeInfo
+ TransactionExtensionBase,
{
const IDENTIFIER: &'static str = "SignedOriginSignature";
type Implicit = ();
}

impl<V: Verify, Call: Dispatchable + Encode + Clone, Context, InnerTx>
TransactionExtension<Call, Context> for SignedOriginSignature<V, InnerTx>
where
V: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
<V::Signer as IdentifyAccount>::AccountId:
Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
<Call as Dispatchable>::RuntimeOrigin: From<Option<<V::Signer as IdentifyAccount>::AccountId>>,
InnerTx: Codec
+ Debug
+ Sync
+ Send
+ Clone
+ Eq
+ PartialEq
+ StaticTypeInfo
+ TransactionExtension<Call, Context>,
{
type Val = InnerTx::Val;
type Pre = InnerTx::Pre;

fn validate(
&self,
origin: <Call as Dispatchable>::RuntimeOrigin,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
context: &mut Context,
_self_implicit: (),
inherited_implication: &impl Encode,
) -> Result<
(ValidTransaction, Self::Val, <Call as Dispatchable>::RuntimeOrigin),
TransactionValidityError,
> {
let (signature, account_id) = match &self.signature {
Some((s, a)) => (s, a.clone()), // TODO check if origin None
None => {
let implicit = self.extension.implicit()?;
return self.extension.validate(
origin,
call,
info,
len,
context,
implicit,
inherited_implication,
)
},
};

let implicit = self.extension.implicit()?;
let signed_payload = (call, &self.extension, &implicit);
if !signed_payload
.using_encoded(|payload| signature.verify(&blake2_256(payload)[..], &account_id))
{
return Err(InvalidTransaction::BadProof.into())
}

let origin = Some(account_id).into();
self.extension
.validate(origin, call, info, len, context, implicit, inherited_implication)
}

fn prepare(
self,
val: Self::Val,
origin: &sp_runtime::traits::OriginOf<Call>,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
context: &Context,
) -> Result<Self::Pre, TransactionValidityError> {
self.extension.prepare(val, origin, call, info, len, context)
}

fn post_dispatch(
pre: Self::Pre,
info: &DispatchInfoOf<Call>,
post_info: &sp_runtime::traits::PostDispatchInfoOf<Call>,
len: usize,
result: &sp_runtime::DispatchResult,
context: &Context,
) -> Result<(), TransactionValidityError> {
InnerTx::post_dispatch(pre, info, post_info, len, result, context)
}
}

/// Transaction extension that sets the origin to the given account ID if the provided signature by
/// that account is valid for the provided payload.
#[derive(
CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, RuntimeDebugNoBound, TypeInfo,
)]
#[codec(encode_bound())]
#[codec(decode_bound())]
pub struct CheckSignedPayload<V: Verify, P: Encode>
where
V: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
<V::Signer as IdentifyAccount>::AccountId:
Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
P: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
{
pub signature: Option<(V, <V::Signer as IdentifyAccount>::AccountId, P)>,
}

impl<V: Verify, P: Encode> CheckSignedPayload<V, P>
where
V: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
<V::Signer as IdentifyAccount>::AccountId:
Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
P: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
{
pub fn new_with_sign(
signature: V,
account_id: <V::Signer as IdentifyAccount>::AccountId,
payload: P,
) -> Self {
Self { signature: Some((signature, account_id)) }
Self { signature: Some((signature, account_id, payload)) }
}

pub fn new() -> Self {
Self { signature: None }
}
}

impl<V: Verify> TransactionExtensionBase for SignedOriginSignature<V>
impl<V: Verify, P: Encode> TransactionExtensionBase for CheckSignedPayload<V, P>
where
V: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
<V::Signer as IdentifyAccount>::AccountId:
Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
P: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
{
const IDENTIFIER: &'static str = "SignedOriginSignature";
const IDENTIFIER: &'static str = "CheckSignedPayload";
type Implicit = ();
}

impl<V: Verify, Call: Dispatchable + Encode, Context> TransactionExtension<Call, Context>
for SignedOriginSignature<V>
impl<V: Verify, P: Encode, Call: Dispatchable + Encode + Clone, Context>
TransactionExtension<Call, Context> for CheckSignedPayload<V, P>
where
V: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
<V::Signer as IdentifyAccount>::AccountId:
Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
P: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo,
<Call as Dispatchable>::RuntimeOrigin: From<Option<<V::Signer as IdentifyAccount>::AccountId>>,
{
type Val = ();
type Pre = ();

impl_tx_ext_default!(Call; Context; prepare);

fn validate(
Expand All @@ -163,23 +301,23 @@ where
_call: &Call,
_info: &DispatchInfoOf<Call>,
_len: usize,
_: &mut Context,
_: (),
inherited_implication: &impl Encode,
_context: &mut Context,
_self_implicit: (),
_inherited_implication: &impl Encode,
) -> Result<
(ValidTransaction, Self::Val, <Call as Dispatchable>::RuntimeOrigin),
TransactionValidityError,
> {
let (signature, account_id) = match &self.signature {
Some((s, a)) => (s, a.clone()), // TODO check if origin None
let (signature, account_id, payload) = match &self.signature {
Some((s, a, p)) => (s, a.clone(), p), // TODO check if origin None
None => return Ok((ValidTransaction::default(), (), origin)),
};

let msg = inherited_implication.using_encoded(blake2_256);

if !signature.verify(&msg[..], &account_id) {
Err(InvalidTransaction::BadProof)?
if !payload.using_encoded(|payload| signature.verify(&blake2_256(payload)[..], &account_id))
{
return Err(InvalidTransaction::BadProof.into())
}

let origin = Some(account_id).into();
Ok((ValidTransaction::default(), (), origin))
}
Expand Down
30 changes: 23 additions & 7 deletions substrate/frame/transaction-payment/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::Pallet;
use frame_benchmarking::v2::*;
use frame_support::dispatch::{DispatchInfo, PostDispatchInfo};
use frame_system::{EventRecord, RawOrigin};
use sp_runtime::traits::{DispatchTransaction, Dispatchable};
use sp_runtime::traits::Dispatchable;

fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
let events = frame_system::Pallet::<T>::events();
Expand Down Expand Up @@ -60,15 +60,31 @@ mod benchmarks {
actual_weight: Some(Weight::from_parts(10, 0)),
pays_fee: Pays::Yes,
};
let mut context: Context<T::AccountId> = Context::default();

#[block]
{
assert!(ext
.test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 10, |_| Ok(
post_info
))
.unwrap()
.is_ok());
let (_, val, origin) = ext
.validate(
RawOrigin::Signed(caller.clone()).into(),
&call,
&info,
10,
&mut context,
(),
&call,
)
.unwrap();
let pre = ext.prepare(val, &origin, &call, &info, 10, &context).unwrap();
ChargeTransactionPayment::<T>::post_dispatch(
pre,
&info,
&post_info,
10,
&Ok(()),
&context,
)
.unwrap();
}

let actual_fee = Pallet::<T>::compute_actual_fee(10, &info, &post_info, tip);
Expand Down
Loading

0 comments on commit e508c32

Please sign in to comment.