pub trait SignedExtension: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo {
    type AccountId;
    type Call: Dispatchable;
    type AdditionalSigned: Encode + TypeInfo;
    type Pre;

    const IDENTIFIER: &'static str;

    fn additional_signed(
        &self
    ) -> Result<Self::AdditionalSigned, TransactionValidityError>; fn pre_dispatch(
        self,
        who: &Self::AccountId,
        call: &Self::Call,
        info: &DispatchInfoOf<Self::Call>,
        len: usize
    ) -> Result<Self::Pre, TransactionValidityError>; fn validate(
        &self,
        _who: &Self::AccountId,
        _call: &Self::Call,
        _info: &DispatchInfoOf<Self::Call>,
        _len: usize
    ) -> TransactionValidity { ... } fn validate_unsigned(
        _call: &Self::Call,
        _info: &DispatchInfoOf<Self::Call>,
        _len: usize
    ) -> TransactionValidity { ... } fn pre_dispatch_unsigned(
        call: &Self::Call,
        info: &DispatchInfoOf<Self::Call>,
        len: usize
    ) -> Result<(), TransactionValidityError> { ... } fn post_dispatch(
        _pre: Option<Self::Pre>,
        _info: &DispatchInfoOf<Self::Call>,
        _post_info: &PostDispatchInfoOf<Self::Call>,
        _len: usize,
        _result: &DispatchResult
    ) -> Result<(), TransactionValidityError> { ... } fn metadata() -> Vec<SignedExtensionMetadata> { ... } }
Expand description

Means by which a transaction may be extended. This type embodies both the data and the logic that should be additionally associated with the transaction. It should be plain old data.

Required Associated Types§

The type which encodes the sender identity.

The type which encodes the call to be dispatched.

Any additional data that will go into the signed payload. This may be created dynamically from the transaction using the additional_signed function.

The type that encodes information that can be passed from pre_dispatch to post-dispatch.

Required Associated Constants§

Unique identifier of this signed extension.

This will be exposed in the metadata to identify the signed extension used in an extrinsic.

Required Methods§

Construct any additional data that should be in the signed payload of the transaction. Can also perform any pre-signature-verification checks and return an error if needed.

Do any pre-flight stuff for a signed transaction.

Make sure to perform the same checks as in Self::validate.

Provided Methods§

Validate a signed transaction for the transaction queue.

This function can be called frequently by the transaction queue, to obtain transaction validity against current state. It should perform all checks that determine a valid transaction, that can pay for its execution and quickly eliminate ones that are stale or incorrect.

Make sure to perform the same checks in pre_dispatch function.

