Skip to content

Commit 2c52885

Browse files
authored
Improve SignedExtension matching logic and remove SkipCheckIfFeeless bits (paritytech#1283)
* First pass making matching on signed exts more general and handlng SkipCheckifFeeless * remove unneeded derives (only exts we can decode into are handled by the user) * No SkipCheckIfFeeless in integration tests either * Cargo fmt * Remove SkipCheckIfFeeless specific logic * clippy * matches to just return bool, not result * remove now-invalid comment * return error from find if .iter() errors
1 parent 6855b1f commit 2c52885

File tree

8 files changed

+135
-380
lines changed

8 files changed

+135
-380
lines changed

subxt/examples/setup_config_custom.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use codec::Encode;
22
use subxt::client::OfflineClientT;
3-
use subxt::config::{Config, ExtrinsicParams, ExtrinsicParamsEncoder};
3+
use subxt::config::{Config, ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError};
44
use subxt_signer::sr25519::dev;
55

66
#[subxt::subxt(
@@ -66,14 +66,13 @@ impl CustomExtrinsicParamsBuilder {
6666
// Describe how to fetch and then encode the params:
6767
impl<T: Config> ExtrinsicParams<T> for CustomExtrinsicParams<T> {
6868
type OtherParams = CustomExtrinsicParamsBuilder;
69-
type Error = std::convert::Infallible;
7069

7170
// Gather together all of the params we will need to encode:
7271
fn new<Client: OfflineClientT<T>>(
7372
_nonce: u64,
7473
client: Client,
7574
other_params: Self::OtherParams,
76-
) -> Result<Self, Self::Error> {
75+
) -> Result<Self, ExtrinsicParamsError> {
7776
Ok(Self {
7877
genesis_hash: client.genesis_hash(),
7978
tip: other_params.tip,

subxt/examples/setup_config_signed_extension.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use codec::Encode;
22
use scale_encode::EncodeAsType;
3+
use scale_info::PortableRegistry;
34
use subxt::client::OfflineClientT;
45
use subxt::config::signed_extensions;
56
use subxt::config::{
67
Config, DefaultExtrinsicParamsBuilder, ExtrinsicParams, ExtrinsicParamsEncoder,
8+
ExtrinsicParamsError,
79
};
810
use subxt_signer::sr25519::dev;
911

@@ -34,10 +36,6 @@ impl Config for CustomConfig {
3436
signed_extensions::CheckMortality<Self>,
3537
signed_extensions::ChargeAssetTxPayment<Self>,
3638
signed_extensions::ChargeTransactionPayment,
37-
signed_extensions::SkipCheckIfFeeless<
38-
Self,
39-
signed_extensions::ChargeAssetTxPayment<Self>,
40-
>,
4139
// And add a new one of our own:
4240
CustomSignedExtension,
4341
),
@@ -51,20 +49,21 @@ pub struct CustomSignedExtension;
5149
// Give the extension a name; this allows `AnyOf` to look it
5250
// up in the chain metadata in order to know when and if to use it.
5351
impl<T: Config> signed_extensions::SignedExtension<T> for CustomSignedExtension {
54-
const NAME: &'static str = "CustomSignedExtension";
5552
type Decoded = ();
53+
fn matches(identifier: &str, _type_id: u32, _types: &PortableRegistry) -> bool {
54+
identifier == "CustomSignedExtension"
55+
}
5656
}
5757

5858
// Gather together any params we need for our signed extension, here none.
5959
impl<T: Config> ExtrinsicParams<T> for CustomSignedExtension {
6060
type OtherParams = ();
61-
type Error = std::convert::Infallible;
6261

6362
fn new<Client: OfflineClientT<T>>(
6463
_nonce: u64,
6564
_client: Client,
6665
_other_params: Self::OtherParams,
67-
) -> Result<Self, Self::Error> {
66+
) -> Result<Self, ExtrinsicParamsError> {
6867
Ok(CustomSignedExtension)
6968
}
7069
}
@@ -87,8 +86,8 @@ impl ExtrinsicParamsEncoder for CustomSignedExtension {
8786
pub fn custom(
8887
params: DefaultExtrinsicParamsBuilder<CustomConfig>,
8988
) -> <<CustomConfig as Config>::ExtrinsicParams as ExtrinsicParams<CustomConfig>>::OtherParams {
90-
let (a, b, c, d, e, f, g, h) = params.build();
91-
(a, b, c, d, e, f, g, h, ())
89+
let (a, b, c, d, e, f, g) = params.build();
90+
(a, b, c, d, e, f, g, ())
9291
}
9392

9493
#[tokio::main]

subxt/src/blocks/extrinsic_types.rs

+26-33
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::{
1313
};
1414

1515
use crate::config::signed_extensions::{
16-
ChargeAssetTxPayment, ChargeTransactionPayment, CheckNonce, SkipCheckIfFeeless,
16+
ChargeAssetTxPayment, ChargeTransactionPayment, CheckNonce,
1717
};
1818
use crate::config::SignedExtension;
1919
use crate::dynamic::DecodedValue;
@@ -660,24 +660,24 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> {
660660
})
661661
}
662662

663-
fn find_by_name(&self, name: &str) -> Option<ExtrinsicSignedExtension<'_, T>> {
664-
let signed_extension = self
665-
.iter()
666-
.find_map(|e| e.ok().filter(|e| e.name() == name))?;
667-
Some(signed_extension)
668-
}
669-
670663
/// Searches through all signed extensions to find a specific one.
671664
/// If the Signed Extension is not found `Ok(None)` is returned.
672665
/// If the Signed Extension is found but decoding failed `Err(_)` is returned.
673666
pub fn find<S: SignedExtension<T>>(&self) -> Result<Option<S::Decoded>, Error> {
674-
self.find_by_name(S::NAME)
675-
.map(|s| {
676-
s.as_signed_extra::<S>().map(|e| {
677-
e.expect("signed extra name is correct, because it was found before; qed.")
678-
})
679-
})
680-
.transpose()
667+
for ext in self.iter() {
668+
// If we encounter an error while iterating, we won't get any more results
669+
// back, so just return that error as we won't find the signed ext anyway.
670+
let ext = ext?;
671+
match ext.as_signed_extension::<S>() {
672+
// We found a match; return it:
673+
Ok(Some(e)) => return Ok(Some(e)),
674+
// No error, but no match either; next!
675+
Ok(None) => continue,
676+
// Error? return it
677+
Err(e) => return Err(e),
678+
}
679+
}
680+
Ok(None)
681681
}
682682

683683
/// The tip of an extrinsic, extracted from the ChargeTransactionPayment or ChargeAssetTxPayment
@@ -696,20 +696,13 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> {
696696
.flatten()
697697
.map(|e| e.tip())
698698
})
699-
.or_else(|| {
700-
self.find::<SkipCheckIfFeeless<T, ChargeAssetTxPayment<T>>>()
701-
.ok()
702-
.flatten()
703-
.map(|skip_check| skip_check.inner_signed_extension().tip())
704-
})
705699
}
706700

707701
/// The nonce of the account that submitted the extrinsic, extracted from the CheckNonce signed extension.
708702
///
709703
/// Returns `None` if `nonce` was not found or decoding failed.
710704
pub fn nonce(&self) -> Option<u64> {
711-
let nonce = self.find::<CheckNonce>().ok()??.0;
712-
Some(nonce)
705+
self.find::<CheckNonce>().ok()?
713706
}
714707
}
715708

@@ -744,20 +737,20 @@ impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> {
744737
self.as_type()
745738
}
746739

747-
/// Decodes the `extra` bytes of this Signed Extension into a static type.
748-
fn as_type<E: DecodeAsType>(&self) -> Result<E, Error> {
749-
let value = E::decode_as_type(&mut &self.bytes[..], self.ty_id, self.metadata.types())?;
750-
Ok(value)
751-
}
752-
753-
/// Decodes the `extra` bytes of this Signed Extension into its associated `Decoded` type.
754-
/// Returns `Ok(None)` if the identitfier of this Signed Extension object does not line up with the `NAME` constant of the provided Signed Extension type.
755-
pub fn as_signed_extra<S: SignedExtension<T>>(&self) -> Result<Option<S::Decoded>, Error> {
756-
if self.identifier != S::NAME {
740+
/// Decodes the bytes of this Signed Extension into its associated `Decoded` type.
741+
/// Returns `Ok(None)` if the data we have doesn't match the Signed Extension we're asking to
742+
/// decode with.
743+
pub fn as_signed_extension<S: SignedExtension<T>>(&self) -> Result<Option<S::Decoded>, Error> {
744+
if !S::matches(self.identifier, self.ty_id, self.metadata.types()) {
757745
return Ok(None);
758746
}
759747
self.as_type::<S::Decoded>().map(Some)
760748
}
749+
750+
fn as_type<E: DecodeAsType>(&self) -> Result<E, Error> {
751+
let value = E::decode_as_type(&mut &self.bytes[..], self.ty_id, self.metadata.types())?;
752+
Ok(value)
753+
}
761754
}
762755

763756
#[cfg(test)]

subxt/src/config/default_extrinsic_params.rs

-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ pub type DefaultExtrinsicParams<T> = signed_extensions::AnyOf<
1717
signed_extensions::CheckMortality<T>,
1818
signed_extensions::ChargeAssetTxPayment<T>,
1919
signed_extensions::ChargeTransactionPayment,
20-
signed_extensions::SkipCheckIfFeeless<T, signed_extensions::ChargeAssetTxPayment<T>>,
2120
),
2221
>;
2322

@@ -132,9 +131,6 @@ impl<T: Config> DefaultExtrinsicParamsBuilder<T> {
132131
let charge_transaction_params =
133132
signed_extensions::ChargeTransactionPaymentParams::tip(self.tip);
134133

135-
let skip_check_params =
136-
signed_extensions::SkipCheckIfFeelessParams::from(charge_asset_tx_params.clone());
137-
138134
(
139135
(),
140136
(),
@@ -143,7 +139,6 @@ impl<T: Config> DefaultExtrinsicParamsBuilder<T> {
143139
check_mortality_params,
144140
charge_asset_tx_params,
145141
charge_transaction_params,
146-
skip_check_params,
147142
)
148143
}
149144
}

subxt/src/config/extrinsic_params.rs

+23-24
Original file line numberDiff line numberDiff line change
@@ -10,39 +10,41 @@
1010
use crate::{client::OfflineClientT, Config};
1111
use core::fmt::Debug;
1212

13-
/// An error that can be emitted when trying to construct
14-
/// an instance of [`ExtrinsicParams`].
13+
/// An error that can be emitted when trying to construct an instance of [`ExtrinsicParams`],
14+
/// encode data from the instance, or match on signed extensions.
1515
#[derive(thiserror::Error, Debug)]
1616
#[non_exhaustive]
1717
pub enum ExtrinsicParamsError {
18-
/// A signed extension was encountered that we don't know about.
19-
#[error("Error constructing extrinsic parameters: Unknown signed extension '{0}'")]
18+
/// Cannot find a type id in the metadata. The context provides some additional
19+
/// information about the source of the error (eg the signed extension name).
20+
#[error("Cannot find type id '{type_id} in the metadata (context: {context})")]
21+
MissingTypeId {
22+
/// Type ID.
23+
type_id: u32,
24+
/// Some arbitrary context to help narrow the source of the error.
25+
context: &'static str,
26+
},
27+
/// A signed extension in use on some chain was not provided.
28+
#[error("The chain expects a signed extension with the name {0}, but we did not provide one")]
2029
UnknownSignedExtension(String),
21-
/// Cannot find the type id of a signed extension in the metadata.
22-
#[error("Cannot find extension's '{0}' type id '{1} in the metadata")]
23-
MissingTypeId(String, u32),
24-
/// User provided a different signed extension than the one expected.
25-
#[error("Provided a different signed extension for '{0}', the metadata expect '{1}'")]
26-
ExpectedAnotherExtension(String, String),
27-
/// The inner type of a signed extension is not present in the metadata.
28-
#[error("The inner type of the signed extension '{0}' is not present in the metadata")]
29-
MissingInnerSignedExtension(String),
30-
/// The inner type of the signed extension is not named.
31-
#[error("The signed extension's '{0}' type id '{1}' does not have a name in the metadata")]
32-
ExpectedNamedTypeId(String, u32),
33-
/// Some custom error.s
30+
/// Some custom error.
3431
#[error("Error constructing extrinsic parameters: {0}")]
35-
Custom(CustomError),
32+
Custom(CustomExtrinsicParamsError),
3633
}
3734

3835
/// A custom error.
39-
type CustomError = Box<dyn std::error::Error + Send + Sync + 'static>;
36+
pub type CustomExtrinsicParamsError = Box<dyn std::error::Error + Send + Sync + 'static>;
4037

4138
impl From<std::convert::Infallible> for ExtrinsicParamsError {
4239
fn from(value: std::convert::Infallible) -> Self {
4340
match value {}
4441
}
4542
}
43+
impl From<CustomExtrinsicParamsError> for ExtrinsicParamsError {
44+
fn from(value: CustomExtrinsicParamsError) -> Self {
45+
ExtrinsicParamsError::Custom(value)
46+
}
47+
}
4648

4749
/// This trait allows you to configure the "signed extra" and
4850
/// "additional" parameters that are a part of the transaction payload
@@ -53,15 +55,12 @@ pub trait ExtrinsicParams<T: Config>: ExtrinsicParamsEncoder + Sized + 'static {
5355
/// help construct your [`ExtrinsicParams`] object.
5456
type OtherParams;
5557

56-
/// The type of error returned from [`ExtrinsicParams::new()`].
57-
type Error: Into<ExtrinsicParamsError>;
58-
59-
/// Construct a new instance of our [`ExtrinsicParams`]
58+
/// Construct a new instance of our [`ExtrinsicParams`].
6059
fn new<Client: OfflineClientT<T>>(
6160
nonce: u64,
6261
client: Client,
6362
other_params: Self::OtherParams,
64-
) -> Result<Self, Self::Error>;
63+
) -> Result<Self, ExtrinsicParamsError>;
6564
}
6665

6766
/// This trait is expected to be implemented for any [`ExtrinsicParams`], and

0 commit comments

Comments
 (0)