diff --git a/substrate/abi/src/block.rs b/substrate/abi/src/block.rs index 93a8e4e8..301aa0d7 100644 --- a/substrate/abi/src/block.rs +++ b/substrate/abi/src/block.rs @@ -80,7 +80,6 @@ mod substrate { }; use super::*; - use crate::Call; /// The digest for all of the Serai-specific header fields. #[derive(Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize)] @@ -165,14 +164,10 @@ mod substrate { /// A block, as needed by Substrate. #[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, sp_runtime::Serialize)] - #[codec(encode_bound(skip_type_params(RuntimeCall)))] - #[codec(decode_bound(skip_type_params(RuntimeCall)))] - pub struct SubstrateBlock< - RuntimeCall: 'static + Send + Sync + Clone + PartialEq + Eq + Debug + From, - > { + pub struct SubstrateBlock { header: SubstrateHeader, #[serde(skip)] // This makes this unsafe to deserialize, but we don't impl `Deserialize` - transactions: Vec>, + transactions: Vec, } impl HeaderTrait for SubstrateHeader { @@ -266,16 +261,12 @@ mod substrate { } } - impl> - HeaderProvider for SubstrateBlock - { + impl HeaderProvider for SubstrateBlock { type HeaderT = SubstrateHeader; } - impl> BlockTrait - for SubstrateBlock - { - type Extrinsic = Transaction; + impl BlockTrait for SubstrateBlock { + type Extrinsic = Transaction; type Header = SubstrateHeader; type Hash = H256; fn header(&self) -> &Self::Header { diff --git a/substrate/abi/src/transaction.rs b/substrate/abi/src/transaction.rs index 33e6d2a8..4a4729db 100644 --- a/substrate/abi/src/transaction.rs +++ b/substrate/abi/src/transaction.rs @@ -104,20 +104,18 @@ pub struct ContextualizedSignature { /// The Serai transaction type. #[derive(Clone, PartialEq, Eq, Debug)] -pub struct Transaction = Call> { +pub struct Transaction { /// The calls, as defined in Serai's ABI. /// /// These calls are executed atomically. Either all successfully execute or none do. The /// transaction's fee is paid regardless. // TODO: if this is unsigned, we only allow a single call. Should we serialize that as 0? calls: BoundedVec>, - /// The calls, as defined by Substrate. - runtime_calls: Vec, /// The signature, if present. contextualized_signature: Option, } -impl> BorshSerialize for Transaction { +impl BorshSerialize for Transaction { fn serialize(&self, writer: &mut W) -> io::Result<()> { // Write the calls self.calls.serialize(writer)?; @@ -129,16 +127,11 @@ impl> BorshSerialize for Transaction> BorshDeserialize for Transaction { +impl BorshDeserialize for Transaction { fn deserialize_reader(reader: &mut R) -> io::Result { // Read the calls let calls = serai_primitives::sp_borsh::borsh_deserialize_bounded_vec::<_, Call, MAX_CALLS>(reader)?; - // Populate the runtime calls - let mut runtime_calls = Vec::with_capacity(calls.len()); - for call in calls.iter().cloned() { - runtime_calls.push(RuntimeCall::from(call)); - } // Determine if this is signed or unsigned let mut signed = None; @@ -159,11 +152,11 @@ impl> BorshDeserialize for Transaction::deserialize_reader(reader)?) } else { None }; - Ok(Transaction { calls, runtime_calls, contextualized_signature }) + Ok(Transaction { calls, contextualized_signature }) } } -impl> Transaction { +impl Transaction { /// The message to sign to produce a signature, for calls which may or may not be signed and are /// unchecked. fn signature_message_unchecked( @@ -198,13 +191,8 @@ impl> Transaction { signature: Signature, ) -> Self { let calls = calls.0; - let mut runtime_calls = Vec::with_capacity(calls.len()); - for call in calls.iter().cloned() { - runtime_calls.push(call.into()); - } Self { calls, - runtime_calls, contextualized_signature: Some(ContextualizedSignature { explicit_context, signature }), } } @@ -216,7 +204,6 @@ impl> Transaction { calls: vec![call.clone()] .try_into() .expect("couldn't convert a length-1 Vec to a BoundedVec"), - runtime_calls: vec![call.into()], contextualized_signature: None, } } @@ -242,12 +229,12 @@ mod substrate { use super::*; - impl> Encode for Transaction { + impl Encode for Transaction { fn encode(&self) -> Vec { borsh::to_vec(self).unwrap() } } - impl> Decode for Transaction { + impl Decode for Transaction { fn decode(input: &mut I) -> Result { struct ScaleRead<'a, I: scale::Input>(&'a mut I, Option); impl borsh::io::Read for ScaleRead<'_, I> { @@ -274,12 +261,19 @@ mod substrate { } /// The context which transactions are executed in. - pub trait TransactionContext>: - 'static + Send + Sync + Clone + PartialEq + Eq + Debug - { + pub trait TransactionContext: 'static + Send + Sync + Clone + PartialEq + Eq + Debug { /// The base weight for a signed transaction. const SIGNED_WEIGHT: Weight; + /// The call type for the runtime. + type RuntimeCall: From + + GetDispatchInfo + + Dispatchable< + RuntimeOrigin: From>, + Info = DispatchInfo, + PostInfo = PostDispatchInfo, + >; + /// The implicit context to verify transactions with. fn implicit_context() -> &'static ImplicitContext; @@ -297,12 +291,12 @@ mod substrate { /// A transaction with the context necessary to evaluate it within Substrate. #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)] - pub struct TransactionWithContext< - RuntimeCall: 'static + From, - Context: TransactionContext, - >(Transaction, #[codec(skip)] PhantomData); + pub struct TransactionWithContext( + Transaction, + #[codec(skip)] PhantomData, + ); - impl> ExtrinsicLike for Transaction { + impl ExtrinsicLike for Transaction { fn is_signed(&self) -> Option { Some(Transaction::is_signed(self)) } @@ -311,11 +305,7 @@ mod substrate { } } - impl< - RuntimeCall: 'static + From + GetDispatchInfo, - Context: TransactionContext, - > GetDispatchInfo for TransactionWithContext - { + impl GetDispatchInfo for TransactionWithContext { fn get_dispatch_info(&self) -> DispatchInfo { let (extension_weight, class, pays_fee) = if Transaction::is_signed(&self.0) { (Context::SIGNED_WEIGHT, DispatchClass::Normal, Pays::Yes) @@ -328,7 +318,7 @@ mod substrate { .calls .iter() .cloned() - .map(|call| RuntimeCall::from(call).get_dispatch_info().call_weight) + .map(|call| Context::RuntimeCall::from(call).get_dispatch_info().call_weight) .fold(Weight::zero(), |accum, item| accum + item), extension_weight, class, @@ -337,10 +327,8 @@ mod substrate { } } - impl, Context: TransactionContext> - Checkable for Transaction - { - type Checked = TransactionWithContext; + impl Checkable for Transaction { + type Checked = TransactionWithContext; fn check(self, context: &Context) -> Result { if let Some(ContextualizedSignature { explicit_context, signature }) = @@ -373,7 +361,7 @@ mod substrate { } } if !sp_core::sr25519::Signature::from(*signature).verify( - Transaction::::signature_message_unchecked( + Transaction::signature_message_unchecked( &self.calls, Context::implicit_context(), explicit_context, @@ -400,22 +388,10 @@ mod substrate { } } - impl< - RuntimeCall: 'static - + Send - + Sync - + From - + Dispatchable< - RuntimeOrigin: From>, - Info = DispatchInfo, - PostInfo = PostDispatchInfo, - >, - Context: TransactionContext, - > Applyable for TransactionWithContext - { - type Call = RuntimeCall; + impl Applyable for TransactionWithContext { + type Call = Context::RuntimeCall; - fn validate>( + fn validate>( &self, source: sp_runtime::transaction_validity::TransactionSource, info: &DispatchInfo, @@ -423,7 +399,7 @@ mod substrate { ) -> sp_runtime::transaction_validity::TransactionValidity { if !self.0.is_signed() { let ValidTransaction { priority: _, requires, provides, longevity: _, propagate: _ } = - V::validate_unsigned(source, &self.0.runtime_calls[0])?; + V::validate_unsigned(source, &Context::RuntimeCall::from(self.0.calls[0].clone()))?; Ok(ValidTransaction { // We should always try to include unsigned transactions prior to signed priority: u64::MAX, @@ -459,14 +435,15 @@ mod substrate { } } - fn apply>( + fn apply>( mut self, _info: &DispatchInfo, _len: usize, ) -> sp_runtime::ApplyExtrinsicResultWithInfo { if !self.0.is_signed() { - V::pre_dispatch(&self.0.runtime_calls[0])?; - match self.0.runtime_calls.remove(0).dispatch(None.into()) { + let call = Context::RuntimeCall::from(self.0.calls.remove(0)); + V::pre_dispatch(&call)?; + match call.dispatch(None.into()) { Ok(res) => Ok(Ok(res)), // Unsigned transactions should only be included if valid in all regards // This isn't actually a "mandatory" but the intent is the same @@ -474,7 +451,8 @@ mod substrate { } } else { Ok(frame_support::storage::transactional::with_storage_layer(|| { - for call in self.0.runtime_calls { + for call in self.0.calls { + let call = Context::RuntimeCall::from(call); match call.dispatch( Some(self.0.contextualized_signature.as_ref().unwrap().explicit_context.signer) .into(),