Examples found in repository?
src/traits.rs (line 1241)
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
	fn validate(
		&self,
		who: &Self::AccountId,
		call: &Self::Call,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> TransactionValidity {
		let valid = ValidTransaction::default();
		for_tuples!( #( let valid = valid.combine_with(Tuple.validate(who, call, info, len)?); )* );
		Ok(valid)
	}

	fn pre_dispatch(
		self,
		who: &Self::AccountId,
		call: &Self::Call,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> Result<Self::Pre, TransactionValidityError> {
		Ok(for_tuples!( ( #( Tuple.pre_dispatch(who, call, info, len)? ),* ) ))
	}

	fn validate_unsigned(
		call: &Self::Call,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> TransactionValidity {
		let valid = ValidTransaction::default();
		for_tuples!( #( let valid = valid.combine_with(Tuple::validate_unsigned(call, info, len)?); )* );
		Ok(valid)
	}

	fn pre_dispatch_unsigned(
		call: &Self::Call,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> Result<(), TransactionValidityError> {
		for_tuples!( #( Tuple::pre_dispatch_unsigned(call, info, len)?; )* );
		Ok(())
	}

	fn post_dispatch(
		pre: Option<Self::Pre>,
		info: &DispatchInfoOf<Self::Call>,
		post_info: &PostDispatchInfoOf<Self::Call>,
		len: usize,
		result: &DispatchResult,
	) -> Result<(), TransactionValidityError> {
		match pre {
			Some(x) => {
				for_tuples!( #( Tuple::post_dispatch(Some(x.Tuple), info, post_info, len, result)?; )* );
			},
			None => {
				for_tuples!( #( Tuple::post_dispatch(None, info, post_info, len, result)?; )* );
			},
		}
		Ok(())
	}

	fn metadata() -> Vec<SignedExtensionMetadata> {
		let mut ids = Vec::new();
		for_tuples!( #( ids.extend(Tuple::metadata()); )* );
		ids
	}
}

/// Only for bare bone testing when you don't care about signed extensions at all.
#[cfg(feature = "std")]
impl SignedExtension for () {
	type AccountId = u64;
	type AdditionalSigned = ();
	type Call = ();
	type Pre = ();
	const IDENTIFIER: &'static str = "UnitSignedExtension";
	fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {
		Ok(())
	}
	fn pre_dispatch(
		self,
		who: &Self::AccountId,
		call: &Self::Call,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> Result<Self::Pre, TransactionValidityError> {
		self.validate(who, call, info, len).map(|_| ())
	}
More examples
Hide additional examples
src/testing.rs (line 385)
378
379
380
381
382
383
384
385
386
387
388
389
390
391
	fn validate<U: ValidateUnsigned<Call = Self::Call>>(
		&self,
		source: TransactionSource,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> TransactionValidity {
		if let Some((ref id, ref extra)) = self.signature {
			Extra::validate(extra, id, &self.call, info, len)
		} else {
			let valid = Extra::validate_unsigned(&self.call, info, len)?;
			let unsigned_validation = U::validate_unsigned(source, &self.call)?;
			Ok(valid.combine_with(unsigned_validation))
		}
	}
src/generic/checked_extrinsic.rs (line 61)
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
	fn validate<U: ValidateUnsigned<Call = Self::Call>>(
		&self,
		// TODO [#5006;ToDr] should source be passed to `SignedExtension`s?
		// Perhaps a change for 2.0 to avoid breaking too much APIs?
		source: TransactionSource,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> TransactionValidity {
		if let Some((ref id, ref extra)) = self.signed {
			Extra::validate(extra, id, &self.function, info, len)
		} else {
			let valid = Extra::validate_unsigned(&self.function, info, len)?;
			let unsigned_validation = U::validate_unsigned(source, &self.function)?;
			Ok(valid.combine_with(unsigned_validation))
		}
	}

Validate an unsigned transaction for the transaction queue.

This function can be called frequently by the transaction queue to obtain transaction validity against current state. It should perform all checks that determine a valid unsigned transaction, and quickly eliminate ones that are stale or incorrect.

Make sure to perform the same checks in pre_dispatch_unsigned function.

Examples found in repository?
src/traits.rs (line 1164)
1159
1160
1161
1162
1163
1164
1165
	fn pre_dispatch_unsigned(
		call: &Self::Call,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> Result<(), TransactionValidityError> {
		Self::validate_unsigned(call, info, len).map(|_| ()).map_err(Into::into)
	}
More examples
Hide additional examples
src/testing.rs (line 387)
378
379
380
381
382
383
384
385
386
387
388
389
390
391
	fn validate<U: ValidateUnsigned<Call = Self::Call>>(
		&self,
		source: TransactionSource,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> TransactionValidity {
		if let Some((ref id, ref extra)) = self.signature {
			Extra::validate(extra, id, &self.call, info, len)
		} else {
			let valid = Extra::validate_unsigned(&self.call, info, len)?;
			let unsigned_validation = U::validate_unsigned(source, &self.call)?;
			Ok(valid.combine_with(unsigned_validation))
		}
	}
src/generic/checked_extrinsic.rs (line 63)
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
	fn validate<U: ValidateUnsigned<Call = Self::Call>>(
		&self,
		// TODO [#5006;ToDr] should source be passed to `SignedExtension`s?
		// Perhaps a change for 2.0 to avoid breaking too much APIs?
		source: TransactionSource,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> TransactionValidity {
		if let Some((ref id, ref extra)) = self.signed {
			Extra::validate(extra, id, &self.function, info, len)
		} else {
			let valid = Extra::validate_unsigned(&self.function, info, len)?;
			let unsigned_validation = U::validate_unsigned(source, &self.function)?;
			Ok(valid.combine_with(unsigned_validation))
		}
	}

Do any pre-flight stuff for a unsigned transaction.

Note this function by default delegates to validate_unsigned, so that all checks performed for the transaction queue are also performed during the dispatch phase (applying the extrinsic).

If you ever override this function, you need to make sure to always perform the same validation as in validate_unsigned.

Examples found in repository?
src/testing.rs (line 404)
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
	fn apply<U: ValidateUnsigned<Call = Self::Call>>(
		self,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Self::Call>> {
		let maybe_who = if let Some((who, extra)) = self.signature {
			Extra::pre_dispatch(extra, &who, &self.call, info, len)?;
			Some(who)
		} else {
			Extra::pre_dispatch_unsigned(&self.call, info, len)?;
			U::pre_dispatch(&self.call)?;
			None
		};

		Ok(self.call.dispatch(maybe_who.into()))
	}
More examples
Hide additional examples
src/generic/checked_extrinsic.rs (line 78)
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
	fn apply<U: ValidateUnsigned<Call = Self::Call>>(
		self,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> crate::ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Self::Call>> {
		let (maybe_who, maybe_pre) = if let Some((id, extra)) = self.signed {
			let pre = Extra::pre_dispatch(extra, &id, &self.function, info, len)?;
			(Some(id), Some(pre))
		} else {
			Extra::pre_dispatch_unsigned(&self.function, info, len)?;
			U::pre_dispatch(&self.function)?;
			(None, None)
		};
		let res = self.function.dispatch(RuntimeOrigin::from(maybe_who));
		let post_info = match res {
			Ok(info) => info,
			Err(err) => err.post_info,
		};
		Extra::post_dispatch(
			maybe_pre,
			info,
			&post_info,
			len,
			&res.map(|_| ()).map_err(|e| e.error),
		)?;
		Ok(res)
	}

Do any post-flight stuff for an extrinsic.

If the transaction is signed, then _pre will contain the output of pre_dispatch, and None otherwise.

This gets given the DispatchResult _result from the extrinsic and can, if desired, introduce a TransactionValidityError, causing the block to become invalid for including it.

WARNING: It is dangerous to return an error here. To do so will fundamentally invalidate the transaction and any block that it is included in, causing the block author to not be compensated for their work in validating the transaction or producing the block so far.

It can only be used safely when you know that the extrinsic is one that can only be introduced by the current block author; generally this implies that it is an inherent and will come from either an offchain-worker or via InherentData.

Examples found in repository?
src/generic/checked_extrinsic.rs (lines 87-93)
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
	fn apply<U: ValidateUnsigned<Call = Self::Call>>(
		self,
		info: &DispatchInfoOf<Self::Call>,
		len: usize,
	) -> crate::ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Self::Call>> {
		let (maybe_who, maybe_pre) = if let Some((id, extra)) = self.signed {
			let pre = Extra::pre_dispatch(extra, &id, &self.function, info, len)?;
			(Some(id), Some(pre))
		} else {
			Extra::pre_dispatch_unsigned(&self.function, info, len)?;
			U::pre_dispatch(&self.function)?;
			(None, None)
		};
		let res = self.function.dispatch(RuntimeOrigin::from(maybe_who));
		let post_info = match res {
			Ok(info) => info,
			Err(err) => err.post_info,
		};
		Extra::post_dispatch(
			maybe_pre,
			info,
			&post_info,
			len,
			&res.map(|_| ()).map_err(|e| e.error),
		)?;
		Ok(res)
	}

Returns the metadata for this signed extension.

As a SignedExtension can be a tuple of SignedExtensions we need to return a Vec that holds the metadata of each one. Each individual SignedExtension must return exactly one SignedExtensionMetadata.

This method provides a default implementation that returns a vec containing a single SignedExtensionMetadata.

Implementations on Foreign Types§

Only for bare bone testing when you don’t care about signed extensions at all.

Implementors§